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