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