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