Make work better the (hexdump) popup menus.
[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.53 2000/08/18 09:05:02 itojun 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 /* Port used for DNS. */
65 #define UDP_PORT_DNS     53
66
67 /* Offsets of fields in the DNS header. */
68 #define DNS_ID          0
69 #define DNS_FLAGS       2
70 #define DNS_QUEST       4
71 #define DNS_ANS         6
72 #define DNS_AUTH        8
73 #define DNS_ADD         10
74
75 /* Length of DNS header. */
76 #define DNS_HDRLEN      12
77
78 /* type values  */
79 #define T_A             1               /* host address */
80 #define T_NS            2               /* authoritative name server */
81 #define T_MD            3               /* mail destination (obsolete) */
82 #define T_MF            4               /* mail forwarder (obsolete) */
83 #define T_CNAME         5               /* canonical name */
84 #define T_SOA           6               /* start of authority zone */
85 #define T_MB            7               /* mailbox domain name (experimental) */
86 #define T_MG            8               /* mail group member (experimental) */
87 #define T_MR            9               /* mail rename domain name (experimental) */
88 #define T_NULL          10              /* null RR (experimental) */
89 #define T_WKS           11              /* well known service */
90 #define T_PTR           12              /* domain name pointer */
91 #define T_HINFO         13              /* host information */
92 #define T_MINFO         14              /* mailbox or mail list information */
93 #define T_MX            15              /* mail routing information */
94 #define T_TXT           16              /* text strings */
95 #define T_RP            17              /* responsible person (RFC 1183) */
96 #define T_AFSDB         18              /* AFS data base location (RFC 1183) */
97 #define T_X25           19              /* X.25 address (RFC 1183) */
98 #define T_ISDN          20              /* ISDN address (RFC 1183) */
99 #define T_RT            21              /* route-through (RFC 1183) */
100 #define T_NSAP          22              /* OSI NSAP (RFC 1706) */
101 #define T_NSAP_PTR      23              /* PTR equivalent for OSI NSAP (RFC 1348 - obsolete) */
102 #define T_SIG           24              /* digital signature (RFC 2065) */
103 #define T_KEY           25              /* public key (RFC 2065) */
104 #define T_PX            26              /* pointer to X.400/RFC822 mapping info (RFC 1664) */
105 #define T_GPOS          27              /* geographical position (RFC 1712) */
106 #define T_AAAA          28              /* IPv6 address (RFC 1886) */
107 #define T_LOC           29              /* geographical location (RFC 1876) */
108 #define T_NXT           30              /* "next" name (RFC 2065) */
109 #define T_EID           31              /* ??? (Nimrod?) */
110 #define T_NIMLOC        32              /* ??? (Nimrod?) */
111 #define T_SRV           33              /* service location (RFC 2052) */
112 #define T_ATMA          34              /* ??? */
113 #define T_NAPTR         35              /* naming authority pointer (RFC 2168) */
114 #define T_A6            38              /* IPv6 address with indirection (RFC 2874) */
115 #define T_OPT           41              /* OPT pseudo-RR (RFC 2671) */
116 #define T_WINS          65281           /* Microsoft's WINS RR */
117 #define T_WINS_R        65282           /* Microsoft's WINS-R RR */
118
119 /* Class values */
120 #define C_IN            1               /* the Internet */
121 #define C_CS            2               /* CSNET (obsolete) */
122 #define C_CH            3               /* CHAOS */
123 #define C_HS            4               /* Hesiod */
124
125 /* Bit fields in the flags */
126 #define F_RESPONSE      (1<<15)         /* packet is response */
127 #define F_OPCODE        (0xF<<11)       /* query opcode */
128 #define F_AUTHORITATIVE (1<<10)         /* response is authoritative */
129 #define F_TRUNCATED     (1<<9)          /* response is truncated */
130 #define F_RECDESIRED    (1<<8)          /* recursion desired */
131 #define F_RECAVAIL      (1<<7)          /* recursion available */
132 #define F_AUTHENTIC     (1<<5)          /* authentic data (RFC2535) */
133 #define F_CHECKDISABLE  (1<<4)          /* checking disabled (RFC2535) */
134 #define F_RCODE         (0xF<<0)        /* reply code */
135
136 /* Opcodes */
137 #define OPCODE_QUERY    (0<<11)         /* standard query */
138 #define OPCODE_IQUERY   (1<<11)         /* inverse query */
139 #define OPCODE_STATUS   (2<<11)         /* server status request */
140
141 /* Reply codes */
142 #define RCODE_NOERROR   (0<<0)
143 #define RCODE_FMTERROR  (1<<0)
144 #define RCODE_SERVFAIL  (2<<0)
145 #define RCODE_NAMEERROR (3<<0)
146 #define RCODE_NOTIMPL   (4<<0)
147 #define RCODE_REFUSED   (5<<0)
148
149 /* See RFC 1035 for all RR types for which no RFC is listed, except for
150    the ones with "???", and for the Microsoft WINS and WINS-R RRs, for
151    which one should look at
152
153 http://www.windows.com/windows2000/en/server/help/sag_DNS_imp_UsingWinsLookup.htm
154    
155    and
156    
157 http://www.microsoft.com/windows2000/library/resources/reskit/samplechapters/cncf/cncf_imp_wwaw.asp
158
159    which discuss them to some extent. */
160 static char *
161 dns_type_name (u_int type)
162 {
163   char *type_names[] = {
164     "unused",
165     "A",
166     "NS",
167     "MD",
168     "MF",
169     "CNAME",
170     "SOA",
171     "MB",
172     "MG",
173     "MR",
174     "NULL",
175     "WKS",
176     "PTR",
177     "HINFO",
178     "MINFO",
179     "MX",
180     "TXT",
181     "RP",                               /* RFC 1183 */
182     "AFSDB",                            /* RFC 1183 */
183     "X25",                              /* RFC 1183 */
184     "ISDN",                             /* RFC 1183 */
185     "RT",                               /* RFC 1183 */
186     "NSAP",                             /* RFC 1706 */
187     "NSAP-PTR",                         /* RFC 1348 */
188     "SIG",                              /* RFC 2065 */
189     "KEY",                              /* RFC 2065 */
190     "PX",                               /* RFC 1664 */
191     "GPOS",                             /* RFC 1712 */
192     "AAAA",                             /* RFC 1886 */
193     "LOC",                              /* RFC 1876 */
194     "NXT",                              /* RFC 2065 */
195     "EID",
196     "NIMLOC",
197     "SRV",                              /* RFC 2052 */
198     "ATMA",
199     "NAPTR",                            /* RFC 2168 */
200     NULL,
201     NULL,
202     "A6",                               /* RFC 2874 */
203     NULL,
204     NULL,
205     "OPT"                               /* RFC 2671 */
206   };
207   
208   if (type < sizeof(type_names)/sizeof(type_names[0]))
209     return type_names[type] ? type_names[type] : "unknown";
210   
211   /* special cases */
212   switch (type) 
213     {
214       /* non standard  */
215     case 100:
216       return "UINFO";
217     case 101:
218       return "UID";
219     case 102:
220       return "GID";
221     case 103:
222       return "UNSPEC";
223     case T_WINS:
224       return "WINS";
225     case T_WINS_R:
226       return "WINS-R";
227
228       /* queries  */
229     case 251:
230       return "IXFR";    /* RFC 1995 */
231     case 252:
232       return "AXFR";
233     case 253:
234       return "MAILB";
235     case 254:
236       return "MAILA";
237     case 255:
238       return "ANY";
239
240     }
241
242   return "unknown";
243 }
244
245
246 static char *
247 dns_long_type_name (u_int type)
248 {
249   char *type_names[] = {
250     "unused",
251     "Host address",
252     "Authoritative name server",        
253     "Mail destination",
254     "Mail forwarder",
255     "Canonical name for an alias",
256     "Start of zone of authority",
257     "Mailbox domain name",
258     "Mail group member",
259     "Mail rename domain name",
260     "Null resource record",
261     "Well-known service description",
262     "Domain name pointer",
263     "Host information",
264     "Mailbox or mail list information",
265     "Mail exchange",
266     "Text strings",
267     "Responsible person",               /* RFC 1183 */
268     "AFS data base location",           /* RFC 1183 */
269     "X.25 address",                     /* RFC 1183 */
270     "ISDN number",                      /* RFC 1183 */
271     "Route through",                    /* RFC 1183 */
272     "OSI NSAP",                         /* RFC 1706 */
273     "OSI NSAP name pointer",            /* RFC 1348 */
274     "Signature",                        /* RFC 2065 */
275     "Public key",                       /* RFC 2065 */
276     "Pointer to X.400/RFC822 mapping info", /* RFC 1664 */
277     "Geographical position",            /* RFC 1712 */
278     "IPv6 address",                     /* RFC 1886 */
279     "Location",                         /* RFC 1876 */
280     "Next",                             /* RFC 2065 */
281     "EID",
282     "NIMLOC",
283     "Service location",                 /* RFC 2052 */
284     "ATMA",
285     "Naming authority pointer",         /* RFC 2168 */
286     NULL,
287     NULL,
288     "IPv6 address with indirection",    /* RFC 2874 */
289     NULL,
290     NULL,
291     "EDNS0 option"                      /* RFC 2671 */
292   };
293   static char unkbuf[7+1+2+1+4+1+1+10+1+1];     /* "Unknown RR type (%d)" */
294   
295   if (type < sizeof(type_names)/sizeof(type_names[0]))
296     return type_names[type] ? type_names[type] : "unknown";
297   
298   /* special cases */
299   switch (type) 
300     {
301       /* non standard  */
302     case 100:
303       return "UINFO";
304     case 101:
305       return "UID";
306     case 102:
307       return "GID";
308     case 103:
309       return "UNSPEC";
310     case T_WINS:
311       return "WINS";
312     case T_WINS_R:
313       return "WINS-R";
314
315       /* queries  */
316     case 251:
317       return "Request for incremental zone transfer";   /* RFC 1995 */
318     case 252:
319       return "Request for full zone transfer";
320     case 253:
321       return "Request for mailbox-related records";
322     case 254:
323       return "Request for mail agent resource records";
324     case 255:
325       return "Request for all records";
326     }
327   
328   sprintf(unkbuf, "Unknown RR type (%d)", type);
329   return unkbuf;
330 }
331
332
333 char *
334 dns_class_name(int class)
335 {
336   char *class_name;
337   
338   switch (class) {
339   case C_IN:
340     class_name = "inet";
341     break;
342   case C_CS:
343     class_name = "csnet";
344     break;
345   case C_CH:
346     class_name = "chaos";
347     break;
348   case C_HS:
349     class_name = "hesiod";
350     break;
351   default:
352     class_name = "unknown";
353   }
354
355   return class_name;
356 }
357
358 int
359 get_dns_name(const u_char *pd, int offset, int dns_data_offset,
360     char *name, int maxname)
361 {
362   const u_char *dp = pd + offset;
363   const u_char *dptr = dp;
364   char *np = name;
365   int len = -1;
366   int chars_processed = 0;
367   int data_size = pi.len - dns_data_offset;
368   u_int component_len;
369
370   maxname--;    /* reserve space for the trailing '\0' */
371   for (;;) {
372     if (!BYTES_ARE_IN_FRAME(offset, 1))
373       goto overflow;
374     component_len = *dp++;
375     offset++;
376     if (component_len == 0)
377       break;
378     chars_processed++;
379     switch (component_len & 0xc0) {
380
381     case 0x00:
382       /* Label */
383       if (np != name) {
384         /* Not the first component - put in a '.'. */
385         if (maxname > 0) {
386           *np++ = '.';
387           maxname--;
388         }
389       }
390       if (!BYTES_ARE_IN_FRAME(offset, component_len))
391         goto overflow;
392       while (component_len > 0) {
393         if (maxname > 0) {
394           *np++ = *dp;
395           maxname--;
396         }
397         component_len--;
398         dp++;
399         offset++;
400         chars_processed++;
401       }
402       break;
403
404     case 0x40:
405     case 0x80:
406       goto error;       /* error */
407
408     case 0xc0:
409       /* Pointer. */
410       if (!BYTES_ARE_IN_FRAME(offset, 1))
411         goto overflow;
412       offset = dns_data_offset + (((component_len & ~0xc0) << 8) | (*dp++));
413       chars_processed++;
414
415       /* If "len" is negative, we are still working on the original name,
416          not something pointed to by a pointer, and so we should set "len"
417          to the length of the original name. */
418       if (len < 0)
419         len = dp - dptr;
420
421       if (offset >= pi.len) {
422         strcpy(name, "<Name contains a pointer that goes past the end of the packet>");
423         return len;
424       }
425
426       /* If we've looked at every character in the message, this pointer
427          will make us look at some character again, which means we're
428          looping. */
429       if (chars_processed >= data_size) {
430         strcpy(name, "<Name contains a pointer that loops>");
431         return len;
432       }
433
434       dp = pd + offset;
435       break;    /* now continue processing from there */
436     }
437   }
438         
439 error:
440   *np = '\0';
441   /* If "len" is negative, we haven't seen a pointer, and thus haven't
442      set the length, so set it. */
443   if (len < 0)
444     len = dp - dptr;
445   /* Zero-length name means "root server" */
446   if (*name == '\0')
447     strcpy(name, "<Root>");
448   return len;
449
450 overflow:
451   /* We ran past the end of the captured data in the packet. */
452   strcpy(name, "<Name goes past end of captured data in packet>");
453   /* If "len" is negative, we haven't seen a pointer, and thus haven't
454      set the length, so set it. */
455   if (len < 0)
456     len = dp - dptr;
457   return len;
458 }
459
460
461 static int
462 get_dns_name_type_class(const u_char *pd, int offset, int dns_data_offset,
463     char *name_ret, int *name_len_ret, int *type_ret, int *class_ret)
464 {
465   int len;
466   int name_len;
467   int type;
468   int class;
469   char name[MAXDNAME];
470   int start_offset = offset;
471
472   name_len = get_dns_name(pd, offset, dns_data_offset, name, sizeof(name));
473   offset += name_len;
474   
475   if (!BYTES_ARE_IN_FRAME(offset, 2)) {
476     /* We ran past the end of the captured data in the packet. */
477     return -1;
478   }
479   type = pntohs(&pd[offset]);
480   offset += 2;
481
482   if (!BYTES_ARE_IN_FRAME(offset, 2)) {
483     /* We ran past the end of the captured data in the packet. */
484     return -1;
485   }
486   class = pntohs(&pd[offset]);
487   offset += 2;
488
489   strcpy (name_ret, name);
490   *type_ret = type;
491   *class_ret = class;
492   *name_len_ret = name_len;
493
494   len = offset - start_offset;
495   return len;
496 }
497
498 static double
499 rfc1867_size(u_char val)
500 {
501   double size;
502   guint32 exponent;
503
504   size = (val & 0xF0) >> 4;
505   exponent = (val & 0x0F);
506   while (exponent != 0) {
507     size *= 10;
508     exponent--;
509   }
510   return size / 100;    /* return size in meters, not cm */
511 }
512
513 static char *
514 rfc1867_angle(const u_char *dptr, const char *nsew)
515 {
516   guint32 angle;
517   char direction;
518   guint32 degrees, minutes, secs, tsecs;
519   static char buf[10+1+3+1 + 2+1+3+1 + 2+1+3+1+3+1 + 1 + 1];
520
521   angle = pntohl(dptr);
522
523   if (angle < 0x80000000U) {
524     angle = 0x80000000U - angle;
525     direction = nsew[1];
526   } else {
527     angle = angle - 0x80000000U;
528     direction = nsew[0];
529   }
530   tsecs = angle % 1000;
531   angle = angle / 1000;
532   secs = angle % 60;
533   angle = angle / 60;
534   minutes = angle % 60;
535   degrees = angle / 60;
536   sprintf(buf, "%u deg %u min %u.%03u sec %c", degrees, minutes, secs,
537                 tsecs, direction);
538   return buf;
539 }
540
541 static int
542 dissect_dns_query(const u_char *pd, int offset, int dns_data_offset,
543   frame_data *fd, proto_tree *dns_tree)
544 {
545   int len;
546   char name[MAXDNAME];
547   int name_len;
548   int type;
549   int class;
550   char *class_name;
551   char *type_name;
552   char *long_type_name;
553   const u_char *dptr;
554   const u_char *data_start;
555   proto_tree *q_tree;
556   proto_item *tq;
557
558   data_start = dptr = pd + offset;
559
560   len = get_dns_name_type_class(pd, offset, dns_data_offset, name, &name_len,
561     &type, &class);
562   if (len < 0) {
563     /* We ran past the end of the data in the packet. */
564     return 0;
565   }
566   dptr += len;
567
568   type_name = dns_type_name(type);
569   class_name = dns_class_name(class);
570   long_type_name = dns_long_type_name(type);
571
572   if (fd != NULL)
573     col_append_fstr(fd, COL_INFO, " %s %s", type_name, name);
574   if (dns_tree != NULL) {
575     tq = proto_tree_add_text(dns_tree, NullTVB, offset, len, "%s: type %s, class %s", 
576                    name, type_name, class_name);
577     q_tree = proto_item_add_subtree(tq, ett_dns_qd);
578
579     proto_tree_add_text(q_tree, NullTVB, offset, name_len, "Name: %s", name);
580     offset += name_len;
581
582     proto_tree_add_text(q_tree, NullTVB, offset, 2, "Type: %s", long_type_name);
583     offset += 2;
584
585     proto_tree_add_text(q_tree, NullTVB, offset, 2, "Class: %s", class_name);
586     offset += 2;
587   }
588   
589   return dptr - data_start;
590 }
591
592
593 proto_tree *
594 add_rr_to_tree(proto_item *trr, int rr_type, int offset, const char *name,
595   int namelen, const char *type_name, const char *class_name, u_int ttl,
596   u_short data_len)
597 {
598   proto_tree *rr_tree;
599
600   rr_tree = proto_item_add_subtree(trr, rr_type);
601   proto_tree_add_text(rr_tree, NullTVB, offset, namelen, "Name: %s", name);
602   offset += namelen;
603   proto_tree_add_text(rr_tree, NullTVB, offset, 2, "Type: %s", type_name);
604   offset += 2;
605   proto_tree_add_text(rr_tree, NullTVB, offset, 2, "Class: %s", class_name);
606   offset += 2;
607   proto_tree_add_text(rr_tree, NullTVB, offset, 4, "Time to live: %s",
608                                                 time_secs_to_str(ttl));
609   offset += 4;
610   proto_tree_add_text(rr_tree, NullTVB, offset, 2, "Data length: %u", data_len);
611   return rr_tree;
612 }
613
614 static proto_tree *
615 add_opt_rr_to_tree(proto_item *trr, int rr_type, int offset, const char *name,
616   int namelen, const char *type_name, int class, u_int ttl, u_short data_len)
617 {
618   proto_tree *rr_tree;
619
620   rr_tree = proto_item_add_subtree(trr, rr_type);
621   proto_tree_add_text(rr_tree, NullTVB, offset, namelen, "Name: %s", name);
622   offset += namelen;
623   proto_tree_add_text(rr_tree, NullTVB, offset, 2, "Type: %s", type_name);
624   offset += 2;
625   proto_tree_add_text(rr_tree, NullTVB, offset, 2, "UDP payload size: %u",
626       class & 0xffff);
627   offset += 2;
628   proto_tree_add_text(rr_tree, NullTVB, offset, 1, "Higher bits in extended RCODE: 0x%x",
629       (ttl >> 24) & 0xff0);
630   offset++;
631   proto_tree_add_text(rr_tree, NullTVB, offset, 1, "EDNS0 version: %u",
632       (ttl >> 16) & 0xff);
633   offset++;
634   proto_tree_add_text(rr_tree, NullTVB, offset, 2, "Must be zero: 0x%x", ttl & 0xffff);
635   offset += 2;
636   proto_tree_add_text(rr_tree, NullTVB, offset, 2, "Data length: %u", data_len);
637   return rr_tree;
638 }
639
640 /*
641  * SIG and KEY RR algorithms.
642  */
643 #define DNS_ALGO_RSAMD5         1       /* RSA/MD5 */
644 #define DNS_ALGO_DH             2       /* Diffie-Hellman */
645 #define DNS_ALGO_DSA            3       /* DSA */
646 #define DNS_ALGO_ECC            4       /* Elliptic curve crypto */
647 #define DNS_ALGO_INDIRECT       252     /* Indirect key */
648 #define DNS_ALGO_PRIVATEDNS     253     /* Private, domain name  */
649 #define DNS_ALGO_PRIVATEOID     254     /* Private, OID */      
650
651 static const value_string algo_vals[] = {
652           { DNS_ALGO_RSAMD5,     "RSA/MD5" },
653           { DNS_ALGO_DH,         "Diffie-Hellman" },
654           { DNS_ALGO_DSA,        "DSA" },
655           { DNS_ALGO_ECC,        "Elliptic curve crypto" },
656           { DNS_ALGO_INDIRECT,   "Indirect key" },
657           { DNS_ALGO_PRIVATEDNS, "Private, domain name" },
658           { DNS_ALGO_PRIVATEOID, "Private, OID" },
659           { 0,                   NULL }
660 };
661
662 static int
663 dissect_dns_answer(const u_char *pd, int offset, int dns_data_offset,
664   frame_data *fd, proto_tree *dns_tree)
665 {
666   int len;
667   char name[MAXDNAME];
668   int name_len;
669   int type;
670   int class;
671   char *class_name;
672   char *type_name;
673   char *long_type_name;
674   const u_char *dptr;
675   int cur_offset;
676   const u_char *data_start;
677   u_int ttl;
678   u_short data_len;
679   proto_tree *rr_tree = NULL;
680   proto_item *trr = NULL;
681
682   data_start = dptr = pd + offset;
683   cur_offset = offset;
684
685   len = get_dns_name_type_class(pd, offset, dns_data_offset, name, &name_len,
686     &type, &class);
687   if (len < 0) {
688     /* We ran past the end of the captured data in the packet. */
689     return 0;
690   }
691   dptr += len;
692   cur_offset += len;
693
694   type_name = dns_type_name(type);
695   class_name = dns_class_name(class);
696   long_type_name = dns_long_type_name(type);
697
698   if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
699     /* We ran past the end of the captured data in the packet. */
700     return 0;
701   }
702   ttl = pntohl(dptr);
703   dptr += 4;
704   cur_offset += 4;
705
706   if (!BYTES_ARE_IN_FRAME(cur_offset, 2)) {
707     /* We ran past the end of the captured data in the packet. */
708     return 0;
709   }
710   data_len = pntohs(dptr);
711   dptr += 2;
712   cur_offset += 2;
713
714   if (fd != NULL)
715     col_append_fstr(fd, COL_INFO, " %s", type_name);
716   if (dns_tree != NULL) {
717     trr = proto_tree_add_notext(dns_tree, NullTVB, offset,
718                                 (dptr - data_start) + data_len);
719     if (type != T_OPT) {
720       rr_tree = add_rr_to_tree(trr, ett_dns_rr, offset, name, name_len,
721                      long_type_name, class_name, ttl, data_len);
722     } else  {
723       rr_tree = add_opt_rr_to_tree(trr, ett_dns_rr, offset, name, name_len,
724                      long_type_name, class, ttl, data_len);
725     }
726   }
727
728   switch (type) {
729
730   case T_A:
731     if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
732       /* We ran past the end of the captured data in the packet. */
733       if (dns_tree != NULL) {
734         proto_item_set_text(trr,
735                 "%s: type %s, class %s, <Address goes past end of captured data in packet>",
736                        name, type_name, class_name);
737       }
738       return 0;
739     }
740     if (fd != NULL)
741       col_append_fstr(fd, COL_INFO, " %s", ip_to_str((guint8 *)dptr));
742     if (dns_tree != NULL) {
743       proto_item_set_text(trr, "%s: type %s, class %s, addr %s",
744                      name, type_name, class_name,
745                      ip_to_str((guint8 *)dptr));
746       proto_tree_add_text(rr_tree, NullTVB, cur_offset, 4, "Addr: %s",
747                      ip_to_str((guint8 *)dptr));
748     }
749     if (class == C_IN) {
750       guint32 addr;
751       memcpy(&addr, dptr, sizeof(addr));
752       add_host_name(addr, name);
753     }
754     break;
755
756   case T_NS:
757     {
758       char ns_name[MAXDNAME];
759       int ns_name_len;
760       
761       ns_name_len = get_dns_name(pd, cur_offset, dns_data_offset, ns_name, sizeof(ns_name));
762       if (ns_name_len < 0) {
763         /* We ran past the end of the captured data in the packet. */
764         if (dns_tree != NULL) {
765           proto_item_set_text(trr,
766                 "%s: type %s, class %s, <Nameserver name goes past end of captured data in packet>",
767                        name, type_name, class_name);
768         }
769         return 0;
770       }
771       if (fd != NULL)
772         col_append_fstr(fd, COL_INFO, " %s", ns_name);
773       if (dns_tree != NULL) {
774         proto_item_set_text(trr, "%s: type %s, class %s, ns %s",
775                        name, type_name, class_name, ns_name);
776         proto_tree_add_text(rr_tree, NullTVB, cur_offset, ns_name_len, "Name server: %s",
777                         ns_name);
778       }
779     }
780     break;
781
782   case T_CNAME:
783     {
784       char cname[MAXDNAME];
785       int cname_len;
786       
787       cname_len = get_dns_name(pd, cur_offset, dns_data_offset, cname, sizeof(cname));
788       if (cname_len < 0) {
789         /* We ran past the end of the captured data in the packet. */
790         if (dns_tree != NULL) {
791           proto_item_set_text(trr,
792                 "%s: type %s, class %s, <Primary name goes past end of captured data in packet>",
793                        name, type_name, class_name);
794         }
795         return 0;
796       }
797       if (fd != NULL)
798         col_append_fstr(fd, COL_INFO, " %s", cname);
799       if (dns_tree != NULL) {
800         proto_item_set_text(trr, "%s: type %s, class %s, cname %s",
801                      name, type_name, class_name, cname);
802         proto_tree_add_text(rr_tree, NullTVB, cur_offset, cname_len, "Primary name: %s",
803                         cname);
804       }
805     }
806     break;
807
808   case T_SOA:
809     {
810       char mname[MAXDNAME];
811       int mname_len;
812       char rname[MAXDNAME];
813       int rname_len;
814       guint32 serial;
815       guint32 refresh;
816       guint32 retry;
817       guint32 expire;
818       guint32 minimum;
819
820       mname_len = get_dns_name(pd, cur_offset, dns_data_offset, mname, sizeof(mname));
821       if (mname_len < 0) {
822         /* We ran past the end of the captured data in the packet. */
823         if (dns_tree != NULL) {
824           proto_item_set_text(trr,
825                 "%s: type %s, class %s, <mname goes past end of captured data in packet>",
826                        name, type_name, class_name);
827         }
828         return 0;
829       }
830       if (fd != NULL)
831         col_append_fstr(fd, COL_INFO, " %s", mname);
832       if (dns_tree != NULL) {
833         proto_item_set_text(trr, "%s: type %s, class %s, mname %s",
834                      name, type_name, class_name, mname);
835         proto_tree_add_text(rr_tree, NullTVB, cur_offset, mname_len, "Primary name server: %s",
836                        mname);
837         cur_offset += mname_len;
838       
839         rname_len = get_dns_name(pd, cur_offset, dns_data_offset, rname, sizeof(rname));
840         if (rname_len < 0) {
841           /* We ran past the end of the captured data in the packet. */
842           return 0;
843         }
844         proto_tree_add_text(rr_tree, NullTVB, cur_offset, rname_len, "Responsible authority's mailbox: %s",
845                        rname);
846         cur_offset += rname_len;
847
848         if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
849           /* We ran past the end of the captured data in the packet. */
850           return 0;
851         }
852         serial = pntohl(&pd[cur_offset]);
853         proto_tree_add_text(rr_tree, NullTVB, cur_offset, 4, "Serial number: %u",
854                        serial);
855         cur_offset += 4;
856
857         if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
858           /* We ran past the end of the captured data in the packet. */
859           return 0;
860         }
861         refresh = pntohl(&pd[cur_offset]);
862         proto_tree_add_text(rr_tree, NullTVB, cur_offset, 4, "Refresh interval: %s",
863                        time_secs_to_str(refresh));
864         cur_offset += 4;
865
866         if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
867           /* We ran past the end of the captured data in the packet. */
868           return 0;
869         }
870         retry = pntohl(&pd[cur_offset]);
871         proto_tree_add_text(rr_tree, NullTVB, cur_offset, 4, "Retry interval: %s",
872                        time_secs_to_str(retry));
873         cur_offset += 4;
874
875         if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
876           /* We ran past the end of the captured data in the packet. */
877           return 0;
878         }
879         expire = pntohl(&pd[cur_offset]);
880         proto_tree_add_text(rr_tree, NullTVB, cur_offset, 4, "Expiration limit: %s",
881                        time_secs_to_str(expire));
882         cur_offset += 4;
883
884         if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
885           /* We ran past the end of the captured data in the packet. */
886           return 0;
887         }
888         minimum = pntohl(&pd[cur_offset]);
889         proto_tree_add_text(rr_tree, NullTVB, cur_offset, 4, "Minimum TTL: %s",
890                        time_secs_to_str(minimum));
891       }
892     }
893     break;
894
895   case T_PTR:
896     {
897       char pname[MAXDNAME];
898       int pname_len;
899       
900       pname_len = get_dns_name(pd, cur_offset, dns_data_offset, pname, sizeof(pname));
901       if (pname_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, <Domain 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", pname);
912       if (dns_tree != NULL) {
913         proto_item_set_text(trr, "%s: type %s, class %s, ptr %s",
914                      name, type_name, class_name, pname);
915         proto_tree_add_text(rr_tree, NullTVB, cur_offset, pname_len, "Domain name: %s",
916                         pname);
917       }
918       break;
919     }
920     break;
921
922   case T_WKS:
923     {
924       int rr_len = data_len;
925       guint8 protocol;
926       guint8 bits;
927       int mask;
928       int port_num;
929       int i;
930       char bitnames[128+1];
931       char portnumstring[10+1];
932       
933       if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
934         /* We ran past the end of the captured data in the packet. */
935         if (dns_tree != NULL) {
936           proto_item_set_text(trr,
937                 "%s: type %s, class %s, <Address goes past end of captured data in packet>",
938                        name, type_name, class_name);
939         }
940         return 0;
941       }
942       if (fd != NULL)
943         col_append_fstr(fd, COL_INFO, " %s", ip_to_str((guint8 *)dptr));
944       if (dns_tree != NULL) {
945         proto_item_set_text(trr, "%s: type %s, class %s, addr %s",
946                      name, type_name, class_name,
947                      ip_to_str((guint8 *)dptr));
948         proto_tree_add_text(rr_tree, NullTVB, cur_offset, 4, "Addr: %s",
949                      ip_to_str((guint8 *)dptr));
950         cur_offset += 4;
951         rr_len -= 4;
952
953         if (!BYTES_ARE_IN_FRAME(cur_offset, 1)) {
954           /* We ran past the end of the captured data in the packet. */
955           proto_tree_add_text(rr_tree, NullTVB, cur_offset, END_OF_FRAME,
956                        "<Protocol goes past end of captured data in packet>");
957           return 0;
958         }
959         protocol = pd[cur_offset];
960         proto_tree_add_text(rr_tree, NullTVB, cur_offset, 1, "Protocol: %s",
961                      ipprotostr(protocol));
962         cur_offset += 1;
963         rr_len -= 1;
964
965         port_num = 0;
966         while (rr_len != 0) {
967           if (!BYTES_ARE_IN_FRAME(cur_offset, 1)) {
968             /* We ran past the end of the captured data in the packet. */
969             proto_tree_add_text(rr_tree, NullTVB, cur_offset, END_OF_FRAME,
970                        "<Bit map goes past end of captured data in packet>");
971             return 0;
972           }
973           bits = pd[cur_offset];
974           if (bits != 0) {
975             mask = 1<<7;
976             bitnames[0] = '\0';
977             for (i = 0; i < 8; i++) {
978               if (bits & mask) {
979                 if (bitnames[0] != '\0')
980                   strcat(bitnames, ", ");
981                 switch (protocol) {
982
983                 case IP_PROTO_TCP:
984                   strcat(bitnames, get_tcp_port(port_num));
985                   break;
986
987                 case IP_PROTO_UDP:
988                   strcat(bitnames, get_udp_port(port_num));
989                   break;
990
991                 default:
992                   sprintf(portnumstring, "%u", port_num);
993                   strcat(bitnames, portnumstring);
994                   break;
995                 }
996               }
997               mask >>= 1;
998               port_num++;
999             }
1000             proto_tree_add_text(rr_tree, NullTVB, cur_offset, 1,
1001                 "Bits: 0x%02x (%s)", bits, bitnames);
1002           } else
1003             port_num += 8;
1004           cur_offset += 1;
1005           rr_len -= 1;
1006         }
1007       }
1008     }
1009     break;
1010
1011   case T_HINFO:
1012     {
1013       int cpu_offset;
1014       int cpu_len;
1015       int os_offset;
1016       int os_len;
1017
1018       cpu_offset = cur_offset;
1019       if (!BYTES_ARE_IN_FRAME(cpu_offset, 1)) {
1020         /* We ran past the end of the captured data in the packet. */
1021         if (dns_tree != NULL) {
1022           proto_item_set_text(trr,
1023                        "%s: type %s, class %s, <CPU goes past end of captured data in packet>",
1024                        name, type_name, class_name);
1025         }
1026         return 0;
1027       }
1028       cpu_len = pd[cpu_offset];
1029       if (!BYTES_ARE_IN_FRAME(cpu_offset + 1, cpu_len)) {
1030         /* We ran past the end of the captured data in the packet. */
1031         if (dns_tree != NULL) {
1032           proto_item_set_text(trr,
1033                        "%s: type %s, class %s, <CPU goes past end of captured data in packet>",
1034                        name, type_name, class_name);
1035         }
1036         return 0;
1037       }
1038       os_offset = cpu_offset + 1 + cpu_len;
1039       if (!BYTES_ARE_IN_FRAME(os_offset, 1)) {
1040         /* We ran past the end of the captured data in the packet. */
1041         if (dns_tree != NULL) {
1042           proto_item_set_text(trr,
1043                        "%s: type %s, class %s, CPU %.*s, <OS goes past end of captured data in packet>",
1044                        name, type_name, class_name, cpu_len, &pd[cpu_offset + 1]);
1045         }
1046         return 0;
1047       }
1048       os_len = pd[os_offset];
1049       if (!BYTES_ARE_IN_FRAME(os_offset + 1, os_len)) {
1050         /* We ran past the end of the captured data in the packet. */
1051         if (dns_tree != NULL) {
1052           proto_item_set_text(trr,
1053                        "%s: type %s, class %s, CPU %.*s, <OS goes past end of captured data in packet>",
1054                        name, type_name, class_name, cpu_len, &pd[cpu_offset + 1]);
1055         }
1056         return 0;
1057       }
1058       if (fd != NULL)
1059         col_append_fstr(fd, COL_INFO, " %.*s %.*s", cpu_len,
1060             &pd[cpu_offset + 1], os_len, &pd[os_offset + 1]);
1061       if (dns_tree != NULL) {
1062         proto_item_set_text(trr,
1063                      "%s: type %s, class %s, CPU %.*s, OS %.*s",
1064                      name, type_name, class_name,
1065                      cpu_len, &pd[cpu_offset + 1], os_len, &pd[os_offset + 1]);
1066         proto_tree_add_text(rr_tree, NullTVB, cpu_offset, 1 + cpu_len, "CPU: %.*s",
1067                         cpu_len, &pd[cpu_offset + 1]);
1068         proto_tree_add_text(rr_tree, NullTVB, os_offset, 1 + os_len, "OS: %.*s",
1069                         os_len, &pd[os_offset + 1]);
1070       }
1071       break;
1072     }
1073     break;
1074
1075   case T_MX:
1076     {
1077       guint16 preference = 0;
1078       char mx_name[MAXDNAME];
1079       int mx_name_len;
1080       
1081       if (!BYTES_ARE_IN_FRAME(cur_offset, 2)) {
1082         /* We ran past the end of the captured data in the packet. */
1083         if (dns_tree != NULL) {
1084           proto_item_set_text(trr,
1085                        "%s: type %s, class %s, <preference goes past end of captured data in packet>",
1086                        name, type_name, class_name);
1087         }
1088         return 0;
1089       }
1090       preference = pntohs(&pd[cur_offset]);
1091       mx_name_len = get_dns_name(pd, cur_offset + 2, dns_data_offset, mx_name, sizeof(mx_name));
1092       if (mx_name_len < 0) {
1093         /* We ran past the end of the captured data in the packet. */
1094         if (dns_tree != NULL) {
1095           proto_item_set_text(trr,
1096                        "%s: type %s, class %s, preference %u, <mx goes past end of captured data in packet>",
1097                        name, type_name, class_name, preference);
1098         }
1099         return 0;
1100       }
1101       if (fd != NULL)
1102         col_append_fstr(fd, COL_INFO, " %u %s", preference, mx_name);
1103       if (dns_tree != NULL) {
1104         proto_item_set_text(trr,
1105                        "%s: type %s, class %s, preference %u, mx %s",
1106                        name, type_name, class_name, preference, mx_name);
1107         proto_tree_add_text(rr_tree, NullTVB, cur_offset, 2, "Preference: %u", preference);
1108         proto_tree_add_text(rr_tree, NullTVB, cur_offset + 2, mx_name_len, "Mail exchange: %s",
1109                         mx_name);
1110       }
1111     }
1112     break;
1113
1114   case T_TXT:
1115     {
1116       int rr_len = data_len;
1117       int txt_offset;
1118       int txt_len;
1119
1120       if (dns_tree != NULL) {
1121         proto_item_set_text(trr,
1122                 "%s: type %s, class %s", name, type_name, class_name);
1123
1124         txt_offset = cur_offset;
1125         while (rr_len != 0) {
1126           if (!BYTES_ARE_IN_FRAME(txt_offset, 1)) {
1127             /* We ran past the end of the captured data in the packet. */
1128             proto_tree_add_text(rr_tree, NullTVB, txt_offset, END_OF_FRAME,
1129                        "<String goes past end of captured data in packet>");
1130             return 0;
1131           }
1132           txt_len = pd[txt_offset];
1133           if (!BYTES_ARE_IN_FRAME(txt_offset + 1, txt_len)) {
1134             /* We ran past the end of the captured data in the packet. */
1135             proto_tree_add_text(rr_tree, NullTVB, txt_offset, END_OF_FRAME,
1136                        "<String goes past end of captured data in packet>");
1137             return 0;
1138           }
1139           proto_tree_add_text(rr_tree, NullTVB, txt_offset, 1 + txt_len,
1140            "Text: %.*s", txt_len, &pd[txt_offset + 1]);
1141           txt_offset += 1 + txt_len;
1142           rr_len -= 1 + txt_len;
1143         }
1144       }
1145     }
1146     break;
1147
1148   case T_SIG:
1149     {
1150       int rr_len = data_len;
1151       struct timeval unixtime;
1152       char signer_name[MAXDNAME];
1153       int signer_name_len;
1154
1155       if (dns_tree != NULL) {
1156         proto_item_set_text(trr,
1157                 "%s: type %s, class %s", name, type_name, class_name);
1158
1159         if (!BYTES_ARE_IN_FRAME(cur_offset, 2)) {
1160           /* We ran past the end of the captured data in the packet. */
1161           return 0;
1162         }
1163         proto_tree_add_text(rr_tree, NullTVB, cur_offset, 2, "Type covered: %s (%s)",
1164                 dns_type_name(pntohs(&pd[cur_offset])),
1165                 dns_long_type_name(pntohs(&pd[cur_offset])));
1166         cur_offset += 2;
1167         rr_len -= 2;
1168
1169         if (!BYTES_ARE_IN_FRAME(cur_offset, 1)) {
1170           /* We ran past the end of the captured data in the packet. */
1171           return 0;
1172         }
1173         proto_tree_add_text(rr_tree, NullTVB, cur_offset, 1, "Algorithm: %s",
1174                 val_to_str(pd[cur_offset], algo_vals,
1175                     "Unknown (0x%02X)"));
1176         cur_offset += 1;
1177         rr_len -= 1;
1178
1179         if (!BYTES_ARE_IN_FRAME(cur_offset, 1)) {
1180           /* We ran past the end of the captured data in the packet. */
1181           return 0;
1182         }
1183         proto_tree_add_text(rr_tree, NullTVB, cur_offset, 1, "Labels: %u",
1184                 pd[cur_offset]);
1185         cur_offset += 1;
1186         rr_len -= 1;
1187
1188         if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
1189           /* We ran past the end of the captured data in the packet. */
1190           return 0;
1191         }
1192         proto_tree_add_text(rr_tree, NullTVB, cur_offset, 4, "Original TTL: %s",
1193                 time_secs_to_str(pntohl(&pd[cur_offset])));
1194         cur_offset += 4;
1195         rr_len -= 4;
1196
1197         if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
1198           /* We ran past the end of the captured data in the packet. */
1199           return 0;
1200         }
1201         unixtime.tv_sec = pntohl(&pd[cur_offset]);
1202         unixtime.tv_usec = 0;
1203         proto_tree_add_text(rr_tree, NullTVB, cur_offset, 4, "Signature expiration: %s",
1204                 abs_time_to_str(&unixtime));
1205         cur_offset += 4;
1206         rr_len -= 4;
1207
1208         if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
1209           /* We ran past the end of the captured data in the packet. */
1210           return 0;
1211         }
1212         unixtime.tv_sec = pntohl(&pd[cur_offset]);
1213         unixtime.tv_usec = 0;
1214         proto_tree_add_text(rr_tree, NullTVB, cur_offset, 4, "Time signed: %s",
1215                 abs_time_to_str(&unixtime));
1216         cur_offset += 4;
1217         rr_len -= 4;
1218
1219         if (!BYTES_ARE_IN_FRAME(cur_offset, 2)) {
1220           /* We ran past the end of the captured data in the packet. */
1221           return 0;
1222         }
1223         proto_tree_add_text(rr_tree, NullTVB, cur_offset, 2, "Key footprint: 0x%04x",
1224                 pntohs(&pd[cur_offset]));
1225         cur_offset += 2;
1226         rr_len -= 2;
1227
1228         signer_name_len = get_dns_name(pd, cur_offset, dns_data_offset, signer_name, sizeof(signer_name));
1229         if (signer_name_len < 0) {
1230           /* We ran past the end of the captured data in the packet. */
1231           return 0;
1232         }
1233         proto_tree_add_text(rr_tree, NullTVB, cur_offset, signer_name_len,
1234                 "Signer's name: %s", signer_name);
1235         cur_offset += signer_name_len;
1236         rr_len -= signer_name_len;
1237
1238         proto_tree_add_text(rr_tree, NullTVB, cur_offset, rr_len, "Signature");
1239       }
1240     }
1241     break;
1242
1243   case T_KEY:
1244     {
1245       int rr_len = data_len;
1246       guint16 flags;
1247       proto_item *tf;
1248       proto_tree *flags_tree;
1249
1250       if (dns_tree != NULL) {
1251         proto_item_set_text(trr,
1252                 "%s: type %s, class %s", name, type_name, class_name);
1253
1254         if (!BYTES_ARE_IN_FRAME(cur_offset, 2)) {
1255           /* We ran past the end of the captured data in the packet. */
1256           return 0;
1257         }
1258         flags = pntohs(&pd[cur_offset]);
1259         tf = proto_tree_add_text(rr_tree, NullTVB, cur_offset, 2, "Flags: 0x%04X", flags);
1260         flags_tree = proto_item_add_subtree(tf, ett_t_key_flags);
1261         proto_tree_add_text(flags_tree, NullTVB, cur_offset, 2, "%s",
1262                 decode_boolean_bitfield(flags, 0x8000,
1263                   2*8, "Key prohibited for authentication",
1264                        "Key allowed for authentication"));
1265         proto_tree_add_text(flags_tree, NullTVB, cur_offset, 2, "%s",
1266                 decode_boolean_bitfield(flags, 0x4000,
1267                   2*8, "Key prohibited for confidentiality",
1268                        "Key allowed for confidentiality"));
1269         if ((flags & 0xC000) != 0xC000) {
1270           /* We have a key */
1271           proto_tree_add_text(flags_tree, NullTVB, cur_offset, 2, "%s",
1272                 decode_boolean_bitfield(flags, 0x2000,
1273                   2*8, "Key is experimental or optional",
1274                        "Key is required"));
1275           proto_tree_add_text(flags_tree, NullTVB, cur_offset, 2, "%s",
1276                 decode_boolean_bitfield(flags, 0x0400,
1277                   2*8, "Key is associated with a user",
1278                        "Key is not associated with a user"));
1279           proto_tree_add_text(flags_tree, NullTVB, cur_offset, 2, "%s",
1280                 decode_boolean_bitfield(flags, 0x0200,
1281                   2*8, "Key is associated with the named entity",
1282                        "Key is not associated with the named entity"));
1283           proto_tree_add_text(flags_tree, NullTVB, cur_offset, 2, "%s",
1284                 decode_boolean_bitfield(flags, 0x0100,
1285                   2*8, "This is the zone key for the specified zone",
1286                        "This is not a zone key"));
1287           proto_tree_add_text(flags_tree, NullTVB, cur_offset, 2, "%s",
1288                 decode_boolean_bitfield(flags, 0x0080,
1289                   2*8, "Key is valid for use with IPSEC",
1290                        "Key is not valid for use with IPSEC"));
1291           proto_tree_add_text(flags_tree, NullTVB, cur_offset, 2, "%s",
1292                 decode_boolean_bitfield(flags, 0x0040,
1293                   2*8, "Key is valid for use with MIME security multiparts",
1294                        "Key is not valid for use with MIME security multiparts"));
1295           proto_tree_add_text(flags_tree, NullTVB, cur_offset, 2, "%s",
1296                 decode_numeric_bitfield(flags, 0x000F,
1297                   2*8, "Signatory = %u"));
1298         }
1299         cur_offset += 2;
1300         rr_len -= 2;
1301
1302         if (!BYTES_ARE_IN_FRAME(cur_offset, 1)) {
1303           /* We ran past the end of the captured data in the packet. */
1304           return 0;
1305         }
1306         proto_tree_add_text(rr_tree, NullTVB, cur_offset, 1, "Protocol: %u",
1307                 pd[cur_offset]);
1308         cur_offset += 1;
1309         rr_len -= 1;
1310
1311         if (!BYTES_ARE_IN_FRAME(cur_offset, 1)) {
1312           /* We ran past the end of the captured data in the packet. */
1313           return 0;
1314         }
1315         proto_tree_add_text(rr_tree, NullTVB, cur_offset, 1, "Algorithm: %s",
1316                 val_to_str(pd[cur_offset], algo_vals,
1317                     "Unknown (0x%02X)"));
1318         cur_offset += 1;
1319                 rr_len -= 1;
1320
1321         proto_tree_add_text(rr_tree, NullTVB, cur_offset, rr_len, "Public key");
1322       }
1323     }
1324     break;
1325
1326   case T_AAAA:
1327     if (!BYTES_ARE_IN_FRAME(cur_offset, 16)) {
1328       /* We ran past the end of the captured data in the packet. */
1329       if (dns_tree != NULL) {
1330         proto_item_set_text(trr,
1331                 "%s: type %s, class %s, <Address goes past end of captured data in packet>",
1332                        name, type_name, class_name);
1333       }
1334       return 0;
1335     }
1336     if (fd != NULL) {
1337       col_append_fstr(fd, COL_INFO, " %s", 
1338                         ip6_to_str((struct e_in6_addr *)dptr));
1339     }
1340     if (dns_tree != NULL) {
1341       proto_item_set_text(trr, "%s: type %s, class %s, addr %s",
1342                      name, type_name, class_name,
1343                      ip6_to_str((struct e_in6_addr *)dptr));
1344       proto_tree_add_text(rr_tree, NullTVB, cur_offset, 16, "Addr: %s",
1345                      ip6_to_str((struct e_in6_addr *)dptr));
1346     }
1347     break;
1348
1349   case T_LOC:
1350     {
1351       if (dns_tree != NULL) {
1352         proto_item_set_text(trr,
1353                 "%s: type %s, class %s", name, type_name, class_name);
1354
1355         if (!BYTES_ARE_IN_FRAME(cur_offset, 1)) {
1356           /* We ran past the end of the captured data in the packet. */
1357           return 0;
1358         }
1359         proto_tree_add_text(rr_tree, NullTVB, cur_offset, 1, "Version: %u", pd[cur_offset]);
1360         if (pd[cur_offset] == 0) {
1361           /* Version 0, the only version RFC 1876 discusses. */
1362           cur_offset++;
1363
1364           if (!BYTES_ARE_IN_FRAME(cur_offset, 1)) {
1365             /* We ran past the end of the captured data in the packet. */
1366             return 0;
1367           }
1368           proto_tree_add_text(rr_tree, NullTVB, cur_offset, 1, "Size: %g m",
1369                                 rfc1867_size(pd[cur_offset]));
1370           cur_offset++;
1371
1372           if (!BYTES_ARE_IN_FRAME(cur_offset, 1)) {
1373             /* We ran past the end of the captured data in the packet. */
1374             return 0;
1375           }
1376           proto_tree_add_text(rr_tree, NullTVB, cur_offset, 1, "Horizontal precision: %g m",
1377                                 rfc1867_size(pd[cur_offset]));
1378           cur_offset++;
1379
1380           if (!BYTES_ARE_IN_FRAME(cur_offset, 1)) {
1381             /* We ran past the end of the captured data in the packet. */
1382             return 0;
1383           }
1384           proto_tree_add_text(rr_tree, NullTVB, cur_offset, 1, "Vertical precision: %g m",
1385                                 rfc1867_size(pd[cur_offset]));
1386           cur_offset++;
1387
1388           if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
1389             /* We ran past the end of the captured data in the packet. */
1390             return 0;
1391           }
1392           proto_tree_add_text(rr_tree, NullTVB, cur_offset, 4, "Latitude: %s",
1393                                 rfc1867_angle(&pd[cur_offset], "NS"));
1394           cur_offset += 4;
1395
1396           if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
1397             /* We ran past the end of the captured data in the packet. */
1398             return 0;
1399           }
1400           proto_tree_add_text(rr_tree, NullTVB, cur_offset, 4, "Longitude: %s",
1401                                 rfc1867_angle(&pd[cur_offset], "EW"));
1402           cur_offset += 4;
1403
1404           if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
1405             /* We ran past the end of the captured data in the packet. */
1406             return 0;
1407           }
1408           proto_tree_add_text(rr_tree, NullTVB, cur_offset, 4, "Altitude: %g m",
1409                                 (pntohl(&pd[cur_offset]) - 10000000)/100.0);
1410         } else
1411           proto_tree_add_text(rr_tree, NullTVB, cur_offset, data_len, "Data");
1412       }
1413       break;
1414     }
1415     break;
1416       
1417   case T_NXT:
1418     {
1419       int rr_len = data_len;
1420       char next_domain_name[MAXDNAME];
1421       int next_domain_name_len;
1422       int rr_type;
1423       guint8 bits;
1424       int mask;
1425       int i;
1426
1427       next_domain_name_len = get_dns_name(pd, cur_offset, dns_data_offset,
1428                         next_domain_name, sizeof(next_domain_name));
1429       if (next_domain_name_len < 0) {
1430         /* We ran past the end of the captured data in the packet. */
1431         if (dns_tree != NULL) {
1432           proto_item_set_text(trr,
1433                 "%s: type %s, class %s, <Next domain name goes past end of captured data in packet>",
1434                        name, type_name, class_name);
1435         }
1436         return 0;
1437       }
1438       if (fd != NULL)
1439         col_append_fstr(fd, COL_INFO, " %s", next_domain_name);
1440       if (dns_tree != NULL) {
1441         proto_item_set_text(trr, "%s: type %s, class %s, next domain name %s",
1442                      name, type_name, class_name, next_domain_name);
1443         proto_tree_add_text(rr_tree, NullTVB, cur_offset, next_domain_name_len,
1444                         "Next domain name: %s", next_domain_name);
1445         cur_offset += next_domain_name_len;
1446         rr_len -= next_domain_name_len;
1447         rr_type = 0;
1448         while (rr_len != 0) {
1449           if (!BYTES_ARE_IN_FRAME(cur_offset, 1)) {
1450             /* We ran past the end of the captured data in the packet. */
1451             proto_tree_add_text(rr_tree, NullTVB, cur_offset, END_OF_FRAME,
1452                        "<Bit map goes past end of captured data in packet>");
1453             return 0;
1454           }
1455           bits = pd[cur_offset];
1456           mask = 1<<7;
1457           for (i = 0; i < 8; i++) {
1458             if (bits & mask) {
1459               proto_tree_add_text(rr_tree, NullTVB, cur_offset, 1,
1460                         "RR type in bit map: %s (%s)",
1461                         dns_type_name(rr_type),
1462                         dns_long_type_name(rr_type));
1463             }
1464             mask >>= 1;
1465             rr_type++;
1466           }
1467           cur_offset += 1;
1468           rr_len -= 1;
1469         }
1470       }
1471     }
1472     break;
1473
1474   case T_OPT:
1475     if (dns_tree != NULL) {
1476       proto_item_set_text(trr, "%s: type %s", name, type_name);
1477       proto_tree_add_text(rr_tree, NullTVB, cur_offset, data_len, "Data");
1478     }
1479     break;
1480
1481   case T_WINS:
1482     {
1483       int rr_len = data_len;
1484       guint32 local_flag;
1485       guint32 lookup_timeout;
1486       guint32 cache_timeout;
1487       guint32 nservers;
1488
1489       if (dns_tree != NULL) {
1490         proto_item_set_text(trr, "%s: type %s, class %s", name, type_name,
1491                                 class_name);
1492         if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
1493           /* We ran past the end of the captured data in the packet. */
1494           return 0;
1495         }
1496         local_flag = pntohl(&pd[cur_offset]);
1497         if (dns_tree != NULL) {
1498           proto_tree_add_text(rr_tree, NullTVB, cur_offset, 4, "Local flag: %s",
1499                        local_flag ? "true" : "false");
1500         }
1501         cur_offset += 4;
1502         rr_len -= 4;
1503
1504         if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
1505           /* We ran past the end of the captured data in the packet. */
1506           return 0;
1507         }
1508         lookup_timeout = pntohl(&pd[cur_offset]);
1509         if (dns_tree != NULL) {
1510           proto_tree_add_text(rr_tree, NullTVB, cur_offset, 4, "Lookup timeout: %u seconds",
1511                        lookup_timeout);
1512         }
1513         cur_offset += 4;
1514         rr_len -= 4;
1515
1516         if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
1517           /* We ran past the end of the captured data in the packet. */
1518           return 0;
1519         }
1520         cache_timeout = pntohl(&pd[cur_offset]);
1521         if (dns_tree != NULL) {
1522           proto_tree_add_text(rr_tree, NullTVB, cur_offset, 4, "Cache timeout: %u seconds",
1523                        cache_timeout);
1524         }
1525         cur_offset += 4;
1526         rr_len -= 4;
1527
1528         if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
1529           /* We ran past the end of the captured data in the packet. */
1530           return 0;
1531         }
1532         nservers = pntohl(&pd[cur_offset]);
1533         if (dns_tree != NULL) {
1534           proto_tree_add_text(rr_tree, NullTVB, cur_offset, 4, "Number of WINS servers: %u",
1535                        nservers);
1536         }
1537         cur_offset += 4;
1538         rr_len -= 4;
1539
1540         while (rr_len != 0 && nservers != 0) {
1541           if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
1542             /* We ran past the end of the captured data in the packet. */
1543             return 0;
1544           }
1545           if (dns_tree != NULL) {
1546             proto_tree_add_text(rr_tree, NullTVB, cur_offset, 4, "WINS server address: %s",
1547                      ip_to_str((guint8 *)&pd[cur_offset]));
1548           }
1549           cur_offset += 4;
1550           rr_len -= 4;
1551           nservers--;
1552         }
1553       }
1554     }
1555     break;
1556
1557   case T_WINS_R:
1558     {
1559       int rr_len = data_len;
1560       guint32 local_flag;
1561       guint32 lookup_timeout;
1562       guint32 cache_timeout;
1563       char dname[MAXDNAME];
1564       int dname_len;
1565
1566       if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
1567         /* We ran past the end of the captured data in the packet. */
1568         if (dns_tree != NULL) {
1569           proto_item_set_text(trr,
1570                 "%s: type %s, class %s, <Local flag goes past end of captured data in packet>",
1571                        name, type_name, class_name);
1572         }
1573         return 0;
1574       }
1575       local_flag = pntohl(&pd[cur_offset]);
1576       if (dns_tree != NULL) {
1577         proto_tree_add_text(rr_tree, NullTVB, cur_offset, 4, "Local flag: %s",
1578                        local_flag ? "true" : "false");
1579       }
1580       cur_offset += 4;
1581       rr_len -= 4;
1582
1583       if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
1584         /* We ran past the end of the captured data in the packet. */
1585         if (dns_tree != NULL) {
1586           proto_item_set_text(trr,
1587                 "%s: type %s, class %s, <Lookup timeout goes past end of captured data in packet>",
1588                        name, type_name, class_name);
1589         }
1590         return 0;
1591       }
1592       lookup_timeout = pntohl(&pd[cur_offset]);
1593       if (dns_tree != NULL) {
1594         proto_tree_add_text(rr_tree, NullTVB, cur_offset, 4, "Lookup timeout: %u seconds",
1595                        lookup_timeout);
1596       }
1597       cur_offset += 4;
1598       rr_len -= 4;
1599
1600       if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
1601         /* We ran past the end of the captured data in the packet. */
1602         if (dns_tree != NULL) {
1603           proto_item_set_text(trr,
1604                 "%s: type %s, class %s, <Cache timeout goes past end of captured data in packet>",
1605                        name, type_name, class_name);
1606         }
1607         return 0;
1608       }
1609       cache_timeout = pntohl(&pd[cur_offset]);
1610       if (dns_tree != NULL) {
1611         proto_tree_add_text(rr_tree, NullTVB, cur_offset, 4, "Cache timeout: %u seconds",
1612                        cache_timeout);
1613       }
1614       cur_offset += 4;
1615       rr_len -= 4;
1616
1617       dname_len = get_dns_name(pd, cur_offset, dns_data_offset, dname, sizeof(dname));
1618       if (dname_len < 0) {
1619         /* We ran past the end of the captured data in the packet. */
1620         if (dns_tree != NULL) {
1621           proto_item_set_text(trr,
1622                 "%s: type %s, class %s, <Name result domain goes past end of captured data in packet>",
1623                        name, type_name, class_name);
1624         }
1625         return 0;
1626       }
1627       if (fd != NULL)
1628         col_append_fstr(fd, COL_INFO, " %s", dname);
1629       if (dns_tree != NULL) {
1630         proto_item_set_text(trr, "%s: type %s, class %s, name result domain %s",
1631                      name, type_name, class_name, dname);
1632         proto_tree_add_text(rr_tree, NullTVB, cur_offset, dname_len, "Name result domain: %s",
1633                         dname);
1634       }
1635     }
1636     break;
1637
1638     /* TODO: parse more record types */
1639
1640   default:
1641     if (dns_tree != NULL) {
1642       proto_item_set_text(trr,
1643                 "%s: type %s, class %s", name, type_name, class_name);
1644       proto_tree_add_text(rr_tree, NullTVB, cur_offset, data_len, "Data");
1645     }
1646     break;
1647   }
1648   
1649   dptr += data_len;
1650         
1651   return dptr - data_start;
1652 }
1653
1654 static int
1655 dissect_query_records(const u_char *pd, int cur_off, int dns_data_offset,
1656     int count, frame_data *fd, proto_tree *dns_tree)
1657 {
1658   int start_off, add_off;
1659   proto_tree *qatree = NULL;
1660   proto_item *ti = NULL;
1661   
1662   start_off = cur_off;
1663   if (dns_tree) {
1664     ti = proto_tree_add_text(dns_tree, NullTVB, start_off, 0, "Queries");
1665     qatree = proto_item_add_subtree(ti, ett_dns_qry);
1666   }
1667   while (count-- > 0) {
1668     add_off = dissect_dns_query(pd, cur_off, dns_data_offset, fd, qatree);
1669     if (add_off <= 0) {
1670       /* We ran past the end of the captured data in the packet. */
1671       break;
1672     }
1673     cur_off += add_off;
1674   }
1675   if (ti)
1676     proto_item_set_len(ti, cur_off - start_off);
1677
1678   return cur_off - start_off;
1679 }
1680
1681 static int
1682 dissect_answer_records(const u_char *pd, int cur_off, int dns_data_offset,
1683     int count, frame_data *fd, proto_tree *dns_tree, char *name)
1684 {
1685   int start_off, add_off;
1686   proto_tree *qatree = NULL;
1687   proto_item *ti = NULL;
1688   
1689   start_off = cur_off;
1690   if (dns_tree) {
1691     ti = proto_tree_add_text(dns_tree, NullTVB, start_off, 0, name);
1692     qatree = proto_item_add_subtree(ti, ett_dns_ans);
1693   }
1694   while (count-- > 0) {
1695     add_off = dissect_dns_answer(pd, cur_off, dns_data_offset, fd, qatree);
1696     if (add_off <= 0) {
1697       /* We ran past the end of the captured data in the packet. */
1698       break;
1699     }
1700     cur_off += add_off;
1701   }
1702   if (ti)
1703     proto_item_set_len(ti, cur_off - start_off);
1704
1705   return cur_off - start_off;
1706 }
1707
1708 static void
1709 dissect_dns(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
1710 {
1711   int dns_data_offset;
1712   proto_tree *dns_tree = NULL, *field_tree;
1713   proto_item *ti, *tf;
1714   guint16    id, flags, quest, ans, auth, add;
1715   char buf[128+1];
1716   int cur_off;
1717   static const value_string opcode_vals[] = {
1718                   { OPCODE_QUERY,  "Standard query"        },
1719                   { OPCODE_IQUERY, "Inverse query"         },
1720                   { OPCODE_STATUS, "Server status request" },
1721                   { 0,              NULL                   } };
1722   static const value_string rcode_vals[] = {
1723                   { RCODE_NOERROR,   "No error"        },
1724                   { RCODE_FMTERROR,  "Format error"    },
1725                   { RCODE_SERVFAIL,  "Server failure"  },
1726                   { RCODE_NAMEERROR, "Name error"      },
1727                   { RCODE_NOTIMPL,   "Not implemented" },
1728                   { RCODE_REFUSED,   "Refused"         },
1729                   { 0,               NULL              } };
1730
1731   OLD_CHECK_DISPLAY_AS_DATA(proto_dns, pd, offset, fd, tree);
1732
1733   dns_data_offset = offset;
1734
1735   if (check_col(fd, COL_PROTOCOL))
1736     col_add_str(fd, COL_PROTOCOL, "DNS");
1737
1738   if (pi.captured_len < DNS_HDRLEN) {
1739     col_add_str(fd, COL_INFO, "Short DNS packet");
1740     old_dissect_data(pd, offset, fd, tree);
1741     return;
1742   }
1743
1744   /* To do: check for errs, etc. */
1745   id    = pntohs(&pd[offset + DNS_ID]);
1746   flags = pntohs(&pd[offset + DNS_FLAGS]);
1747   quest = pntohs(&pd[offset + DNS_QUEST]);
1748   ans   = pntohs(&pd[offset + DNS_ANS]);
1749   auth  = pntohs(&pd[offset + DNS_AUTH]);
1750   add   = pntohs(&pd[offset + DNS_ADD]);
1751
1752   if (check_col(fd, COL_INFO)) {
1753     strcpy(buf, val_to_str(flags & F_OPCODE, opcode_vals, "Unknown operation (%x)"));
1754     if (flags & F_RESPONSE) {
1755       strcat(buf, " response");
1756       if ((flags & F_RCODE) != RCODE_NOERROR) {
1757         strcat(buf, ", ");
1758         strcat(buf, val_to_str(flags & F_RCODE, rcode_vals,
1759             "Unknown error (%x)"));
1760       }
1761     }
1762     col_add_str(fd, COL_INFO, buf);
1763   } else {
1764     /* Set "fd" to NULL; we pass a NULL "fd" to the query and answer
1765        dissectors, as a way of saying that they shouldn't add stuff
1766        to the COL_INFO column (a call to "check_col(fd, COL_INFO)"
1767        is more expensive than a check that a pointer isn't NULL). */
1768     fd = NULL;
1769   }
1770   
1771   if (tree) {
1772     ti = proto_tree_add_protocol_format(tree, proto_dns, NullTVB, offset, 4,
1773       "Domain Name System (%s)", (flags & F_RESPONSE) ? "response" : "query");
1774     
1775     dns_tree = proto_item_add_subtree(ti, ett_dns);
1776
1777     if (flags & F_RESPONSE)
1778       proto_tree_add_boolean_hidden(dns_tree, hf_dns_response, NullTVB, offset, 4, 1);
1779     else
1780       proto_tree_add_boolean_hidden(dns_tree, hf_dns_query, NullTVB, offset, 4, 1);
1781
1782     proto_tree_add_uint(dns_tree, hf_dns_transaction_id, NullTVB, 
1783                         offset + DNS_ID, 2, id);
1784
1785     strcpy(buf, val_to_str(flags & F_OPCODE, opcode_vals, "Unknown operation"));
1786     if (flags & F_RESPONSE) {
1787       strcat(buf, " response");
1788       strcat(buf, ", ");
1789       strcat(buf, val_to_str(flags & F_RCODE, rcode_vals,
1790             "Unknown error"));
1791     }
1792     tf = proto_tree_add_uint_format(dns_tree, hf_dns_flags, NullTVB, 
1793                                     offset + DNS_FLAGS, 2, 
1794                                     flags,
1795                                     "Flags: 0x%04x (%s)",
1796                                     flags, buf);
1797     field_tree = proto_item_add_subtree(tf, ett_dns_flags);
1798     proto_tree_add_text(field_tree, NullTVB, offset + DNS_FLAGS, 2, "%s",
1799        decode_boolean_bitfield(flags, F_RESPONSE,
1800             2*8, "Response", "Query"));
1801     proto_tree_add_text(field_tree, NullTVB, offset + DNS_FLAGS, 2, "%s",
1802        decode_enumerated_bitfield(flags, F_OPCODE,
1803             2*8, opcode_vals, "%s"));
1804     if (flags & F_RESPONSE) {
1805       proto_tree_add_text(field_tree, NullTVB, offset + DNS_FLAGS, 2, "%s",
1806          decode_boolean_bitfield(flags, F_AUTHORITATIVE,
1807               2*8,
1808               "Server is an authority for domain",
1809               "Server isn't an authority for domain"));
1810     }
1811     proto_tree_add_text(field_tree, NullTVB, offset + DNS_FLAGS, 2, "%s",
1812        decode_boolean_bitfield(flags, F_TRUNCATED,
1813             2*8,
1814             "Message is truncated",
1815             "Message is not truncated"));
1816     proto_tree_add_text(field_tree, NullTVB, offset + DNS_FLAGS, 2, "%s",
1817        decode_boolean_bitfield(flags, F_RECDESIRED,
1818             2*8,
1819             "Do query recursively",
1820             "Don't do query recursively"));
1821     if (flags & F_RESPONSE) {
1822       proto_tree_add_text(field_tree, NullTVB, offset + DNS_FLAGS, 2, "%s",
1823          decode_boolean_bitfield(flags, F_RECAVAIL,
1824               2*8,
1825               "Server can do recursive queries",
1826               "Server can't do recursive queries"));
1827       proto_tree_add_text(field_tree, NullTVB, offset + DNS_FLAGS, 2, "%s",
1828          decode_boolean_bitfield(flags, F_AUTHENTIC,
1829             2*8,
1830             "Answer/authority portion was autenticated by the server",
1831             "Answer/authority portion was not autenticated by the server"));
1832     }
1833     if ((flags & F_RESPONSE) == 0) {
1834       proto_tree_add_text(field_tree, NullTVB, offset + DNS_FLAGS, 2, "%s",
1835          decode_boolean_bitfield(flags, F_CHECKDISABLE,
1836             2*8,
1837             "Non-authenticated data is acceptable",
1838             "Non-authenticated data is unacceptable"));
1839     }
1840     if (flags & F_RESPONSE) {
1841       proto_tree_add_text(field_tree, NullTVB, offset + DNS_FLAGS, 2, "%s",
1842          decode_enumerated_bitfield(flags, F_RCODE,
1843               2*8, rcode_vals, "%s"));
1844     }
1845     proto_tree_add_uint(dns_tree, hf_dns_count_questions, NullTVB, 
1846                         offset + DNS_QUEST, 2, quest);
1847     proto_tree_add_uint(dns_tree, hf_dns_count_answers, NullTVB, 
1848                         offset + DNS_ANS, 2, ans);
1849     proto_tree_add_uint(dns_tree, hf_dns_count_auth_rr, NullTVB, 
1850                         offset + DNS_AUTH, 2, auth);
1851     proto_tree_add_uint(dns_tree, hf_dns_count_add_rr, NullTVB, 
1852                         offset + DNS_ADD, 2, add);
1853
1854   }
1855   cur_off = offset + DNS_HDRLEN;
1856
1857   if (quest > 0) {
1858     /* If this is a response, don't add information about the queries
1859        to the summary, just add information about the answers. */
1860     cur_off += dissect_query_records(pd, cur_off, dns_data_offset, quest,
1861                                         (!(flags & F_RESPONSE) ? fd : NULL),
1862                                         dns_tree);
1863   }
1864     
1865   if (ans > 0) {
1866     /* If this is a request, don't add information about the answers
1867        to the summary, just add information about the queries. */
1868     cur_off += dissect_answer_records(pd, cur_off, dns_data_offset, ans,
1869                                         ((flags & F_RESPONSE) ? fd : NULL),
1870                                         dns_tree, "Answers");
1871   }
1872     
1873   if (tree) {
1874     /* Don't add information about the authoritative name servers, or the
1875        additional records, to the summary. */
1876     if (auth > 0)
1877       cur_off += dissect_answer_records(pd, cur_off, dns_data_offset, auth,
1878           NULL, dns_tree, "Authoritative nameservers");
1879
1880     if (add > 0)
1881       cur_off += dissect_answer_records(pd, cur_off, dns_data_offset, add,
1882           NULL, dns_tree, "Additional records");
1883   }
1884 }
1885
1886 void
1887 proto_register_dns(void)
1888 {
1889   static hf_register_info hf[] = {
1890     { &hf_dns_response,
1891       { "Response",             "dns.response",  
1892         FT_BOOLEAN, BASE_NONE, NULL, 0x0,
1893         "TRUE if DNS response" }},
1894     { &hf_dns_query,
1895       { "Query",                "dns.query",  
1896         FT_BOOLEAN, BASE_NONE, NULL, 0x0,
1897         "TRUE if DNS query" }},
1898     { &hf_dns_flags,
1899       { "Flags",                "dns.flags",  
1900         FT_UINT16, BASE_HEX, NULL, 0x0,
1901         "" }},
1902     { &hf_dns_transaction_id,
1903       { "Transaction ID",       "dns.id",  
1904         FT_UINT16, BASE_HEX, NULL, 0x0,
1905         "Identification of transaction" }},
1906     { &hf_dns_count_questions,
1907       { "Questions",            "dns.count.queries",  
1908         FT_UINT16, BASE_DEC, NULL, 0x0,
1909         "Number of queries in packet" }},
1910     { &hf_dns_count_answers,
1911       { "Answer RRs",           "dns.count.answers",  
1912         FT_UINT16, BASE_DEC, NULL, 0x0,
1913         "Number of answers in packet" }},
1914     { &hf_dns_count_auth_rr,
1915       { "Authority RRs",        "dns.count.auth_rr",  
1916         FT_UINT16, BASE_DEC, NULL, 0x0,
1917         "Number of authoritative records in packet" }},
1918     { &hf_dns_count_add_rr,
1919       { "Additional RRs",       "dns.count.add_rr",  
1920         FT_UINT16, BASE_DEC, NULL, 0x0,
1921         "Number of additional records in packet" }}
1922   };
1923   static gint *ett[] = {
1924     &ett_dns,
1925     &ett_dns_qd,
1926     &ett_dns_rr,
1927     &ett_dns_qry,
1928     &ett_dns_ans,
1929     &ett_dns_flags,
1930     &ett_t_key_flags,
1931   };
1932
1933   proto_dns = proto_register_protocol("Domain Name Service", "dns");
1934   proto_register_field_array(proto_dns, hf, array_length(hf));
1935   proto_register_subtree_array(ett, array_length(ett));
1936 }
1937
1938 void
1939 proto_reg_handoff_dns(void)
1940 {
1941   old_dissector_add("udp.port", UDP_PORT_DNS, dissect_dns);
1942 }