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