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