Add display filters.
[metze/wireshark/wip.git] / packet-dns.c
1 /* packet-dns.c
2  * Routines for DNS packet disassembly
3  *
4  * $Id: packet-dns.c,v 1.25 1999/10/16 15:08:11 deniel Exp $
5  *
6  * Ethereal - Network traffic analyzer
7  * By Gerald Combs <gerald@zing.org>
8  * Copyright 1998 Gerald Combs
9  *
10  * 
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  * 
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  * 
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
24  */
25
26 #ifdef HAVE_CONFIG_H
27 # include "config.h"
28 #endif
29
30 #ifdef HAVE_SYS_TYPES_H
31 # include <sys/types.h>
32 #endif
33
34 #include <stdio.h>
35 #include <string.h>
36 #include <memory.h>
37
38 #include <glib.h>
39 #include "packet.h"
40 #include "packet-dns.h"
41 #include "util.h"
42
43 static int proto_dns = -1;
44 static int hf_dns_response = -1;
45 static int hf_dns_query = -1;
46 static int hf_dns_flags = -1;
47 static int hf_dns_transaction_id = -1;
48 static int hf_dns_count_questions = -1;
49 static int hf_dns_count_answers = -1;
50 static int hf_dns_count_auth_rr = -1;
51 static int hf_dns_count_add_rr = -1;
52
53 /* DNS structs and definitions */
54
55 /* Offsets of fields in the DNS header. */
56 #define DNS_ID          0
57 #define DNS_FLAGS       2
58 #define DNS_QUEST       4
59 #define DNS_ANS         6
60 #define DNS_AUTH        8
61 #define DNS_ADD         10
62
63 /* Length of DNS header. */
64 #define DNS_HDRLEN      12
65
66 /* type values  */
67 #define T_A             1               /* host address */
68 #define T_NS            2               /* authoritative name server */
69 #define T_MD            3               /* mail destination (obsolete) */
70 #define T_MF            4               /* mail forwarder (obsolete) */
71 #define T_CNAME         5               /* canonical name */
72 #define T_SOA           6               /* start of authority zone */
73 #define T_MB            7               /* mailbox domain name (experimental) */
74 #define T_MG            8               /* mail group member (experimental) */
75 #define T_MR            9               /* mail rename domain name (experimental) */
76 #define T_NULL          10              /* null RR (experimental) */
77 #define T_WKS           11              /* well known service */
78 #define T_PTR           12              /* domain name pointer */
79 #define T_HINFO         13              /* host information */
80 #define T_MINFO         14              /* mailbox or mail list information */
81 #define T_MX            15              /* mail routing information */
82 #define T_TXT           16              /* text strings */
83 #define T_RP            17              /* responsible person (RFC 1183) */
84 #define T_AFSDB         18              /* AFS data base location (RFC 1183) */
85 #define T_X25           19              /* X.25 address (RFC 1183) */
86 #define T_ISDN          20              /* ISDN address (RFC 1183) */
87 #define T_RT            21              /* route-through (RFC 1183) */
88 #define T_NSAP          22              /* OSI NSAP (RFC 1706) */
89 #define T_NSAP_PTR      23              /* PTR equivalent for OSI NSAP (RFC 1348 - obsolete) */
90 #define T_SIG           24              /* digital signature (RFC 2065) */
91 #define T_KEY           25              /* public key (RFC 2065) */
92 #define T_PX            26              /* pointer to X.400/RFC822 mapping info (RFC 1664) */
93 #define T_GPOS          27              /* geographical position (RFC 1712) */
94 #define T_AAAA          28              /* IPv6 address (RFC 1886) */
95 #define T_LOC           29              /* geographical location (RFC 1876) */
96 #define T_NXT           30              /* "next" name (RFC 2065) */
97 #define T_EID           31              /* ??? (Nimrod?) */
98 #define T_NIMLOC        32              /* ??? (Nimrod?) */
99 #define T_SRV           33              /* service location (RFC 2052) */
100 #define T_ATMA          34              /* ??? */
101 #define T_NAPTR         35              /* naming authority pointer (RFC 2168) */
102
103 /* Bit fields in the flags */
104 #define F_RESPONSE      (1<<15)         /* packet is response */
105 #define F_OPCODE        (0xF<<11)       /* query opcode */
106 #define F_AUTHORITATIVE (1<<10)         /* response is authoritative */
107 #define F_TRUNCATED     (1<<9)          /* response is truncated */
108 #define F_RECDESIRED    (1<<8)          /* recursion desired */
109 #define F_RECAVAIL      (1<<7)          /* recursion available */
110 #define F_RCODE         (0xF<<0)        /* reply code */
111
112 /* Opcodes */
113 #define OPCODE_QUERY    (0<<11)         /* standard query */
114 #define OPCODE_IQUERY   (1<<11)         /* inverse query */
115 #define OPCODE_STATUS   (2<<11)         /* server status request */
116
117 /* Reply codes */
118 #define RCODE_NOERROR   (0<<0)
119 #define RCODE_FMTERROR  (1<<0)
120 #define RCODE_SERVFAIL  (2<<0)
121 #define RCODE_NAMEERROR (3<<0)
122 #define RCODE_NOTIMPL   (4<<0)
123 #define RCODE_REFUSED   (5<<0)
124
125 /* See RFC 1035 for all RR types for which no RFC is listed. */
126 static char *
127 dns_type_name (int type)
128 {
129   char *type_names[36] = {
130     "unused",
131     "A",
132     "NS",
133     "MD",
134     "MF",
135     "CNAME",
136     "SOA",
137     "MB",
138     "MG",
139     "MR",
140     "NULL",
141     "WKS",
142     "PTR",
143     "HINFO",
144     "MINFO",
145     "MX",
146     "TXT",
147     "RP",                               /* RFC 1183 */
148     "AFSDB",                            /* RFC 1183 */
149     "X25",                              /* RFC 1183 */
150     "ISDN",                             /* RFC 1183 */
151     "RT",                               /* RFC 1183 */
152     "NSAP",                             /* RFC 1706 */
153     "NSAP-PTR",                         /* RFC 1348 */
154     "SIG",                              /* RFC 2065 */
155     "KEY",                              /* RFC 2065 */
156     "PX",                               /* RFC 1664 */
157     "GPOS",                             /* RFC 1712 */
158     "AAAA",                             /* RFC 1886 */
159     "LOC",                              /* RFC 1876 */
160     "NXT",                              /* RFC 2065 */
161     "EID",
162     "NIMLOC",
163     "SRV",                              /* RFC 2052 */
164     "ATMA",
165     "NAPTR"                             /* RFC 2168 */
166   };
167   
168   if (type <= 35)
169     return type_names[type];
170   
171   /* special cases */
172   switch (type) 
173     {
174       /* non standard  */
175     case 100:
176       return "UINFO";
177     case 101:
178       return "UID";
179     case 102:
180       return "GID";
181     case 103:
182       return "UNSPEC";
183       
184       /* queries  */
185     case 251:
186       return "IXFR";    /* RFC 1995 */
187     case 252:
188       return "AXFR";
189     case 253:
190       return "MAILB";
191     case 254:
192       return "MAILA";
193     case 255:
194       return "ANY";
195     }
196   
197   return "unknown";
198 }
199
200
201 static char *
202 dns_long_type_name (int type)
203 {
204   char *type_names[36] = {
205     "unused",
206     "Host address",
207     "Authoritative name server",        
208     "Mail destination",
209     "Mail forwarder",
210     "Canonical name for an alias",
211     "Start of zone of authority",
212     "Mailbox domain name",
213     "Mail group member",
214     "Mail rename domain name",
215     "Null resource record",
216     "Well-known service description",
217     "Domain name pointer",
218     "Host information",
219     "Mailbox or mail list information",
220     "Mail exchange",
221     "Text strings",
222     "Responsible person",               /* RFC 1183 */
223     "AFS data base location",           /* RFC 1183 */
224     "X.25 address",                     /* RFC 1183 */
225     "ISDN number",                      /* RFC 1183 */
226     "Route through",                    /* RFC 1183 */
227     "OSI NSAP",                         /* RFC 1706 */
228     "OSI NSAP name pointer",            /* RFC 1348 */
229     "Signature",                        /* RFC 2065 */
230     "Public key",                       /* RFC 2065 */
231     "Pointer to X.400/RFC822 mapping info", /* RFC 1664 */
232     "Geographical position",            /* RFC 1712 */
233     "IPv6 address",                     /* RFC 1886 */
234     "Location",                         /* RFC 1876 */
235     "Next",                             /* RFC 2065 */
236     "EID",
237     "NIMLOC",
238     "Service location",                 /* RFC 2052 */
239     "ATMA",
240     "Naming authority pointer"          /* RFC 2168 */
241   };
242   static char unkbuf[7+1+2+1+4+1+1+10+1+1];     /* "Unknown RR type (%d)" */
243   
244   if (type <= 35)
245     return type_names[type];
246   
247   /* special cases */
248   switch (type) 
249     {
250       /* non standard  */
251     case 100:
252       return "UINFO";
253     case 101:
254       return "UID";
255     case 102:
256       return "GID";
257     case 103:
258       return "UNSPEC";
259       
260       /* queries  */
261     case 251:
262       return "Request for incremental zone transfer";   /* RFC 1995 */
263     case 252:
264       return "Request for full zone transfer";
265     case 253:
266       return "Request for mailbox-related records";
267     case 254:
268       return "Request for mail agent resource records";
269     case 255:
270       return "Request for all records";
271     }
272   
273   sprintf(unkbuf, "Unknown RR type (%d)", type);
274   return unkbuf;
275 }
276
277
278 char *
279 dns_class_name(int class)
280 {
281   char *class_name;
282   
283   switch (class) {
284   case 1:
285     class_name = "inet";
286     break;
287   case 3:
288     class_name = "chaos";
289     break;
290   case 4:
291     class_name = "hesiod";
292     break;
293   default:
294     class_name = "unknown";
295   }
296
297   return class_name;
298 }
299
300 int
301 get_dns_name(const u_char *pd, int offset, int dns_data_offset,
302     char *name, int maxname)
303 {
304   const u_char *dp = pd + offset;
305   const u_char *dptr = dp;
306   char *np = name;
307   int len = -1;
308   u_int component_len;
309
310   maxname--;    /* reserve space for the trailing '\0' */
311   for (;;) {
312     if (!BYTES_ARE_IN_FRAME(offset, 1))
313       goto overflow;
314     component_len = *dp++;
315     offset++;
316     if (component_len == 0)
317       break;
318     switch (component_len & 0xc0) {
319
320     case 0x00:
321       /* Label */
322       if (np != name) {
323         /* Not the first component - put in a '.'. */
324         if (maxname > 0) {
325           *np++ = '.';
326           maxname--;
327         }
328       }
329       if (!BYTES_ARE_IN_FRAME(offset, component_len))
330         goto overflow;
331       while (component_len > 0) {
332         if (maxname > 0) {
333           *np++ = *dp;
334           maxname--;
335         }
336         component_len--;
337         dp++;
338         offset++;
339       }
340       break;
341
342     case 0x40:
343     case 0x80:
344       goto error;       /* error */
345
346     case 0xc0:
347       /* Pointer. */
348       /* XXX - check to make sure we aren't looping, by keeping track
349          of how many characters are in the DNS packet, and of how many
350          characters we've looked at, and quitting if the latter
351          becomes bigger than the former. */
352       if (!BYTES_ARE_IN_FRAME(offset, 1))
353         goto overflow;
354       offset = dns_data_offset + (((component_len & ~0xc0) << 8) | (*dp++));
355       /* If "len" is negative, we are still working on the original name,
356          not something pointed to by a pointer, and so we should set "len"
357          to the length of the original name. */
358       if (len < 0)
359         len = dp - dptr;
360       dp = pd + offset;
361       break;    /* now continue processing from there */
362     }
363   }
364         
365 error:
366   *np = '\0';
367   /* If "len" is negative, we haven't seen a pointer, and thus haven't
368      set the length, so set it. */
369   if (len < 0)
370     len = dp - dptr;
371   /* Zero-length name means "root server" */
372   if (*name == '\0')
373     strcpy(name, "<Root>");
374   return len;
375
376 overflow:
377   /* We ran past the end of the captured data in the packet. */
378   strcpy(name, "<Name goes past end of captured data in packet>");
379   /* If "len" is negative, we haven't seen a pointer, and thus haven't
380      set the length, so set it. */
381   if (len < 0)
382     len = dp - dptr;
383   return len;
384 }
385
386
387 static int
388 get_dns_name_type_class(const u_char *pd, int offset, int dns_data_offset,
389     char *name_ret, int *name_len_ret, int *type_ret, int *class_ret)
390 {
391   int len;
392   int name_len;
393   int type;
394   int class;
395   char name[MAXDNAME];
396   int start_offset = offset;
397
398   name_len = get_dns_name(pd, offset, dns_data_offset, name, sizeof(name));
399   offset += name_len;
400   
401   if (!BYTES_ARE_IN_FRAME(offset, 2)) {
402     /* We ran past the end of the captured data in the packet. */
403     return -1;
404   }
405   type = pntohs(&pd[offset]);
406   offset += 2;
407
408   if (!BYTES_ARE_IN_FRAME(offset, 2)) {
409     /* We ran past the end of the captured data in the packet. */
410     return -1;
411   }
412   class = pntohs(&pd[offset]);
413   offset += 2;
414
415   strcpy (name_ret, name);
416   *type_ret = type;
417   *class_ret = class;
418   *name_len_ret = name_len;
419
420   len = offset - start_offset;
421   return len;
422 }
423
424 static double
425 rfc1867_size(u_char val)
426 {
427   double size;
428   guint32 exponent;
429
430   size = (val & 0xF0) >> 4;
431   exponent = (val & 0x0F);
432   while (exponent != 0) {
433     size *= 10;
434     exponent--;
435   }
436   return size / 100;    /* return size in meters, not cm */
437 }
438
439 static char *
440 rfc1867_angle(const u_char *dptr, const char *nsew)
441 {
442   guint32 angle;
443   char direction;
444   guint32 degrees, minutes, secs, tsecs;
445   static char buf[10+1+3+1 + 2+1+3+1 + 2+1+3+1+3+1 + 1 + 1];
446
447   angle = pntohl(dptr);
448
449   if (angle < 0x80000000U) {
450     angle = 0x80000000U - angle;
451     direction = nsew[1];
452   } else {
453     angle = angle - 0x80000000U;
454     direction = nsew[0];
455   }
456   tsecs = angle % 1000;
457   angle = angle / 1000;
458   secs = angle % 60;
459   angle = angle / 60;
460   minutes = angle % 60;
461   degrees = angle / 60;
462   sprintf(buf, "%u deg %u min %u.%03u sec %c", degrees, minutes, secs,
463                 tsecs, direction);
464   return buf;
465 }
466
467 static int
468 dissect_dns_query(const u_char *pd, int offset, int dns_data_offset,
469   proto_tree *dns_tree)
470 {
471   int len;
472   char name[MAXDNAME];
473   int name_len;
474   int type;
475   int class;
476   char *class_name;
477   char *type_name;
478   char *long_type_name;
479   const u_char *dptr;
480   const u_char *data_start;
481   proto_tree *q_tree;
482   proto_item *tq;
483
484   data_start = dptr = pd + offset;
485
486   len = get_dns_name_type_class(pd, offset, dns_data_offset, name, &name_len,
487     &type, &class);
488   if (len < 0) {
489     /* We ran past the end of the data in the packet. */
490     return 0;
491   }
492   dptr += len;
493
494   type_name = dns_type_name(type);
495   class_name = dns_class_name(class);
496   long_type_name = dns_long_type_name(type);
497
498   tq = proto_tree_add_text(dns_tree, offset, len, "%s: type %s, class %s", 
499                    name, type_name, class_name);
500   q_tree = proto_item_add_subtree(tq, ETT_DNS_QD);
501
502   proto_tree_add_text(q_tree, offset, name_len, "Name: %s", name);
503   offset += name_len;
504
505   proto_tree_add_text(q_tree, offset, 2, "Type: %s", long_type_name);
506   offset += 2;
507
508   proto_tree_add_text(q_tree, offset, 2, "Class: %s", class_name);
509   offset += 2;
510   
511   return dptr - data_start;
512 }
513
514
515 proto_tree *
516 add_rr_to_tree(proto_item *trr, int rr_type, int offset, const char *name,
517   int namelen, const char *type_name, const char *class_name, u_int ttl,
518   u_short data_len)
519 {
520   proto_tree *rr_tree;
521
522   rr_tree = proto_item_add_subtree(trr, rr_type);
523   proto_tree_add_text(rr_tree, offset, namelen, "Name: %s", name);
524   offset += namelen;
525   proto_tree_add_text(rr_tree, offset, 2, "Type: %s", type_name);
526   offset += 2;
527   proto_tree_add_text(rr_tree, offset, 2, "Class: %s", class_name);
528   offset += 2;
529   proto_tree_add_text(rr_tree, offset, 4, "Time to live: %s",
530                                                 time_secs_to_str(ttl));
531   offset += 4;
532   proto_tree_add_text(rr_tree, offset, 2, "Data length: %u", data_len);
533   return rr_tree;
534 }
535
536 static int
537 dissect_dns_answer(const u_char *pd, int offset, int dns_data_offset,
538   proto_tree *dns_tree)
539 {
540   int len;
541   char name[MAXDNAME];
542   int name_len;
543   int type;
544   int class;
545   char *class_name;
546   char *type_name;
547   char *long_type_name;
548   const u_char *dptr;
549   int cur_offset;
550   const u_char *data_start;
551   u_int ttl;
552   u_short data_len;
553   proto_tree *rr_tree;
554   proto_item *trr;
555
556   data_start = dptr = pd + offset;
557   cur_offset = offset;
558
559   len = get_dns_name_type_class(pd, offset, dns_data_offset, name, &name_len,
560     &type, &class);
561   if (len < 0) {
562     /* We ran past the end of the captured data in the packet. */
563     return 0;
564   }
565   dptr += len;
566   cur_offset += len;
567
568   type_name = dns_type_name(type);
569   class_name = dns_class_name(class);
570   long_type_name = dns_long_type_name(type);
571
572   if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
573     /* We ran past the end of the captured data in the packet. */
574     return 0;
575   }
576   ttl = pntohl(dptr);
577   dptr += 4;
578   cur_offset += 4;
579
580   if (!BYTES_ARE_IN_FRAME(cur_offset, 2)) {
581     /* We ran past the end of the captured data in the packet. */
582     return 0;
583   }
584   data_len = pntohs(dptr);
585   dptr += 2;
586   cur_offset += 2;
587
588   switch (type) {
589   case T_A:
590     trr = proto_tree_add_text(dns_tree, offset, (dptr - data_start) + data_len,
591                      "%s: type %s, class %s, addr %s",
592                      name, type_name, class_name,
593                      ip_to_str((guint8 *)dptr));
594     rr_tree = add_rr_to_tree(trr, ETT_DNS_RR, offset, name, name_len,
595                      long_type_name, class_name, ttl, data_len);
596     if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
597       /* We ran past the end of the captured data in the packet. */
598       return 0;
599     }
600     proto_tree_add_text(rr_tree, cur_offset, 4, "Addr: %s",
601                      ip_to_str((guint8 *)dptr));
602     break;
603
604   case T_NS:
605     {
606       char ns_name[MAXDNAME];
607       int ns_name_len;
608       
609       ns_name_len = get_dns_name(pd, cur_offset, dns_data_offset, ns_name, sizeof(ns_name));
610       trr = proto_tree_add_text(dns_tree, offset, (dptr - data_start) + data_len,
611                        "%s: type %s, class %s, ns %s",
612                        name, type_name, class_name, ns_name);
613       rr_tree = add_rr_to_tree(trr, ETT_DNS_RR, offset, name, name_len,
614                        long_type_name, class_name, ttl, data_len);
615       if (ns_name_len < 0) {
616         /* We ran past the end of the captured data in the packet. */
617         return 0;
618       }
619       proto_tree_add_text(rr_tree, cur_offset, ns_name_len, "Name server: %s",
620                         ns_name);
621     }
622     break;
623
624   case T_CNAME:
625     {
626       char cname[MAXDNAME];
627       int cname_len;
628       
629       cname_len = get_dns_name(pd, cur_offset, dns_data_offset, cname, sizeof(cname));
630       trr = proto_tree_add_text(dns_tree, offset, (dptr - data_start) + data_len,
631                      "%s: type %s, class %s, cname %s",
632                      name, type_name, class_name, cname);
633       rr_tree = add_rr_to_tree(trr, ETT_DNS_RR, offset, name, name_len,
634                        long_type_name, class_name, ttl, data_len);
635       if (cname_len < 0) {
636         /* We ran past the end of the captured data in the packet. */
637         return 0;
638       }
639       proto_tree_add_text(rr_tree, cur_offset, cname_len, "Primary name: %s",
640                         cname);
641     }
642     break;
643
644   case T_SOA:
645     {
646       char mname[MAXDNAME];
647       int mname_len;
648       char rname[MAXDNAME];
649       int rname_len;
650       guint32 serial;
651       guint32 refresh;
652       guint32 retry;
653       guint32 expire;
654       guint32 minimum;
655
656       mname_len = get_dns_name(pd, cur_offset, dns_data_offset, mname, sizeof(mname));
657       if (mname_len >= 0)
658         rname_len = get_dns_name(pd, cur_offset + mname_len, dns_data_offset, rname, sizeof(rname));
659       else {
660         /* We ran past the end of the captured data in the packet. */
661         rname_len = -1;
662       }
663       trr = proto_tree_add_text(dns_tree, offset, (dptr - data_start) + data_len,
664                      "%s: type %s, class %s, mname %s",
665                      name, type_name, class_name, mname);
666       rr_tree = add_rr_to_tree(trr, ETT_DNS_RR, offset, name, name_len,
667                        long_type_name, class_name, ttl, data_len);
668       if (mname_len < 0) {
669         /* We ran past the end of the captured data in the packet. */
670         return 0;
671       }
672       proto_tree_add_text(rr_tree, cur_offset, mname_len, "Primary name server: %s",
673                        mname);
674       cur_offset += mname_len;
675       
676       if (rname_len < 0) {
677         /* We ran past the end of the captured data in the packet. */
678         return 0;
679       }
680       proto_tree_add_text(rr_tree, cur_offset, rname_len, "Responsible authority's mailbox: %s",
681                        rname);
682       cur_offset += rname_len;
683
684       if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
685         /* We ran past the end of the captured data in the packet. */
686         return 0;
687       }
688       serial = pntohl(&pd[cur_offset]);
689       proto_tree_add_text(rr_tree, cur_offset, 4, "Serial number: %u",
690                        serial);
691       cur_offset += 4;
692
693       if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
694         /* We ran past the end of the captured data in the packet. */
695         return 0;
696       }
697       refresh = pntohl(&pd[cur_offset]);
698       proto_tree_add_text(rr_tree, cur_offset, 4, "Refresh interval: %s",
699                        time_secs_to_str(refresh));
700       cur_offset += 4;
701
702       if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
703         /* We ran past the end of the captured data in the packet. */
704         return 0;
705       }
706       retry = pntohl(&pd[cur_offset]);
707       proto_tree_add_text(rr_tree, cur_offset, 4, "Retry interval: %s",
708                        time_secs_to_str(retry));
709       cur_offset += 4;
710
711       if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
712         /* We ran past the end of the captured data in the packet. */
713         return 0;
714       }
715       expire = pntohl(&pd[cur_offset]);
716       proto_tree_add_text(rr_tree, cur_offset, 4, "Expiration limit: %s",
717                        time_secs_to_str(expire));
718       cur_offset += 4;
719
720       if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
721         /* We ran past the end of the captured data in the packet. */
722         return 0;
723       }
724       minimum = pntohl(&pd[cur_offset]);
725       proto_tree_add_text(rr_tree, cur_offset, 4, "Minimum TTL: %s",
726                        time_secs_to_str(minimum));
727     }
728     break;
729
730   case T_PTR:
731     {
732       char pname[MAXDNAME];
733       int pname_len;
734       
735       pname_len = get_dns_name(pd, cur_offset, dns_data_offset, pname, sizeof(pname));
736       trr = proto_tree_add_text(dns_tree, offset, (dptr - data_start) + data_len,
737                      "%s: type %s, class %s, ptr %s",
738                      name, type_name, class_name, pname);
739       rr_tree = add_rr_to_tree(trr, ETT_DNS_RR, offset, name, name_len,
740                        long_type_name, class_name, ttl, data_len);
741       if (pname_len < 0) {
742         /* We ran past the end of the captured data in the packet. */
743         return 0;
744       }
745       proto_tree_add_text(rr_tree, cur_offset, pname_len, "Domain name: %s",
746                         pname);
747       break;
748     }
749     break;
750
751   case T_MX:
752     {
753       guint16 preference = 0;
754       char mx_name[MAXDNAME];
755       int mx_name_len;
756       
757       mx_name_len = get_dns_name(pd, cur_offset + 2, dns_data_offset, mx_name, sizeof(mx_name));
758       if (!BYTES_ARE_IN_FRAME(cur_offset, 2)) {
759         /* We ran past the end of the captured data in the packet. */
760         trr = proto_tree_add_text(dns_tree, offset, (dptr - data_start) + data_len,
761                        "%s: type %s, class %s, <preference goes past end of captured data in packet>",
762                        name, type_name, class_name, preference, mx_name);
763       } else {
764         preference = pntohs(&pd[cur_offset]);
765         trr = proto_tree_add_text(dns_tree, offset, (dptr - data_start) + data_len,
766                        "%s: type %s, class %s, preference %u, mx %s",
767                        name, type_name, class_name, preference, mx_name);
768       }
769       rr_tree = add_rr_to_tree(trr, ETT_DNS_RR, offset, name, name_len,
770                        long_type_name, class_name, ttl, data_len);
771       if (!BYTES_ARE_IN_FRAME(cur_offset, 2)) {
772         /* We ran past the end of the captured data in the packet. */
773         return 0;
774       }
775       proto_tree_add_text(rr_tree, cur_offset, 2, "Preference: %u", preference);
776       if (mx_name_len < 0) {
777         /* We ran past the end of the captured data in the packet. */
778         return 0;
779       }
780       proto_tree_add_text(rr_tree, cur_offset + 2, mx_name_len, "Mail exchange: %s",
781                         mx_name);
782     }
783     break;
784       
785   case T_LOC:
786     {
787       trr = proto_tree_add_text(dns_tree, offset, (dptr - data_start) + data_len,
788                      "%s: type %s, class %s",
789                      name, type_name, class_name);
790       rr_tree = add_rr_to_tree(trr, ETT_DNS_RR, offset, name, name_len,
791                        long_type_name, class_name, ttl, data_len);
792       if (!BYTES_ARE_IN_FRAME(cur_offset, 1)) {
793         /* We ran past the end of the captured data in the packet. */
794         return 0;
795       }
796       proto_tree_add_text(rr_tree, cur_offset, 1, "Version: %u", pd[cur_offset]);
797       if (pd[cur_offset] == 0) {
798         /* Version 0, the only version RFC 1876 discusses. */
799         cur_offset++;
800
801         if (!BYTES_ARE_IN_FRAME(cur_offset, 1)) {
802           /* We ran past the end of the captured data in the packet. */
803           return 0;
804         }
805         proto_tree_add_text(rr_tree, cur_offset, 1, "Size: %g m",
806                                 rfc1867_size(pd[cur_offset]));
807         cur_offset++;
808
809         if (!BYTES_ARE_IN_FRAME(cur_offset, 1)) {
810           /* We ran past the end of the captured data in the packet. */
811           return 0;
812         }
813         proto_tree_add_text(rr_tree, cur_offset, 1, "Horizontal precision: %g m",
814                                 rfc1867_size(pd[cur_offset]));
815         cur_offset++;
816
817         if (!BYTES_ARE_IN_FRAME(cur_offset, 1)) {
818           /* We ran past the end of the captured data in the packet. */
819           return 0;
820         }
821         proto_tree_add_text(rr_tree, cur_offset, 1, "Vertical precision: %g m",
822                                 rfc1867_size(pd[cur_offset]));
823         cur_offset++;
824
825         if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
826           /* We ran past the end of the captured data in the packet. */
827           return 0;
828         }
829         proto_tree_add_text(rr_tree, cur_offset, 4, "Latitude: %s",
830                                 rfc1867_angle(&pd[cur_offset], "NS"));
831         cur_offset += 4;
832
833         if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
834           /* We ran past the end of the captured data in the packet. */
835           return 0;
836         }
837         proto_tree_add_text(rr_tree, cur_offset, 4, "Longitude: %s",
838                                 rfc1867_angle(&pd[cur_offset], "EW"));
839         cur_offset += 4;
840
841         if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
842           /* We ran past the end of the captured data in the packet. */
843           return 0;
844         }
845         proto_tree_add_text(rr_tree, cur_offset, 4, "Altitude: %g m",
846                                 (pntohl(&pd[cur_offset]) - 10000000)/100.0);
847       } else
848         proto_tree_add_text(rr_tree, cur_offset, data_len, "Data");
849       break;
850     }
851     break;
852       
853     /* TODO: parse more record types */
854
855   default:
856     trr = proto_tree_add_text(dns_tree, offset, (dptr - data_start) + data_len,
857                      "%s: type %s, class %s",
858                      name, type_name, class_name);
859     rr_tree = add_rr_to_tree(trr, ETT_DNS_RR, offset, name, name_len,
860                        long_type_name, class_name, ttl, data_len);
861     proto_tree_add_text(rr_tree, cur_offset, data_len, "Data");
862   }
863   
864   dptr += data_len;
865         
866   return dptr - data_start;
867 }
868
869 static int
870 dissect_query_records(const u_char *pd, int cur_off, int dns_data_offset,
871     int count, proto_tree *dns_tree)
872 {
873   int start_off, add_off;
874   proto_tree *qatree;
875   proto_item *ti;
876   
877   start_off = cur_off;
878   ti = proto_tree_add_text(dns_tree, start_off, 0, "Queries");
879   qatree = proto_item_add_subtree(ti, ETT_DNS_QRY);
880   while (count-- > 0) {
881     add_off = dissect_dns_query(pd, cur_off, dns_data_offset, qatree);
882     if (add_off <= 0) {
883       /* We ran past the end of the captured data in the packet. */
884       break;
885     }
886     cur_off += add_off;
887   }
888   proto_item_set_len(ti, cur_off - start_off);
889
890   return cur_off - start_off;
891 }
892
893 static int
894 dissect_answer_records(const u_char *pd, int cur_off, int dns_data_offset,
895     int count, proto_tree *dns_tree, char *name)
896 {
897   int start_off, add_off;
898   proto_tree *qatree;
899   proto_item *ti;
900   
901   start_off = cur_off;
902   ti = proto_tree_add_text(dns_tree, start_off, 0, name);
903   qatree = proto_item_add_subtree(ti, ETT_DNS_ANS);
904   while (count-- > 0) {
905     add_off = dissect_dns_answer(pd, cur_off, dns_data_offset, qatree);
906     if (add_off <= 0) {
907       /* We ran past the end of the captured data in the packet. */
908       break;
909     }
910     cur_off += add_off;
911   }
912   proto_item_set_len(ti, cur_off - start_off);
913
914   return cur_off - start_off;
915 }
916
917 void
918 dissect_dns(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
919 {
920   int dns_data_offset;
921   proto_tree *dns_tree, *field_tree;
922   proto_item *ti, *tf;
923   guint16    id, flags, quest, ans, auth, add;
924   char buf[128+1];
925   int cur_off;
926   static const value_string opcode_vals[] = {
927                   { OPCODE_QUERY,  "Standard query"        },
928                   { OPCODE_IQUERY, "Inverse query"         },
929                   { OPCODE_STATUS, "Server status request" },
930                   { 0,              NULL                   } };
931   static const value_string rcode_vals[] = {
932                   { RCODE_NOERROR,   "No error"        },
933                   { RCODE_FMTERROR,  "Format error"    },
934                   { RCODE_SERVFAIL,  "Server failure"  },
935                   { RCODE_NAMEERROR, "Name error"      },
936                   { RCODE_NOTIMPL,   "Not implemented" },
937                   { RCODE_REFUSED,   "Refused"         },
938                   { 0,               NULL              } };
939
940   dns_data_offset = offset;
941
942   if (check_col(fd, COL_PROTOCOL))
943     col_add_str(fd, COL_PROTOCOL, "DNS (UDP)");
944
945   if (pi.captured_len < DNS_HDRLEN) {
946     col_add_str(fd, COL_INFO, "Short DNS packet");
947     dissect_data(pd, offset, fd, tree);
948     return;
949   }
950
951   /* To do: check for errs, etc. */
952   id    = pntohs(&pd[offset + DNS_ID]);
953   flags = pntohs(&pd[offset + DNS_FLAGS]);
954   quest = pntohs(&pd[offset + DNS_QUEST]);
955   ans   = pntohs(&pd[offset + DNS_ANS]);
956   auth  = pntohs(&pd[offset + DNS_AUTH]);
957   add   = pntohs(&pd[offset + DNS_ADD]);
958   
959   if (check_col(fd, COL_INFO)) {
960     col_add_fstr(fd, COL_INFO, "%s%s",
961                 val_to_str(flags & F_OPCODE, opcode_vals,
962                            "Unknown operation (%x)"),
963                 (flags & F_RESPONSE) ? " response" : "");
964   }
965   
966   if (tree) {
967     ti = proto_tree_add_item_format(tree, proto_dns, offset, 4, NULL,
968                           (flags & F_RESPONSE) ? "DNS response" : "DNS query");
969     
970     dns_tree = proto_item_add_subtree(ti, ETT_DNS);
971
972     if (flags & F_RESPONSE)
973       proto_tree_add_item_hidden(dns_tree, hf_dns_response, offset, 4, 1);
974     else
975       proto_tree_add_item_hidden(dns_tree, hf_dns_query, offset, 4, 1);
976
977     proto_tree_add_item(dns_tree, hf_dns_transaction_id, 
978                         offset + DNS_ID, 2, id);
979
980     strcpy(buf, val_to_str(flags & F_OPCODE, opcode_vals, "Unknown operation"));
981     if (flags & F_RESPONSE) {
982       strcat(buf, " response");
983       strcat(buf, ", ");
984       strcat(buf, val_to_str(flags & F_RCODE, rcode_vals,
985             "Unknown error"));
986     }
987     tf = proto_tree_add_item_format(dns_tree, hf_dns_flags, 
988                                     offset + DNS_FLAGS, 2, 
989                                     flags,
990                                     "Flags: 0x%04x (%s)",
991                                     flags, buf);
992     field_tree = proto_item_add_subtree(tf, ETT_DNS_FLAGS);
993     proto_tree_add_text(field_tree, offset + DNS_FLAGS, 2, "%s",
994        decode_boolean_bitfield(flags, F_RESPONSE,
995             2*8, "Response", "Query"));
996     proto_tree_add_text(field_tree, offset + DNS_FLAGS, 2, "%s",
997        decode_enumerated_bitfield(flags, F_OPCODE,
998             2*8, opcode_vals, "%s"));
999     if (flags & F_RESPONSE) {
1000       proto_tree_add_text(field_tree, offset + DNS_FLAGS, 2, "%s",
1001          decode_boolean_bitfield(flags, F_AUTHORITATIVE,
1002               2*8,
1003               "Server is an authority for domain",
1004               "Server isn't an authority for domain"));
1005     }
1006     proto_tree_add_text(field_tree, offset + DNS_FLAGS, 2, "%s",
1007        decode_boolean_bitfield(flags, F_TRUNCATED,
1008             2*8,
1009             "Message is truncated",
1010             "Message is not truncated"));
1011     proto_tree_add_text(field_tree, offset + DNS_FLAGS, 2, "%s",
1012        decode_boolean_bitfield(flags, F_RECDESIRED,
1013             2*8,
1014             "Do query recursively",
1015             "Don't do query recursively"));
1016     if (flags & F_RESPONSE) {
1017       proto_tree_add_text(field_tree, offset + DNS_FLAGS, 2, "%s",
1018          decode_boolean_bitfield(flags, F_RECAVAIL,
1019               2*8,
1020               "Server can do recursive queries",
1021               "Server can't do recursive queries"));
1022       proto_tree_add_text(field_tree, offset + DNS_FLAGS, 2, "%s",
1023          decode_enumerated_bitfield(flags, F_RCODE,
1024               2*8, rcode_vals, "%s"));
1025     }
1026     proto_tree_add_item(dns_tree, hf_dns_count_questions, 
1027                         offset + DNS_QUEST, 2, quest);
1028     proto_tree_add_item(dns_tree, hf_dns_count_answers, 
1029                         offset + DNS_ANS, 2, ans);
1030     proto_tree_add_item(dns_tree, hf_dns_count_auth_rr, 
1031                         offset + DNS_AUTH, 2, auth);
1032     proto_tree_add_item(dns_tree, hf_dns_count_add_rr, 
1033                         offset + DNS_ADD, 2, add);
1034
1035     cur_off = offset + DNS_HDRLEN;
1036     
1037     if (quest > 0)
1038       cur_off += dissect_query_records(pd, cur_off, dns_data_offset, quest,
1039                                         dns_tree);
1040     
1041     if (ans > 0)
1042       cur_off += dissect_answer_records(pd, cur_off, dns_data_offset, ans,
1043           dns_tree, "Answers");
1044     
1045     if (auth > 0)
1046       cur_off += dissect_answer_records(pd, cur_off, dns_data_offset, auth,
1047           dns_tree, "Authoritative nameservers");
1048
1049     if (add > 0)
1050       cur_off += dissect_answer_records(pd, cur_off, dns_data_offset, add,
1051           dns_tree, "Additional records");
1052   }
1053 }
1054
1055 void
1056 proto_register_dns(void)
1057 {
1058   static hf_register_info hf[] = {
1059     { &hf_dns_response,
1060       { "Response",             "dns.response",  
1061         FT_BOOLEAN, BASE_NONE, NULL, 0x0,
1062         "TRUE if DNS response" }},
1063     { &hf_dns_query,
1064       { "Query",                "dns.query",  
1065         FT_BOOLEAN, BASE_NONE, NULL, 0x0,
1066         "TRUE if DNS query" }},
1067     { &hf_dns_flags,
1068       { "Flags",                "dns.flags",  
1069         FT_UINT16, BASE_HEX, NULL, 0x0,
1070         "" }},
1071     { &hf_dns_transaction_id,
1072       { "Transaction ID",       "dns.id",  
1073         FT_UINT16, BASE_HEX, NULL, 0x0,
1074         "Identification of transaction" }},
1075     { &hf_dns_count_questions,
1076       { "Questions",            "dns.count.queries",  
1077         FT_UINT16, BASE_DEC, NULL, 0x0,
1078         "Number of queries in packet" }},
1079     { &hf_dns_count_answers,
1080       { "Answer RRs",           "dns.count.answers",  
1081         FT_UINT16, BASE_DEC, NULL, 0x0,
1082         "Number of answers in packet" }},
1083     { &hf_dns_count_auth_rr,
1084       { "Authority RRs",        "dns.count.auth_rr",  
1085         FT_UINT16, BASE_DEC, NULL, 0x0,
1086         "Number of authoritative records in packet" }},
1087     { &hf_dns_count_add_rr,
1088       { "Additional RRs",       "dns.count.add_rr",  
1089         FT_UINT16, BASE_DEC, NULL, 0x0,
1090         "Number of additional records in packet" }}
1091   };
1092
1093   proto_dns = proto_register_protocol("Domain Name Service", "dns");
1094   proto_register_field_array(proto_dns, hf, array_length(hf));
1095
1096 }