Add tables of "conversation" dissectors, which are associated with
[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.60 2001/01/03 06:55:27 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 "resolv.h"
41 #include "packet-dns.h"
42 #include "packet-ip.h"
43
44 static int proto_dns = -1;
45 static int hf_dns_response = -1;
46 static int hf_dns_query = -1;
47 static int hf_dns_flags = -1;
48 static int hf_dns_transaction_id = -1;
49 static int hf_dns_count_questions = -1;
50 static int hf_dns_count_answers = -1;
51 static int hf_dns_count_auth_rr = -1;
52 static int hf_dns_count_add_rr = -1;
53
54 static gint ett_dns = -1;
55 static gint ett_dns_qd = -1;
56 static gint ett_dns_rr = -1;
57 static gint ett_dns_qry = -1;
58 static gint ett_dns_ans = -1;
59 static gint ett_dns_flags = -1;
60 static gint ett_t_key_flags = -1;
61
62 /* DNS structs and definitions */
63
64 /* Ports used for DNS. */
65 #define UDP_PORT_DNS     53
66 #define TCP_PORT_DNS     53
67
68 /* Offsets of fields in the DNS header. */
69 #define DNS_ID          0
70 #define DNS_FLAGS       2
71 #define DNS_QUEST       4
72 #define DNS_ANS         6
73 #define DNS_AUTH        8
74 #define DNS_ADD         10
75
76 /* Length of DNS header. */
77 #define DNS_HDRLEN      12
78
79 /* type values  */
80 #define T_A             1               /* host address */
81 #define T_NS            2               /* authoritative name server */
82 #define T_MD            3               /* mail destination (obsolete) */
83 #define T_MF            4               /* mail forwarder (obsolete) */
84 #define T_CNAME         5               /* canonical name */
85 #define T_SOA           6               /* start of authority zone */
86 #define T_MB            7               /* mailbox domain name (experimental) */
87 #define T_MG            8               /* mail group member (experimental) */
88 #define T_MR            9               /* mail rename domain name (experimental) */
89 #define T_NULL          10              /* null RR (experimental) */
90 #define T_WKS           11              /* well known service */
91 #define T_PTR           12              /* domain name pointer */
92 #define T_HINFO         13              /* host information */
93 #define T_MINFO         14              /* mailbox or mail list information */
94 #define T_MX            15              /* mail routing information */
95 #define T_TXT           16              /* text strings */
96 #define T_RP            17              /* responsible person (RFC 1183) */
97 #define T_AFSDB         18              /* AFS data base location (RFC 1183) */
98 #define T_X25           19              /* X.25 address (RFC 1183) */
99 #define T_ISDN          20              /* ISDN address (RFC 1183) */
100 #define T_RT            21              /* route-through (RFC 1183) */
101 #define T_NSAP          22              /* OSI NSAP (RFC 1706) */
102 #define T_NSAP_PTR      23              /* PTR equivalent for OSI NSAP (RFC 1348 - obsolete) */
103 #define T_SIG           24              /* digital signature (RFC 2535) */
104 #define T_KEY           25              /* public key (RFC 2535) */
105 #define T_PX            26              /* pointer to X.400/RFC822 mapping info (RFC 1664) */
106 #define T_GPOS          27              /* geographical position (RFC 1712) */
107 #define T_AAAA          28              /* IPv6 address (RFC 1886) */
108 #define T_LOC           29              /* geographical location (RFC 1876) */
109 #define T_NXT           30              /* "next" name (RFC 2535) */
110 #define T_EID           31              /* ??? (Nimrod?) */
111 #define T_NIMLOC        32              /* ??? (Nimrod?) */
112 #define T_SRV           33              /* service location (RFC 2052) */
113 #define T_ATMA          34              /* ??? */
114 #define T_NAPTR         35              /* naming authority pointer (RFC 2168) */
115 #define T_KX            36              /* Key Exchange (RFC 2230) */
116 #define T_CERT          37              /* Certificate (RFC 2538) */
117 #define T_A6            38              /* IPv6 address with indirection (RFC 2874) */
118 #define T_DNAME         39              /* Non-terminal DNS name redirection (RFC 2672) */
119 #define T_OPT           41              /* OPT pseudo-RR (RFC 2671) */
120 #define T_TKEY          249             /* Transaction Key (RFC 2930) */
121 #define T_TSIG          250             /* Transaction Signature (RFC 2845) */
122 #define T_WINS          65281           /* Microsoft's WINS RR */
123 #define T_WINS_R        65282           /* Microsoft's WINS-R RR */
124
125 /* Class values */
126 #define C_IN            1               /* the Internet */
127 #define C_CS            2               /* CSNET (obsolete) */
128 #define C_CH            3               /* CHAOS */
129 #define C_HS            4               /* Hesiod */
130 #define C_NONE          254             /* none */
131 #define C_ANY           255             /* any */
132
133 /* Bit fields in the flags */
134 #define F_RESPONSE      (1<<15)         /* packet is response */
135 #define F_OPCODE        (0xF<<11)       /* query opcode */
136 #define F_AUTHORITATIVE (1<<10)         /* response is authoritative */
137 #define F_TRUNCATED     (1<<9)          /* response is truncated */
138 #define F_RECDESIRED    (1<<8)          /* recursion desired */
139 #define F_RECAVAIL      (1<<7)          /* recursion available */
140 #define F_AUTHENTIC     (1<<5)          /* authentic data (RFC2535) */
141 #define F_CHECKDISABLE  (1<<4)          /* checking disabled (RFC2535) */
142 #define F_RCODE         (0xF<<0)        /* reply code */
143
144 /* Opcodes */
145 #define OPCODE_QUERY    (0<<11)         /* standard query */
146 #define OPCODE_IQUERY   (1<<11)         /* inverse query */
147 #define OPCODE_STATUS   (2<<11)         /* server status request */
148 #define OPCODE_NOTIFY   (4<<11)         /* zone change notification */
149 #define OPCODE_UPDATE   (5<<11)         /* dynamic update */
150
151 /* Reply codes */
152 #define RCODE_NOERROR   (0<<0)
153 #define RCODE_FORMERR   (1<<0)
154 #define RCODE_SERVFAIL  (2<<0)
155 #define RCODE_NXDOMAIN  (3<<0)
156 #define RCODE_NOTIMPL   (4<<0)
157 #define RCODE_REFUSED   (5<<0)
158 #define RCODE_YXDOMAIN  (6<<0)
159 #define RCODE_YXRRSET   (7<<0)
160 #define RCODE_NXRRSET   (8<<0)
161 #define RCODE_NOTAUTH   (9<<0)
162 #define RCODE_NOTZONE   (10<<0)
163
164 static const value_string rcode_vals[] = {
165           { RCODE_NOERROR,   "No error"             },
166           { RCODE_FORMERR,   "Format error"         },
167           { RCODE_SERVFAIL,  "Server failure"       },
168           { RCODE_NXDOMAIN,  "No such name"         },
169           { RCODE_NOTIMPL,   "Not implemented"      },
170           { RCODE_REFUSED,   "Refused"              },
171           { RCODE_YXDOMAIN,  "Name exists"          },
172           { RCODE_YXRRSET,   "RRset exists"         },
173           { RCODE_NXRRSET,   "RRset does not exist" },
174           { RCODE_NOTAUTH,   "Not authoritative"    },
175           { RCODE_NOTZONE,   "Name out of zone"     },
176           { 0,               NULL                   } };
177
178 /* TSIG/TKEY extended errors */
179 #define TSIGERROR_BADSIG   (16)
180 #define TSIGERROR_BADKEY   (17)
181 #define TSIGERROR_BADTIME  (18)
182 #define TSIGERROR_BADMODE  (19)
183 #define TSIGERROR_BADNAME  (20)
184 #define TSIGERROR_BADALG   (21)
185
186 static const value_string tsigerror_vals[] = {
187           { TSIGERROR_BADSIG,   "Bad signature"        },
188           { TSIGERROR_BADKEY,   "Bad key"              },
189           { TSIGERROR_BADTIME,  "Bad time failure"     },
190           { TSIGERROR_BADMODE,  "Bad mode such name"   },
191           { TSIGERROR_BADNAME,  "Bad name implemented" },
192           { TSIGERROR_BADALG,   "Bad algorithm"        },
193           { 0,                  NULL                   } };
194
195 #define TKEYMODE_SERVERASSIGNED             (1)
196 #define TKEYMODE_DIFFIEHELLMAN              (2)
197 #define TKEYMODE_GSSAPI                     (3)
198 #define TKEYMODE_RESOLVERASSIGNED           (4)
199 #define TKEYMODE_DELETE                     (5)
200
201 /* See RFC 1035 for all RR types for which no RFC is listed, except for
202    the ones with "???", and for the Microsoft WINS and WINS-R RRs, for
203    which one should look at
204
205 http://www.windows.com/windows2000/en/server/help/sag_DNS_imp_UsingWinsLookup.htm
206    
207    and
208    
209 http://www.microsoft.com/windows2000/library/resources/reskit/samplechapters/cncf/cncf_imp_wwaw.asp
210
211    which discuss them to some extent. */
212 static char *
213 dns_type_name (u_int type)
214 {
215   char *type_names[] = {
216     "unused",
217     "A",
218     "NS",
219     "MD",
220     "MF",
221     "CNAME",
222     "SOA",
223     "MB",
224     "MG",
225     "MR",
226     "NULL",
227     "WKS",
228     "PTR",
229     "HINFO",
230     "MINFO",
231     "MX",
232     "TXT",
233     "RP",                               /* RFC 1183 */
234     "AFSDB",                            /* RFC 1183 */
235     "X25",                              /* RFC 1183 */
236     "ISDN",                             /* RFC 1183 */
237     "RT",                               /* RFC 1183 */
238     "NSAP",                             /* RFC 1706 */
239     "NSAP-PTR",                         /* RFC 1348 */
240     "SIG",                              /* RFC 2535 */
241     "KEY",                              /* RFC 2535 */
242     "PX",                               /* RFC 1664 */
243     "GPOS",                             /* RFC 1712 */
244     "AAAA",                             /* RFC 1886 */
245     "LOC",                              /* RFC 1876 */
246     "NXT",                              /* RFC 2535 */
247     "EID",
248     "NIMLOC",
249     "SRV",                              /* RFC 2052 */
250     "ATMA",
251     "NAPTR",                            /* RFC 2168 */
252     "KX",                               /* RFC 2230 */
253     "CERT",                             /* RFC 2538 */
254     "A6",                               /* RFC 2874 */
255     "DNAME",                            /* RFC 2672 */
256     NULL,
257     "OPT"                               /* RFC 2671 */
258   };
259   
260   if (type < sizeof(type_names)/sizeof(type_names[0]))
261     return type_names[type] ? type_names[type] : "unknown";
262   
263   /* special cases */
264   switch (type) 
265     {
266       /* non standard  */
267     case 100:
268       return "UINFO";
269     case 101:
270       return "UID";
271     case 102:
272       return "GID";
273     case 103:
274       return "UNSPEC";
275     case T_WINS:
276       return "WINS";
277     case T_WINS_R:
278       return "WINS-R";
279
280       /* meta */
281     case T_TKEY:
282       return "TKEY";
283     case T_TSIG:
284       return "TSIG";
285
286       /* queries  */
287     case 251:
288       return "IXFR";    /* RFC 1995 */
289     case 252:
290       return "AXFR";
291     case 253:
292       return "MAILB";
293     case 254:
294       return "MAILA";
295     case 255:
296       return "ANY";
297
298     }
299
300   return "unknown";
301 }
302
303
304 static char *
305 dns_long_type_name (u_int type)
306 {
307   char *type_names[] = {
308     "unused",
309     "Host address",
310     "Authoritative name server",        
311     "Mail destination",
312     "Mail forwarder",
313     "Canonical name for an alias",
314     "Start of zone of authority",
315     "Mailbox domain name",
316     "Mail group member",
317     "Mail rename domain name",
318     "Null resource record",
319     "Well-known service description",
320     "Domain name pointer",
321     "Host information",
322     "Mailbox or mail list information",
323     "Mail exchange",
324     "Text strings",
325     "Responsible person",               /* RFC 1183 */
326     "AFS data base location",           /* RFC 1183 */
327     "X.25 address",                     /* RFC 1183 */
328     "ISDN number",                      /* RFC 1183 */
329     "Route through",                    /* RFC 1183 */
330     "OSI NSAP",                         /* RFC 1706 */
331     "OSI NSAP name pointer",            /* RFC 1348 */
332     "Signature",                        /* RFC 2535 */
333     "Public key",                       /* RFC 2535 */
334     "Pointer to X.400/RFC822 mapping info", /* RFC 1664 */
335     "Geographical position",            /* RFC 1712 */
336     "IPv6 address",                     /* RFC 1886 */
337     "Location",                         /* RFC 1876 */
338     "Next",                             /* RFC 2535 */
339     "EID",
340     "NIMLOC",
341     "Service location",                 /* RFC 2052 */
342     "ATMA",
343     "Naming authority pointer",         /* RFC 2168 */
344     "Key Exchange",                     /* RFC 2230 */
345     "Certificate",                      /* RFC 2538 */
346     "IPv6 address with indirection",    /* RFC 2874 */
347     "Non-terminal DNS name redirection", /* RFC 2672 */
348     NULL,
349     "EDNS0 option"                      /* RFC 2671 */
350   };
351   static char unkbuf[7+1+2+1+4+1+1+10+1+1];     /* "Unknown RR type (%d)" */
352   
353   if (type < sizeof(type_names)/sizeof(type_names[0]))
354     return type_names[type] ? type_names[type] : "unknown";
355   
356   /* special cases */
357   switch (type) 
358     {
359       /* non standard  */
360     case 100:
361       return "UINFO";
362     case 101:
363       return "UID";
364     case 102:
365       return "GID";
366     case 103:
367       return "UNSPEC";
368     case T_WINS:
369       return "WINS";
370     case T_WINS_R:
371       return "WINS-R";
372
373       /* meta */
374     case T_TKEY:
375       return "Transaction Key";
376     case T_TSIG:
377       return "Transaction Signature";
378
379       /* queries  */
380     case 251:
381       return "Request for incremental zone transfer";   /* RFC 1995 */
382     case 252:
383       return "Request for full zone transfer";
384     case 253:
385       return "Request for mailbox-related records";
386     case 254:
387       return "Request for mail agent resource records";
388     case 255:
389       return "Request for all records";
390     }
391   
392   sprintf(unkbuf, "Unknown RR type (%d)", type);
393   return unkbuf;
394 }
395
396
397 char *
398 dns_class_name(int class)
399 {
400   char *class_name;
401   
402   switch (class) {
403   case C_IN:
404     class_name = "inet";
405     break;
406   case C_CS:
407     class_name = "csnet";
408     break;
409   case C_CH:
410     class_name = "chaos";
411     break;
412   case C_HS:
413     class_name = "hesiod";
414     break;
415   case C_NONE:
416     class_name = "none";
417     break;
418   case C_ANY:
419     class_name = "any";
420     break;
421   default:
422     class_name = "unknown";
423   }
424
425   return class_name;
426 }
427
428 int
429 get_dns_name(const u_char *pd, int offset, int dns_data_offset,
430     char *name, int maxname)
431 {
432   const u_char *dp = pd + offset;
433   const u_char *dptr = dp;
434   char *np = name;
435   int len = -1;
436   int chars_processed = 0;
437   int data_size = pi.len - dns_data_offset;
438   u_int component_len;
439
440   maxname--;    /* reserve space for the trailing '\0' */
441   for (;;) {
442     if (!BYTES_ARE_IN_FRAME(offset, 1))
443       goto overflow;
444     component_len = *dp++;
445     offset++;
446     if (component_len == 0)
447       break;
448     chars_processed++;
449     switch (component_len & 0xc0) {
450
451     case 0x00:
452       /* Label */
453       if (np != name) {
454         /* Not the first component - put in a '.'. */
455         if (maxname > 0) {
456           *np++ = '.';
457           maxname--;
458         }
459       }
460       if (!BYTES_ARE_IN_FRAME(offset, component_len))
461         goto overflow;
462       while (component_len > 0) {
463         if (maxname > 0) {
464           *np++ = *dp;
465           maxname--;
466         }
467         component_len--;
468         dp++;
469         offset++;
470         chars_processed++;
471       }
472       break;
473
474     case 0x40:
475       /* Extended label (RFC 2673) */
476       switch (component_len & 0x3f) {
477
478       case 0x01:
479         /* Bitstring label */
480         {
481           int bit_count;
482           int label_len;
483
484           bit_count = *dp++;
485           label_len = (bit_count - 1) / 8 + 1;
486         
487           np += sprintf(np, "\\[x");
488           while(label_len--) {
489             np += sprintf(np, "%02x", *dp++);
490           }
491           np += sprintf(np, "/%d]", bit_count);
492         }
493         break;
494
495       default:
496         strcpy(name, "<Unknown extended label>");
497         /* Parsing will propably fail from here on, since the */
498         /* label length is unknown... */
499         return dp - dptr;
500       }
501       break;
502
503     case 0x80:
504       goto error;       /* error */
505
506     case 0xc0:
507       /* Pointer. */
508       if (!BYTES_ARE_IN_FRAME(offset, 1))
509         goto overflow;
510       offset = dns_data_offset + (((component_len & ~0xc0) << 8) | (*dp++));
511       chars_processed++;
512
513       /* If "len" is negative, we are still working on the original name,
514          not something pointed to by a pointer, and so we should set "len"
515          to the length of the original name. */
516       if (len < 0)
517         len = dp - dptr;
518
519       if (offset >= pi.len) {
520         strcpy(name, "<Name contains a pointer that goes past the end of the packet>");
521         return len;
522       }
523
524       /* If we've looked at every character in the message, this pointer
525          will make us look at some character again, which means we're
526          looping. */
527       if (chars_processed >= data_size) {
528         strcpy(name, "<Name contains a pointer that loops>");
529         return len;
530       }
531
532       dp = pd + offset;
533       break;    /* now continue processing from there */
534     }
535   }
536         
537 error:
538   *np = '\0';
539   /* If "len" is negative, we haven't seen a pointer, and thus haven't
540      set the length, so set it. */
541   if (len < 0)
542     len = dp - dptr;
543   /* Zero-length name means "root server" */
544   if (*name == '\0')
545     strcpy(name, "<Root>");
546   return len;
547
548 overflow:
549   /* We ran past the end of the captured data in the packet. */
550   strcpy(name, "<Name goes past end of captured data in packet>");
551   /* If "len" is negative, we haven't seen a pointer, and thus haven't
552      set the length, so set it. */
553   if (len < 0)
554     len = dp - dptr;
555   return len;
556 }
557
558
559 static int
560 get_dns_name_type_class(const u_char *pd, int offset, int dns_data_offset,
561     char *name_ret, int *name_len_ret, int *type_ret, int *class_ret)
562 {
563   int len;
564   int name_len;
565   int type;
566   int class;
567   char name[MAXDNAME];
568   int start_offset = offset;
569
570   name_len = get_dns_name(pd, offset, dns_data_offset, name, sizeof(name));
571   offset += name_len;
572   
573   if (!BYTES_ARE_IN_FRAME(offset, 2)) {
574     /* We ran past the end of the captured data in the packet. */
575     return -1;
576   }
577   type = pntohs(&pd[offset]);
578   offset += 2;
579
580   if (!BYTES_ARE_IN_FRAME(offset, 2)) {
581     /* We ran past the end of the captured data in the packet. */
582     return -1;
583   }
584   class = pntohs(&pd[offset]);
585   offset += 2;
586
587   strcpy (name_ret, name);
588   *type_ret = type;
589   *class_ret = class;
590   *name_len_ret = name_len;
591
592   len = offset - start_offset;
593   return len;
594 }
595
596 static double
597 rfc1867_size(u_char val)
598 {
599   double size;
600   guint32 exponent;
601
602   size = (val & 0xF0) >> 4;
603   exponent = (val & 0x0F);
604   while (exponent != 0) {
605     size *= 10;
606     exponent--;
607   }
608   return size / 100;    /* return size in meters, not cm */
609 }
610
611 static char *
612 rfc1867_angle(const u_char *dptr, const char *nsew)
613 {
614   guint32 angle;
615   char direction;
616   guint32 degrees, minutes, secs, tsecs;
617   static char buf[10+1+3+1 + 2+1+3+1 + 2+1+3+1+3+1 + 1 + 1];
618
619   angle = pntohl(dptr);
620
621   if (angle < 0x80000000U) {
622     angle = 0x80000000U - angle;
623     direction = nsew[1];
624   } else {
625     angle = angle - 0x80000000U;
626     direction = nsew[0];
627   }
628   tsecs = angle % 1000;
629   angle = angle / 1000;
630   secs = angle % 60;
631   angle = angle / 60;
632   minutes = angle % 60;
633   degrees = angle / 60;
634   sprintf(buf, "%u deg %u min %u.%03u sec %c", degrees, minutes, secs,
635                 tsecs, direction);
636   return buf;
637 }
638
639 static int
640 dissect_dns_query(const u_char *pd, int offset, int dns_data_offset,
641   frame_data *fd, proto_tree *dns_tree)
642 {
643   int len;
644   char name[MAXDNAME];
645   int name_len;
646   int type;
647   int class;
648   char *class_name;
649   char *type_name;
650   char *long_type_name;
651   const u_char *dptr;
652   const u_char *data_start;
653   proto_tree *q_tree;
654   proto_item *tq;
655
656   data_start = dptr = pd + offset;
657
658   len = get_dns_name_type_class(pd, offset, dns_data_offset, name, &name_len,
659     &type, &class);
660   if (len < 0) {
661     /* We ran past the end of the data in the packet. */
662     return 0;
663   }
664   dptr += len;
665
666   type_name = dns_type_name(type);
667   class_name = dns_class_name(class);
668   long_type_name = dns_long_type_name(type);
669
670   if (fd != NULL)
671     col_append_fstr(fd, COL_INFO, " %s %s", type_name, name);
672   if (dns_tree != NULL) {
673     tq = proto_tree_add_text(dns_tree, NullTVB, offset, len, "%s: type %s, class %s", 
674                    name, type_name, class_name);
675     q_tree = proto_item_add_subtree(tq, ett_dns_qd);
676
677     proto_tree_add_text(q_tree, NullTVB, offset, name_len, "Name: %s", name);
678     offset += name_len;
679
680     proto_tree_add_text(q_tree, NullTVB, offset, 2, "Type: %s", long_type_name);
681     offset += 2;
682
683     proto_tree_add_text(q_tree, NullTVB, offset, 2, "Class: %s", class_name);
684     offset += 2;
685   }
686   
687   return dptr - data_start;
688 }
689
690
691 proto_tree *
692 add_rr_to_tree(proto_item *trr, int rr_type, int offset, const char *name,
693   int namelen, const char *type_name, const char *class_name, u_int ttl,
694   u_short data_len)
695 {
696   proto_tree *rr_tree;
697
698   rr_tree = proto_item_add_subtree(trr, rr_type);
699   proto_tree_add_text(rr_tree, NullTVB, offset, namelen, "Name: %s", name);
700   offset += namelen;
701   proto_tree_add_text(rr_tree, NullTVB, offset, 2, "Type: %s", type_name);
702   offset += 2;
703   proto_tree_add_text(rr_tree, NullTVB, offset, 2, "Class: %s", class_name);
704   offset += 2;
705   proto_tree_add_text(rr_tree, NullTVB, offset, 4, "Time to live: %s",
706                                                 time_secs_to_str(ttl));
707   offset += 4;
708   proto_tree_add_text(rr_tree, NullTVB, offset, 2, "Data length: %u", data_len);
709   return rr_tree;
710 }
711
712 static proto_tree *
713 add_opt_rr_to_tree(proto_item *trr, int rr_type, int offset, const char *name,
714   int namelen, const char *type_name, int class, u_int ttl, u_short data_len)
715 {
716   proto_tree *rr_tree;
717
718   rr_tree = proto_item_add_subtree(trr, rr_type);
719   proto_tree_add_text(rr_tree, NullTVB, offset, namelen, "Name: %s", name);
720   offset += namelen;
721   proto_tree_add_text(rr_tree, NullTVB, offset, 2, "Type: %s", type_name);
722   offset += 2;
723   proto_tree_add_text(rr_tree, NullTVB, offset, 2, "UDP payload size: %u",
724       class & 0xffff);
725   offset += 2;
726   proto_tree_add_text(rr_tree, NullTVB, offset, 1, "Higher bits in extended RCODE: 0x%x",
727       (ttl >> 24) & 0xff0);
728   offset++;
729   proto_tree_add_text(rr_tree, NullTVB, offset, 1, "EDNS0 version: %u",
730       (ttl >> 16) & 0xff);
731   offset++;
732   proto_tree_add_text(rr_tree, NullTVB, offset, 2, "Must be zero: 0x%x", ttl & 0xffff);
733   offset += 2;
734   proto_tree_add_text(rr_tree, NullTVB, offset, 2, "Data length: %u", data_len);
735   return rr_tree;
736 }
737
738 /*
739  * SIG, KEY, and CERT RR algorithms.
740  */
741 #define DNS_ALGO_RSAMD5         1       /* RSA/MD5 */
742 #define DNS_ALGO_DH             2       /* Diffie-Hellman */
743 #define DNS_ALGO_DSA            3       /* DSA */
744 #define DNS_ALGO_ECC            4       /* Elliptic curve crypto */
745 #define DNS_ALGO_INDIRECT       252     /* Indirect key */
746 #define DNS_ALGO_PRIVATEDNS     253     /* Private, domain name  */
747 #define DNS_ALGO_PRIVATEOID     254     /* Private, OID */      
748
749 static const value_string algo_vals[] = {
750           { DNS_ALGO_RSAMD5,     "RSA/MD5" },
751           { DNS_ALGO_DH,         "Diffie-Hellman" },
752           { DNS_ALGO_DSA,        "DSA" },
753           { DNS_ALGO_ECC,        "Elliptic curve crypto" },
754           { DNS_ALGO_INDIRECT,   "Indirect key" },
755           { DNS_ALGO_PRIVATEDNS, "Private, domain name" },
756           { DNS_ALGO_PRIVATEOID, "Private, OID" },
757           { 0,                   NULL }
758 };
759
760 #define DNS_CERT_PGP            1       /* PGP */
761 #define DNS_CERT_PKIX           2       /* PKIX */
762 #define DNS_CERT_SPKI           3       /* SPKI */
763 #define DNS_CERT_PRIVATEURI     253     /* Private, URI */
764 #define DNS_CERT_PRIVATEOID     254     /* Private, OID */
765
766 static const value_string cert_vals[] = {
767           { DNS_CERT_PGP,        "PGP" },
768           { DNS_CERT_PKIX,       "PKIX" },
769           { DNS_CERT_SPKI,       "SPKI" },
770           { DNS_CERT_PRIVATEURI, "Private, URI" },
771           { DNS_CERT_PRIVATEOID, "Private, OID" },
772           { 0,                   NULL }
773 };
774
775 static int
776 dissect_dns_answer(const u_char *pd, int offset, int dns_data_offset,
777   frame_data *fd, proto_tree *dns_tree)
778 {
779   int len;
780   char name[MAXDNAME];
781   int name_len;
782   int type;
783   int class;
784   char *class_name;
785   char *type_name;
786   char *long_type_name;
787   const u_char *dptr;
788   int cur_offset;
789   const u_char *data_start;
790   u_int ttl;
791   u_short data_len;
792   proto_tree *rr_tree = NULL;
793   proto_item *trr = NULL;
794
795   data_start = dptr = pd + offset;
796   cur_offset = offset;
797
798   len = get_dns_name_type_class(pd, offset, dns_data_offset, name, &name_len,
799     &type, &class);
800   if (len < 0) {
801     /* We ran past the end of the captured data in the packet. */
802     return 0;
803   }
804   dptr += len;
805   cur_offset += len;
806
807   type_name = dns_type_name(type);
808   class_name = dns_class_name(class);
809   long_type_name = dns_long_type_name(type);
810
811   if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
812     /* We ran past the end of the captured data in the packet. */
813     return 0;
814   }
815   ttl = pntohl(dptr);
816   dptr += 4;
817   cur_offset += 4;
818
819   if (!BYTES_ARE_IN_FRAME(cur_offset, 2)) {
820     /* We ran past the end of the captured data in the packet. */
821     return 0;
822   }
823   data_len = pntohs(dptr);
824   dptr += 2;
825   cur_offset += 2;
826
827   if (fd != NULL)
828     col_append_fstr(fd, COL_INFO, " %s", type_name);
829   if (dns_tree != NULL) {
830     trr = proto_tree_add_notext(dns_tree, NullTVB, offset,
831                                 (dptr - data_start) + data_len);
832     if (type != T_OPT) {
833       rr_tree = add_rr_to_tree(trr, ett_dns_rr, offset, name, name_len,
834                      long_type_name, class_name, ttl, data_len);
835     } else  {
836       rr_tree = add_opt_rr_to_tree(trr, ett_dns_rr, offset, name, name_len,
837                      long_type_name, class, ttl, data_len);
838     }
839   }
840
841   switch (type) {
842
843   case T_A:
844     if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
845       /* We ran past the end of the captured data in the packet. */
846       if (dns_tree != NULL) {
847         proto_item_set_text(trr,
848                 "%s: type %s, class %s, <Address goes past end of captured data in packet>",
849                        name, type_name, class_name);
850       }
851       return 0;
852     }
853     if (fd != NULL)
854       col_append_fstr(fd, COL_INFO, " %s", ip_to_str((guint8 *)dptr));
855     if (dns_tree != NULL) {
856       proto_item_set_text(trr, "%s: type %s, class %s, addr %s",
857                      name, type_name, class_name,
858                      ip_to_str((guint8 *)dptr));
859       proto_tree_add_text(rr_tree, NullTVB, cur_offset, 4, "Addr: %s",
860                      ip_to_str((guint8 *)dptr));
861     }
862     if (class == C_IN) {
863       guint32 addr;
864       memcpy(&addr, dptr, sizeof(addr));
865       add_host_name(addr, name);
866     }
867     break;
868
869   case T_NS:
870     {
871       char ns_name[MAXDNAME];
872       int ns_name_len;
873       
874       ns_name_len = get_dns_name(pd, cur_offset, dns_data_offset, ns_name, sizeof(ns_name));
875       if (ns_name_len < 0) {
876         /* We ran past the end of the captured data in the packet. */
877         if (dns_tree != NULL) {
878           proto_item_set_text(trr,
879                 "%s: type %s, class %s, <Nameserver name goes past end of captured data in packet>",
880                        name, type_name, class_name);
881         }
882         return 0;
883       }
884       if (fd != NULL)
885         col_append_fstr(fd, COL_INFO, " %s", ns_name);
886       if (dns_tree != NULL) {
887         proto_item_set_text(trr, "%s: type %s, class %s, ns %s",
888                        name, type_name, class_name, ns_name);
889         proto_tree_add_text(rr_tree, NullTVB, cur_offset, ns_name_len, "Name server: %s",
890                         ns_name);
891       }
892     }
893     break;
894
895   case T_CNAME:
896     {
897       char cname[MAXDNAME];
898       int cname_len;
899       
900       cname_len = get_dns_name(pd, cur_offset, dns_data_offset, cname, sizeof(cname));
901       if (cname_len < 0) {
902         /* We ran past the end of the captured data in the packet. */
903         if (dns_tree != NULL) {
904           proto_item_set_text(trr,
905                 "%s: type %s, class %s, <Primary name goes past end of captured data in packet>",
906                        name, type_name, class_name);
907         }
908         return 0;
909       }
910       if (fd != NULL)
911         col_append_fstr(fd, COL_INFO, " %s", cname);
912       if (dns_tree != NULL) {
913         proto_item_set_text(trr, "%s: type %s, class %s, cname %s",
914                      name, type_name, class_name, cname);
915         proto_tree_add_text(rr_tree, NullTVB, cur_offset, cname_len, "Primary name: %s",
916                         cname);
917       }
918     }
919     break;
920
921   case T_SOA:
922     {
923       char mname[MAXDNAME];
924       int mname_len;
925       char rname[MAXDNAME];
926       int rname_len;
927       guint32 serial;
928       guint32 refresh;
929       guint32 retry;
930       guint32 expire;
931       guint32 minimum;
932
933       mname_len = get_dns_name(pd, cur_offset, dns_data_offset, mname, sizeof(mname));
934       if (mname_len < 0) {
935         /* We ran past the end of the captured data in the packet. */
936         if (dns_tree != NULL) {
937           proto_item_set_text(trr,
938                 "%s: type %s, class %s, <mname goes past end of captured data in packet>",
939                        name, type_name, class_name);
940         }
941         return 0;
942       }
943       if (fd != NULL)
944         col_append_fstr(fd, COL_INFO, " %s", mname);
945       if (dns_tree != NULL) {
946         proto_item_set_text(trr, "%s: type %s, class %s, mname %s",
947                      name, type_name, class_name, mname);
948         proto_tree_add_text(rr_tree, NullTVB, cur_offset, mname_len, "Primary name server: %s",
949                        mname);
950         cur_offset += mname_len;
951       
952         rname_len = get_dns_name(pd, cur_offset, dns_data_offset, rname, sizeof(rname));
953         if (rname_len < 0) {
954           /* We ran past the end of the captured data in the packet. */
955           return 0;
956         }
957         proto_tree_add_text(rr_tree, NullTVB, cur_offset, rname_len, "Responsible authority's mailbox: %s",
958                        rname);
959         cur_offset += rname_len;
960
961         if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
962           /* We ran past the end of the captured data in the packet. */
963           return 0;
964         }
965         serial = pntohl(&pd[cur_offset]);
966         proto_tree_add_text(rr_tree, NullTVB, cur_offset, 4, "Serial number: %u",
967                        serial);
968         cur_offset += 4;
969
970         if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
971           /* We ran past the end of the captured data in the packet. */
972           return 0;
973         }
974         refresh = pntohl(&pd[cur_offset]);
975         proto_tree_add_text(rr_tree, NullTVB, cur_offset, 4, "Refresh interval: %s",
976                        time_secs_to_str(refresh));
977         cur_offset += 4;
978
979         if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
980           /* We ran past the end of the captured data in the packet. */
981           return 0;
982         }
983         retry = pntohl(&pd[cur_offset]);
984         proto_tree_add_text(rr_tree, NullTVB, cur_offset, 4, "Retry interval: %s",
985                        time_secs_to_str(retry));
986         cur_offset += 4;
987
988         if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
989           /* We ran past the end of the captured data in the packet. */
990           return 0;
991         }
992         expire = pntohl(&pd[cur_offset]);
993         proto_tree_add_text(rr_tree, NullTVB, cur_offset, 4, "Expiration limit: %s",
994                        time_secs_to_str(expire));
995         cur_offset += 4;
996
997         if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
998           /* We ran past the end of the captured data in the packet. */
999           return 0;
1000         }
1001         minimum = pntohl(&pd[cur_offset]);
1002         proto_tree_add_text(rr_tree, NullTVB, cur_offset, 4, "Minimum TTL: %s",
1003                        time_secs_to_str(minimum));
1004       }
1005     }
1006     break;
1007
1008   case T_PTR:
1009     {
1010       char pname[MAXDNAME];
1011       int pname_len;
1012       
1013       pname_len = get_dns_name(pd, cur_offset, dns_data_offset, pname, sizeof(pname));
1014       if (pname_len < 0) {
1015         /* We ran past the end of the captured data in the packet. */
1016         if (dns_tree != NULL) {
1017           proto_item_set_text(trr,
1018                 "%s: type %s, class %s, <Domain name goes past end of captured data in packet>",
1019                        name, type_name, class_name);
1020         }
1021         return 0;
1022       }
1023       if (fd != NULL)
1024         col_append_fstr(fd, COL_INFO, " %s", pname);
1025       if (dns_tree != NULL) {
1026         proto_item_set_text(trr, "%s: type %s, class %s, ptr %s",
1027                      name, type_name, class_name, pname);
1028         proto_tree_add_text(rr_tree, NullTVB, cur_offset, pname_len, "Domain name: %s",
1029                         pname);
1030       }
1031       break;
1032     }
1033     break;
1034
1035   case T_WKS:
1036     {
1037       int rr_len = data_len;
1038       guint8 protocol;
1039       guint8 bits;
1040       int mask;
1041       int port_num;
1042       int i;
1043       char bitnames[128+1];
1044       char portnumstring[10+1];
1045       
1046       if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
1047         /* We ran past the end of the captured data in the packet. */
1048         if (dns_tree != NULL) {
1049           proto_item_set_text(trr,
1050                 "%s: type %s, class %s, <Address goes past end of captured data in packet>",
1051                        name, type_name, class_name);
1052         }
1053         return 0;
1054       }
1055       if (fd != NULL)
1056         col_append_fstr(fd, COL_INFO, " %s", ip_to_str((guint8 *)dptr));
1057       if (dns_tree != NULL) {
1058         proto_item_set_text(trr, "%s: type %s, class %s, addr %s",
1059                      name, type_name, class_name,
1060                      ip_to_str((guint8 *)dptr));
1061         proto_tree_add_text(rr_tree, NullTVB, cur_offset, 4, "Addr: %s",
1062                      ip_to_str((guint8 *)dptr));
1063         cur_offset += 4;
1064         rr_len -= 4;
1065
1066         if (!BYTES_ARE_IN_FRAME(cur_offset, 1)) {
1067           /* We ran past the end of the captured data in the packet. */
1068           proto_tree_add_text(rr_tree, NullTVB, cur_offset, END_OF_FRAME,
1069                        "<Protocol goes past end of captured data in packet>");
1070           return 0;
1071         }
1072         protocol = pd[cur_offset];
1073         proto_tree_add_text(rr_tree, NullTVB, cur_offset, 1, "Protocol: %s",
1074                      ipprotostr(protocol));
1075         cur_offset += 1;
1076         rr_len -= 1;
1077
1078         port_num = 0;
1079         while (rr_len != 0) {
1080           if (!BYTES_ARE_IN_FRAME(cur_offset, 1)) {
1081             /* We ran past the end of the captured data in the packet. */
1082             proto_tree_add_text(rr_tree, NullTVB, cur_offset, END_OF_FRAME,
1083                        "<Bit map goes past end of captured data in packet>");
1084             return 0;
1085           }
1086           bits = pd[cur_offset];
1087           if (bits != 0) {
1088             mask = 1<<7;
1089             bitnames[0] = '\0';
1090             for (i = 0; i < 8; i++) {
1091               if (bits & mask) {
1092                 if (bitnames[0] != '\0')
1093                   strcat(bitnames, ", ");
1094                 switch (protocol) {
1095
1096                 case IP_PROTO_TCP:
1097                   strcat(bitnames, get_tcp_port(port_num));
1098                   break;
1099
1100                 case IP_PROTO_UDP:
1101                   strcat(bitnames, get_udp_port(port_num));
1102                   break;
1103
1104                 default:
1105                   sprintf(portnumstring, "%u", port_num);
1106                   strcat(bitnames, portnumstring);
1107                   break;
1108                 }
1109               }
1110               mask >>= 1;
1111               port_num++;
1112             }
1113             proto_tree_add_text(rr_tree, NullTVB, cur_offset, 1,
1114                 "Bits: 0x%02x (%s)", bits, bitnames);
1115           } else
1116             port_num += 8;
1117           cur_offset += 1;
1118           rr_len -= 1;
1119         }
1120       }
1121     }
1122     break;
1123
1124   case T_HINFO:
1125     {
1126       int cpu_offset;
1127       int cpu_len;
1128       int os_offset;
1129       int os_len;
1130
1131       cpu_offset = cur_offset;
1132       if (!BYTES_ARE_IN_FRAME(cpu_offset, 1)) {
1133         /* We ran past the end of the captured data in the packet. */
1134         if (dns_tree != NULL) {
1135           proto_item_set_text(trr,
1136                        "%s: type %s, class %s, <CPU goes past end of captured data in packet>",
1137                        name, type_name, class_name);
1138         }
1139         return 0;
1140       }
1141       cpu_len = pd[cpu_offset];
1142       if (!BYTES_ARE_IN_FRAME(cpu_offset + 1, cpu_len)) {
1143         /* We ran past the end of the captured data in the packet. */
1144         if (dns_tree != NULL) {
1145           proto_item_set_text(trr,
1146                        "%s: type %s, class %s, <CPU goes past end of captured data in packet>",
1147                        name, type_name, class_name);
1148         }
1149         return 0;
1150       }
1151       os_offset = cpu_offset + 1 + cpu_len;
1152       if (!BYTES_ARE_IN_FRAME(os_offset, 1)) {
1153         /* We ran past the end of the captured data in the packet. */
1154         if (dns_tree != NULL) {
1155           proto_item_set_text(trr,
1156                        "%s: type %s, class %s, CPU %.*s, <OS goes past end of captured data in packet>",
1157                        name, type_name, class_name, cpu_len, &pd[cpu_offset + 1]);
1158         }
1159         return 0;
1160       }
1161       os_len = pd[os_offset];
1162       if (!BYTES_ARE_IN_FRAME(os_offset + 1, os_len)) {
1163         /* We ran past the end of the captured data in the packet. */
1164         if (dns_tree != NULL) {
1165           proto_item_set_text(trr,
1166                        "%s: type %s, class %s, CPU %.*s, <OS goes past end of captured data in packet>",
1167                        name, type_name, class_name, cpu_len, &pd[cpu_offset + 1]);
1168         }
1169         return 0;
1170       }
1171       if (fd != NULL)
1172         col_append_fstr(fd, COL_INFO, " %.*s %.*s", cpu_len,
1173             &pd[cpu_offset + 1], os_len, &pd[os_offset + 1]);
1174       if (dns_tree != NULL) {
1175         proto_item_set_text(trr,
1176                      "%s: type %s, class %s, CPU %.*s, OS %.*s",
1177                      name, type_name, class_name,
1178                      cpu_len, &pd[cpu_offset + 1], os_len, &pd[os_offset + 1]);
1179         proto_tree_add_text(rr_tree, NullTVB, cpu_offset, 1 + cpu_len, "CPU: %.*s",
1180                         cpu_len, &pd[cpu_offset + 1]);
1181         proto_tree_add_text(rr_tree, NullTVB, os_offset, 1 + os_len, "OS: %.*s",
1182                         os_len, &pd[os_offset + 1]);
1183       }
1184       break;
1185     }
1186     break;
1187
1188   case T_MX:
1189     {
1190       guint16 preference = 0;
1191       char mx_name[MAXDNAME];
1192       int mx_name_len;
1193       
1194       if (!BYTES_ARE_IN_FRAME(cur_offset, 2)) {
1195         /* We ran past the end of the captured data in the packet. */
1196         if (dns_tree != NULL) {
1197           proto_item_set_text(trr,
1198                        "%s: type %s, class %s, <preference goes past end of captured data in packet>",
1199                        name, type_name, class_name);
1200         }
1201         return 0;
1202       }
1203       preference = pntohs(&pd[cur_offset]);
1204       mx_name_len = get_dns_name(pd, cur_offset + 2, dns_data_offset, mx_name, sizeof(mx_name));
1205       if (mx_name_len < 0) {
1206         /* We ran past the end of the captured data in the packet. */
1207         if (dns_tree != NULL) {
1208           proto_item_set_text(trr,
1209                        "%s: type %s, class %s, preference %u, <mx goes past end of captured data in packet>",
1210                        name, type_name, class_name, preference);
1211         }
1212         return 0;
1213       }
1214       if (fd != NULL)
1215         col_append_fstr(fd, COL_INFO, " %u %s", preference, mx_name);
1216       if (dns_tree != NULL) {
1217         proto_item_set_text(trr,
1218                        "%s: type %s, class %s, preference %u, mx %s",
1219                        name, type_name, class_name, preference, mx_name);
1220         proto_tree_add_text(rr_tree, NullTVB, cur_offset, 2, "Preference: %u", preference);
1221         proto_tree_add_text(rr_tree, NullTVB, cur_offset + 2, mx_name_len, "Mail exchange: %s",
1222                         mx_name);
1223       }
1224     }
1225     break;
1226
1227   case T_TXT:
1228     {
1229       int rr_len = data_len;
1230       int txt_offset;
1231       int txt_len;
1232
1233       if (dns_tree != NULL) {
1234         proto_item_set_text(trr,
1235                 "%s: type %s, class %s", name, type_name, class_name);
1236
1237         txt_offset = cur_offset;
1238         while (rr_len != 0) {
1239           if (!BYTES_ARE_IN_FRAME(txt_offset, 1)) {
1240             /* We ran past the end of the captured data in the packet. */
1241             proto_tree_add_text(rr_tree, NullTVB, txt_offset, END_OF_FRAME,
1242                        "<String goes past end of captured data in packet>");
1243             return 0;
1244           }
1245           txt_len = pd[txt_offset];
1246           if (!BYTES_ARE_IN_FRAME(txt_offset + 1, txt_len)) {
1247             /* We ran past the end of the captured data in the packet. */
1248             proto_tree_add_text(rr_tree, NullTVB, txt_offset, END_OF_FRAME,
1249                        "<String goes past end of captured data in packet>");
1250             return 0;
1251           }
1252           proto_tree_add_text(rr_tree, NullTVB, txt_offset, 1 + txt_len,
1253            "Text: %.*s", txt_len, &pd[txt_offset + 1]);
1254           txt_offset += 1 + txt_len;
1255           rr_len -= 1 + txt_len;
1256         }
1257       }
1258     }
1259     break;
1260
1261   case T_SIG:
1262     {
1263       int rr_len = data_len;
1264       struct timeval unixtime;
1265       char signer_name[MAXDNAME];
1266       int signer_name_len;
1267
1268       if (dns_tree != NULL) {
1269         proto_item_set_text(trr,
1270                 "%s: type %s, class %s", name, type_name, class_name);
1271
1272         if (!BYTES_ARE_IN_FRAME(cur_offset, 2)) {
1273           /* We ran past the end of the captured data in the packet. */
1274           return 0;
1275         }
1276         proto_tree_add_text(rr_tree, NullTVB, cur_offset, 2, "Type covered: %s (%s)",
1277                 dns_type_name(pntohs(&pd[cur_offset])),
1278                 dns_long_type_name(pntohs(&pd[cur_offset])));
1279         cur_offset += 2;
1280         rr_len -= 2;
1281
1282         if (!BYTES_ARE_IN_FRAME(cur_offset, 1)) {
1283           /* We ran past the end of the captured data in the packet. */
1284           return 0;
1285         }
1286         proto_tree_add_text(rr_tree, NullTVB, cur_offset, 1, "Algorithm: %s",
1287                 val_to_str(pd[cur_offset], algo_vals,
1288                     "Unknown (0x%02X)"));
1289         cur_offset += 1;
1290         rr_len -= 1;
1291
1292         if (!BYTES_ARE_IN_FRAME(cur_offset, 1)) {
1293           /* We ran past the end of the captured data in the packet. */
1294           return 0;
1295         }
1296         proto_tree_add_text(rr_tree, NullTVB, cur_offset, 1, "Labels: %u",
1297                 pd[cur_offset]);
1298         cur_offset += 1;
1299         rr_len -= 1;
1300
1301         if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
1302           /* We ran past the end of the captured data in the packet. */
1303           return 0;
1304         }
1305         proto_tree_add_text(rr_tree, NullTVB, cur_offset, 4, "Original TTL: %s",
1306                 time_secs_to_str(pntohl(&pd[cur_offset])));
1307         cur_offset += 4;
1308         rr_len -= 4;
1309
1310         if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
1311           /* We ran past the end of the captured data in the packet. */
1312           return 0;
1313         }
1314         unixtime.tv_sec = pntohl(&pd[cur_offset]);
1315         unixtime.tv_usec = 0;
1316         proto_tree_add_text(rr_tree, NullTVB, cur_offset, 4, "Signature expiration: %s",
1317                 abs_time_to_str(&unixtime));
1318         cur_offset += 4;
1319         rr_len -= 4;
1320
1321         if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
1322           /* We ran past the end of the captured data in the packet. */
1323           return 0;
1324         }
1325         unixtime.tv_sec = pntohl(&pd[cur_offset]);
1326         unixtime.tv_usec = 0;
1327         proto_tree_add_text(rr_tree, NullTVB, cur_offset, 4, "Time signed: %s",
1328                 abs_time_to_str(&unixtime));
1329         cur_offset += 4;
1330         rr_len -= 4;
1331
1332         if (!BYTES_ARE_IN_FRAME(cur_offset, 2)) {
1333           /* We ran past the end of the captured data in the packet. */
1334           return 0;
1335         }
1336         proto_tree_add_text(rr_tree, NullTVB, cur_offset, 2, "Key footprint: 0x%04x",
1337                 pntohs(&pd[cur_offset]));
1338         cur_offset += 2;
1339         rr_len -= 2;
1340
1341         signer_name_len = get_dns_name(pd, cur_offset, dns_data_offset, signer_name, sizeof(signer_name));
1342         if (signer_name_len < 0) {
1343           /* We ran past the end of the captured data in the packet. */
1344           return 0;
1345         }
1346         proto_tree_add_text(rr_tree, NullTVB, cur_offset, signer_name_len,
1347                 "Signer's name: %s", signer_name);
1348         cur_offset += signer_name_len;
1349         rr_len -= signer_name_len;
1350
1351         proto_tree_add_text(rr_tree, NullTVB, cur_offset, rr_len, "Signature");
1352       }
1353     }
1354     break;
1355
1356   case T_KEY:
1357     {
1358       int rr_len = data_len;
1359       guint16 flags;
1360       proto_item *tf;
1361       proto_tree *flags_tree;
1362
1363       if (dns_tree != NULL) {
1364         proto_item_set_text(trr,
1365                 "%s: type %s, class %s", name, type_name, class_name);
1366
1367         if (!BYTES_ARE_IN_FRAME(cur_offset, 2)) {
1368           /* We ran past the end of the captured data in the packet. */
1369           return 0;
1370         }
1371         flags = pntohs(&pd[cur_offset]);
1372         tf = proto_tree_add_text(rr_tree, NullTVB, cur_offset, 2, "Flags: 0x%04X", flags);
1373         flags_tree = proto_item_add_subtree(tf, ett_t_key_flags);
1374         proto_tree_add_text(flags_tree, NullTVB, cur_offset, 2, "%s",
1375                 decode_boolean_bitfield(flags, 0x8000,
1376                   2*8, "Key prohibited for authentication",
1377                        "Key allowed for authentication"));
1378         proto_tree_add_text(flags_tree, NullTVB, cur_offset, 2, "%s",
1379                 decode_boolean_bitfield(flags, 0x4000,
1380                   2*8, "Key prohibited for confidentiality",
1381                        "Key allowed for confidentiality"));
1382         if ((flags & 0xC000) != 0xC000) {
1383           /* We have a key */
1384           proto_tree_add_text(flags_tree, NullTVB, cur_offset, 2, "%s",
1385                 decode_boolean_bitfield(flags, 0x2000,
1386                   2*8, "Key is experimental or optional",
1387                        "Key is required"));
1388           proto_tree_add_text(flags_tree, NullTVB, cur_offset, 2, "%s",
1389                 decode_boolean_bitfield(flags, 0x0400,
1390                   2*8, "Key is associated with a user",
1391                        "Key is not associated with a user"));
1392           proto_tree_add_text(flags_tree, NullTVB, cur_offset, 2, "%s",
1393                 decode_boolean_bitfield(flags, 0x0200,
1394                   2*8, "Key is associated with the named entity",
1395                        "Key is not associated with the named entity"));
1396           proto_tree_add_text(flags_tree, NullTVB, cur_offset, 2, "%s",
1397                 decode_boolean_bitfield(flags, 0x0100,
1398                   2*8, "This is the zone key for the specified zone",
1399                        "This is not a zone key"));
1400           proto_tree_add_text(flags_tree, NullTVB, cur_offset, 2, "%s",
1401                 decode_boolean_bitfield(flags, 0x0080,
1402                   2*8, "Key is valid for use with IPSEC",
1403                        "Key is not valid for use with IPSEC"));
1404           proto_tree_add_text(flags_tree, NullTVB, cur_offset, 2, "%s",
1405                 decode_boolean_bitfield(flags, 0x0040,
1406                   2*8, "Key is valid for use with MIME security multiparts",
1407                        "Key is not valid for use with MIME security multiparts"));
1408           proto_tree_add_text(flags_tree, NullTVB, cur_offset, 2, "%s",
1409                 decode_numeric_bitfield(flags, 0x000F,
1410                   2*8, "Signatory = %u"));
1411         }
1412         cur_offset += 2;
1413         rr_len -= 2;
1414
1415         if (!BYTES_ARE_IN_FRAME(cur_offset, 1)) {
1416           /* We ran past the end of the captured data in the packet. */
1417           return 0;
1418         }
1419         proto_tree_add_text(rr_tree, NullTVB, cur_offset, 1, "Protocol: %u",
1420                 pd[cur_offset]);
1421         cur_offset += 1;
1422         rr_len -= 1;
1423
1424         if (!BYTES_ARE_IN_FRAME(cur_offset, 1)) {
1425           /* We ran past the end of the captured data in the packet. */
1426           return 0;
1427         }
1428         proto_tree_add_text(rr_tree, NullTVB, cur_offset, 1, "Algorithm: %s",
1429                 val_to_str(pd[cur_offset], algo_vals,
1430                     "Unknown (0x%02X)"));
1431         cur_offset += 1;
1432                 rr_len -= 1;
1433
1434         proto_tree_add_text(rr_tree, NullTVB, cur_offset, rr_len, "Public key");
1435       }
1436     }
1437     break;
1438
1439   case T_AAAA:
1440     if (!BYTES_ARE_IN_FRAME(cur_offset, 16)) {
1441       /* We ran past the end of the captured data in the packet. */
1442       if (dns_tree != NULL) {
1443         proto_item_set_text(trr,
1444                 "%s: type %s, class %s, <Address goes past end of captured data in packet>",
1445                        name, type_name, class_name);
1446       }
1447       return 0;
1448     }
1449     if (fd != NULL) {
1450       col_append_fstr(fd, COL_INFO, " %s", 
1451                         ip6_to_str((struct e_in6_addr *)dptr));
1452     }
1453     if (dns_tree != NULL) {
1454       proto_item_set_text(trr, "%s: type %s, class %s, addr %s",
1455                      name, type_name, class_name,
1456                      ip6_to_str((struct e_in6_addr *)dptr));
1457       proto_tree_add_text(rr_tree, NullTVB, cur_offset, 16, "Addr: %s",
1458                      ip6_to_str((struct e_in6_addr *)dptr));
1459     }
1460     break;
1461
1462   case T_A6:
1463     {
1464       unsigned short pre_len;
1465       unsigned short suf_len;
1466       unsigned short suf_octet_count;
1467       char pname[MAXDNAME];
1468       int pname_len = 0;
1469       int a6_offset;
1470       int suf_offset;
1471       guint8 suffix[16];
1472
1473       a6_offset = cur_offset;
1474       if (!BYTES_ARE_IN_FRAME(cur_offset, 1)) {
1475         /* We ran past the end of the captured data in the packet. */
1476         return 0;
1477       }
1478       pre_len = pd[cur_offset++];
1479       suf_len = 128 - pre_len;
1480       suf_octet_count = suf_len ? (suf_len - 1) / 8 + 1 : 0;
1481       if (!BYTES_ARE_IN_FRAME(cur_offset, suf_octet_count)) {
1482         /* We ran past the end of the captured data in the packet. */
1483         return 0;
1484       }
1485       /* Pad prefix */
1486       for (suf_offset = 0; suf_offset < 16 - suf_octet_count; suf_offset++) {
1487         suffix[suf_offset] = 0;
1488       }
1489       for (; suf_offset < 16; suf_offset++) {
1490         suffix[suf_offset] = pd[cur_offset++];
1491       }
1492
1493       if (pre_len > 0) {
1494         pname_len = get_dns_name(pd, cur_offset, dns_data_offset, 
1495                                  pname, sizeof(pname));
1496         if (pname_len < 0) {
1497           /* We ran past the end of the captured data in the packet. */
1498           return 0;
1499         }
1500       } else {
1501         strcpy(pname, "");   
1502       }
1503
1504       if (fd != NULL) {
1505         col_append_fstr(fd, COL_INFO, " %d %s %s", 
1506                         pre_len, 
1507                         ip6_to_str((struct e_in6_addr *)&suffix), 
1508                         pname);
1509       }
1510       if (dns_tree != NULL) {
1511         proto_tree_add_text(rr_tree, NullTVB, a6_offset, 1, 
1512                             "Prefix len: %u", pre_len);
1513         a6_offset++;
1514         if (suf_len) {
1515           proto_tree_add_text(rr_tree, NullTVB, a6_offset, suf_octet_count,
1516                               "Address suffix: %s", 
1517                               ip6_to_str((struct e_in6_addr *)&suffix));
1518           a6_offset += suf_octet_count;
1519         }
1520         if (pre_len > 0) {
1521           proto_tree_add_text(rr_tree, NullTVB, a6_offset, pname_len, 
1522                               "Prefix name: %s", pname);
1523         }
1524         proto_item_set_text(trr, "%s: type %s, class %s, addr %d %s %s",
1525                             name, 
1526                             type_name, 
1527                             class_name, 
1528                             pre_len, 
1529                             ip6_to_str((struct e_in6_addr *)&suffix), 
1530                             pname);
1531       }
1532     }
1533     break;
1534
1535   case T_DNAME:
1536     {
1537       char dname[MAXDNAME];
1538       int dname_len;
1539       
1540       dname_len = get_dns_name(pd, cur_offset, dns_data_offset, 
1541                                dname, sizeof(dname));
1542       if (dname_len < 0) {
1543         /* We ran past the end of the captured data in the packet. */
1544         if (dns_tree != NULL) {
1545           proto_item_set_text(trr,
1546                               "%s: type %s, class %s, <Primary name goes past end of captured data in packet>",
1547                               name, type_name, class_name);
1548         }
1549         return 0;
1550       }
1551       if (fd != NULL)
1552         col_append_fstr(fd, COL_INFO, " %s", dname);
1553       if (dns_tree != NULL) {
1554         proto_item_set_text(trr, "%s: type %s, class %s, dname %s",
1555                             name, type_name, class_name, dname);
1556         proto_tree_add_text(rr_tree, NullTVB, cur_offset, 
1557                             dname_len, "Target name: %s", dname);
1558       }
1559     }
1560     break;
1561
1562   case T_LOC:
1563     {
1564       if (dns_tree != NULL) {
1565         proto_item_set_text(trr,
1566                 "%s: type %s, class %s", name, type_name, class_name);
1567
1568         if (!BYTES_ARE_IN_FRAME(cur_offset, 1)) {
1569           /* We ran past the end of the captured data in the packet. */
1570           return 0;
1571         }
1572         proto_tree_add_text(rr_tree, NullTVB, cur_offset, 1, "Version: %u", pd[cur_offset]);
1573         if (pd[cur_offset] == 0) {
1574           /* Version 0, the only version RFC 1876 discusses. */
1575           cur_offset++;
1576
1577           if (!BYTES_ARE_IN_FRAME(cur_offset, 1)) {
1578             /* We ran past the end of the captured data in the packet. */
1579             return 0;
1580           }
1581           proto_tree_add_text(rr_tree, NullTVB, cur_offset, 1, "Size: %g m",
1582                                 rfc1867_size(pd[cur_offset]));
1583           cur_offset++;
1584
1585           if (!BYTES_ARE_IN_FRAME(cur_offset, 1)) {
1586             /* We ran past the end of the captured data in the packet. */
1587             return 0;
1588           }
1589           proto_tree_add_text(rr_tree, NullTVB, cur_offset, 1, "Horizontal precision: %g m",
1590                                 rfc1867_size(pd[cur_offset]));
1591           cur_offset++;
1592
1593           if (!BYTES_ARE_IN_FRAME(cur_offset, 1)) {
1594             /* We ran past the end of the captured data in the packet. */
1595             return 0;
1596           }
1597           proto_tree_add_text(rr_tree, NullTVB, cur_offset, 1, "Vertical precision: %g m",
1598                                 rfc1867_size(pd[cur_offset]));
1599           cur_offset++;
1600
1601           if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
1602             /* We ran past the end of the captured data in the packet. */
1603             return 0;
1604           }
1605           proto_tree_add_text(rr_tree, NullTVB, cur_offset, 4, "Latitude: %s",
1606                                 rfc1867_angle(&pd[cur_offset], "NS"));
1607           cur_offset += 4;
1608
1609           if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
1610             /* We ran past the end of the captured data in the packet. */
1611             return 0;
1612           }
1613           proto_tree_add_text(rr_tree, NullTVB, cur_offset, 4, "Longitude: %s",
1614                                 rfc1867_angle(&pd[cur_offset], "EW"));
1615           cur_offset += 4;
1616
1617           if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
1618             /* We ran past the end of the captured data in the packet. */
1619             return 0;
1620           }
1621           proto_tree_add_text(rr_tree, NullTVB, cur_offset, 4, "Altitude: %g m",
1622                                 (pntohl(&pd[cur_offset]) - 10000000)/100.0);
1623         } else
1624           proto_tree_add_text(rr_tree, NullTVB, cur_offset, data_len, "Data");
1625       }
1626       break;
1627     }
1628     break;
1629       
1630   case T_NXT:
1631     {
1632       int rr_len = data_len;
1633       char next_domain_name[MAXDNAME];
1634       int next_domain_name_len;
1635       int rr_type;
1636       guint8 bits;
1637       int mask;
1638       int i;
1639
1640       next_domain_name_len = get_dns_name(pd, cur_offset, dns_data_offset,
1641                         next_domain_name, sizeof(next_domain_name));
1642       if (next_domain_name_len < 0) {
1643         /* We ran past the end of the captured data in the packet. */
1644         if (dns_tree != NULL) {
1645           proto_item_set_text(trr,
1646                 "%s: type %s, class %s, <Next domain name goes past end of captured data in packet>",
1647                        name, type_name, class_name);
1648         }
1649         return 0;
1650       }
1651       if (fd != NULL)
1652         col_append_fstr(fd, COL_INFO, " %s", next_domain_name);
1653       if (dns_tree != NULL) {
1654         proto_item_set_text(trr, "%s: type %s, class %s, next domain name %s",
1655                      name, type_name, class_name, next_domain_name);
1656         proto_tree_add_text(rr_tree, NullTVB, cur_offset, next_domain_name_len,
1657                         "Next domain name: %s", next_domain_name);
1658         cur_offset += next_domain_name_len;
1659         rr_len -= next_domain_name_len;
1660         rr_type = 0;
1661         while (rr_len != 0) {
1662           if (!BYTES_ARE_IN_FRAME(cur_offset, 1)) {
1663             /* We ran past the end of the captured data in the packet. */
1664             proto_tree_add_text(rr_tree, NullTVB, cur_offset, END_OF_FRAME,
1665                        "<Bit map goes past end of captured data in packet>");
1666             return 0;
1667           }
1668           bits = pd[cur_offset];
1669           mask = 1<<7;
1670           for (i = 0; i < 8; i++) {
1671             if (bits & mask) {
1672               proto_tree_add_text(rr_tree, NullTVB, cur_offset, 1,
1673                         "RR type in bit map: %s (%s)",
1674                         dns_type_name(rr_type),
1675                         dns_long_type_name(rr_type));
1676             }
1677             mask >>= 1;
1678             rr_type++;
1679           }
1680           cur_offset += 1;
1681           rr_len -= 1;
1682         }
1683       }
1684     }
1685     break;
1686
1687   case T_KX:
1688     {
1689       guint16 preference = 0;
1690       char kx_name[MAXDNAME];
1691       int kx_name_len;
1692       
1693       if (!BYTES_ARE_IN_FRAME(cur_offset, 2)) {
1694         /* We ran past the end of the captured data in the packet. */
1695         if (dns_tree != NULL) {
1696           proto_item_set_text(trr,
1697                        "%s: type %s, class %s, <preference goes past end of captured data in packet>",
1698                        name, type_name, class_name);
1699         }
1700         return 0;
1701       }
1702       preference = pntohs(&pd[cur_offset]);
1703       kx_name_len = get_dns_name(pd, cur_offset + 2, dns_data_offset, kx_name, sizeof(kx_name));
1704       if (kx_name_len < 0) {
1705         /* We ran past the end of the captured data in the packet. */
1706         if (dns_tree != NULL) {
1707           proto_item_set_text(trr,
1708                        "%s: type %s, class %s, preference %u, <kx goes past end of captured data in packet>",
1709                        name, type_name, class_name, preference);
1710         }
1711         return 0;
1712       }
1713       if (fd != NULL)
1714         col_append_fstr(fd, COL_INFO, " %u %s", preference, kx_name);
1715       if (dns_tree != NULL) {
1716         proto_item_set_text(trr,
1717                        "%s: type %s, class %s, preference %u, kx %s",
1718                        name, type_name, class_name, preference, kx_name);
1719         proto_tree_add_text(rr_tree, NullTVB, cur_offset, 2, "Preference: %u", preference);
1720         proto_tree_add_text(rr_tree, NullTVB, cur_offset + 2, kx_name_len, "Key exchange: %s",
1721                         kx_name);
1722       }
1723     }
1724     break;
1725
1726   case T_CERT:
1727     {
1728       guint16 cert_type, cert_keytag;
1729       guint8 cert_keyalg;
1730       int rr_len = data_len;
1731
1732       if (!BYTES_ARE_IN_FRAME(cur_offset, 2)) {
1733         /* We ran past the end of the captured data in the packet. */
1734         if (dns_tree != NULL) {
1735           proto_item_set_text(trr,
1736                        "%s: type %s, class %s, <preference goes past end of captured data in packet>",
1737                        name, type_name, class_name);
1738         }
1739         return 0;
1740       }
1741       cert_type = pntohs(&pd[cur_offset]);
1742       cur_offset += 2;
1743       rr_len -= 2;
1744       if (!BYTES_ARE_IN_FRAME(cur_offset, 2)) {
1745         /* We ran past the end of the captured data in the packet. */
1746         if (dns_tree != NULL) {
1747           proto_item_set_text(trr,
1748                        "%s: type %s, class %s, <preference goes past end of captured data in packet>",
1749                        name, type_name, class_name);
1750         }
1751         return 0;
1752       }
1753       cert_keytag = pntohs(&pd[cur_offset]);
1754       cur_offset += 2;
1755       rr_len -= 2;
1756       if (!BYTES_ARE_IN_FRAME(cur_offset, 2)) {
1757         /* We ran past the end of the captured data in the packet. */
1758         if (dns_tree != NULL) {
1759           proto_item_set_text(trr,
1760                        "%s: type %s, class %s, <preference goes past end of captured data in packet>",
1761                        name, type_name, class_name);
1762         }
1763         return 0;
1764       }
1765       cert_keyalg = pd[cur_offset];
1766       cur_offset += 1;
1767       rr_len -= 1;
1768
1769       if (dns_tree != NULL) {
1770         proto_tree_add_text(rr_tree, NullTVB, cur_offset, 1, "Type: %s",
1771                 val_to_str(cert_keyalg, cert_vals,
1772                     "Unknown (0x%02X)"));
1773         proto_tree_add_text(rr_tree, NullTVB, cur_offset, 2, "Key footprint: 0x%04x",
1774                 cert_keytag);
1775         proto_tree_add_text(rr_tree, NullTVB, cur_offset, 1, "Algorithm: %s",
1776                 val_to_str(cert_keyalg, algo_vals,
1777                     "Unknown (0x%02X)"));
1778         proto_tree_add_text(rr_tree, NullTVB, cur_offset, rr_len, "Public key");
1779       }
1780
1781     }
1782     break;
1783
1784   case T_OPT:
1785     if (dns_tree != NULL) {
1786       proto_item_set_text(trr, "%s: type %s", name, type_name);
1787       proto_tree_add_text(rr_tree, NullTVB, cur_offset, data_len, "Data");
1788     }
1789     break;
1790
1791   case T_TKEY:
1792     {
1793       char tkey_algname[MAXDNAME];
1794       int tkey_algname_len;
1795       guint16 tkey_mode, tkey_error, tkey_keylen, tkey_otherlen;
1796       int rr_len = data_len;
1797       struct timeval unixtime;
1798       static const value_string tkey_modes[] = {
1799                   { TKEYMODE_SERVERASSIGNED,   "Server assigned"   },
1800                   { TKEYMODE_DIFFIEHELLMAN,    "Diffie Hellman"    },
1801                   { TKEYMODE_GSSAPI,           "GSSAPI "           },
1802                   { TKEYMODE_RESOLVERASSIGNED, "Resolver assigned" },
1803                   { TKEYMODE_DELETE,           "Delete"            },
1804                   { 0,                         NULL                } };
1805
1806       if (dns_tree != NULL) {
1807         proto_item_set_text(trr,
1808                 "%s: type %s, class %s", name, type_name, class_name);
1809         tkey_algname_len = get_dns_name(pd, cur_offset, dns_data_offset, tkey_algname, sizeof(tkey_algname));
1810         if (tkey_algname_len < 0) {
1811           /* We ran past the end of the captured data in the packet. */
1812           return 0;
1813         }
1814         proto_tree_add_text(rr_tree, NullTVB, cur_offset, tkey_algname_len,
1815                 "Algorithm name: %s", tkey_algname);
1816         cur_offset += tkey_algname_len;
1817         rr_len -= tkey_algname_len;
1818
1819         if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
1820           /* We ran past the end of the captured data in the packet. */
1821           return 0;
1822         }
1823         unixtime.tv_sec = pntohl(&pd[cur_offset]);
1824         unixtime.tv_usec = 0;
1825         proto_tree_add_text(rr_tree, NullTVB, cur_offset, 4, "Signature inception: %s",
1826                 abs_time_to_str(&unixtime));
1827         cur_offset += 4;
1828         rr_len -= 4;
1829
1830         if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
1831           /* We ran past the end of the captured data in the packet. */
1832           return 0;
1833         }
1834         unixtime.tv_sec = pntohl(&pd[cur_offset]);
1835         unixtime.tv_usec = 0;
1836         proto_tree_add_text(rr_tree, NullTVB, cur_offset, 4, "Signature expiration: %s",
1837                 abs_time_to_str(&unixtime));
1838         cur_offset += 4;
1839         rr_len -= 4;
1840
1841         if (!BYTES_ARE_IN_FRAME(cur_offset, 2)) {
1842           /* We ran past the end of the captured data in the packet. */
1843           return 0;
1844         }
1845         tkey_mode = pntohs(&pd[cur_offset]);
1846         cur_offset += 2;
1847         rr_len -= 2;
1848         proto_tree_add_text(rr_tree, NullTVB, cur_offset, 1, "Mode: %s",
1849                 val_to_str(tkey_mode, tkey_modes,
1850                     "Unknown (0x%02X)"));
1851
1852         tkey_error = pntohs(&pd[cur_offset]);
1853         cur_offset += 2;
1854         rr_len -= 2;
1855
1856         proto_tree_add_text(rr_tree, NullTVB, cur_offset, 4, "Error: %s",
1857                 val_to_str(tkey_error, rcode_vals,
1858                 val_to_str(tkey_error, tsigerror_vals, "Unknown error (%x)")));
1859
1860         tkey_keylen = pntohs(&pd[cur_offset]);
1861         cur_offset += 2;
1862         rr_len -= 2;
1863
1864         if (!BYTES_ARE_IN_FRAME(cur_offset, tkey_keylen)) {
1865           /* We ran past the end of the captured data in the packet. */
1866           return 0;
1867         }
1868
1869         proto_tree_add_text(rr_tree, NullTVB, cur_offset, tkey_keylen, "Key");
1870         cur_offset += tkey_keylen;
1871         rr_len -= tkey_keylen;
1872
1873         tkey_otherlen = pntohs(&pd[cur_offset]);
1874         cur_offset += 2;
1875         rr_len -= 2;
1876
1877         if (!BYTES_ARE_IN_FRAME(cur_offset, tkey_otherlen)) {
1878           /* We ran past the end of the captured data in the packet. */
1879           return 0;
1880         }
1881
1882         proto_tree_add_text(rr_tree, NullTVB, cur_offset, tkey_otherlen, "Other");
1883         cur_offset += tkey_otherlen;
1884         rr_len -= tkey_otherlen;
1885       }
1886     }
1887     break;
1888
1889   case T_TSIG:
1890     {
1891       guint8 tsig_fudge;
1892       guint16 tsig_originalid, tsig_error, tsig_timehi, tsig_siglen, tsig_otherlen;
1893       guint32 tsig_timelo;
1894       char tsig_algname[MAXDNAME];
1895       int tsig_algname_len;
1896       struct timeval unixtime;
1897       int rr_len = data_len;
1898
1899       if (dns_tree != NULL) {
1900         proto_item_set_text(trr,
1901                 "%s: type %s, class %s", name, type_name, class_name);
1902         tsig_algname_len = get_dns_name(pd, cur_offset, dns_data_offset, tsig_algname, sizeof(tsig_algname));
1903         if (tsig_algname_len < 0) {
1904           /* We ran past the end of the captured data in the packet. */
1905           return 0;
1906         }
1907         proto_tree_add_text(rr_tree, NullTVB, cur_offset, tsig_algname_len,
1908                 "Algorithm name: %s", tsig_algname);
1909         cur_offset += tsig_algname_len;
1910         rr_len -= tsig_algname_len;
1911
1912         if (!BYTES_ARE_IN_FRAME(cur_offset, 6)) {
1913           /* We ran past the end of the captured data in the packet. */
1914           return 0;
1915         }
1916
1917         tsig_timehi = pntohs(&pd[cur_offset]);
1918         cur_offset += 2;
1919         rr_len -= 2;
1920
1921         tsig_timelo = pntohl(&pd[cur_offset]);
1922         cur_offset += 4;
1923         rr_len -= 4;
1924
1925         unixtime.tv_sec = tsig_timelo;
1926         unixtime.tv_usec = 0;
1927         proto_tree_add_text(rr_tree, NullTVB, cur_offset, 6, "Time signed: %s%s",
1928                 abs_time_to_str(&unixtime), tsig_timehi == 0 ? "" : "(high bits set)");
1929
1930         if (!BYTES_ARE_IN_FRAME(cur_offset, 2)) {
1931           /* We ran past the end of the captured data in the packet. */
1932           return 0;
1933         }
1934
1935         tsig_fudge = pntohs(&pd[cur_offset]);
1936         cur_offset += 2;
1937         rr_len -= 2;
1938
1939         proto_tree_add_text(rr_tree, NullTVB, cur_offset, 2, "Fudge: %d",
1940                 tsig_fudge);
1941
1942         if (!BYTES_ARE_IN_FRAME(cur_offset, 2)) {
1943           /* We ran past the end of the captured data in the packet. */
1944           return 0;
1945         }
1946
1947         tsig_siglen = pntohs(&pd[cur_offset]);
1948         cur_offset += 2;
1949         rr_len -= 2;
1950
1951         if (!BYTES_ARE_IN_FRAME(cur_offset, tsig_siglen)) {
1952           /* We ran past the end of the captured data in the packet. */
1953           return 0;
1954         }
1955
1956         proto_tree_add_text(rr_tree, NullTVB, cur_offset, tsig_siglen, "Signature");
1957         cur_offset += tsig_siglen;
1958         rr_len -= tsig_siglen;
1959
1960         if (!BYTES_ARE_IN_FRAME(cur_offset, 2)) {
1961           /* We ran past the end of the captured data in the packet. */
1962           return 0;
1963         }
1964
1965         tsig_originalid = pntohs(&pd[cur_offset]);
1966         cur_offset += 2;
1967         rr_len -= 2;
1968
1969         proto_tree_add_text(rr_tree, NullTVB, cur_offset, 4, "Original id: %d",
1970                 tsig_originalid);
1971
1972         if (!BYTES_ARE_IN_FRAME(cur_offset, 2)) {
1973           /* We ran past the end of the captured data in the packet. */
1974           return 0;
1975         }
1976
1977         tsig_error = pntohs(&pd[cur_offset]);
1978         cur_offset += 2;
1979         rr_len -= 2;
1980
1981         proto_tree_add_text(rr_tree, NullTVB, cur_offset, 4, "Error: %s",
1982                 val_to_str(tsig_error, rcode_vals,
1983                 val_to_str(tsig_error, tsigerror_vals, "Unknown error (%x)")));
1984
1985         if (!BYTES_ARE_IN_FRAME(cur_offset, 2)) {
1986           /* We ran past the end of the captured data in the packet. */
1987           return 0;
1988         }
1989
1990         tsig_otherlen = pntohs(&pd[cur_offset]);
1991         cur_offset += 2;
1992         rr_len -= 2;
1993
1994         if (!BYTES_ARE_IN_FRAME(cur_offset, tsig_otherlen)) {
1995           /* We ran past the end of the captured data in the packet. */
1996           return 0;
1997         }
1998
1999         proto_tree_add_text(rr_tree, NullTVB, cur_offset, tsig_otherlen, "Other");
2000         cur_offset += tsig_otherlen;
2001         rr_len -= tsig_otherlen;
2002       }
2003     }
2004     break;
2005
2006   case T_WINS:
2007     {
2008       int rr_len = data_len;
2009       guint32 local_flag;
2010       guint32 lookup_timeout;
2011       guint32 cache_timeout;
2012       guint32 nservers;
2013
2014       if (dns_tree != NULL) {
2015         proto_item_set_text(trr, "%s: type %s, class %s", name, type_name,
2016                                 class_name);
2017         if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
2018           /* We ran past the end of the captured data in the packet. */
2019           return 0;
2020         }
2021         local_flag = pntohl(&pd[cur_offset]);
2022         if (dns_tree != NULL) {
2023           proto_tree_add_text(rr_tree, NullTVB, cur_offset, 4, "Local flag: %s",
2024                        local_flag ? "true" : "false");
2025         }
2026         cur_offset += 4;
2027         rr_len -= 4;
2028
2029         if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
2030           /* We ran past the end of the captured data in the packet. */
2031           return 0;
2032         }
2033         lookup_timeout = pntohl(&pd[cur_offset]);
2034         if (dns_tree != NULL) {
2035           proto_tree_add_text(rr_tree, NullTVB, cur_offset, 4, "Lookup timeout: %u seconds",
2036                        lookup_timeout);
2037         }
2038         cur_offset += 4;
2039         rr_len -= 4;
2040
2041         if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
2042           /* We ran past the end of the captured data in the packet. */
2043           return 0;
2044         }
2045         cache_timeout = pntohl(&pd[cur_offset]);
2046         if (dns_tree != NULL) {
2047           proto_tree_add_text(rr_tree, NullTVB, cur_offset, 4, "Cache timeout: %u seconds",
2048                        cache_timeout);
2049         }
2050         cur_offset += 4;
2051         rr_len -= 4;
2052
2053         if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
2054           /* We ran past the end of the captured data in the packet. */
2055           return 0;
2056         }
2057         nservers = pntohl(&pd[cur_offset]);
2058         if (dns_tree != NULL) {
2059           proto_tree_add_text(rr_tree, NullTVB, cur_offset, 4, "Number of WINS servers: %u",
2060                        nservers);
2061         }
2062         cur_offset += 4;
2063         rr_len -= 4;
2064
2065         while (rr_len != 0 && nservers != 0) {
2066           if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
2067             /* We ran past the end of the captured data in the packet. */
2068             return 0;
2069           }
2070           if (dns_tree != NULL) {
2071             proto_tree_add_text(rr_tree, NullTVB, cur_offset, 4, "WINS server address: %s",
2072                      ip_to_str((guint8 *)&pd[cur_offset]));
2073           }
2074           cur_offset += 4;
2075           rr_len -= 4;
2076           nservers--;
2077         }
2078       }
2079     }
2080     break;
2081
2082   case T_WINS_R:
2083     {
2084       int rr_len = data_len;
2085       guint32 local_flag;
2086       guint32 lookup_timeout;
2087       guint32 cache_timeout;
2088       char dname[MAXDNAME];
2089       int dname_len;
2090
2091       if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
2092         /* We ran past the end of the captured data in the packet. */
2093         if (dns_tree != NULL) {
2094           proto_item_set_text(trr,
2095                 "%s: type %s, class %s, <Local flag goes past end of captured data in packet>",
2096                        name, type_name, class_name);
2097         }
2098         return 0;
2099       }
2100       local_flag = pntohl(&pd[cur_offset]);
2101       if (dns_tree != NULL) {
2102         proto_tree_add_text(rr_tree, NullTVB, cur_offset, 4, "Local flag: %s",
2103                        local_flag ? "true" : "false");
2104       }
2105       cur_offset += 4;
2106       rr_len -= 4;
2107
2108       if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
2109         /* We ran past the end of the captured data in the packet. */
2110         if (dns_tree != NULL) {
2111           proto_item_set_text(trr,
2112                 "%s: type %s, class %s, <Lookup timeout goes past end of captured data in packet>",
2113                        name, type_name, class_name);
2114         }
2115         return 0;
2116       }
2117       lookup_timeout = pntohl(&pd[cur_offset]);
2118       if (dns_tree != NULL) {
2119         proto_tree_add_text(rr_tree, NullTVB, cur_offset, 4, "Lookup timeout: %u seconds",
2120                        lookup_timeout);
2121       }
2122       cur_offset += 4;
2123       rr_len -= 4;
2124
2125       if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
2126         /* We ran past the end of the captured data in the packet. */
2127         if (dns_tree != NULL) {
2128           proto_item_set_text(trr,
2129                 "%s: type %s, class %s, <Cache timeout goes past end of captured data in packet>",
2130                        name, type_name, class_name);
2131         }
2132         return 0;
2133       }
2134       cache_timeout = pntohl(&pd[cur_offset]);
2135       if (dns_tree != NULL) {
2136         proto_tree_add_text(rr_tree, NullTVB, cur_offset, 4, "Cache timeout: %u seconds",
2137                        cache_timeout);
2138       }
2139       cur_offset += 4;
2140       rr_len -= 4;
2141
2142       dname_len = get_dns_name(pd, cur_offset, dns_data_offset, dname, sizeof(dname));
2143       if (dname_len < 0) {
2144         /* We ran past the end of the captured data in the packet. */
2145         if (dns_tree != NULL) {
2146           proto_item_set_text(trr,
2147                 "%s: type %s, class %s, <Name result domain goes past end of captured data in packet>",
2148                        name, type_name, class_name);
2149         }
2150         return 0;
2151       }
2152       if (fd != NULL)
2153         col_append_fstr(fd, COL_INFO, " %s", dname);
2154       if (dns_tree != NULL) {
2155         proto_item_set_text(trr, "%s: type %s, class %s, name result domain %s",
2156                      name, type_name, class_name, dname);
2157         proto_tree_add_text(rr_tree, NullTVB, cur_offset, dname_len, "Name result domain: %s",
2158                         dname);
2159       }
2160     }
2161     break;
2162
2163     /* TODO: parse more record types */
2164
2165   default:
2166     if (dns_tree != NULL) {
2167       proto_item_set_text(trr,
2168                 "%s: type %s, class %s", name, type_name, class_name);
2169       proto_tree_add_text(rr_tree, NullTVB, cur_offset, data_len, "Data");
2170     }
2171     break;
2172   }
2173   
2174   dptr += data_len;
2175         
2176   return dptr - data_start;
2177 }
2178
2179 static int
2180 dissect_query_records(const u_char *pd, int cur_off, int dns_data_offset,
2181     int count, frame_data *fd, proto_tree *dns_tree, int isupdate)
2182 {
2183   int start_off, add_off;
2184   proto_tree *qatree = NULL;
2185   proto_item *ti = NULL;
2186   
2187   start_off = cur_off;
2188   if (dns_tree) {
2189     char *s = (isupdate ?  "Zone" : "Queries");
2190     ti = proto_tree_add_text(dns_tree, NullTVB, start_off, 0, s);
2191     qatree = proto_item_add_subtree(ti, ett_dns_qry);
2192   }
2193   while (count-- > 0) {
2194     add_off = dissect_dns_query(pd, cur_off, dns_data_offset, fd, qatree);
2195     if (add_off <= 0) {
2196       /* We ran past the end of the captured data in the packet. */
2197       break;
2198     }
2199     cur_off += add_off;
2200   }
2201   if (ti)
2202     proto_item_set_len(ti, cur_off - start_off);
2203
2204   return cur_off - start_off;
2205 }
2206
2207 static int
2208 dissect_answer_records(const u_char *pd, int cur_off, int dns_data_offset,
2209     int count, frame_data *fd, proto_tree *dns_tree, char *name)
2210 {
2211   int start_off, add_off;
2212   proto_tree *qatree = NULL;
2213   proto_item *ti = NULL;
2214   
2215   start_off = cur_off;
2216   if (dns_tree) {
2217     ti = proto_tree_add_text(dns_tree, NullTVB, start_off, 0, name);
2218     qatree = proto_item_add_subtree(ti, ett_dns_ans);
2219   }
2220   while (count-- > 0) {
2221     add_off = dissect_dns_answer(pd, cur_off, dns_data_offset, fd, qatree);
2222     if (add_off <= 0) {
2223       /* We ran past the end of the captured data in the packet. */
2224       break;
2225     }
2226     cur_off += add_off;
2227   }
2228   if (ti)
2229     proto_item_set_len(ti, cur_off - start_off);
2230
2231   return cur_off - start_off;
2232 }
2233
2234 static void
2235 dissect_dns(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
2236 {
2237   int dns_data_offset;
2238   proto_tree *dns_tree = NULL, *field_tree;
2239   proto_item *ti, *tf;
2240   guint16    id, flags, quest, ans, auth, add;
2241   char buf[128+1];
2242   int cur_off;
2243   int isupdate;
2244   static const value_string opcode_vals[] = {
2245                   { OPCODE_QUERY,  "Standard query"           },
2246                   { OPCODE_IQUERY, "Inverse query"            },
2247                   { OPCODE_STATUS, "Server status request"    },
2248                   { OPCODE_NOTIFY, "Zone change notification" },
2249                   { OPCODE_UPDATE, "Dynamic update"           },
2250                   { 0,              NULL                      } };
2251
2252   OLD_CHECK_DISPLAY_AS_DATA(proto_dns, pd, offset, fd, tree);
2253
2254   dns_data_offset = offset;
2255
2256   if (check_col(fd, COL_PROTOCOL))
2257     col_set_str(fd, COL_PROTOCOL, "DNS");
2258
2259   if (!BYTES_ARE_IN_FRAME(offset, DNS_HDRLEN)) {
2260     if (check_col(fd, COL_INFO)) {
2261       col_set_str(fd, COL_INFO, "Short DNS packet");
2262     }
2263     old_dissect_data(pd, offset, fd, tree);
2264     return;
2265   }
2266
2267   /* To do: check for errs, etc. */
2268   id    = pntohs(&pd[offset + DNS_ID]);
2269   flags = pntohs(&pd[offset + DNS_FLAGS]);
2270   quest = pntohs(&pd[offset + DNS_QUEST]);
2271   ans   = pntohs(&pd[offset + DNS_ANS]);
2272   auth  = pntohs(&pd[offset + DNS_AUTH]);
2273   add   = pntohs(&pd[offset + DNS_ADD]);
2274
2275   if (check_col(fd, COL_INFO)) {
2276     strcpy(buf, val_to_str(flags & F_OPCODE, opcode_vals, "Unknown operation (%x)"));
2277     if (flags & F_RESPONSE) {
2278       strcat(buf, " response");
2279       if ((flags & F_RCODE) != RCODE_NOERROR) {
2280         strcat(buf, ", ");
2281         strcat(buf, val_to_str(flags & F_RCODE, rcode_vals,
2282             "Unknown error (%x)"));
2283       }
2284     }
2285     col_add_str(fd, COL_INFO, buf);
2286   } else {
2287     /* Set "fd" to NULL; we pass a NULL "fd" to the query and answer
2288        dissectors, as a way of saying that they shouldn't add stuff
2289        to the COL_INFO column (a call to "check_col(fd, COL_INFO)"
2290        is more expensive than a check that a pointer isn't NULL). */
2291     fd = NULL;
2292   }
2293   if ((flags & F_OPCODE) == OPCODE_UPDATE)
2294     isupdate = 1;
2295   else
2296     isupdate = 0;
2297   
2298   if (tree) {
2299     ti = proto_tree_add_protocol_format(tree, proto_dns, NullTVB, offset, 4,
2300       "Domain Name System (%s)", (flags & F_RESPONSE) ? "response" : "query");
2301     
2302     dns_tree = proto_item_add_subtree(ti, ett_dns);
2303
2304     if (flags & F_RESPONSE)
2305       proto_tree_add_boolean_hidden(dns_tree, hf_dns_response, NullTVB, offset, 4, 1);
2306     else
2307       proto_tree_add_boolean_hidden(dns_tree, hf_dns_query, NullTVB, offset, 4, 1);
2308
2309     proto_tree_add_uint(dns_tree, hf_dns_transaction_id, NullTVB, 
2310                         offset + DNS_ID, 2, id);
2311
2312     strcpy(buf, val_to_str(flags & F_OPCODE, opcode_vals, "Unknown operation"));
2313     if (flags & F_RESPONSE) {
2314       strcat(buf, " response");
2315       strcat(buf, ", ");
2316       strcat(buf, val_to_str(flags & F_RCODE, rcode_vals,
2317             "Unknown error"));
2318     }
2319     tf = proto_tree_add_uint_format(dns_tree, hf_dns_flags, NullTVB, 
2320                                     offset + DNS_FLAGS, 2, 
2321                                     flags,
2322                                     "Flags: 0x%04x (%s)",
2323                                     flags, buf);
2324     field_tree = proto_item_add_subtree(tf, ett_dns_flags);
2325     proto_tree_add_text(field_tree, NullTVB, offset + DNS_FLAGS, 2, "%s",
2326        decode_boolean_bitfield(flags, F_RESPONSE,
2327             2*8, "Response", "Query"));
2328     proto_tree_add_text(field_tree, NullTVB, offset + DNS_FLAGS, 2, "%s",
2329        decode_enumerated_bitfield(flags, F_OPCODE,
2330             2*8, opcode_vals, "%s"));
2331     if (flags & F_RESPONSE) {
2332       proto_tree_add_text(field_tree, NullTVB, offset + DNS_FLAGS, 2, "%s",
2333          decode_boolean_bitfield(flags, F_AUTHORITATIVE,
2334               2*8,
2335               "Server is an authority for domain",
2336               "Server is not an authority for domain"));
2337     }
2338     proto_tree_add_text(field_tree, NullTVB, offset + DNS_FLAGS, 2, "%s",
2339        decode_boolean_bitfield(flags, F_TRUNCATED,
2340             2*8,
2341             "Message is truncated",
2342             "Message is not truncated"));
2343     proto_tree_add_text(field_tree, NullTVB, offset + DNS_FLAGS, 2, "%s",
2344        decode_boolean_bitfield(flags, F_RECDESIRED,
2345             2*8,
2346             "Do query recursively",
2347             "Don't do query recursively"));
2348     if (flags & F_RESPONSE) {
2349       proto_tree_add_text(field_tree, NullTVB, offset + DNS_FLAGS, 2, "%s",
2350          decode_boolean_bitfield(flags, F_RECAVAIL,
2351               2*8,
2352               "Server can do recursive queries",
2353               "Server can't do recursive queries"));
2354       proto_tree_add_text(field_tree, NullTVB, offset + DNS_FLAGS, 2, "%s",
2355          decode_boolean_bitfield(flags, F_AUTHENTIC,
2356             2*8,
2357             "Answer/authority portion was authenticated by the server",
2358             "Answer/authority portion was not authenticated by the server"));
2359     }
2360     if ((flags & F_RESPONSE) == 0) {
2361       proto_tree_add_text(field_tree, NullTVB, offset + DNS_FLAGS, 2, "%s",
2362          decode_boolean_bitfield(flags, F_CHECKDISABLE,
2363             2*8,
2364             "Non-authenticated data is acceptable",
2365             "Non-authenticated data is unacceptable"));
2366     }
2367     if (flags & F_RESPONSE) {
2368       proto_tree_add_text(field_tree, NullTVB, offset + DNS_FLAGS, 2, "%s",
2369          decode_enumerated_bitfield(flags, F_RCODE,
2370               2*8, rcode_vals, "%s"));
2371     }
2372     proto_tree_add_uint(dns_tree, hf_dns_count_questions, NullTVB, 
2373                         offset + DNS_QUEST, 2, quest);
2374     proto_tree_add_uint(dns_tree, hf_dns_count_answers, NullTVB, 
2375                         offset + DNS_ANS, 2, ans);
2376     proto_tree_add_uint(dns_tree, hf_dns_count_auth_rr, NullTVB, 
2377                         offset + DNS_AUTH, 2, auth);
2378     proto_tree_add_uint(dns_tree, hf_dns_count_add_rr, NullTVB, 
2379                         offset + DNS_ADD, 2, add);
2380
2381   }
2382   cur_off = offset + DNS_HDRLEN;
2383
2384   if (quest > 0) {
2385     /* If this is a response, don't add information about the queries
2386        to the summary, just add information about the answers. */
2387     cur_off += dissect_query_records(pd, cur_off, dns_data_offset, quest,
2388                                         (!(flags & F_RESPONSE) ? fd : NULL),
2389                                         dns_tree, isupdate);
2390   }
2391     
2392   if (ans > 0) {
2393     /* If this is a request, don't add information about the answers
2394        to the summary, just add information about the queries. */
2395     char *s = (isupdate ?  "Prerequisites" : "Answers");
2396     cur_off += dissect_answer_records(pd, cur_off, dns_data_offset, ans,
2397                                         ((flags & F_RESPONSE) ? fd : NULL),
2398                                         dns_tree, s);
2399   }
2400     
2401   if (tree) {
2402     /* Don't add information about the authoritative name servers, or the
2403        additional records, to the summary. */
2404     if (auth > 0) {
2405       char *s = (isupdate ?  "Updates" : "Authoritative nameservers");
2406       cur_off += dissect_answer_records(pd, cur_off, dns_data_offset, auth,
2407           NULL, dns_tree, s);
2408     }
2409
2410     if (add > 0)
2411       cur_off += dissect_answer_records(pd, cur_off, dns_data_offset, add,
2412           NULL, dns_tree, "Additional records");
2413   }
2414 }
2415
2416 static void
2417 dissect_dns_tcp(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
2418 {
2419         guint16 plen;
2420
2421         if (pi.captured_len < 2)
2422                 return;
2423         plen = pntohs(&pd[offset]);
2424         offset += 2;
2425         if (END_OF_FRAME != plen)
2426                 return;
2427         dissect_dns(pd, offset, fd, tree);
2428 }
2429
2430 void
2431 proto_register_dns(void)
2432 {
2433   static hf_register_info hf[] = {
2434     { &hf_dns_response,
2435       { "Response",             "dns.response",  
2436         FT_BOOLEAN, BASE_NONE, NULL, 0x0,
2437         "TRUE if DNS response" }},
2438     { &hf_dns_query,
2439       { "Query",                "dns.query",  
2440         FT_BOOLEAN, BASE_NONE, NULL, 0x0,
2441         "TRUE if DNS query" }},
2442     { &hf_dns_flags,
2443       { "Flags",                "dns.flags",  
2444         FT_UINT16, BASE_HEX, NULL, 0x0,
2445         "" }},
2446     { &hf_dns_transaction_id,
2447       { "Transaction ID",       "dns.id",  
2448         FT_UINT16, BASE_HEX, NULL, 0x0,
2449         "Identification of transaction" }},
2450     { &hf_dns_count_questions,
2451       { "Questions",            "dns.count.queries",  
2452         FT_UINT16, BASE_DEC, NULL, 0x0,
2453         "Number of queries in packet" }},
2454     { &hf_dns_count_answers,
2455       { "Answer RRs",           "dns.count.answers",  
2456         FT_UINT16, BASE_DEC, NULL, 0x0,
2457         "Number of answers in packet" }},
2458     { &hf_dns_count_auth_rr,
2459       { "Authority RRs",        "dns.count.auth_rr",  
2460         FT_UINT16, BASE_DEC, NULL, 0x0,
2461         "Number of authoritative records in packet" }},
2462     { &hf_dns_count_add_rr,
2463       { "Additional RRs",       "dns.count.add_rr",  
2464         FT_UINT16, BASE_DEC, NULL, 0x0,
2465         "Number of additional records in packet" }}
2466   };
2467   static gint *ett[] = {
2468     &ett_dns,
2469     &ett_dns_qd,
2470     &ett_dns_rr,
2471     &ett_dns_qry,
2472     &ett_dns_ans,
2473     &ett_dns_flags,
2474     &ett_t_key_flags,
2475   };
2476
2477   proto_dns = proto_register_protocol("Domain Name Service", "DNS", "dns");
2478   proto_register_field_array(proto_dns, hf, array_length(hf));
2479   proto_register_subtree_array(ett, array_length(ett));
2480 }
2481
2482 void
2483 proto_reg_handoff_dns(void)
2484 {
2485   old_dissector_add("udp.port", UDP_PORT_DNS, dissect_dns);
2486   old_dissector_add("tcp.port", TCP_PORT_DNS, dissect_dns_tcp);
2487 }