Get rid of the "(UDP)" in the DNS protocol string.
[obnox/wireshark/wip.git] / packet-dns.c
1 /* packet-dns.c
2  * Routines for DNS packet disassembly
3  *
4  * $Id: packet-dns.c,v 1.33 1999/12/29 10:36:13 guy 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 static gint ett_dns = -1;
54 static gint ett_dns_qd = -1;
55 static gint ett_dns_rr = -1;
56 static gint ett_dns_qry = -1;
57 static gint ett_dns_ans = -1;
58 static gint ett_dns_flags = -1;
59 static gint ett_t_key_flags = -1;
60
61 /* DNS structs and definitions */
62
63 /* Offsets of fields in the DNS header. */
64 #define DNS_ID          0
65 #define DNS_FLAGS       2
66 #define DNS_QUEST       4
67 #define DNS_ANS         6
68 #define DNS_AUTH        8
69 #define DNS_ADD         10
70
71 /* Length of DNS header. */
72 #define DNS_HDRLEN      12
73
74 /* type values  */
75 #define T_A             1               /* host address */
76 #define T_NS            2               /* authoritative name server */
77 #define T_MD            3               /* mail destination (obsolete) */
78 #define T_MF            4               /* mail forwarder (obsolete) */
79 #define T_CNAME         5               /* canonical name */
80 #define T_SOA           6               /* start of authority zone */
81 #define T_MB            7               /* mailbox domain name (experimental) */
82 #define T_MG            8               /* mail group member (experimental) */
83 #define T_MR            9               /* mail rename domain name (experimental) */
84 #define T_NULL          10              /* null RR (experimental) */
85 #define T_WKS           11              /* well known service */
86 #define T_PTR           12              /* domain name pointer */
87 #define T_HINFO         13              /* host information */
88 #define T_MINFO         14              /* mailbox or mail list information */
89 #define T_MX            15              /* mail routing information */
90 #define T_TXT           16              /* text strings */
91 #define T_RP            17              /* responsible person (RFC 1183) */
92 #define T_AFSDB         18              /* AFS data base location (RFC 1183) */
93 #define T_X25           19              /* X.25 address (RFC 1183) */
94 #define T_ISDN          20              /* ISDN address (RFC 1183) */
95 #define T_RT            21              /* route-through (RFC 1183) */
96 #define T_NSAP          22              /* OSI NSAP (RFC 1706) */
97 #define T_NSAP_PTR      23              /* PTR equivalent for OSI NSAP (RFC 1348 - obsolete) */
98 #define T_SIG           24              /* digital signature (RFC 2065) */
99 #define T_KEY           25              /* public key (RFC 2065) */
100 #define T_PX            26              /* pointer to X.400/RFC822 mapping info (RFC 1664) */
101 #define T_GPOS          27              /* geographical position (RFC 1712) */
102 #define T_AAAA          28              /* IPv6 address (RFC 1886) */
103 #define T_LOC           29              /* geographical location (RFC 1876) */
104 #define T_NXT           30              /* "next" name (RFC 2065) */
105 #define T_EID           31              /* ??? (Nimrod?) */
106 #define T_NIMLOC        32              /* ??? (Nimrod?) */
107 #define T_SRV           33              /* service location (RFC 2052) */
108 #define T_ATMA          34              /* ??? */
109 #define T_NAPTR         35              /* naming authority pointer (RFC 2168) */
110
111 /* Bit fields in the flags */
112 #define F_RESPONSE      (1<<15)         /* packet is response */
113 #define F_OPCODE        (0xF<<11)       /* query opcode */
114 #define F_AUTHORITATIVE (1<<10)         /* response is authoritative */
115 #define F_TRUNCATED     (1<<9)          /* response is truncated */
116 #define F_RECDESIRED    (1<<8)          /* recursion desired */
117 #define F_RECAVAIL      (1<<7)          /* recursion available */
118 #define F_RCODE         (0xF<<0)        /* reply code */
119
120 /* Opcodes */
121 #define OPCODE_QUERY    (0<<11)         /* standard query */
122 #define OPCODE_IQUERY   (1<<11)         /* inverse query */
123 #define OPCODE_STATUS   (2<<11)         /* server status request */
124
125 /* Reply codes */
126 #define RCODE_NOERROR   (0<<0)
127 #define RCODE_FMTERROR  (1<<0)
128 #define RCODE_SERVFAIL  (2<<0)
129 #define RCODE_NAMEERROR (3<<0)
130 #define RCODE_NOTIMPL   (4<<0)
131 #define RCODE_REFUSED   (5<<0)
132
133 /* See RFC 1035 for all RR types for which no RFC is listed. */
134 static char *
135 dns_type_name (u_int type)
136 {
137   char *type_names[36] = {
138     "unused",
139     "A",
140     "NS",
141     "MD",
142     "MF",
143     "CNAME",
144     "SOA",
145     "MB",
146     "MG",
147     "MR",
148     "NULL",
149     "WKS",
150     "PTR",
151     "HINFO",
152     "MINFO",
153     "MX",
154     "TXT",
155     "RP",                               /* RFC 1183 */
156     "AFSDB",                            /* RFC 1183 */
157     "X25",                              /* RFC 1183 */
158     "ISDN",                             /* RFC 1183 */
159     "RT",                               /* RFC 1183 */
160     "NSAP",                             /* RFC 1706 */
161     "NSAP-PTR",                         /* RFC 1348 */
162     "SIG",                              /* RFC 2065 */
163     "KEY",                              /* RFC 2065 */
164     "PX",                               /* RFC 1664 */
165     "GPOS",                             /* RFC 1712 */
166     "AAAA",                             /* RFC 1886 */
167     "LOC",                              /* RFC 1876 */
168     "NXT",                              /* RFC 2065 */
169     "EID",
170     "NIMLOC",
171     "SRV",                              /* RFC 2052 */
172     "ATMA",
173     "NAPTR"                             /* RFC 2168 */
174   };
175   
176   if (type <= 35)
177     return type_names[type];
178   
179   /* special cases */
180   switch (type) 
181     {
182       /* non standard  */
183     case 100:
184       return "UINFO";
185     case 101:
186       return "UID";
187     case 102:
188       return "GID";
189     case 103:
190       return "UNSPEC";
191       
192       /* queries  */
193     case 251:
194       return "IXFR";    /* RFC 1995 */
195     case 252:
196       return "AXFR";
197     case 253:
198       return "MAILB";
199     case 254:
200       return "MAILA";
201     case 255:
202       return "ANY";
203     }
204
205   return "unknown";
206 }
207
208
209 static char *
210 dns_long_type_name (u_int type)
211 {
212   char *type_names[36] = {
213     "unused",
214     "Host address",
215     "Authoritative name server",        
216     "Mail destination",
217     "Mail forwarder",
218     "Canonical name for an alias",
219     "Start of zone of authority",
220     "Mailbox domain name",
221     "Mail group member",
222     "Mail rename domain name",
223     "Null resource record",
224     "Well-known service description",
225     "Domain name pointer",
226     "Host information",
227     "Mailbox or mail list information",
228     "Mail exchange",
229     "Text strings",
230     "Responsible person",               /* RFC 1183 */
231     "AFS data base location",           /* RFC 1183 */
232     "X.25 address",                     /* RFC 1183 */
233     "ISDN number",                      /* RFC 1183 */
234     "Route through",                    /* RFC 1183 */
235     "OSI NSAP",                         /* RFC 1706 */
236     "OSI NSAP name pointer",            /* RFC 1348 */
237     "Signature",                        /* RFC 2065 */
238     "Public key",                       /* RFC 2065 */
239     "Pointer to X.400/RFC822 mapping info", /* RFC 1664 */
240     "Geographical position",            /* RFC 1712 */
241     "IPv6 address",                     /* RFC 1886 */
242     "Location",                         /* RFC 1876 */
243     "Next",                             /* RFC 2065 */
244     "EID",
245     "NIMLOC",
246     "Service location",                 /* RFC 2052 */
247     "ATMA",
248     "Naming authority pointer"          /* RFC 2168 */
249   };
250   static char unkbuf[7+1+2+1+4+1+1+10+1+1];     /* "Unknown RR type (%d)" */
251   
252   if (type <= 35)
253     return type_names[type];
254   
255   /* special cases */
256   switch (type) 
257     {
258       /* non standard  */
259     case 100:
260       return "UINFO";
261     case 101:
262       return "UID";
263     case 102:
264       return "GID";
265     case 103:
266       return "UNSPEC";
267       
268       /* queries  */
269     case 251:
270       return "Request for incremental zone transfer";   /* RFC 1995 */
271     case 252:
272       return "Request for full zone transfer";
273     case 253:
274       return "Request for mailbox-related records";
275     case 254:
276       return "Request for mail agent resource records";
277     case 255:
278       return "Request for all records";
279     }
280   
281   sprintf(unkbuf, "Unknown RR type (%d)", type);
282   return unkbuf;
283 }
284
285
286 char *
287 dns_class_name(int class)
288 {
289   char *class_name;
290   
291   switch (class) {
292   case 1:
293     class_name = "inet";
294     break;
295   case 3:
296     class_name = "chaos";
297     break;
298   case 4:
299     class_name = "hesiod";
300     break;
301   default:
302     class_name = "unknown";
303   }
304
305   return class_name;
306 }
307
308 int
309 get_dns_name(const u_char *pd, int offset, int dns_data_offset,
310     char *name, int maxname)
311 {
312   const u_char *dp = pd + offset;
313   const u_char *dptr = dp;
314   char *np = name;
315   int len = -1;
316   u_int component_len;
317
318   maxname--;    /* reserve space for the trailing '\0' */
319   for (;;) {
320     if (!BYTES_ARE_IN_FRAME(offset, 1))
321       goto overflow;
322     component_len = *dp++;
323     offset++;
324     if (component_len == 0)
325       break;
326     switch (component_len & 0xc0) {
327
328     case 0x00:
329       /* Label */
330       if (np != name) {
331         /* Not the first component - put in a '.'. */
332         if (maxname > 0) {
333           *np++ = '.';
334           maxname--;
335         }
336       }
337       if (!BYTES_ARE_IN_FRAME(offset, component_len))
338         goto overflow;
339       while (component_len > 0) {
340         if (maxname > 0) {
341           *np++ = *dp;
342           maxname--;
343         }
344         component_len--;
345         dp++;
346         offset++;
347       }
348       break;
349
350     case 0x40:
351     case 0x80:
352       goto error;       /* error */
353
354     case 0xc0:
355       /* Pointer. */
356       /* XXX - check to make sure we aren't looping, by keeping track
357          of how many characters are in the DNS packet, and of how many
358          characters we've looked at, and quitting if the latter
359          becomes bigger than the former. */
360       if (!BYTES_ARE_IN_FRAME(offset, 1))
361         goto overflow;
362       offset = dns_data_offset + (((component_len & ~0xc0) << 8) | (*dp++));
363       /* If "len" is negative, we are still working on the original name,
364          not something pointed to by a pointer, and so we should set "len"
365          to the length of the original name. */
366       if (len < 0)
367         len = dp - dptr;
368       dp = pd + offset;
369       break;    /* now continue processing from there */
370     }
371   }
372         
373 error:
374   *np = '\0';
375   /* If "len" is negative, we haven't seen a pointer, and thus haven't
376      set the length, so set it. */
377   if (len < 0)
378     len = dp - dptr;
379   /* Zero-length name means "root server" */
380   if (*name == '\0')
381     strcpy(name, "<Root>");
382   return len;
383
384 overflow:
385   /* We ran past the end of the captured data in the packet. */
386   strcpy(name, "<Name goes past end of captured data in packet>");
387   /* If "len" is negative, we haven't seen a pointer, and thus haven't
388      set the length, so set it. */
389   if (len < 0)
390     len = dp - dptr;
391   return len;
392 }
393
394
395 static int
396 get_dns_name_type_class(const u_char *pd, int offset, int dns_data_offset,
397     char *name_ret, int *name_len_ret, int *type_ret, int *class_ret)
398 {
399   int len;
400   int name_len;
401   int type;
402   int class;
403   char name[MAXDNAME];
404   int start_offset = offset;
405
406   name_len = get_dns_name(pd, offset, dns_data_offset, name, sizeof(name));
407   offset += name_len;
408   
409   if (!BYTES_ARE_IN_FRAME(offset, 2)) {
410     /* We ran past the end of the captured data in the packet. */
411     return -1;
412   }
413   type = pntohs(&pd[offset]);
414   offset += 2;
415
416   if (!BYTES_ARE_IN_FRAME(offset, 2)) {
417     /* We ran past the end of the captured data in the packet. */
418     return -1;
419   }
420   class = pntohs(&pd[offset]);
421   offset += 2;
422
423   strcpy (name_ret, name);
424   *type_ret = type;
425   *class_ret = class;
426   *name_len_ret = name_len;
427
428   len = offset - start_offset;
429   return len;
430 }
431
432 static double
433 rfc1867_size(u_char val)
434 {
435   double size;
436   guint32 exponent;
437
438   size = (val & 0xF0) >> 4;
439   exponent = (val & 0x0F);
440   while (exponent != 0) {
441     size *= 10;
442     exponent--;
443   }
444   return size / 100;    /* return size in meters, not cm */
445 }
446
447 static char *
448 rfc1867_angle(const u_char *dptr, const char *nsew)
449 {
450   guint32 angle;
451   char direction;
452   guint32 degrees, minutes, secs, tsecs;
453   static char buf[10+1+3+1 + 2+1+3+1 + 2+1+3+1+3+1 + 1 + 1];
454
455   angle = pntohl(dptr);
456
457   if (angle < 0x80000000U) {
458     angle = 0x80000000U - angle;
459     direction = nsew[1];
460   } else {
461     angle = angle - 0x80000000U;
462     direction = nsew[0];
463   }
464   tsecs = angle % 1000;
465   angle = angle / 1000;
466   secs = angle % 60;
467   angle = angle / 60;
468   minutes = angle % 60;
469   degrees = angle / 60;
470   sprintf(buf, "%u deg %u min %u.%03u sec %c", degrees, minutes, secs,
471                 tsecs, direction);
472   return buf;
473 }
474
475 static int
476 dissect_dns_query(const u_char *pd, int offset, int dns_data_offset,
477   frame_data *fd, proto_tree *dns_tree)
478 {
479   int len;
480   char name[MAXDNAME];
481   int name_len;
482   int type;
483   int class;
484   char *class_name;
485   char *type_name;
486   char *long_type_name;
487   const u_char *dptr;
488   const u_char *data_start;
489   proto_tree *q_tree;
490   proto_item *tq;
491
492   data_start = dptr = pd + offset;
493
494   len = get_dns_name_type_class(pd, offset, dns_data_offset, name, &name_len,
495     &type, &class);
496   if (len < 0) {
497     /* We ran past the end of the data in the packet. */
498     return 0;
499   }
500   dptr += len;
501
502   type_name = dns_type_name(type);
503   class_name = dns_class_name(class);
504   long_type_name = dns_long_type_name(type);
505
506   if (fd != NULL)
507     col_append_fstr(fd, COL_INFO, " %s %s", type_name, name);
508   if (dns_tree != NULL) {
509     tq = proto_tree_add_text(dns_tree, offset, len, "%s: type %s, class %s", 
510                    name, type_name, class_name);
511     q_tree = proto_item_add_subtree(tq, ett_dns_qd);
512
513     proto_tree_add_text(q_tree, offset, name_len, "Name: %s", name);
514     offset += name_len;
515
516     proto_tree_add_text(q_tree, offset, 2, "Type: %s", long_type_name);
517     offset += 2;
518
519     proto_tree_add_text(q_tree, offset, 2, "Class: %s", class_name);
520     offset += 2;
521   }
522   
523   return dptr - data_start;
524 }
525
526
527 proto_tree *
528 add_rr_to_tree(proto_item *trr, int rr_type, int offset, const char *name,
529   int namelen, const char *type_name, const char *class_name, u_int ttl,
530   u_short data_len)
531 {
532   proto_tree *rr_tree;
533
534   rr_tree = proto_item_add_subtree(trr, rr_type);
535   proto_tree_add_text(rr_tree, offset, namelen, "Name: %s", name);
536   offset += namelen;
537   proto_tree_add_text(rr_tree, offset, 2, "Type: %s", type_name);
538   offset += 2;
539   proto_tree_add_text(rr_tree, offset, 2, "Class: %s", class_name);
540   offset += 2;
541   proto_tree_add_text(rr_tree, offset, 4, "Time to live: %s",
542                                                 time_secs_to_str(ttl));
543   offset += 4;
544   proto_tree_add_text(rr_tree, offset, 2, "Data length: %u", data_len);
545   return rr_tree;
546 }
547
548 /*
549  * SIG and KEY RR algorithms.
550  */
551 #define DNS_ALGO_MD5            1       /* MD5/RSA */
552 #define DNS_ALGO_EDATE          253     /* Expiration date */
553 #define DNS_ALGO_PRIVATE        254     /* Private use */       
554
555 static const value_string algo_vals[] = {
556           { DNS_ALGO_MD5,     "MD5/RSA" },
557           { DNS_ALGO_EDATE,   "Expiration date" },
558           { DNS_ALGO_PRIVATE, "Private use" },
559           { 0,                NULL }
560 };
561
562 static int
563 dissect_dns_answer(const u_char *pd, int offset, int dns_data_offset,
564   frame_data *fd, proto_tree *dns_tree)
565 {
566   int len;
567   char name[MAXDNAME];
568   int name_len;
569   int type;
570   int class;
571   char *class_name;
572   char *type_name;
573   char *long_type_name;
574   const u_char *dptr;
575   int cur_offset;
576   const u_char *data_start;
577   u_int ttl;
578   u_short data_len;
579   proto_tree *rr_tree;
580   proto_item *trr;
581
582   data_start = dptr = pd + offset;
583   cur_offset = offset;
584
585   len = get_dns_name_type_class(pd, offset, dns_data_offset, name, &name_len,
586     &type, &class);
587   if (len < 0) {
588     /* We ran past the end of the captured data in the packet. */
589     return 0;
590   }
591   dptr += len;
592   cur_offset += len;
593
594   type_name = dns_type_name(type);
595   class_name = dns_class_name(class);
596   long_type_name = dns_long_type_name(type);
597
598   if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
599     /* We ran past the end of the captured data in the packet. */
600     return 0;
601   }
602   ttl = pntohl(dptr);
603   dptr += 4;
604   cur_offset += 4;
605
606   if (!BYTES_ARE_IN_FRAME(cur_offset, 2)) {
607     /* We ran past the end of the captured data in the packet. */
608     return 0;
609   }
610   data_len = pntohs(dptr);
611   dptr += 2;
612   cur_offset += 2;
613
614   switch (type) {
615   case T_A:
616     if (fd != NULL) {
617       col_append_fstr(fd, COL_INFO, " %s %s", type_name,
618                         ip_to_str((guint8 *)dptr));
619     }
620     if (dns_tree != NULL) {
621       trr = proto_tree_add_text(dns_tree, offset, (dptr - data_start) + data_len,
622                      "%s: type %s, class %s, addr %s",
623                      name, type_name, class_name,
624                      ip_to_str((guint8 *)dptr));
625       rr_tree = add_rr_to_tree(trr, ett_dns_rr, offset, name, name_len,
626                      long_type_name, class_name, ttl, data_len);
627       if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
628         /* We ran past the end of the captured data in the packet. */
629         return 0;
630       }
631       proto_tree_add_text(rr_tree, cur_offset, 4, "Addr: %s",
632                      ip_to_str((guint8 *)dptr));
633     }
634     break;
635
636   case T_NS:
637     {
638       char ns_name[MAXDNAME];
639       int ns_name_len;
640       
641       ns_name_len = get_dns_name(pd, cur_offset, dns_data_offset, ns_name, sizeof(ns_name));
642       if (fd != NULL)
643         col_append_fstr(fd, COL_INFO, " %s %s", type_name, ns_name);
644       if (dns_tree != NULL) {
645         trr = proto_tree_add_text(dns_tree, offset, (dptr - data_start) + data_len,
646                        "%s: type %s, class %s, ns %s",
647                        name, type_name, class_name, ns_name);
648         rr_tree = add_rr_to_tree(trr, ett_dns_rr, offset, name, name_len,
649                        long_type_name, class_name, ttl, data_len);
650         if (ns_name_len < 0) {
651           /* We ran past the end of the captured data in the packet. */
652           return 0;
653         }
654         proto_tree_add_text(rr_tree, cur_offset, ns_name_len, "Name server: %s",
655                         ns_name);
656       }
657     }
658     break;
659
660   case T_CNAME:
661     {
662       char cname[MAXDNAME];
663       int cname_len;
664       
665       cname_len = get_dns_name(pd, cur_offset, dns_data_offset, cname, sizeof(cname));
666       if (fd != NULL)
667         col_append_fstr(fd, COL_INFO, " %s %s", type_name, cname);
668       if (dns_tree != NULL) {
669         trr = proto_tree_add_text(dns_tree, offset, (dptr - data_start) + data_len,
670                      "%s: type %s, class %s, cname %s",
671                      name, type_name, class_name, cname);
672         rr_tree = add_rr_to_tree(trr, ett_dns_rr, offset, name, name_len,
673                        long_type_name, class_name, ttl, data_len);
674         if (cname_len < 0) {
675           /* We ran past the end of the captured data in the packet. */
676           return 0;
677         }
678         proto_tree_add_text(rr_tree, cur_offset, cname_len, "Primary name: %s",
679                         cname);
680       }
681     }
682     break;
683
684   case T_SOA:
685     {
686       char mname[MAXDNAME];
687       int mname_len;
688       char rname[MAXDNAME];
689       int rname_len;
690       guint32 serial;
691       guint32 refresh;
692       guint32 retry;
693       guint32 expire;
694       guint32 minimum;
695
696       mname_len = get_dns_name(pd, cur_offset, dns_data_offset, mname, sizeof(mname));
697       if (mname_len >= 0)
698         rname_len = get_dns_name(pd, cur_offset + mname_len, dns_data_offset, rname, sizeof(rname));
699       else {
700         /* We ran past the end of the captured data in the packet. */
701         rname_len = -1;
702       }
703       if (fd != NULL)
704         col_append_fstr(fd, COL_INFO, " %s %s", type_name, mname);
705       if (dns_tree != NULL) {
706         trr = proto_tree_add_text(dns_tree, offset, (dptr - data_start) + data_len,
707                      "%s: type %s, class %s, mname %s",
708                      name, type_name, class_name, mname);
709         rr_tree = add_rr_to_tree(trr, ett_dns_rr, offset, name, name_len,
710                        long_type_name, class_name, ttl, data_len);
711         if (mname_len < 0) {
712           /* We ran past the end of the captured data in the packet. */
713           return 0;
714         }
715         proto_tree_add_text(rr_tree, cur_offset, mname_len, "Primary name server: %s",
716                        mname);
717         cur_offset += mname_len;
718       
719         if (rname_len < 0) {
720           /* We ran past the end of the captured data in the packet. */
721           return 0;
722         }
723         proto_tree_add_text(rr_tree, cur_offset, rname_len, "Responsible authority's mailbox: %s",
724                        rname);
725         cur_offset += rname_len;
726
727         if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
728           /* We ran past the end of the captured data in the packet. */
729           return 0;
730         }
731         serial = pntohl(&pd[cur_offset]);
732         proto_tree_add_text(rr_tree, cur_offset, 4, "Serial number: %u",
733                        serial);
734         cur_offset += 4;
735
736         if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
737           /* We ran past the end of the captured data in the packet. */
738           return 0;
739         }
740         refresh = pntohl(&pd[cur_offset]);
741         proto_tree_add_text(rr_tree, cur_offset, 4, "Refresh interval: %s",
742                        time_secs_to_str(refresh));
743         cur_offset += 4;
744
745         if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
746           /* We ran past the end of the captured data in the packet. */
747           return 0;
748         }
749         retry = pntohl(&pd[cur_offset]);
750         proto_tree_add_text(rr_tree, cur_offset, 4, "Retry interval: %s",
751                        time_secs_to_str(retry));
752         cur_offset += 4;
753
754         if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
755           /* We ran past the end of the captured data in the packet. */
756           return 0;
757         }
758         expire = pntohl(&pd[cur_offset]);
759         proto_tree_add_text(rr_tree, cur_offset, 4, "Expiration limit: %s",
760                        time_secs_to_str(expire));
761         cur_offset += 4;
762
763         if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
764           /* We ran past the end of the captured data in the packet. */
765           return 0;
766         }
767         minimum = pntohl(&pd[cur_offset]);
768         proto_tree_add_text(rr_tree, cur_offset, 4, "Minimum TTL: %s",
769                        time_secs_to_str(minimum));
770       }
771     }
772     break;
773
774   case T_PTR:
775     {
776       char pname[MAXDNAME];
777       int pname_len;
778       
779       pname_len = get_dns_name(pd, cur_offset, dns_data_offset, pname, sizeof(pname));
780       if (fd != NULL)
781         col_append_fstr(fd, COL_INFO, " %s %s", type_name, pname);
782       if (dns_tree != NULL) {
783         trr = proto_tree_add_text(dns_tree, offset, (dptr - data_start) + data_len,
784                      "%s: type %s, class %s, ptr %s",
785                      name, type_name, class_name, pname);
786         rr_tree = add_rr_to_tree(trr, ett_dns_rr, offset, name, name_len,
787                        long_type_name, class_name, ttl, data_len);
788         if (pname_len < 0) {
789           /* We ran past the end of the captured data in the packet. */
790           return 0;
791         }
792         proto_tree_add_text(rr_tree, cur_offset, pname_len, "Domain name: %s",
793                         pname);
794       }
795       break;
796     }
797     break;
798
799   case T_HINFO:
800     {
801       int cpu_offset;
802       int cpu_len;
803       int os_offset;
804       int os_len;
805
806       cpu_offset = cur_offset;
807       if (!BYTES_ARE_IN_FRAME(cpu_offset, 1)) {
808         /* We ran past the end of the captured data in the packet. */
809         if (dns_tree != NULL) {
810           trr = proto_tree_add_text(dns_tree, offset, (dptr - data_start) + data_len,
811                        "%s: type %s, class %s, <CPU goes past end of captured data in packet>",
812                        name, type_name, class_name);
813           rr_tree = add_rr_to_tree(trr, ett_dns_rr, offset, name, name_len,
814                        long_type_name, class_name, ttl, data_len);
815         }
816         return 0;
817       }
818       cpu_len = pd[cpu_offset];
819       if (!BYTES_ARE_IN_FRAME(cpu_offset + 1, cpu_len)) {
820         /* We ran past the end of the captured data in the packet. */
821         if (dns_tree != NULL) {
822           trr = proto_tree_add_text(dns_tree, offset, (dptr - data_start) + data_len,
823                        "%s: type %s, class %s, <CPU goes past end of captured data in packet>",
824                        name, type_name, class_name);
825           rr_tree = add_rr_to_tree(trr, ett_dns_rr, offset, name, name_len,
826                        long_type_name, class_name, ttl, data_len);
827         }
828         return 0;
829       }
830       os_offset = cpu_offset + 1 + cpu_len;
831       if (!BYTES_ARE_IN_FRAME(os_offset, 1)) {
832         /* We ran past the end of the captured data in the packet. */
833         if (dns_tree != NULL) {
834           trr = proto_tree_add_text(dns_tree, offset, (dptr - data_start) + data_len,
835                        "%s: type %s, class %s, CPU %.*s, <OS goes past end of captured data in packet>",
836                        name, type_name, class_name, cpu_len, &pd[cpu_offset + 1]);
837           rr_tree = add_rr_to_tree(trr, ett_dns_rr, offset, name, name_len,
838                        long_type_name, class_name, ttl, data_len);
839         }
840         return 0;
841       }
842       os_len = pd[os_offset];
843       if (!BYTES_ARE_IN_FRAME(os_offset + 1, os_len)) {
844         /* We ran past the end of the captured data in the packet. */
845         if (dns_tree != NULL) {
846           trr = proto_tree_add_text(dns_tree, offset, (dptr - data_start) + data_len,
847                        "%s: type %s, class %s, CPU %*.s, <OS goes past end of captured data in packet>",
848                        name, type_name, class_name, cpu_len, &pd[cpu_offset + 1]);
849           rr_tree = add_rr_to_tree(trr, ett_dns_rr, offset, name, name_len,
850                        long_type_name, class_name, ttl, data_len);
851         }
852         return 0;
853       }
854       if (fd != NULL)
855         col_append_fstr(fd, COL_INFO, " %s %.*s %.*s", type_name, cpu_len,
856             &pd[cpu_offset + 1], os_len, &pd[os_offset + 1]);
857       if (dns_tree != NULL) {
858         trr = proto_tree_add_text(dns_tree, offset, (dptr - data_start) + data_len,
859                      "%s: type %s, class %s, CPU %.*s, OS %.*s",
860                      name, type_name, class_name,
861                      cpu_len, &pd[cpu_offset + 1], os_len, &pd[os_offset + 1]);
862         rr_tree = add_rr_to_tree(trr, ett_dns_rr, offset, name, name_len,
863                        long_type_name, class_name, ttl, data_len);
864         proto_tree_add_text(rr_tree, cpu_offset, 1 + cpu_len, "CPU: %.*s",
865                         cpu_len, &pd[cpu_offset + 1]);
866         proto_tree_add_text(rr_tree, os_offset, 1 + os_len, "OS: %.*s",
867                         os_len, &pd[os_offset + 1]);
868       }
869       break;
870     }
871     break;
872
873   case T_MX:
874     {
875       guint16 preference = 0;
876       char mx_name[MAXDNAME];
877       int mx_name_len;
878       
879       if (!BYTES_ARE_IN_FRAME(cur_offset, 2)) {
880         /* We ran past the end of the captured data in the packet. */
881         if (dns_tree != NULL) {
882           trr = proto_tree_add_text(dns_tree, offset, (dptr - data_start) + data_len,
883                        "%s: type %s, class %s, <preference goes past end of captured data in packet>",
884                        name, type_name, class_name);
885           rr_tree = add_rr_to_tree(trr, ett_dns_rr, offset, name, name_len,
886                        long_type_name, class_name, ttl, data_len);
887         }
888         return 0;
889       }
890       preference = pntohs(&pd[cur_offset]);
891       mx_name_len = get_dns_name(pd, cur_offset + 2, dns_data_offset, mx_name, sizeof(mx_name));
892       if (mx_name_len < 0) {
893         /* We ran past the end of the captured data in the packet. */
894         if (dns_tree != NULL) {
895           trr = proto_tree_add_text(dns_tree, offset, (dptr - data_start) + data_len,
896                        "%s: type %s, class %s, preference %u, <mx goes past end of captured data in packet>",
897                        name, type_name, class_name, preference);
898           rr_tree = add_rr_to_tree(trr, ett_dns_rr, offset, name, name_len,
899                        long_type_name, class_name, ttl, data_len);
900         }
901         return 0;
902       }
903       if (fd != NULL)
904         col_append_fstr(fd, COL_INFO, " %s %u %s", type_name, preference, mx_name);
905       if (dns_tree != NULL) {
906         trr = proto_tree_add_text(dns_tree, offset, (dptr - data_start) + data_len,
907                        "%s: type %s, class %s, preference %u, mx %s",
908                        name, type_name, class_name, preference, mx_name);
909         rr_tree = add_rr_to_tree(trr, ett_dns_rr, offset, name, name_len,
910                        long_type_name, class_name, ttl, data_len);
911         proto_tree_add_text(rr_tree, cur_offset, 2, "Preference: %u", preference);
912         proto_tree_add_text(rr_tree, cur_offset + 2, mx_name_len, "Mail exchange: %s",
913                         mx_name);
914       }
915     }
916     break;
917
918   case T_SIG:
919     {
920       int rr_len = data_len;
921       struct timeval unixtime;
922       char signer_name[MAXDNAME];
923       int signer_name_len;
924
925       if (fd != NULL)
926         col_append_fstr(fd, COL_INFO, " %s", type_name);
927       if (dns_tree != NULL) {
928         trr = proto_tree_add_text(dns_tree, offset, (dptr - data_start) + data_len,
929                      "%s: type %s, class %s",
930                      name, type_name, class_name);
931         rr_tree = add_rr_to_tree(trr, ett_dns_rr, offset, name, name_len,
932                        long_type_name, class_name, ttl, data_len);
933
934         if (!BYTES_ARE_IN_FRAME(cur_offset, 2)) {
935           /* We ran past the end of the captured data in the packet. */
936           return 0;
937         }
938         proto_tree_add_text(rr_tree, cur_offset, 2, "Type covered: %s (%s)",
939                 dns_type_name(pntohs(&pd[cur_offset])),
940                 dns_long_type_name(pntohs(&pd[cur_offset])));
941         cur_offset += 2;
942         rr_len -= 2;
943
944         if (!BYTES_ARE_IN_FRAME(cur_offset, 1)) {
945           /* We ran past the end of the captured data in the packet. */
946           return 0;
947         }
948         proto_tree_add_text(rr_tree, cur_offset, 1, "Algorithm: %s",
949                 val_to_str(pd[cur_offset], algo_vals,
950                     "Unknown (0x%02X)"));
951         cur_offset += 1;
952         rr_len -= 1;
953
954         if (!BYTES_ARE_IN_FRAME(cur_offset, 1)) {
955           /* We ran past the end of the captured data in the packet. */
956           return 0;
957         }
958         proto_tree_add_text(rr_tree, cur_offset, 1, "Labels: %u",
959                 pd[cur_offset]);
960         cur_offset += 1;
961         rr_len -= 1;
962
963         if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
964           /* We ran past the end of the captured data in the packet. */
965           return 0;
966         }
967         proto_tree_add_text(rr_tree, cur_offset, 4, "Original TTL: %s",
968                 time_secs_to_str(pntohl(&pd[cur_offset])));
969         cur_offset += 4;
970         rr_len -= 4;
971
972         if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
973           /* We ran past the end of the captured data in the packet. */
974           return 0;
975         }
976         unixtime.tv_sec = pntohl(&pd[cur_offset]);
977         unixtime.tv_usec = 0;
978         proto_tree_add_text(rr_tree, cur_offset, 4, "Signature expiration: %s",
979                 abs_time_to_str(&unixtime));
980         cur_offset += 4;
981         rr_len -= 4;
982
983         if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
984           /* We ran past the end of the captured data in the packet. */
985           return 0;
986         }
987         unixtime.tv_sec = pntohl(&pd[cur_offset]);
988         unixtime.tv_usec = 0;
989         proto_tree_add_text(rr_tree, cur_offset, 4, "Time signed: %s",
990                 abs_time_to_str(&unixtime));
991         cur_offset += 4;
992         rr_len -= 4;
993
994         if (!BYTES_ARE_IN_FRAME(cur_offset, 2)) {
995           /* We ran past the end of the captured data in the packet. */
996           return 0;
997         }
998         proto_tree_add_text(rr_tree, cur_offset, 2, "Key footprint: 0x%04x",
999                 pntohs(&pd[cur_offset]));
1000         cur_offset += 2;
1001         rr_len -= 2;
1002
1003         signer_name_len = get_dns_name(pd, cur_offset, dns_data_offset, signer_name, sizeof(signer_name));
1004         if (signer_name_len < 0) {
1005           /* We ran past the end of the captured data in the packet. */
1006           return 0;
1007         }
1008         proto_tree_add_text(rr_tree, cur_offset, signer_name_len,
1009                 "Signer's name: %s", signer_name);
1010         cur_offset += signer_name_len;
1011         rr_len -= signer_name_len;
1012
1013         proto_tree_add_text(rr_tree, cur_offset, rr_len, "Signature");
1014       }
1015     }
1016     break;
1017
1018   case T_KEY:
1019     {
1020       int rr_len = data_len;
1021       guint16 flags;
1022       proto_item *tf;
1023       proto_tree *flags_tree;
1024
1025       if (fd != NULL)
1026         col_append_fstr(fd, COL_INFO, " %s", type_name);
1027       if (dns_tree != NULL) {
1028         trr = proto_tree_add_text(dns_tree, offset, (dptr - data_start) + data_len,
1029                      "%s: type %s, class %s",
1030                      name, type_name, class_name);
1031         rr_tree = add_rr_to_tree(trr, ett_dns_rr, offset, name, name_len,
1032                        long_type_name, class_name, ttl, data_len);
1033
1034         if (!BYTES_ARE_IN_FRAME(cur_offset, 2)) {
1035           /* We ran past the end of the captured data in the packet. */
1036           return 0;
1037         }
1038         flags = pntohs(&pd[cur_offset]);
1039         tf = proto_tree_add_text(rr_tree, cur_offset, 2, "Flags: 0x%04X", flags);
1040         flags_tree = proto_item_add_subtree(tf, ett_t_key_flags);
1041         proto_tree_add_text(flags_tree, cur_offset, 2, "%s",
1042                 decode_boolean_bitfield(flags, 0x8000,
1043                   2*8, "Key prohibited for authentication",
1044                        "Key allowed for authentication"));
1045         proto_tree_add_text(flags_tree, cur_offset, 2, "%s",
1046                 decode_boolean_bitfield(flags, 0x4000,
1047                   2*8, "Key prohibited for confidentiality",
1048                        "Key allowed for confidentiality"));
1049         if ((flags & 0xC000) != 0xC000) {
1050           /* We have a key */
1051           proto_tree_add_text(flags_tree, cur_offset, 2, "%s",
1052                 decode_boolean_bitfield(flags, 0x2000,
1053                   2*8, "Key is experimental or optional",
1054                        "Key is required"));
1055           proto_tree_add_text(flags_tree, cur_offset, 2, "%s",
1056                 decode_boolean_bitfield(flags, 0x0400,
1057                   2*8, "Key is associated with a user",
1058                        "Key is not associated with a user"));
1059           proto_tree_add_text(flags_tree, cur_offset, 2, "%s",
1060                 decode_boolean_bitfield(flags, 0x0200,
1061                   2*8, "Key is associated with the named entity",
1062                        "Key is not associated with the named entity"));
1063           proto_tree_add_text(flags_tree, cur_offset, 2, "%s",
1064                 decode_boolean_bitfield(flags, 0x0100,
1065                   2*8, "This is the zone key for the specified zone",
1066                        "This is not a zone key"));
1067           proto_tree_add_text(flags_tree, cur_offset, 2, "%s",
1068                 decode_boolean_bitfield(flags, 0x0080,
1069                   2*8, "Key is valid for use with IPSEC",
1070                        "Key is not valid for use with IPSEC"));
1071           proto_tree_add_text(flags_tree, cur_offset, 2, "%s",
1072                 decode_boolean_bitfield(flags, 0x0040,
1073                   2*8, "Key is valid for use with MIME security multiparts",
1074                        "Key is not valid for use with MIME security multiparts"));
1075           proto_tree_add_text(flags_tree, cur_offset, 2, "%s",
1076                 decode_numeric_bitfield(flags, 0x000F,
1077                   2*8, "Signatory = %u"));
1078         }
1079         cur_offset += 2;
1080         rr_len -= 2;
1081
1082         if (!BYTES_ARE_IN_FRAME(cur_offset, 1)) {
1083           /* We ran past the end of the captured data in the packet. */
1084           return 0;
1085         }
1086         proto_tree_add_text(rr_tree, cur_offset, 1, "Protocol: %u",
1087                 pd[cur_offset]);
1088         cur_offset += 1;
1089         rr_len -= 1;
1090
1091         if (!BYTES_ARE_IN_FRAME(cur_offset, 1)) {
1092           /* We ran past the end of the captured data in the packet. */
1093           return 0;
1094         }
1095         proto_tree_add_text(rr_tree, cur_offset, 1, "Algorithm: %s",
1096                 val_to_str(pd[cur_offset], algo_vals,
1097                     "Unknown (0x%02X)"));
1098         cur_offset += 1;
1099                 rr_len -= 1;
1100
1101         proto_tree_add_text(rr_tree, cur_offset, rr_len, "Public key");
1102       }
1103     }
1104     break;
1105
1106   case T_AAAA:
1107     if (fd != NULL) {
1108       col_append_fstr(fd, COL_INFO, " %s %s", type_name,
1109                         ip6_to_str((struct e_in6_addr *)dptr));
1110     }
1111     if (dns_tree != NULL) {
1112       trr = proto_tree_add_text(dns_tree, offset, (dptr - data_start) + data_len,
1113                      "%s: type %s, class %s, addr %s",
1114                      name, type_name, class_name,
1115                      ip6_to_str((struct e_in6_addr *)dptr));
1116       rr_tree = add_rr_to_tree(trr, ett_dns_rr, offset, name, name_len,
1117                      long_type_name, class_name, ttl, data_len);
1118       if (!BYTES_ARE_IN_FRAME(cur_offset, 16)) {
1119         /* We ran past the end of the captured data in the packet. */
1120         return 0;
1121       }
1122       proto_tree_add_text(rr_tree, cur_offset, 16, "Addr: %s",
1123                      ip6_to_str((struct e_in6_addr *)dptr));
1124     }
1125     break;
1126
1127   case T_LOC:
1128     {
1129       if (fd != NULL)
1130         col_append_fstr(fd, COL_INFO, " %s", type_name);
1131       if (dns_tree != NULL) {
1132         trr = proto_tree_add_text(dns_tree, offset, (dptr - data_start) + data_len,
1133                      "%s: type %s, class %s",
1134                      name, type_name, class_name);
1135         rr_tree = add_rr_to_tree(trr, ett_dns_rr, offset, name, name_len,
1136                        long_type_name, class_name, ttl, data_len);
1137         if (!BYTES_ARE_IN_FRAME(cur_offset, 1)) {
1138           /* We ran past the end of the captured data in the packet. */
1139           return 0;
1140         }
1141         proto_tree_add_text(rr_tree, cur_offset, 1, "Version: %u", pd[cur_offset]);
1142         if (pd[cur_offset] == 0) {
1143           /* Version 0, the only version RFC 1876 discusses. */
1144           cur_offset++;
1145
1146           if (!BYTES_ARE_IN_FRAME(cur_offset, 1)) {
1147             /* We ran past the end of the captured data in the packet. */
1148             return 0;
1149           }
1150           proto_tree_add_text(rr_tree, cur_offset, 1, "Size: %g m",
1151                                 rfc1867_size(pd[cur_offset]));
1152           cur_offset++;
1153
1154           if (!BYTES_ARE_IN_FRAME(cur_offset, 1)) {
1155             /* We ran past the end of the captured data in the packet. */
1156             return 0;
1157           }
1158           proto_tree_add_text(rr_tree, cur_offset, 1, "Horizontal precision: %g m",
1159                                 rfc1867_size(pd[cur_offset]));
1160           cur_offset++;
1161
1162           if (!BYTES_ARE_IN_FRAME(cur_offset, 1)) {
1163             /* We ran past the end of the captured data in the packet. */
1164             return 0;
1165           }
1166           proto_tree_add_text(rr_tree, cur_offset, 1, "Vertical precision: %g m",
1167                                 rfc1867_size(pd[cur_offset]));
1168           cur_offset++;
1169
1170           if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
1171             /* We ran past the end of the captured data in the packet. */
1172             return 0;
1173           }
1174           proto_tree_add_text(rr_tree, cur_offset, 4, "Latitude: %s",
1175                                 rfc1867_angle(&pd[cur_offset], "NS"));
1176           cur_offset += 4;
1177
1178           if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
1179             /* We ran past the end of the captured data in the packet. */
1180             return 0;
1181           }
1182           proto_tree_add_text(rr_tree, cur_offset, 4, "Longitude: %s",
1183                                 rfc1867_angle(&pd[cur_offset], "EW"));
1184           cur_offset += 4;
1185
1186           if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
1187             /* We ran past the end of the captured data in the packet. */
1188             return 0;
1189           }
1190           proto_tree_add_text(rr_tree, cur_offset, 4, "Altitude: %g m",
1191                                 (pntohl(&pd[cur_offset]) - 10000000)/100.0);
1192         } else
1193           proto_tree_add_text(rr_tree, cur_offset, data_len, "Data");
1194       }
1195       break;
1196     }
1197     break;
1198       
1199   case T_NXT:
1200     {
1201       int rr_len = data_len;
1202       char next_domain_name[MAXDNAME];
1203       int next_domain_name_len;
1204       int rr_type;
1205       guint8 bits;
1206       int mask;
1207       int i;
1208
1209       next_domain_name_len = get_dns_name(pd, cur_offset, dns_data_offset,
1210                         next_domain_name, sizeof(next_domain_name));
1211       if (fd != NULL)
1212         col_append_fstr(fd, COL_INFO, " %s %s", type_name, next_domain_name);
1213       if (dns_tree != NULL) {
1214         trr = proto_tree_add_text(dns_tree, offset, (dptr - data_start) + data_len,
1215                      "%s: type %s, class %s, next domain name %s",
1216                      name, type_name, class_name, next_domain_name);
1217         rr_tree = add_rr_to_tree(trr, ett_dns_rr, offset, name, name_len,
1218                        long_type_name, class_name, ttl, data_len);
1219         if (next_domain_name_len < 0) {
1220           /* We ran past the end of the captured data in the packet. */
1221           return 0;
1222         }
1223         proto_tree_add_text(rr_tree, cur_offset, next_domain_name_len,
1224                         "Next domain name: %s", next_domain_name);
1225         cur_offset += next_domain_name_len;
1226         rr_len -= next_domain_name_len;
1227         rr_type = 0;
1228         while (rr_len != 0) {
1229           bits = pd[cur_offset];
1230           mask = 1<<8;
1231           for (i = 0; i < 8; i++) {
1232             if (bits & mask) {
1233               proto_tree_add_text(rr_tree, cur_offset, 1,
1234                         "RR type in bit map: %s (%s)",
1235                         dns_type_name(rr_type),
1236                         dns_long_type_name(rr_type));
1237             }
1238             mask >>= 1;
1239             rr_type++;
1240           }
1241           cur_offset += 1;
1242           rr_len -= 1;
1243         }
1244       }
1245     }
1246     break;
1247
1248     /* TODO: parse more record types */
1249
1250   default:
1251     if (fd != NULL)
1252       col_append_fstr(fd, COL_INFO, " %s", type_name);
1253     if (dns_tree != NULL) {
1254       trr = proto_tree_add_text(dns_tree, offset, (dptr - data_start) + data_len,
1255                      "%s: type %s, class %s",
1256                      name, type_name, class_name);
1257       rr_tree = add_rr_to_tree(trr, ett_dns_rr, offset, name, name_len,
1258                        long_type_name, class_name, ttl, data_len);
1259       proto_tree_add_text(rr_tree, cur_offset, data_len, "Data");
1260     }
1261     break;
1262   }
1263   
1264   dptr += data_len;
1265         
1266   return dptr - data_start;
1267 }
1268
1269 static int
1270 dissect_query_records(const u_char *pd, int cur_off, int dns_data_offset,
1271     int count, frame_data *fd, proto_tree *dns_tree)
1272 {
1273   int start_off, add_off;
1274   proto_tree *qatree = NULL;
1275   proto_item *ti = NULL;
1276   
1277   start_off = cur_off;
1278   if (dns_tree) {
1279     ti = proto_tree_add_text(dns_tree, start_off, 0, "Queries");
1280     qatree = proto_item_add_subtree(ti, ett_dns_qry);
1281   }
1282   while (count-- > 0) {
1283     add_off = dissect_dns_query(pd, cur_off, dns_data_offset, fd, qatree);
1284     if (add_off <= 0) {
1285       /* We ran past the end of the captured data in the packet. */
1286       break;
1287     }
1288     cur_off += add_off;
1289   }
1290   if (ti)
1291     proto_item_set_len(ti, cur_off - start_off);
1292
1293   return cur_off - start_off;
1294 }
1295
1296 static int
1297 dissect_answer_records(const u_char *pd, int cur_off, int dns_data_offset,
1298     int count, frame_data *fd, proto_tree *dns_tree, char *name)
1299 {
1300   int start_off, add_off;
1301   proto_tree *qatree = NULL;
1302   proto_item *ti = NULL;
1303   
1304   start_off = cur_off;
1305   if (dns_tree) {
1306     ti = proto_tree_add_text(dns_tree, start_off, 0, name);
1307     qatree = proto_item_add_subtree(ti, ett_dns_ans);
1308   }
1309   while (count-- > 0) {
1310     add_off = dissect_dns_answer(pd, cur_off, dns_data_offset, fd, qatree);
1311     if (add_off <= 0) {
1312       /* We ran past the end of the captured data in the packet. */
1313       break;
1314     }
1315     cur_off += add_off;
1316   }
1317   if (ti)
1318     proto_item_set_len(ti, cur_off - start_off);
1319
1320   return cur_off - start_off;
1321 }
1322
1323 void
1324 dissect_dns(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
1325 {
1326   int dns_data_offset;
1327   proto_tree *dns_tree = NULL, *field_tree;
1328   proto_item *ti, *tf;
1329   guint16    id, flags, quest, ans, auth, add;
1330   char buf[128+1];
1331   int cur_off;
1332   static const value_string opcode_vals[] = {
1333                   { OPCODE_QUERY,  "Standard query"        },
1334                   { OPCODE_IQUERY, "Inverse query"         },
1335                   { OPCODE_STATUS, "Server status request" },
1336                   { 0,              NULL                   } };
1337   static const value_string rcode_vals[] = {
1338                   { RCODE_NOERROR,   "No error"        },
1339                   { RCODE_FMTERROR,  "Format error"    },
1340                   { RCODE_SERVFAIL,  "Server failure"  },
1341                   { RCODE_NAMEERROR, "Name error"      },
1342                   { RCODE_NOTIMPL,   "Not implemented" },
1343                   { RCODE_REFUSED,   "Refused"         },
1344                   { 0,               NULL              } };
1345
1346   dns_data_offset = offset;
1347
1348   if (check_col(fd, COL_PROTOCOL))
1349     col_add_str(fd, COL_PROTOCOL, "DNS");
1350
1351   if (pi.captured_len < DNS_HDRLEN) {
1352     col_add_str(fd, COL_INFO, "Short DNS packet");
1353     dissect_data(pd, offset, fd, tree);
1354     return;
1355   }
1356
1357   /* To do: check for errs, etc. */
1358   id    = pntohs(&pd[offset + DNS_ID]);
1359   flags = pntohs(&pd[offset + DNS_FLAGS]);
1360   quest = pntohs(&pd[offset + DNS_QUEST]);
1361   ans   = pntohs(&pd[offset + DNS_ANS]);
1362   auth  = pntohs(&pd[offset + DNS_AUTH]);
1363   add   = pntohs(&pd[offset + DNS_ADD]);
1364
1365   if (check_col(fd, COL_INFO)) {
1366     strcpy(buf, val_to_str(flags & F_OPCODE, opcode_vals, "Unknown operation (%x)"));
1367     if (flags & F_RESPONSE) {
1368       strcat(buf, " response");
1369       if ((flags & F_RCODE) != RCODE_NOERROR) {
1370         strcat(buf, ", ");
1371         strcat(buf, val_to_str(flags & F_RCODE, rcode_vals,
1372             "Unknown error (%x)"));
1373       }
1374     }
1375     col_add_str(fd, COL_INFO, buf);
1376   } else {
1377     /* Set "fd" to NULL; we pass a NULL "fd" to the query and answer
1378        dissectors, as a way of saying that they shouldn't add stuff
1379        to the COL_INFO column (a call to "check_col(fd, COL_INFO)"
1380        is more expensive than a check that a pointer isn't NULL). */
1381     fd = NULL;
1382   }
1383   
1384   if (tree) {
1385     ti = proto_tree_add_item_format(tree, proto_dns, offset, 4, NULL,
1386       "Domain Name System (%s)", (flags & F_RESPONSE) ? "response" : "query");
1387     
1388     dns_tree = proto_item_add_subtree(ti, ett_dns);
1389
1390     if (flags & F_RESPONSE)
1391       proto_tree_add_item_hidden(dns_tree, hf_dns_response, offset, 4, 1);
1392     else
1393       proto_tree_add_item_hidden(dns_tree, hf_dns_query, offset, 4, 1);
1394
1395     proto_tree_add_item(dns_tree, hf_dns_transaction_id, 
1396                         offset + DNS_ID, 2, id);
1397
1398     strcpy(buf, val_to_str(flags & F_OPCODE, opcode_vals, "Unknown operation"));
1399     if (flags & F_RESPONSE) {
1400       strcat(buf, " response");
1401       strcat(buf, ", ");
1402       strcat(buf, val_to_str(flags & F_RCODE, rcode_vals,
1403             "Unknown error"));
1404     }
1405     tf = proto_tree_add_item_format(dns_tree, hf_dns_flags, 
1406                                     offset + DNS_FLAGS, 2, 
1407                                     flags,
1408                                     "Flags: 0x%04x (%s)",
1409                                     flags, buf);
1410     field_tree = proto_item_add_subtree(tf, ett_dns_flags);
1411     proto_tree_add_text(field_tree, offset + DNS_FLAGS, 2, "%s",
1412        decode_boolean_bitfield(flags, F_RESPONSE,
1413             2*8, "Response", "Query"));
1414     proto_tree_add_text(field_tree, offset + DNS_FLAGS, 2, "%s",
1415        decode_enumerated_bitfield(flags, F_OPCODE,
1416             2*8, opcode_vals, "%s"));
1417     if (flags & F_RESPONSE) {
1418       proto_tree_add_text(field_tree, offset + DNS_FLAGS, 2, "%s",
1419          decode_boolean_bitfield(flags, F_AUTHORITATIVE,
1420               2*8,
1421               "Server is an authority for domain",
1422               "Server isn't an authority for domain"));
1423     }
1424     proto_tree_add_text(field_tree, offset + DNS_FLAGS, 2, "%s",
1425        decode_boolean_bitfield(flags, F_TRUNCATED,
1426             2*8,
1427             "Message is truncated",
1428             "Message is not truncated"));
1429     proto_tree_add_text(field_tree, offset + DNS_FLAGS, 2, "%s",
1430        decode_boolean_bitfield(flags, F_RECDESIRED,
1431             2*8,
1432             "Do query recursively",
1433             "Don't do query recursively"));
1434     if (flags & F_RESPONSE) {
1435       proto_tree_add_text(field_tree, offset + DNS_FLAGS, 2, "%s",
1436          decode_boolean_bitfield(flags, F_RECAVAIL,
1437               2*8,
1438               "Server can do recursive queries",
1439               "Server can't do recursive queries"));
1440       proto_tree_add_text(field_tree, offset + DNS_FLAGS, 2, "%s",
1441          decode_enumerated_bitfield(flags, F_RCODE,
1442               2*8, rcode_vals, "%s"));
1443     }
1444     proto_tree_add_item(dns_tree, hf_dns_count_questions, 
1445                         offset + DNS_QUEST, 2, quest);
1446     proto_tree_add_item(dns_tree, hf_dns_count_answers, 
1447                         offset + DNS_ANS, 2, ans);
1448     proto_tree_add_item(dns_tree, hf_dns_count_auth_rr, 
1449                         offset + DNS_AUTH, 2, auth);
1450     proto_tree_add_item(dns_tree, hf_dns_count_add_rr, 
1451                         offset + DNS_ADD, 2, add);
1452
1453   }
1454   cur_off = offset + DNS_HDRLEN;
1455
1456   if (quest > 0) {
1457     /* If this is a response, don't add information about the queries
1458        to the summary, just add information about the answers. */
1459     cur_off += dissect_query_records(pd, cur_off, dns_data_offset, quest,
1460                                         (!(flags & F_RESPONSE) ? fd : NULL),
1461                                         dns_tree);
1462   }
1463     
1464   if (ans > 0) {
1465     /* If this is a request, don't add information about the answers
1466        to the summary, just add information about the queries. */
1467     cur_off += dissect_answer_records(pd, cur_off, dns_data_offset, ans,
1468                                         ((flags & F_RESPONSE) ? fd : NULL),
1469                                         dns_tree, "Answers");
1470   }
1471     
1472   if (tree) {
1473     /* Don't add information about the authoritative name servers, or the
1474        additional records, to the summary. */
1475     if (auth > 0)
1476       cur_off += dissect_answer_records(pd, cur_off, dns_data_offset, auth,
1477           NULL, dns_tree, "Authoritative nameservers");
1478
1479     if (add > 0)
1480       cur_off += dissect_answer_records(pd, cur_off, dns_data_offset, add,
1481           NULL, dns_tree, "Additional records");
1482   }
1483 }
1484
1485 void
1486 proto_register_dns(void)
1487 {
1488   static hf_register_info hf[] = {
1489     { &hf_dns_response,
1490       { "Response",             "dns.response",  
1491         FT_BOOLEAN, BASE_NONE, NULL, 0x0,
1492         "TRUE if DNS response" }},
1493     { &hf_dns_query,
1494       { "Query",                "dns.query",  
1495         FT_BOOLEAN, BASE_NONE, NULL, 0x0,
1496         "TRUE if DNS query" }},
1497     { &hf_dns_flags,
1498       { "Flags",                "dns.flags",  
1499         FT_UINT16, BASE_HEX, NULL, 0x0,
1500         "" }},
1501     { &hf_dns_transaction_id,
1502       { "Transaction ID",       "dns.id",  
1503         FT_UINT16, BASE_HEX, NULL, 0x0,
1504         "Identification of transaction" }},
1505     { &hf_dns_count_questions,
1506       { "Questions",            "dns.count.queries",  
1507         FT_UINT16, BASE_DEC, NULL, 0x0,
1508         "Number of queries in packet" }},
1509     { &hf_dns_count_answers,
1510       { "Answer RRs",           "dns.count.answers",  
1511         FT_UINT16, BASE_DEC, NULL, 0x0,
1512         "Number of answers in packet" }},
1513     { &hf_dns_count_auth_rr,
1514       { "Authority RRs",        "dns.count.auth_rr",  
1515         FT_UINT16, BASE_DEC, NULL, 0x0,
1516         "Number of authoritative records in packet" }},
1517     { &hf_dns_count_add_rr,
1518       { "Additional RRs",       "dns.count.add_rr",  
1519         FT_UINT16, BASE_DEC, NULL, 0x0,
1520         "Number of additional records in packet" }}
1521   };
1522   static gint *ett[] = {
1523     &ett_dns,
1524     &ett_dns_qd,
1525     &ett_dns_rr,
1526     &ett_dns_qry,
1527     &ett_dns_ans,
1528     &ett_dns_flags,
1529     &ett_t_key_flags,
1530   };
1531
1532   proto_dns = proto_register_protocol("Domain Name Service", "dns");
1533   proto_register_field_array(proto_dns, hf, array_length(hf));
1534   proto_register_subtree_array(ett, array_length(ett));
1535 }