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