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