Correctly handle the case of the root showing up as a name in a DNS
[metze/wireshark/wip.git] / packet-dns.c
1 /* packet-dns.c
2  * Routines for DNS packet disassembly
3  *
4  * $Id: packet-dns.c,v 1.18 1999/05/27 05:35:07 guy Exp $
5  *
6  * Ethereal - Network traffic analyzer
7  * By Gerald Combs <gerald@zing.org>
8  * Copyright 1998 Gerald Combs
9  *
10  * 
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  * 
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  * 
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
24  */
25
26 #ifdef HAVE_CONFIG_H
27 # include "config.h"
28 #endif
29
30 #ifdef HAVE_SYS_TYPES_H
31 # include <sys/types.h>
32 #endif
33
34 #include <stdio.h>
35 #include <string.h>
36 #include <memory.h>
37
38 #include <glib.h>
39 #include "packet.h"
40 #include "packet-dns.h"
41 #include "util.h"
42
43
44 /* DNS structs and definitions */
45
46 /* Offsets of fields in the DNS header. */
47 #define DNS_ID          0
48 #define DNS_FLAGS       2
49 #define DNS_QUEST       4
50 #define DNS_ANS 6
51 #define DNS_AUTH        8
52 #define DNS_ADD 10
53
54 /* Length of DNS header. */
55 #define DNS_HDRLEN      12
56
57 /* type values  */
58 #define T_A             1               /* host address */
59 #define T_NS            2               /* authoritative name server */
60 #define T_MD            3               /* mail destination (obsolete) */
61 #define T_MF            4               /* mail forwarder (obsolete) */
62 #define T_CNAME         5               /* canonical name */
63 #define T_SOA           6               /* start of authority zone */
64 #define T_MB            7               /* mailbox domain name (experimental) */
65 #define T_MG            8               /* mail group member (experimental) */
66 #define T_MR            9               /* mail rename domain name (experimental) */
67 #define T_NULL          10              /* null RR (experimental) */
68 #define T_WKS           11              /* well known service */
69 #define T_PTR           12              /* domain name pointer */
70 #define T_HINFO         13              /* host information */
71 #define T_MINFO         14              /* mailbox or mail list information */
72 #define T_MX            15              /* mail routing information */
73 #define T_TXT           16              /* text strings */
74 #define T_RP            17              /* responsible person (RFC 1183) */
75 #define T_AFSDB         18              /* AFS data base location (RFC 1183) */
76 #define T_X25           19              /* X.25 address (RFC 1183) */
77 #define T_ISDN          20              /* ISDN address (RFC 1183) */
78 #define T_RT            21              /* route-through (RFC 1183) */
79 #define T_NSAP          22              /* OSI NSAP (RFC 1706) */
80 #define T_NSAP_PTR      23              /* PTR equivalent for OSI NSAP (RFC 1348 - obsolete) */
81 #define T_SIG           24              /* digital signature (RFC 2065) */
82 #define T_KEY           25              /* public key (RFC 2065) */
83 #define T_PX            26              /* pointer to X.400/RFC822 mapping info (RFC 1664) */
84 #define T_GPOS          27              /* geographical position (RFC 1712) */
85 #define T_AAAA          28              /* IPv6 address (RFC 1886) */
86 #define T_LOC           29              /* geographical location (RFC 1876) */
87 #define T_NXT           30              /* "next" name (RFC 2065) */
88 #define T_EID           31              /* ??? (Nimrod?) */
89 #define T_NIMLOC        32              /* ??? (Nimrod?) */
90 #define T_SRV           33              /* service location (RFC 2052) */
91 #define T_ATMA          34              /* ??? */
92 #define T_NAPTR         35              /* naming authority pointer (RFC 2168) */
93
94 /* Bit fields in the flags */
95 #define F_RESPONSE      (1<<15)         /* packet is response */
96 #define F_OPCODE        (0xF<<11)       /* query opcode */
97 #define F_AUTHORITATIVE (1<<10)         /* response is authoritative */
98 #define F_TRUNCATED     (1<<9)          /* response is truncated */
99 #define F_RECDESIRED    (1<<8)          /* recursion desired */
100 #define F_RECAVAIL      (1<<7)          /* recursion available */
101 #define F_RCODE         (0xF<<0)        /* reply code */
102
103 /* Opcodes */
104 #define OPCODE_QUERY    (0<<11)         /* standard query */
105 #define OPCODE_IQUERY   (1<<11)         /* inverse query */
106 #define OPCODE_STATUS   (2<<11)         /* server status request */
107
108 /* Reply codes */
109 #define RCODE_NOERROR   (0<<0)
110 #define RCODE_FMTERROR  (1<<0)
111 #define RCODE_SERVFAIL  (2<<0)
112 #define RCODE_NAMEERROR (3<<0)
113 #define RCODE_NOTIMPL   (4<<0)
114 #define RCODE_REFUSED   (5<<0)
115
116 /* See RFC 1035 for all RR types for which no RFC is listed. */
117 static char *
118 dns_type_name (int type)
119 {
120   char *type_names[36] = {
121     "unused",
122     "A",
123     "NS",
124     "MD",
125     "MF",
126     "CNAME",
127     "SOA",
128     "MB",
129     "MG",
130     "MR",
131     "NULL",
132     "WKS",
133     "PTR",
134     "HINFO",
135     "MINFO",
136     "MX",
137     "TXT",
138     "RP",                               /* RFC 1183 */
139     "AFSDB",                            /* RFC 1183 */
140     "X25",                              /* RFC 1183 */
141     "ISDN",                             /* RFC 1183 */
142     "RT",                               /* RFC 1183 */
143     "NSAP",                             /* RFC 1706 */
144     "NSAP-PTR",                         /* RFC 1348 */
145     "SIG",                              /* RFC 2065 */
146     "KEY",                              /* RFC 2065 */
147     "PX",                               /* RFC 1664 */
148     "GPOS",                             /* RFC 1712 */
149     "AAAA",                             /* RFC 1886 */
150     "LOC",                              /* RFC 1876 */
151     "NXT",                              /* RFC 2065 */
152     "EID",
153     "NIMLOC",
154     "SRV",                              /* RFC 2052 */
155     "ATMA",
156     "NAPTR"                             /* RFC 2168 */
157   };
158   
159   if (type <= 35)
160     return type_names[type];
161   
162   /* special cases */
163   switch (type) 
164     {
165       /* non standard  */
166     case 100:
167       return "UINFO";
168     case 101:
169       return "UID";
170     case 102:
171       return "GID";
172     case 103:
173       return "UNSPEC";
174       
175       /* queries  */
176     case 251:
177       return "IXFR";    /* RFC 1995 */
178     case 252:
179       return "AXFR";
180     case 253:
181       return "MAILB";
182     case 254:
183       return "MAILA";
184     case 255:
185       return "ANY";
186     }
187   
188   return "unknown";
189 }
190
191
192 static char *
193 dns_long_type_name (int type)
194 {
195   char *type_names[36] = {
196     "unused",
197     "Host address",
198     "Authoritative name server",        
199     "Mail destination",
200     "Mail forwarder",
201     "Canonical name for an alias",
202     "Start of zone of authority",
203     "Mailbox domain name",
204     "Mail group member",
205     "Mail rename domain name",
206     "Null resource record",
207     "Well-known service description",
208     "Domain name pointer",
209     "Host information",
210     "Mailbox or mail list information",
211     "Mail exchange",
212     "Text strings",
213     "Responsible person",               /* RFC 1183 */
214     "AFS data base location",           /* RFC 1183 */
215     "X.25 address",                     /* RFC 1183 */
216     "ISDN number",                      /* RFC 1183 */
217     "Route through",                    /* RFC 1183 */
218     "OSI NSAP",                         /* RFC 1706 */
219     "OSI NSAP name pointer",            /* RFC 1348 */
220     "Signature",                        /* RFC 2065 */
221     "Public key",                       /* RFC 2065 */
222     "Pointer to X.400/RFC822 mapping info", /* RFC 1664 */
223     "Geographical position",            /* RFC 1712 */
224     "IPv6 address",                     /* RFC 1886 */
225     "Location",                         /* RFC 1876 */
226     "Next",                             /* RFC 2065 */
227     "EID",
228     "NIMLOC",
229     "Service location",                 /* RFC 2052 */
230     "ATMA",
231     "Naming authority pointer"          /* RFC 2168 */
232   };
233   static char unkbuf[7+1+2+1+4+1+1+10+1+1];     /* "Unknown RR type (%d)" */
234   
235   if (type <= 35)
236     return type_names[type];
237   
238   /* special cases */
239   switch (type) 
240     {
241       /* non standard  */
242     case 100:
243       return "UINFO";
244     case 101:
245       return "UID";
246     case 102:
247       return "GID";
248     case 103:
249       return "UNSPEC";
250       
251       /* queries  */
252     case 251:
253       return "Request for incremental zone transfer";   /* RFC 1995 */
254     case 252:
255       return "Request for full zone transfer";
256     case 253:
257       return "Request for mailbox-related records";
258     case 254:
259       return "Request for mail agent resource records";
260     case 255:
261       return "Request for all records";
262     }
263   
264   sprintf(unkbuf, "Unknown RR type (%d)", type);
265   return unkbuf;
266 }
267
268
269 char *
270 dns_class_name(int class)
271 {
272   char *class_name;
273   
274   switch (class) {
275   case 1:
276     class_name = "inet";
277     break;
278   case 3:
279     class_name = "chaos";
280     break;
281   case 4:
282     class_name = "hesiod";
283     break;
284   default:
285     class_name = "unknown";
286   }
287
288   return class_name;
289 }
290
291 int
292 get_dns_name(const u_char *dns_data_ptr, const u_char *dptr, char *name,
293     int maxname)
294 {
295   const u_char *dp = dptr;
296   char *np = name;
297   int len = -1;
298   u_int component_len;
299   int offset;
300
301   maxname--;    /* reserve space for the trailing '\0' */
302   while ((component_len = *dp++) != 0) {
303     switch (component_len & 0xc0) {
304
305     case 0x00:
306       /* Label */
307       if (np != name) {
308         /* Not the first component - put in a '.'. */
309         if (maxname > 0) {
310           *np++ = '.';
311           maxname--;
312         }
313       }
314       while (component_len > 0) {
315         if (maxname > 0) {
316           *np++ = *dp;
317           maxname--;
318         }
319         component_len--;
320         dp++;
321       }
322       break;
323
324     case 0x40:
325     case 0x80:
326       goto error;       /* error */
327
328     case 0xc0:
329       /* Pointer. */
330       /* XXX - check to make sure we aren't looping, by keeping track
331          of how many characters are in the DNS packet, and of how many
332          characters we've looked at, and quitting if the latter
333          becomes bigger than the former. */
334       offset = ((component_len & ~0xc0) << 8) | *dp++;
335       /* If "len" is negative, we are still working on the original name,
336          not something pointed to by a pointer, and so we should set "len"
337          to the length of the original name. */
338       if (len < 0)
339         len = dp - dptr;
340       dp = dns_data_ptr + offset;
341       break;    /* now continue processing from there */
342     }
343   }
344         
345 error:
346   *np = '\0';
347   /* If "len" is negative, we haven't seen a pointer, and thus haven't
348      set the length, so set it. */
349   if (len < 0)
350     len = dp - dptr;
351   /* Zero-length name means "root server" */
352   if (*name == '\0')
353     strcpy(name, "<Root>");
354   return len;
355 }
356
357
358 static int
359 get_dns_name_type_class (const u_char *dns_data_ptr,
360                          const u_char *dptr,
361                          char *name_ret,
362                          int *name_len_ret,
363                          int *type_ret,
364                          int *class_ret)
365 {
366   int len;
367   int name_len;
368   int type;
369   int class;
370   char name[MAXDNAME];
371   const u_char *dptr_save;
372
373   name_len = get_dns_name(dns_data_ptr, dptr, name, sizeof(name));
374   dptr_save = dptr;
375   dptr += name_len;
376   
377   type = pntohs(dptr);
378   dptr += 2;
379   class = pntohs(dptr);
380   dptr += 2;
381
382   strcpy (name_ret, name);
383   *type_ret = type;
384   *class_ret = class;
385   *name_len_ret = name_len;
386
387   len = dptr - dptr_save;
388   return len;
389 }
390
391
392 static int
393 dissect_dns_query(const u_char *dns_data_ptr, const u_char *pd, int offset,
394   proto_tree *dns_tree)
395 {
396   int len;
397   char name[MAXDNAME];
398   int name_len;
399   int type;
400   int class;
401   char *class_name;
402   char *type_name;
403   char *long_type_name;
404   const u_char *dptr;
405   const u_char *data_start;
406   proto_tree *q_tree;
407   proto_item *tq;
408
409   data_start = dptr = pd + offset;
410
411   len = get_dns_name_type_class(dns_data_ptr, dptr, name, &name_len,
412     &type, &class);
413   dptr += len;
414
415   type_name = dns_type_name(type);
416   class_name = dns_class_name(class);
417   long_type_name = dns_long_type_name(type);
418
419   tq = proto_tree_add_item(dns_tree, offset, len, "%s: type %s, class %s", 
420                    name, type_name, class_name);
421   q_tree = proto_tree_new();
422   proto_item_add_subtree(tq, q_tree, ETT_DNS_QD);
423
424   proto_tree_add_item(q_tree, offset, name_len, "Name: %s", name);
425   offset += name_len;
426
427   proto_tree_add_item(q_tree, offset, 2, "Type: %s", long_type_name);
428   offset += 2;
429
430   proto_tree_add_item(q_tree, offset, 2, "Class: %s", class_name);
431   offset += 2;
432   
433   return dptr - data_start;
434 }
435
436
437 proto_tree *
438 add_rr_to_tree(proto_item *trr, int rr_type, int offset, const char *name,
439   int namelen, const char *type_name, const char *class_name, u_int ttl,
440   u_short data_len)
441 {
442   proto_tree *rr_tree;
443
444   rr_tree = proto_tree_new();
445   proto_item_add_subtree(trr, rr_tree, rr_type);
446   proto_tree_add_item(rr_tree, offset, namelen, "Name: %s", name);
447   offset += namelen;
448   proto_tree_add_item(rr_tree, offset, 2, "Type: %s", type_name);
449   offset += 2;
450   proto_tree_add_item(rr_tree, offset, 2, "Class: %s", class_name);
451   offset += 2;
452   proto_tree_add_item(rr_tree, offset, 4, "Time to live: %s",
453                                                 time_secs_to_str(ttl));
454   offset += 4;
455   proto_tree_add_item(rr_tree, offset, 2, "Data length: %u", data_len);
456   return rr_tree;
457 }
458
459 static int
460 dissect_dns_answer(const u_char *dns_data_ptr, const u_char *pd, int offset,
461   proto_tree *dns_tree)
462 {
463   int len;
464   char name[MAXDNAME];
465   int name_len;
466   int type;
467   int class;
468   char *class_name;
469   char *type_name;
470   char *long_type_name;
471   const u_char *dptr;
472   const u_char *data_start;
473   u_int ttl;
474   u_short data_len;
475   proto_tree *rr_tree;
476   proto_item *trr;
477   const u_char *rrptr;
478
479   data_start = dptr = pd + offset;
480
481   len = get_dns_name_type_class(dns_data_ptr, dptr, name, &name_len,
482     &type, &class);
483   dptr += len;
484
485   type_name = dns_type_name(type);
486   class_name = dns_class_name(class);
487   long_type_name = dns_long_type_name(type);
488
489   ttl = pntohl(dptr);
490   dptr += 4;
491
492   data_len = pntohs(dptr);
493   dptr += 2;
494
495   switch (type) {
496   case T_A:
497     trr = proto_tree_add_item(dns_tree, offset, (dptr - data_start) + data_len,
498                      "%s: type %s, class %s, addr %s",
499                      name, type_name, class_name,
500                      ip_to_str((guint8 *)dptr));
501     rr_tree = add_rr_to_tree(trr, ETT_DNS_RR, offset, name, name_len,
502                      long_type_name, class_name, ttl, data_len);
503     offset += (dptr - data_start);
504     proto_tree_add_item(rr_tree, offset, 4, "Addr: %s",
505                      ip_to_str((guint8 *)dptr));
506     break;
507
508   case T_NS:
509     {
510       char ns_name[MAXDNAME];
511       int ns_name_len;
512       
513       ns_name_len = get_dns_name(dns_data_ptr, dptr, ns_name, sizeof(ns_name));
514       trr = proto_tree_add_item(dns_tree, offset, (dptr - data_start) + data_len,
515                        "%s: type %s, class %s, ns %s",
516                        name, type_name, class_name, ns_name);
517       rr_tree = add_rr_to_tree(trr, ETT_DNS_RR, offset, name, name_len,
518                        long_type_name, class_name, ttl, data_len);
519       offset += (dptr - data_start);
520       proto_tree_add_item(rr_tree, offset, ns_name_len, "Name server: %s", ns_name);
521     }
522     break;
523
524   case T_CNAME:
525     {
526       char cname[MAXDNAME];
527       int cname_len;
528       
529       cname_len = get_dns_name(dns_data_ptr, dptr, cname, sizeof(cname));
530       trr = proto_tree_add_item(dns_tree, offset, (dptr - data_start) + data_len,
531                      "%s: type %s, class %s, cname %s",
532                      name, type_name, class_name, cname);
533       rr_tree = add_rr_to_tree(trr, ETT_DNS_RR, offset, name, name_len,
534                        long_type_name, class_name, ttl, data_len);
535       offset += (dptr - data_start);
536       proto_tree_add_item(rr_tree, offset, cname_len, "Primary name: %s", cname);
537     }
538     break;
539
540   case T_SOA:
541     {
542       char mname[MAXDNAME];
543       int mname_len;
544       char rname[MAXDNAME];
545       int rname_len;
546       guint32 serial;
547       guint32 refresh;
548       guint32 retry;
549       guint32 expire;
550       guint32 minimum;
551
552       rrptr = dptr;
553       mname_len = get_dns_name(dns_data_ptr, rrptr, mname, sizeof(mname));
554       rrptr += mname_len;
555       trr = proto_tree_add_item(dns_tree, offset, (dptr - data_start) + data_len,
556                      "%s: type %s, class %s, mname %s",
557                      name, type_name, class_name, mname);
558       rr_tree = add_rr_to_tree(trr, ETT_DNS_RR, offset, name, name_len,
559                        long_type_name, class_name, ttl, data_len);
560       offset += (dptr - data_start);
561       proto_tree_add_item(rr_tree, offset, mname_len, "Primary name server: %s",
562                        mname);
563       offset += mname_len;
564       rname_len = get_dns_name(dns_data_ptr, rrptr, rname, sizeof(rname));
565       proto_tree_add_item(rr_tree, offset, rname_len, "Responsible authority's mailbox: %s",
566                        rname);
567       rrptr += rname_len;
568       offset += rname_len;
569       serial = pntohl(rrptr);
570       proto_tree_add_item(rr_tree, offset, 4, "Serial number: %u",
571                        serial);
572       rrptr += 4;
573       offset += 4;
574       refresh = pntohl(rrptr);
575       proto_tree_add_item(rr_tree, offset, 4, "Refresh interval: %s",
576                        time_secs_to_str(refresh));
577       rrptr += 4;
578       offset += 4;
579       retry = pntohl(rrptr);
580       proto_tree_add_item(rr_tree, offset, 4, "Retry interval: %s",
581                        time_secs_to_str(retry));
582       rrptr += 4;
583       offset += 4;
584       expire = pntohl(rrptr);
585       proto_tree_add_item(rr_tree, offset, 4, "Expiration limit: %s",
586                        time_secs_to_str(expire));
587       rrptr += 4;
588       offset += 4;
589       minimum = pntohl(rrptr);
590       proto_tree_add_item(rr_tree, offset, 4, "Minimum TTL: %s",
591                        time_secs_to_str(minimum));
592     }
593     break;
594
595   case T_PTR:
596     {
597       char pname[MAXDNAME];
598       int pname_len;
599       
600       pname_len = get_dns_name(dns_data_ptr, dptr, pname, sizeof(pname));
601       trr = proto_tree_add_item(dns_tree, offset, (dptr - data_start) + data_len,
602                      "%s: type %s, class %s, ptr %s",
603                      name, type_name, class_name, pname);
604       rr_tree = add_rr_to_tree(trr, ETT_DNS_RR, offset, name, name_len,
605                        long_type_name, class_name, ttl, data_len);
606       offset += (dptr - data_start);
607       proto_tree_add_item(rr_tree, offset, pname_len, "Domain name: %s", pname);
608       break;
609     }
610     break;
611       
612     /* TODO: parse more record types */
613
614   default:
615     trr = proto_tree_add_item(dns_tree, offset, (dptr - data_start) + data_len,
616                      "%s: type %s, class %s",
617                      name, type_name, class_name);
618     rr_tree = add_rr_to_tree(trr, ETT_DNS_RR, offset, name, name_len,
619                        long_type_name, class_name, ttl, data_len);
620     offset += (dptr - data_start);
621     proto_tree_add_item(rr_tree, offset, data_len, "Data");
622   }
623   
624   dptr += data_len;
625         
626   return dptr - data_start;
627 }
628
629 static int
630 dissect_query_records(const u_char *dns_data_ptr, int count, const u_char *pd, 
631                       int cur_off, proto_tree *dns_tree)
632 {
633   int start_off;
634   proto_tree *qatree;
635   proto_item *ti;
636   
637   start_off = cur_off;
638   ti = proto_tree_add_item(dns_tree, start_off, 0, "Queries");
639   qatree = proto_tree_new();
640   proto_item_add_subtree(ti, qatree, ETT_DNS_QRY);
641   while (count-- > 0)
642     cur_off += dissect_dns_query(dns_data_ptr, pd, cur_off, qatree);
643   proto_item_set_len(ti, cur_off - start_off);
644
645   return cur_off - start_off;
646 }
647
648
649
650 static int
651 dissect_answer_records(const u_char *dns_data_ptr, int count,
652                        const u_char *pd, int cur_off, proto_tree *dns_tree,
653                        char *name)
654 {
655   int start_off;
656   proto_tree *qatree;
657   proto_item *ti;
658   
659   start_off = cur_off;
660   ti = proto_tree_add_item(dns_tree, start_off, 0, name);
661   qatree = proto_tree_new();
662   proto_item_add_subtree(ti, qatree, ETT_DNS_ANS);
663   while (count-- > 0)
664     cur_off += dissect_dns_answer(dns_data_ptr, pd, cur_off, qatree);
665   proto_item_set_len(ti, cur_off - start_off);
666
667   return cur_off - start_off;
668 }
669
670
671 void
672 dissect_dns(const u_char *pd, int offset, frame_data *fd, proto_tree *tree) {
673   const u_char *dns_data_ptr;
674   proto_tree *dns_tree, *field_tree;
675   proto_item *ti, *tf;
676   guint16    id, flags, quest, ans, auth, add;
677   char buf[128+1];
678   int cur_off;
679   static const value_string opcode_vals[] = {
680                   { OPCODE_QUERY,  "Standard query"        },
681                   { OPCODE_IQUERY, "Inverse query"         },
682                   { OPCODE_STATUS, "Server status request" },
683                   { 0,              NULL                   } };
684   static const value_string rcode_vals[] = {
685                   { RCODE_NOERROR,   "No error"        },
686                   { RCODE_FMTERROR,  "Format error"    },
687                   { RCODE_SERVFAIL,  "Server failure"  },
688                   { RCODE_NAMEERROR, "Name error"      },
689                   { RCODE_NOTIMPL,   "Not implemented" },
690                   { RCODE_REFUSED,   "Refused"         },
691                   { 0,               NULL              } };
692
693   dns_data_ptr = &pd[offset];
694
695   /* To do: check for runts, errs, etc. */
696   id    = pntohs(&pd[offset + DNS_ID]);
697   flags = pntohs(&pd[offset + DNS_FLAGS]);
698   quest = pntohs(&pd[offset + DNS_QUEST]);
699   ans   = pntohs(&pd[offset + DNS_ANS]);
700   auth  = pntohs(&pd[offset + DNS_AUTH]);
701   add   = pntohs(&pd[offset + DNS_ADD]);
702   
703   if (check_col(fd, COL_PROTOCOL))
704     col_add_str(fd, COL_PROTOCOL, "DNS (UDP)");
705   if (check_col(fd, COL_INFO)) {
706     col_add_fstr(fd, COL_INFO, "%s%s",
707                 val_to_str(flags & F_OPCODE, opcode_vals,
708                            "Unknown operation (%x)"),
709                 (flags & F_RESPONSE) ? " response" : "");
710   }
711   
712   if (tree) {
713     ti = proto_tree_add_item(tree, offset, 4,
714                           (flags & F_RESPONSE) ? "DNS response" : "DNS query");
715     
716     dns_tree = proto_tree_new();
717     proto_item_add_subtree(ti, dns_tree, ETT_DNS);
718     
719     proto_tree_add_item(dns_tree, offset + DNS_ID, 2, "Transaction ID: 0x%04x",
720                         id);
721
722     strcpy(buf, val_to_str(flags & F_OPCODE, opcode_vals, "Unknown operation"));
723     if (flags & F_RESPONSE) {
724       strcat(buf, " response");
725       strcat(buf, ", ");
726       strcat(buf, val_to_str(flags & F_RCODE, rcode_vals,
727             "Unknown error"));
728     }
729     tf = proto_tree_add_item(dns_tree, offset + DNS_FLAGS, 2, "Flags: 0x%04x (%s)",
730                           flags, buf);
731     field_tree = proto_tree_new();
732     proto_item_add_subtree(tf, field_tree, ETT_DNS_FLAGS);
733     proto_tree_add_item(field_tree, offset + DNS_FLAGS, 2, "%s",
734        decode_boolean_bitfield(flags, F_RESPONSE,
735             2*8, "Response", "Query"));
736     proto_tree_add_item(field_tree, offset + DNS_FLAGS, 2, "%s",
737        decode_enumerated_bitfield(flags, F_OPCODE,
738             2*8, opcode_vals, "%s"));
739     if (flags & F_RESPONSE) {
740       proto_tree_add_item(field_tree, offset + DNS_FLAGS, 2, "%s",
741          decode_boolean_bitfield(flags, F_AUTHORITATIVE,
742               2*8,
743               "Server is an authority for domain",
744               "Server isn't an authority for domain"));
745     }
746     proto_tree_add_item(field_tree, offset + DNS_FLAGS, 2, "%s",
747        decode_boolean_bitfield(flags, F_TRUNCATED,
748             2*8,
749             "Message is truncated",
750             "Message is not truncated"));
751     proto_tree_add_item(field_tree, offset + DNS_FLAGS, 2, "%s",
752        decode_boolean_bitfield(flags, F_RECDESIRED,
753             2*8,
754             "Do query recursively",
755             "Don't do query recursively"));
756     if (flags & F_RESPONSE) {
757       proto_tree_add_item(field_tree, offset + DNS_FLAGS, 2, "%s",
758          decode_boolean_bitfield(flags, F_RECAVAIL,
759               2*8,
760               "Server can do recursive queries",
761               "Server can't do recursive queries"));
762       proto_tree_add_item(field_tree, offset + DNS_FLAGS, 2, "%s",
763          decode_enumerated_bitfield(flags, F_RCODE,
764               2*8, rcode_vals, "%s"));
765     }
766     proto_tree_add_item(dns_tree, offset + DNS_QUEST, 2, "Questions: %d", quest);
767     proto_tree_add_item(dns_tree, offset + DNS_ANS, 2, "Answer RRs: %d", ans);
768     proto_tree_add_item(dns_tree, offset + DNS_AUTH, 2, "Authority RRs: %d", auth);
769     proto_tree_add_item(dns_tree, offset + DNS_ADD, 2, "Additional RRs: %d", add);
770
771     cur_off = offset + DNS_HDRLEN;
772     
773     if (quest > 0)
774       cur_off += dissect_query_records(dns_data_ptr, quest, pd, cur_off,
775                                         dns_tree);
776     
777     if (ans > 0)
778       cur_off += dissect_answer_records(dns_data_ptr, ans, pd, cur_off,
779           dns_tree, "Answers");
780     
781     if (auth > 0)
782       cur_off += dissect_answer_records(dns_data_ptr, auth, pd, cur_off,
783           dns_tree, "Authoritative nameservers");
784
785     if (add > 0)
786       cur_off += dissect_answer_records(dns_data_ptr, add, pd, cur_off,
787           dns_tree, "Additional records");
788   }
789 }