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