A DNS or NBNS name may contain pointers to other names in the packet; if
[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.24 1999/10/07 09:21:36 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 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 *pd, int offset, int dns_data_offset,
294     char *name, int maxname)
295 {
296   const u_char *dp = pd + offset;
297   const u_char *dptr = dp;
298   char *np = name;
299   int len = -1;
300   u_int component_len;
301
302   maxname--;    /* reserve space for the trailing '\0' */
303   for (;;) {
304     if (!BYTES_ARE_IN_FRAME(offset, 1))
305       goto overflow;
306     component_len = *dp++;
307     offset++;
308     if (component_len == 0)
309       break;
310     switch (component_len & 0xc0) {
311
312     case 0x00:
313       /* Label */
314       if (np != name) {
315         /* Not the first component - put in a '.'. */
316         if (maxname > 0) {
317           *np++ = '.';
318           maxname--;
319         }
320       }
321       if (!BYTES_ARE_IN_FRAME(offset, component_len))
322         goto overflow;
323       while (component_len > 0) {
324         if (maxname > 0) {
325           *np++ = *dp;
326           maxname--;
327         }
328         component_len--;
329         dp++;
330         offset++;
331       }
332       break;
333
334     case 0x40:
335     case 0x80:
336       goto error;       /* error */
337
338     case 0xc0:
339       /* Pointer. */
340       /* XXX - check to make sure we aren't looping, by keeping track
341          of how many characters are in the DNS packet, and of how many
342          characters we've looked at, and quitting if the latter
343          becomes bigger than the former. */
344       if (!BYTES_ARE_IN_FRAME(offset, 1))
345         goto overflow;
346       offset = dns_data_offset + (((component_len & ~0xc0) << 8) | (*dp++));
347       /* If "len" is negative, we are still working on the original name,
348          not something pointed to by a pointer, and so we should set "len"
349          to the length of the original name. */
350       if (len < 0)
351         len = dp - dptr;
352       dp = pd + offset;
353       break;    /* now continue processing from there */
354     }
355   }
356         
357 error:
358   *np = '\0';
359   /* If "len" is negative, we haven't seen a pointer, and thus haven't
360      set the length, so set it. */
361   if (len < 0)
362     len = dp - dptr;
363   /* Zero-length name means "root server" */
364   if (*name == '\0')
365     strcpy(name, "<Root>");
366   return len;
367
368 overflow:
369   /* We ran past the end of the captured data in the packet. */
370   strcpy(name, "<Name goes past end of captured data in packet>");
371   /* If "len" is negative, we haven't seen a pointer, and thus haven't
372      set the length, so set it. */
373   if (len < 0)
374     len = dp - dptr;
375   return len;
376 }
377
378
379 static int
380 get_dns_name_type_class(const u_char *pd, int offset, int dns_data_offset,
381     char *name_ret, int *name_len_ret, int *type_ret, int *class_ret)
382 {
383   int len;
384   int name_len;
385   int type;
386   int class;
387   char name[MAXDNAME];
388   int start_offset = offset;
389
390   name_len = get_dns_name(pd, offset, dns_data_offset, name, sizeof(name));
391   offset += name_len;
392   
393   if (!BYTES_ARE_IN_FRAME(offset, 2)) {
394     /* We ran past the end of the captured data in the packet. */
395     return -1;
396   }
397   type = pntohs(&pd[offset]);
398   offset += 2;
399
400   if (!BYTES_ARE_IN_FRAME(offset, 2)) {
401     /* We ran past the end of the captured data in the packet. */
402     return -1;
403   }
404   class = pntohs(&pd[offset]);
405   offset += 2;
406
407   strcpy (name_ret, name);
408   *type_ret = type;
409   *class_ret = class;
410   *name_len_ret = name_len;
411
412   len = offset - start_offset;
413   return len;
414 }
415
416 static double
417 rfc1867_size(u_char val)
418 {
419   double size;
420   guint32 exponent;
421
422   size = (val & 0xF0) >> 4;
423   exponent = (val & 0x0F);
424   while (exponent != 0) {
425     size *= 10;
426     exponent--;
427   }
428   return size / 100;    /* return size in meters, not cm */
429 }
430
431 static char *
432 rfc1867_angle(const u_char *dptr, const char *nsew)
433 {
434   guint32 angle;
435   char direction;
436   guint32 degrees, minutes, secs, tsecs;
437   static char buf[10+1+3+1 + 2+1+3+1 + 2+1+3+1+3+1 + 1 + 1];
438
439   angle = pntohl(dptr);
440
441   if (angle < 0x80000000U) {
442     angle = 0x80000000U - angle;
443     direction = nsew[1];
444   } else {
445     angle = angle - 0x80000000U;
446     direction = nsew[0];
447   }
448   tsecs = angle % 1000;
449   angle = angle / 1000;
450   secs = angle % 60;
451   angle = angle / 60;
452   minutes = angle % 60;
453   degrees = angle / 60;
454   sprintf(buf, "%u deg %u min %u.%03u sec %c", degrees, minutes, secs,
455                 tsecs, direction);
456   return buf;
457 }
458
459 static int
460 dissect_dns_query(const u_char *pd, int offset, int dns_data_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   proto_tree *q_tree;
474   proto_item *tq;
475
476   data_start = dptr = pd + offset;
477
478   len = get_dns_name_type_class(pd, offset, dns_data_offset, name, &name_len,
479     &type, &class);
480   if (len < 0) {
481     /* We ran past the end of the data in the packet. */
482     return 0;
483   }
484   dptr += len;
485
486   type_name = dns_type_name(type);
487   class_name = dns_class_name(class);
488   long_type_name = dns_long_type_name(type);
489
490   tq = proto_tree_add_text(dns_tree, offset, len, "%s: type %s, class %s", 
491                    name, type_name, class_name);
492   q_tree = proto_item_add_subtree(tq, ETT_DNS_QD);
493
494   proto_tree_add_text(q_tree, offset, name_len, "Name: %s", name);
495   offset += name_len;
496
497   proto_tree_add_text(q_tree, offset, 2, "Type: %s", long_type_name);
498   offset += 2;
499
500   proto_tree_add_text(q_tree, offset, 2, "Class: %s", class_name);
501   offset += 2;
502   
503   return dptr - data_start;
504 }
505
506
507 proto_tree *
508 add_rr_to_tree(proto_item *trr, int rr_type, int offset, const char *name,
509   int namelen, const char *type_name, const char *class_name, u_int ttl,
510   u_short data_len)
511 {
512   proto_tree *rr_tree;
513
514   rr_tree = proto_item_add_subtree(trr, rr_type);
515   proto_tree_add_text(rr_tree, offset, namelen, "Name: %s", name);
516   offset += namelen;
517   proto_tree_add_text(rr_tree, offset, 2, "Type: %s", type_name);
518   offset += 2;
519   proto_tree_add_text(rr_tree, offset, 2, "Class: %s", class_name);
520   offset += 2;
521   proto_tree_add_text(rr_tree, offset, 4, "Time to live: %s",
522                                                 time_secs_to_str(ttl));
523   offset += 4;
524   proto_tree_add_text(rr_tree, offset, 2, "Data length: %u", data_len);
525   return rr_tree;
526 }
527
528 static int
529 dissect_dns_answer(const u_char *pd, int offset, int dns_data_offset,
530   proto_tree *dns_tree)
531 {
532   int len;
533   char name[MAXDNAME];
534   int name_len;
535   int type;
536   int class;
537   char *class_name;
538   char *type_name;
539   char *long_type_name;
540   const u_char *dptr;
541   int cur_offset;
542   const u_char *data_start;
543   u_int ttl;
544   u_short data_len;
545   proto_tree *rr_tree;
546   proto_item *trr;
547
548   data_start = dptr = pd + offset;
549   cur_offset = offset;
550
551   len = get_dns_name_type_class(pd, offset, dns_data_offset, name, &name_len,
552     &type, &class);
553   if (len < 0) {
554     /* We ran past the end of the captured data in the packet. */
555     return 0;
556   }
557   dptr += len;
558   cur_offset += len;
559
560   type_name = dns_type_name(type);
561   class_name = dns_class_name(class);
562   long_type_name = dns_long_type_name(type);
563
564   if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
565     /* We ran past the end of the captured data in the packet. */
566     return 0;
567   }
568   ttl = pntohl(dptr);
569   dptr += 4;
570   cur_offset += 4;
571
572   if (!BYTES_ARE_IN_FRAME(cur_offset, 2)) {
573     /* We ran past the end of the captured data in the packet. */
574     return 0;
575   }
576   data_len = pntohs(dptr);
577   dptr += 2;
578   cur_offset += 2;
579
580   switch (type) {
581   case T_A:
582     trr = proto_tree_add_text(dns_tree, offset, (dptr - data_start) + data_len,
583                      "%s: type %s, class %s, addr %s",
584                      name, type_name, class_name,
585                      ip_to_str((guint8 *)dptr));
586     rr_tree = add_rr_to_tree(trr, ETT_DNS_RR, offset, name, name_len,
587                      long_type_name, class_name, ttl, data_len);
588     if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
589       /* We ran past the end of the captured data in the packet. */
590       return 0;
591     }
592     proto_tree_add_text(rr_tree, cur_offset, 4, "Addr: %s",
593                      ip_to_str((guint8 *)dptr));
594     break;
595
596   case T_NS:
597     {
598       char ns_name[MAXDNAME];
599       int ns_name_len;
600       
601       ns_name_len = get_dns_name(pd, cur_offset, dns_data_offset, ns_name, sizeof(ns_name));
602       trr = proto_tree_add_text(dns_tree, offset, (dptr - data_start) + data_len,
603                        "%s: type %s, class %s, ns %s",
604                        name, type_name, class_name, ns_name);
605       rr_tree = add_rr_to_tree(trr, ETT_DNS_RR, offset, name, name_len,
606                        long_type_name, class_name, ttl, data_len);
607       if (ns_name_len < 0) {
608         /* We ran past the end of the captured data in the packet. */
609         return 0;
610       }
611       proto_tree_add_text(rr_tree, cur_offset, ns_name_len, "Name server: %s",
612                         ns_name);
613     }
614     break;
615
616   case T_CNAME:
617     {
618       char cname[MAXDNAME];
619       int cname_len;
620       
621       cname_len = get_dns_name(pd, cur_offset, dns_data_offset, cname, sizeof(cname));
622       trr = proto_tree_add_text(dns_tree, offset, (dptr - data_start) + data_len,
623                      "%s: type %s, class %s, cname %s",
624                      name, type_name, class_name, cname);
625       rr_tree = add_rr_to_tree(trr, ETT_DNS_RR, offset, name, name_len,
626                        long_type_name, class_name, ttl, data_len);
627       if (cname_len < 0) {
628         /* We ran past the end of the captured data in the packet. */
629         return 0;
630       }
631       proto_tree_add_text(rr_tree, cur_offset, cname_len, "Primary name: %s",
632                         cname);
633     }
634     break;
635
636   case T_SOA:
637     {
638       char mname[MAXDNAME];
639       int mname_len;
640       char rname[MAXDNAME];
641       int rname_len;
642       guint32 serial;
643       guint32 refresh;
644       guint32 retry;
645       guint32 expire;
646       guint32 minimum;
647
648       mname_len = get_dns_name(pd, cur_offset, dns_data_offset, mname, sizeof(mname));
649       if (mname_len >= 0)
650         rname_len = get_dns_name(pd, cur_offset + mname_len, dns_data_offset, rname, sizeof(rname));
651       else {
652         /* We ran past the end of the captured data in the packet. */
653         rname_len = -1;
654       }
655       trr = proto_tree_add_text(dns_tree, offset, (dptr - data_start) + data_len,
656                      "%s: type %s, class %s, mname %s",
657                      name, type_name, class_name, mname);
658       rr_tree = add_rr_to_tree(trr, ETT_DNS_RR, offset, name, name_len,
659                        long_type_name, class_name, ttl, data_len);
660       if (mname_len < 0) {
661         /* We ran past the end of the captured data in the packet. */
662         return 0;
663       }
664       proto_tree_add_text(rr_tree, cur_offset, mname_len, "Primary name server: %s",
665                        mname);
666       cur_offset += mname_len;
667       
668       if (rname_len < 0) {
669         /* We ran past the end of the captured data in the packet. */
670         return 0;
671       }
672       proto_tree_add_text(rr_tree, cur_offset, rname_len, "Responsible authority's mailbox: %s",
673                        rname);
674       cur_offset += rname_len;
675
676       if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
677         /* We ran past the end of the captured data in the packet. */
678         return 0;
679       }
680       serial = pntohl(&pd[cur_offset]);
681       proto_tree_add_text(rr_tree, cur_offset, 4, "Serial number: %u",
682                        serial);
683       cur_offset += 4;
684
685       if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
686         /* We ran past the end of the captured data in the packet. */
687         return 0;
688       }
689       refresh = pntohl(&pd[cur_offset]);
690       proto_tree_add_text(rr_tree, cur_offset, 4, "Refresh interval: %s",
691                        time_secs_to_str(refresh));
692       cur_offset += 4;
693
694       if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
695         /* We ran past the end of the captured data in the packet. */
696         return 0;
697       }
698       retry = pntohl(&pd[cur_offset]);
699       proto_tree_add_text(rr_tree, cur_offset, 4, "Retry interval: %s",
700                        time_secs_to_str(retry));
701       cur_offset += 4;
702
703       if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
704         /* We ran past the end of the captured data in the packet. */
705         return 0;
706       }
707       expire = pntohl(&pd[cur_offset]);
708       proto_tree_add_text(rr_tree, cur_offset, 4, "Expiration limit: %s",
709                        time_secs_to_str(expire));
710       cur_offset += 4;
711
712       if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
713         /* We ran past the end of the captured data in the packet. */
714         return 0;
715       }
716       minimum = pntohl(&pd[cur_offset]);
717       proto_tree_add_text(rr_tree, cur_offset, 4, "Minimum TTL: %s",
718                        time_secs_to_str(minimum));
719     }
720     break;
721
722   case T_PTR:
723     {
724       char pname[MAXDNAME];
725       int pname_len;
726       
727       pname_len = get_dns_name(pd, cur_offset, dns_data_offset, pname, sizeof(pname));
728       trr = proto_tree_add_text(dns_tree, offset, (dptr - data_start) + data_len,
729                      "%s: type %s, class %s, ptr %s",
730                      name, type_name, class_name, pname);
731       rr_tree = add_rr_to_tree(trr, ETT_DNS_RR, offset, name, name_len,
732                        long_type_name, class_name, ttl, data_len);
733       if (pname_len < 0) {
734         /* We ran past the end of the captured data in the packet. */
735         return 0;
736       }
737       proto_tree_add_text(rr_tree, cur_offset, pname_len, "Domain name: %s",
738                         pname);
739       break;
740     }
741     break;
742
743   case T_MX:
744     {
745       guint16 preference = 0;
746       char mx_name[MAXDNAME];
747       int mx_name_len;
748       
749       mx_name_len = get_dns_name(pd, cur_offset + 2, dns_data_offset, mx_name, sizeof(mx_name));
750       if (!BYTES_ARE_IN_FRAME(cur_offset, 2)) {
751         /* We ran past the end of the captured data in the packet. */
752         trr = proto_tree_add_text(dns_tree, offset, (dptr - data_start) + data_len,
753                        "%s: type %s, class %s, <preference goes past end of captured data in packet>",
754                        name, type_name, class_name, preference, mx_name);
755       } else {
756         preference = pntohs(&pd[cur_offset]);
757         trr = proto_tree_add_text(dns_tree, offset, (dptr - data_start) + data_len,
758                        "%s: type %s, class %s, preference %u, mx %s",
759                        name, type_name, class_name, preference, mx_name);
760       }
761       rr_tree = add_rr_to_tree(trr, ETT_DNS_RR, offset, name, name_len,
762                        long_type_name, class_name, ttl, data_len);
763       if (!BYTES_ARE_IN_FRAME(cur_offset, 2)) {
764         /* We ran past the end of the captured data in the packet. */
765         return 0;
766       }
767       proto_tree_add_text(rr_tree, cur_offset, 2, "Preference: %u", preference);
768       if (mx_name_len < 0) {
769         /* We ran past the end of the captured data in the packet. */
770         return 0;
771       }
772       proto_tree_add_text(rr_tree, cur_offset + 2, mx_name_len, "Mail exchange: %s",
773                         mx_name);
774     }
775     break;
776       
777   case T_LOC:
778     {
779       trr = proto_tree_add_text(dns_tree, offset, (dptr - data_start) + data_len,
780                      "%s: type %s, class %s",
781                      name, type_name, class_name);
782       rr_tree = add_rr_to_tree(trr, ETT_DNS_RR, offset, name, name_len,
783                        long_type_name, class_name, ttl, data_len);
784       if (!BYTES_ARE_IN_FRAME(cur_offset, 1)) {
785         /* We ran past the end of the captured data in the packet. */
786         return 0;
787       }
788       proto_tree_add_text(rr_tree, cur_offset, 1, "Version: %u", pd[cur_offset]);
789       if (pd[cur_offset] == 0) {
790         /* Version 0, the only version RFC 1876 discusses. */
791         cur_offset++;
792
793         if (!BYTES_ARE_IN_FRAME(cur_offset, 1)) {
794           /* We ran past the end of the captured data in the packet. */
795           return 0;
796         }
797         proto_tree_add_text(rr_tree, cur_offset, 1, "Size: %g m",
798                                 rfc1867_size(pd[cur_offset]));
799         cur_offset++;
800
801         if (!BYTES_ARE_IN_FRAME(cur_offset, 1)) {
802           /* We ran past the end of the captured data in the packet. */
803           return 0;
804         }
805         proto_tree_add_text(rr_tree, cur_offset, 1, "Horizontal precision: %g m",
806                                 rfc1867_size(pd[cur_offset]));
807         cur_offset++;
808
809         if (!BYTES_ARE_IN_FRAME(cur_offset, 1)) {
810           /* We ran past the end of the captured data in the packet. */
811           return 0;
812         }
813         proto_tree_add_text(rr_tree, cur_offset, 1, "Vertical precision: %g m",
814                                 rfc1867_size(pd[cur_offset]));
815         cur_offset++;
816
817         if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
818           /* We ran past the end of the captured data in the packet. */
819           return 0;
820         }
821         proto_tree_add_text(rr_tree, cur_offset, 4, "Latitude: %s",
822                                 rfc1867_angle(&pd[cur_offset], "NS"));
823         cur_offset += 4;
824
825         if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
826           /* We ran past the end of the captured data in the packet. */
827           return 0;
828         }
829         proto_tree_add_text(rr_tree, cur_offset, 4, "Longitude: %s",
830                                 rfc1867_angle(&pd[cur_offset], "EW"));
831         cur_offset += 4;
832
833         if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
834           /* We ran past the end of the captured data in the packet. */
835           return 0;
836         }
837         proto_tree_add_text(rr_tree, cur_offset, 4, "Altitude: %g m",
838                                 (pntohl(&pd[cur_offset]) - 10000000)/100.0);
839       } else
840         proto_tree_add_text(rr_tree, cur_offset, data_len, "Data");
841       break;
842     }
843     break;
844       
845     /* TODO: parse more record types */
846
847   default:
848     trr = proto_tree_add_text(dns_tree, offset, (dptr - data_start) + data_len,
849                      "%s: type %s, class %s",
850                      name, type_name, class_name);
851     rr_tree = add_rr_to_tree(trr, ETT_DNS_RR, offset, name, name_len,
852                        long_type_name, class_name, ttl, data_len);
853     proto_tree_add_text(rr_tree, cur_offset, data_len, "Data");
854   }
855   
856   dptr += data_len;
857         
858   return dptr - data_start;
859 }
860
861 static int
862 dissect_query_records(const u_char *pd, int cur_off, int dns_data_offset,
863     int count, proto_tree *dns_tree)
864 {
865   int start_off, add_off;
866   proto_tree *qatree;
867   proto_item *ti;
868   
869   start_off = cur_off;
870   ti = proto_tree_add_text(dns_tree, start_off, 0, "Queries");
871   qatree = proto_item_add_subtree(ti, ETT_DNS_QRY);
872   while (count-- > 0) {
873     add_off = dissect_dns_query(pd, cur_off, dns_data_offset, qatree);
874     if (add_off <= 0) {
875       /* We ran past the end of the captured data in the packet. */
876       break;
877     }
878     cur_off += add_off;
879   }
880   proto_item_set_len(ti, cur_off - start_off);
881
882   return cur_off - start_off;
883 }
884
885 static int
886 dissect_answer_records(const u_char *pd, int cur_off, int dns_data_offset,
887     int count, proto_tree *dns_tree, char *name)
888 {
889   int start_off, add_off;
890   proto_tree *qatree;
891   proto_item *ti;
892   
893   start_off = cur_off;
894   ti = proto_tree_add_text(dns_tree, start_off, 0, name);
895   qatree = proto_item_add_subtree(ti, ETT_DNS_ANS);
896   while (count-- > 0) {
897     add_off = dissect_dns_answer(pd, cur_off, dns_data_offset, qatree);
898     if (add_off <= 0) {
899       /* We ran past the end of the captured data in the packet. */
900       break;
901     }
902     cur_off += add_off;
903   }
904   proto_item_set_len(ti, cur_off - start_off);
905
906   return cur_off - start_off;
907 }
908
909 void
910 dissect_dns(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
911 {
912   int dns_data_offset;
913   proto_tree *dns_tree, *field_tree;
914   proto_item *ti, *tf;
915   guint16    id, flags, quest, ans, auth, add;
916   char buf[128+1];
917   int cur_off;
918   static const value_string opcode_vals[] = {
919                   { OPCODE_QUERY,  "Standard query"        },
920                   { OPCODE_IQUERY, "Inverse query"         },
921                   { OPCODE_STATUS, "Server status request" },
922                   { 0,              NULL                   } };
923   static const value_string rcode_vals[] = {
924                   { RCODE_NOERROR,   "No error"        },
925                   { RCODE_FMTERROR,  "Format error"    },
926                   { RCODE_SERVFAIL,  "Server failure"  },
927                   { RCODE_NAMEERROR, "Name error"      },
928                   { RCODE_NOTIMPL,   "Not implemented" },
929                   { RCODE_REFUSED,   "Refused"         },
930                   { 0,               NULL              } };
931
932   dns_data_offset = offset;
933
934   if (check_col(fd, COL_PROTOCOL))
935     col_add_str(fd, COL_PROTOCOL, "DNS (UDP)");
936
937   if (pi.captured_len < DNS_HDRLEN) {
938     col_add_str(fd, COL_INFO, "Short DNS packet");
939     dissect_data(pd, offset, fd, tree);
940     return;
941   }
942
943   /* To do: check for errs, etc. */
944   id    = pntohs(&pd[offset + DNS_ID]);
945   flags = pntohs(&pd[offset + DNS_FLAGS]);
946   quest = pntohs(&pd[offset + DNS_QUEST]);
947   ans   = pntohs(&pd[offset + DNS_ANS]);
948   auth  = pntohs(&pd[offset + DNS_AUTH]);
949   add   = pntohs(&pd[offset + DNS_ADD]);
950   
951   if (check_col(fd, COL_INFO)) {
952     col_add_fstr(fd, COL_INFO, "%s%s",
953                 val_to_str(flags & F_OPCODE, opcode_vals,
954                            "Unknown operation (%x)"),
955                 (flags & F_RESPONSE) ? " response" : "");
956   }
957   
958   if (tree) {
959     ti = proto_tree_add_item_format(tree, proto_dns, offset, 4, NULL,
960                           (flags & F_RESPONSE) ? "DNS response" : "DNS query");
961     
962     dns_tree = proto_item_add_subtree(ti, ETT_DNS);
963     
964     proto_tree_add_text(dns_tree, offset + DNS_ID, 2, "Transaction ID: 0x%04x",
965                         id);
966
967     strcpy(buf, val_to_str(flags & F_OPCODE, opcode_vals, "Unknown operation"));
968     if (flags & F_RESPONSE) {
969       strcat(buf, " response");
970       strcat(buf, ", ");
971       strcat(buf, val_to_str(flags & F_RCODE, rcode_vals,
972             "Unknown error"));
973     }
974     tf = proto_tree_add_text(dns_tree, offset + DNS_FLAGS, 2, "Flags: 0x%04x (%s)",
975                           flags, buf);
976     field_tree = proto_item_add_subtree(tf, ETT_DNS_FLAGS);
977     proto_tree_add_text(field_tree, offset + DNS_FLAGS, 2, "%s",
978        decode_boolean_bitfield(flags, F_RESPONSE,
979             2*8, "Response", "Query"));
980     proto_tree_add_text(field_tree, offset + DNS_FLAGS, 2, "%s",
981        decode_enumerated_bitfield(flags, F_OPCODE,
982             2*8, opcode_vals, "%s"));
983     if (flags & F_RESPONSE) {
984       proto_tree_add_text(field_tree, offset + DNS_FLAGS, 2, "%s",
985          decode_boolean_bitfield(flags, F_AUTHORITATIVE,
986               2*8,
987               "Server is an authority for domain",
988               "Server isn't an authority for domain"));
989     }
990     proto_tree_add_text(field_tree, offset + DNS_FLAGS, 2, "%s",
991        decode_boolean_bitfield(flags, F_TRUNCATED,
992             2*8,
993             "Message is truncated",
994             "Message is not truncated"));
995     proto_tree_add_text(field_tree, offset + DNS_FLAGS, 2, "%s",
996        decode_boolean_bitfield(flags, F_RECDESIRED,
997             2*8,
998             "Do query recursively",
999             "Don't do query recursively"));
1000     if (flags & F_RESPONSE) {
1001       proto_tree_add_text(field_tree, offset + DNS_FLAGS, 2, "%s",
1002          decode_boolean_bitfield(flags, F_RECAVAIL,
1003               2*8,
1004               "Server can do recursive queries",
1005               "Server can't do recursive queries"));
1006       proto_tree_add_text(field_tree, offset + DNS_FLAGS, 2, "%s",
1007          decode_enumerated_bitfield(flags, F_RCODE,
1008               2*8, rcode_vals, "%s"));
1009     }
1010     proto_tree_add_text(dns_tree, offset + DNS_QUEST, 2, "Questions: %d", quest);
1011     proto_tree_add_text(dns_tree, offset + DNS_ANS, 2, "Answer RRs: %d", ans);
1012     proto_tree_add_text(dns_tree, offset + DNS_AUTH, 2, "Authority RRs: %d", auth);
1013     proto_tree_add_text(dns_tree, offset + DNS_ADD, 2, "Additional RRs: %d", add);
1014
1015     cur_off = offset + DNS_HDRLEN;
1016     
1017     if (quest > 0)
1018       cur_off += dissect_query_records(pd, cur_off, dns_data_offset, quest,
1019                                         dns_tree);
1020     
1021     if (ans > 0)
1022       cur_off += dissect_answer_records(pd, cur_off, dns_data_offset, ans,
1023           dns_tree, "Answers");
1024     
1025     if (auth > 0)
1026       cur_off += dissect_answer_records(pd, cur_off, dns_data_offset, auth,
1027           dns_tree, "Authoritative nameservers");
1028
1029     if (add > 0)
1030       cur_off += dissect_answer_records(pd, cur_off, dns_data_offset, add,
1031           dns_tree, "Additional records");
1032   }
1033 }
1034
1035 void
1036 proto_register_dns(void)
1037 {
1038 /*        static hf_register_info hf[] = {
1039                 { &variable,
1040                 { "Name",           "dns.abbreviation", TYPE, VALS_POINTER }},
1041         };*/
1042
1043         proto_dns = proto_register_protocol("Domain Name Service", "dns");
1044  /*       proto_register_field_array(proto_dns, hf, array_length(hf));*/
1045 }