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