Replace the ETT_ "enum" members, declared in "packet.h", with
[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.29 1999/11/16 11:42:28 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 static int hf_dns_response = -1;
45 static int hf_dns_query = -1;
46 static int hf_dns_flags = -1;
47 static int hf_dns_transaction_id = -1;
48 static int hf_dns_count_questions = -1;
49 static int hf_dns_count_answers = -1;
50 static int hf_dns_count_auth_rr = -1;
51 static int hf_dns_count_add_rr = -1;
52
53 static gint ett_dns = -1;
54 static gint ett_dns_qd = -1;
55 static gint ett_dns_rr = -1;
56 static gint ett_dns_qry = -1;
57 static gint ett_dns_ans = -1;
58 static gint ett_dns_flags = -1;
59
60 /* DNS structs and definitions */
61
62 /* Offsets of fields in the DNS header. */
63 #define DNS_ID          0
64 #define DNS_FLAGS       2
65 #define DNS_QUEST       4
66 #define DNS_ANS         6
67 #define DNS_AUTH        8
68 #define DNS_ADD         10
69
70 /* Length of DNS header. */
71 #define DNS_HDRLEN      12
72
73 /* type values  */
74 #define T_A             1               /* host address */
75 #define T_NS            2               /* authoritative name server */
76 #define T_MD            3               /* mail destination (obsolete) */
77 #define T_MF            4               /* mail forwarder (obsolete) */
78 #define T_CNAME         5               /* canonical name */
79 #define T_SOA           6               /* start of authority zone */
80 #define T_MB            7               /* mailbox domain name (experimental) */
81 #define T_MG            8               /* mail group member (experimental) */
82 #define T_MR            9               /* mail rename domain name (experimental) */
83 #define T_NULL          10              /* null RR (experimental) */
84 #define T_WKS           11              /* well known service */
85 #define T_PTR           12              /* domain name pointer */
86 #define T_HINFO         13              /* host information */
87 #define T_MINFO         14              /* mailbox or mail list information */
88 #define T_MX            15              /* mail routing information */
89 #define T_TXT           16              /* text strings */
90 #define T_RP            17              /* responsible person (RFC 1183) */
91 #define T_AFSDB         18              /* AFS data base location (RFC 1183) */
92 #define T_X25           19              /* X.25 address (RFC 1183) */
93 #define T_ISDN          20              /* ISDN address (RFC 1183) */
94 #define T_RT            21              /* route-through (RFC 1183) */
95 #define T_NSAP          22              /* OSI NSAP (RFC 1706) */
96 #define T_NSAP_PTR      23              /* PTR equivalent for OSI NSAP (RFC 1348 - obsolete) */
97 #define T_SIG           24              /* digital signature (RFC 2065) */
98 #define T_KEY           25              /* public key (RFC 2065) */
99 #define T_PX            26              /* pointer to X.400/RFC822 mapping info (RFC 1664) */
100 #define T_GPOS          27              /* geographical position (RFC 1712) */
101 #define T_AAAA          28              /* IPv6 address (RFC 1886) */
102 #define T_LOC           29              /* geographical location (RFC 1876) */
103 #define T_NXT           30              /* "next" name (RFC 2065) */
104 #define T_EID           31              /* ??? (Nimrod?) */
105 #define T_NIMLOC        32              /* ??? (Nimrod?) */
106 #define T_SRV           33              /* service location (RFC 2052) */
107 #define T_ATMA          34              /* ??? */
108 #define T_NAPTR         35              /* naming authority pointer (RFC 2168) */
109
110 /* Bit fields in the flags */
111 #define F_RESPONSE      (1<<15)         /* packet is response */
112 #define F_OPCODE        (0xF<<11)       /* query opcode */
113 #define F_AUTHORITATIVE (1<<10)         /* response is authoritative */
114 #define F_TRUNCATED     (1<<9)          /* response is truncated */
115 #define F_RECDESIRED    (1<<8)          /* recursion desired */
116 #define F_RECAVAIL      (1<<7)          /* recursion available */
117 #define F_RCODE         (0xF<<0)        /* reply code */
118
119 /* Opcodes */
120 #define OPCODE_QUERY    (0<<11)         /* standard query */
121 #define OPCODE_IQUERY   (1<<11)         /* inverse query */
122 #define OPCODE_STATUS   (2<<11)         /* server status request */
123
124 /* Reply codes */
125 #define RCODE_NOERROR   (0<<0)
126 #define RCODE_FMTERROR  (1<<0)
127 #define RCODE_SERVFAIL  (2<<0)
128 #define RCODE_NAMEERROR (3<<0)
129 #define RCODE_NOTIMPL   (4<<0)
130 #define RCODE_REFUSED   (5<<0)
131
132 /* See RFC 1035 for all RR types for which no RFC is listed. */
133 static char *
134 dns_type_name (int type)
135 {
136   char *type_names[36] = {
137     "unused",
138     "A",
139     "NS",
140     "MD",
141     "MF",
142     "CNAME",
143     "SOA",
144     "MB",
145     "MG",
146     "MR",
147     "NULL",
148     "WKS",
149     "PTR",
150     "HINFO",
151     "MINFO",
152     "MX",
153     "TXT",
154     "RP",                               /* RFC 1183 */
155     "AFSDB",                            /* RFC 1183 */
156     "X25",                              /* RFC 1183 */
157     "ISDN",                             /* RFC 1183 */
158     "RT",                               /* RFC 1183 */
159     "NSAP",                             /* RFC 1706 */
160     "NSAP-PTR",                         /* RFC 1348 */
161     "SIG",                              /* RFC 2065 */
162     "KEY",                              /* RFC 2065 */
163     "PX",                               /* RFC 1664 */
164     "GPOS",                             /* RFC 1712 */
165     "AAAA",                             /* RFC 1886 */
166     "LOC",                              /* RFC 1876 */
167     "NXT",                              /* RFC 2065 */
168     "EID",
169     "NIMLOC",
170     "SRV",                              /* RFC 2052 */
171     "ATMA",
172     "NAPTR"                             /* RFC 2168 */
173   };
174   
175   if (type <= 35)
176     return type_names[type];
177   
178   /* special cases */
179   switch (type) 
180     {
181       /* non standard  */
182     case 100:
183       return "UINFO";
184     case 101:
185       return "UID";
186     case 102:
187       return "GID";
188     case 103:
189       return "UNSPEC";
190       
191       /* queries  */
192     case 251:
193       return "IXFR";    /* RFC 1995 */
194     case 252:
195       return "AXFR";
196     case 253:
197       return "MAILB";
198     case 254:
199       return "MAILA";
200     case 255:
201       return "ANY";
202     }
203   
204   return "unknown";
205 }
206
207
208 static char *
209 dns_long_type_name (int type)
210 {
211   char *type_names[36] = {
212     "unused",
213     "Host address",
214     "Authoritative name server",        
215     "Mail destination",
216     "Mail forwarder",
217     "Canonical name for an alias",
218     "Start of zone of authority",
219     "Mailbox domain name",
220     "Mail group member",
221     "Mail rename domain name",
222     "Null resource record",
223     "Well-known service description",
224     "Domain name pointer",
225     "Host information",
226     "Mailbox or mail list information",
227     "Mail exchange",
228     "Text strings",
229     "Responsible person",               /* RFC 1183 */
230     "AFS data base location",           /* RFC 1183 */
231     "X.25 address",                     /* RFC 1183 */
232     "ISDN number",                      /* RFC 1183 */
233     "Route through",                    /* RFC 1183 */
234     "OSI NSAP",                         /* RFC 1706 */
235     "OSI NSAP name pointer",            /* RFC 1348 */
236     "Signature",                        /* RFC 2065 */
237     "Public key",                       /* RFC 2065 */
238     "Pointer to X.400/RFC822 mapping info", /* RFC 1664 */
239     "Geographical position",            /* RFC 1712 */
240     "IPv6 address",                     /* RFC 1886 */
241     "Location",                         /* RFC 1876 */
242     "Next",                             /* RFC 2065 */
243     "EID",
244     "NIMLOC",
245     "Service location",                 /* RFC 2052 */
246     "ATMA",
247     "Naming authority pointer"          /* RFC 2168 */
248   };
249   static char unkbuf[7+1+2+1+4+1+1+10+1+1];     /* "Unknown RR type (%d)" */
250   
251   if (type <= 35)
252     return type_names[type];
253   
254   /* special cases */
255   switch (type) 
256     {
257       /* non standard  */
258     case 100:
259       return "UINFO";
260     case 101:
261       return "UID";
262     case 102:
263       return "GID";
264     case 103:
265       return "UNSPEC";
266       
267       /* queries  */
268     case 251:
269       return "Request for incremental zone transfer";   /* RFC 1995 */
270     case 252:
271       return "Request for full zone transfer";
272     case 253:
273       return "Request for mailbox-related records";
274     case 254:
275       return "Request for mail agent resource records";
276     case 255:
277       return "Request for all records";
278     }
279   
280   sprintf(unkbuf, "Unknown RR type (%d)", type);
281   return unkbuf;
282 }
283
284
285 char *
286 dns_class_name(int class)
287 {
288   char *class_name;
289   
290   switch (class) {
291   case 1:
292     class_name = "inet";
293     break;
294   case 3:
295     class_name = "chaos";
296     break;
297   case 4:
298     class_name = "hesiod";
299     break;
300   default:
301     class_name = "unknown";
302   }
303
304   return class_name;
305 }
306
307 int
308 get_dns_name(const u_char *pd, int offset, int dns_data_offset,
309     char *name, int maxname)
310 {
311   const u_char *dp = pd + offset;
312   const u_char *dptr = dp;
313   char *np = name;
314   int len = -1;
315   u_int component_len;
316
317   maxname--;    /* reserve space for the trailing '\0' */
318   for (;;) {
319     if (!BYTES_ARE_IN_FRAME(offset, 1))
320       goto overflow;
321     component_len = *dp++;
322     offset++;
323     if (component_len == 0)
324       break;
325     switch (component_len & 0xc0) {
326
327     case 0x00:
328       /* Label */
329       if (np != name) {
330         /* Not the first component - put in a '.'. */
331         if (maxname > 0) {
332           *np++ = '.';
333           maxname--;
334         }
335       }
336       if (!BYTES_ARE_IN_FRAME(offset, component_len))
337         goto overflow;
338       while (component_len > 0) {
339         if (maxname > 0) {
340           *np++ = *dp;
341           maxname--;
342         }
343         component_len--;
344         dp++;
345         offset++;
346       }
347       break;
348
349     case 0x40:
350     case 0x80:
351       goto error;       /* error */
352
353     case 0xc0:
354       /* Pointer. */
355       /* XXX - check to make sure we aren't looping, by keeping track
356          of how many characters are in the DNS packet, and of how many
357          characters we've looked at, and quitting if the latter
358          becomes bigger than the former. */
359       if (!BYTES_ARE_IN_FRAME(offset, 1))
360         goto overflow;
361       offset = dns_data_offset + (((component_len & ~0xc0) << 8) | (*dp++));
362       /* If "len" is negative, we are still working on the original name,
363          not something pointed to by a pointer, and so we should set "len"
364          to the length of the original name. */
365       if (len < 0)
366         len = dp - dptr;
367       dp = pd + offset;
368       break;    /* now continue processing from there */
369     }
370   }
371         
372 error:
373   *np = '\0';
374   /* If "len" is negative, we haven't seen a pointer, and thus haven't
375      set the length, so set it. */
376   if (len < 0)
377     len = dp - dptr;
378   /* Zero-length name means "root server" */
379   if (*name == '\0')
380     strcpy(name, "<Root>");
381   return len;
382
383 overflow:
384   /* We ran past the end of the captured data in the packet. */
385   strcpy(name, "<Name goes past end of captured data in packet>");
386   /* If "len" is negative, we haven't seen a pointer, and thus haven't
387      set the length, so set it. */
388   if (len < 0)
389     len = dp - dptr;
390   return len;
391 }
392
393
394 static int
395 get_dns_name_type_class(const u_char *pd, int offset, int dns_data_offset,
396     char *name_ret, int *name_len_ret, int *type_ret, int *class_ret)
397 {
398   int len;
399   int name_len;
400   int type;
401   int class;
402   char name[MAXDNAME];
403   int start_offset = offset;
404
405   name_len = get_dns_name(pd, offset, dns_data_offset, name, sizeof(name));
406   offset += name_len;
407   
408   if (!BYTES_ARE_IN_FRAME(offset, 2)) {
409     /* We ran past the end of the captured data in the packet. */
410     return -1;
411   }
412   type = pntohs(&pd[offset]);
413   offset += 2;
414
415   if (!BYTES_ARE_IN_FRAME(offset, 2)) {
416     /* We ran past the end of the captured data in the packet. */
417     return -1;
418   }
419   class = pntohs(&pd[offset]);
420   offset += 2;
421
422   strcpy (name_ret, name);
423   *type_ret = type;
424   *class_ret = class;
425   *name_len_ret = name_len;
426
427   len = offset - start_offset;
428   return len;
429 }
430
431 static double
432 rfc1867_size(u_char val)
433 {
434   double size;
435   guint32 exponent;
436
437   size = (val & 0xF0) >> 4;
438   exponent = (val & 0x0F);
439   while (exponent != 0) {
440     size *= 10;
441     exponent--;
442   }
443   return size / 100;    /* return size in meters, not cm */
444 }
445
446 static char *
447 rfc1867_angle(const u_char *dptr, const char *nsew)
448 {
449   guint32 angle;
450   char direction;
451   guint32 degrees, minutes, secs, tsecs;
452   static char buf[10+1+3+1 + 2+1+3+1 + 2+1+3+1+3+1 + 1 + 1];
453
454   angle = pntohl(dptr);
455
456   if (angle < 0x80000000U) {
457     angle = 0x80000000U - angle;
458     direction = nsew[1];
459   } else {
460     angle = angle - 0x80000000U;
461     direction = nsew[0];
462   }
463   tsecs = angle % 1000;
464   angle = angle / 1000;
465   secs = angle % 60;
466   angle = angle / 60;
467   minutes = angle % 60;
468   degrees = angle / 60;
469   sprintf(buf, "%u deg %u min %u.%03u sec %c", degrees, minutes, secs,
470                 tsecs, direction);
471   return buf;
472 }
473
474 static int
475 dissect_dns_query(const u_char *pd, int offset, int dns_data_offset,
476   frame_data *fd, proto_tree *dns_tree)
477 {
478   int len;
479   char name[MAXDNAME];
480   int name_len;
481   int type;
482   int class;
483   char *class_name;
484   char *type_name;
485   char *long_type_name;
486   const u_char *dptr;
487   const u_char *data_start;
488   proto_tree *q_tree;
489   proto_item *tq;
490
491   data_start = dptr = pd + offset;
492
493   len = get_dns_name_type_class(pd, offset, dns_data_offset, name, &name_len,
494     &type, &class);
495   if (len < 0) {
496     /* We ran past the end of the data in the packet. */
497     return 0;
498   }
499   dptr += len;
500
501   type_name = dns_type_name(type);
502   class_name = dns_class_name(class);
503   long_type_name = dns_long_type_name(type);
504
505   if (fd != NULL)
506     col_append_fstr(fd, COL_INFO, " %s %s", type_name, name);
507   if (dns_tree != NULL) {
508     tq = proto_tree_add_text(dns_tree, offset, len, "%s: type %s, class %s", 
509                    name, type_name, class_name);
510     q_tree = proto_item_add_subtree(tq, ett_dns_qd);
511
512     proto_tree_add_text(q_tree, offset, name_len, "Name: %s", name);
513     offset += name_len;
514
515     proto_tree_add_text(q_tree, offset, 2, "Type: %s", long_type_name);
516     offset += 2;
517
518     proto_tree_add_text(q_tree, offset, 2, "Class: %s", class_name);
519     offset += 2;
520   }
521   
522   return dptr - data_start;
523 }
524
525
526 proto_tree *
527 add_rr_to_tree(proto_item *trr, int rr_type, int offset, const char *name,
528   int namelen, const char *type_name, const char *class_name, u_int ttl,
529   u_short data_len)
530 {
531   proto_tree *rr_tree;
532
533   rr_tree = proto_item_add_subtree(trr, rr_type);
534   proto_tree_add_text(rr_tree, offset, namelen, "Name: %s", name);
535   offset += namelen;
536   proto_tree_add_text(rr_tree, offset, 2, "Type: %s", type_name);
537   offset += 2;
538   proto_tree_add_text(rr_tree, offset, 2, "Class: %s", class_name);
539   offset += 2;
540   proto_tree_add_text(rr_tree, offset, 4, "Time to live: %s",
541                                                 time_secs_to_str(ttl));
542   offset += 4;
543   proto_tree_add_text(rr_tree, offset, 2, "Data length: %u", data_len);
544   return rr_tree;
545 }
546
547 static int
548 dissect_dns_answer(const u_char *pd, int offset, int dns_data_offset,
549   frame_data *fd, proto_tree *dns_tree)
550 {
551   int len;
552   char name[MAXDNAME];
553   int name_len;
554   int type;
555   int class;
556   char *class_name;
557   char *type_name;
558   char *long_type_name;
559   const u_char *dptr;
560   int cur_offset;
561   const u_char *data_start;
562   u_int ttl;
563   u_short data_len;
564   proto_tree *rr_tree;
565   proto_item *trr;
566
567   data_start = dptr = pd + offset;
568   cur_offset = offset;
569
570   len = get_dns_name_type_class(pd, offset, dns_data_offset, name, &name_len,
571     &type, &class);
572   if (len < 0) {
573     /* We ran past the end of the captured data in the packet. */
574     return 0;
575   }
576   dptr += len;
577   cur_offset += len;
578
579   type_name = dns_type_name(type);
580   class_name = dns_class_name(class);
581   long_type_name = dns_long_type_name(type);
582
583   if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
584     /* We ran past the end of the captured data in the packet. */
585     return 0;
586   }
587   ttl = pntohl(dptr);
588   dptr += 4;
589   cur_offset += 4;
590
591   if (!BYTES_ARE_IN_FRAME(cur_offset, 2)) {
592     /* We ran past the end of the captured data in the packet. */
593     return 0;
594   }
595   data_len = pntohs(dptr);
596   dptr += 2;
597   cur_offset += 2;
598
599   switch (type) {
600   case T_A:
601     if (fd != NULL) {
602       col_append_fstr(fd, COL_INFO, " %s %s", type_name,
603                         ip_to_str((guint8 *)dptr));
604     }
605     if (dns_tree != NULL) {
606       trr = proto_tree_add_text(dns_tree, offset, (dptr - data_start) + data_len,
607                      "%s: type %s, class %s, addr %s",
608                      name, type_name, class_name,
609                      ip_to_str((guint8 *)dptr));
610       rr_tree = add_rr_to_tree(trr, ett_dns_rr, offset, name, name_len,
611                      long_type_name, class_name, ttl, data_len);
612       if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
613         /* We ran past the end of the captured data in the packet. */
614         return 0;
615       }
616       proto_tree_add_text(rr_tree, cur_offset, 4, "Addr: %s",
617                      ip_to_str((guint8 *)dptr));
618     }
619     break;
620
621   case T_NS:
622     {
623       char ns_name[MAXDNAME];
624       int ns_name_len;
625       
626       ns_name_len = get_dns_name(pd, cur_offset, dns_data_offset, ns_name, sizeof(ns_name));
627       if (fd != NULL)
628         col_append_fstr(fd, COL_INFO, " %s %s", type_name, ns_name);
629       if (dns_tree != NULL) {
630         trr = proto_tree_add_text(dns_tree, offset, (dptr - data_start) + data_len,
631                        "%s: type %s, class %s, ns %s",
632                        name, type_name, class_name, ns_name);
633         rr_tree = add_rr_to_tree(trr, ett_dns_rr, offset, name, name_len,
634                        long_type_name, class_name, ttl, data_len);
635         if (ns_name_len < 0) {
636           /* We ran past the end of the captured data in the packet. */
637           return 0;
638         }
639         proto_tree_add_text(rr_tree, cur_offset, ns_name_len, "Name server: %s",
640                         ns_name);
641       }
642     }
643     break;
644
645   case T_CNAME:
646     {
647       char cname[MAXDNAME];
648       int cname_len;
649       
650       cname_len = get_dns_name(pd, cur_offset, dns_data_offset, cname, sizeof(cname));
651       if (fd != NULL)
652         col_append_fstr(fd, COL_INFO, " %s %s", type_name, cname);
653       if (dns_tree != NULL) {
654         trr = proto_tree_add_text(dns_tree, offset, (dptr - data_start) + data_len,
655                      "%s: type %s, class %s, cname %s",
656                      name, type_name, class_name, cname);
657         rr_tree = add_rr_to_tree(trr, ett_dns_rr, offset, name, name_len,
658                        long_type_name, class_name, ttl, data_len);
659         if (cname_len < 0) {
660           /* We ran past the end of the captured data in the packet. */
661           return 0;
662         }
663         proto_tree_add_text(rr_tree, cur_offset, cname_len, "Primary name: %s",
664                         cname);
665       }
666     }
667     break;
668
669   case T_SOA:
670     {
671       char mname[MAXDNAME];
672       int mname_len;
673       char rname[MAXDNAME];
674       int rname_len;
675       guint32 serial;
676       guint32 refresh;
677       guint32 retry;
678       guint32 expire;
679       guint32 minimum;
680
681       mname_len = get_dns_name(pd, cur_offset, dns_data_offset, mname, sizeof(mname));
682       if (mname_len >= 0)
683         rname_len = get_dns_name(pd, cur_offset + mname_len, dns_data_offset, rname, sizeof(rname));
684       else {
685         /* We ran past the end of the captured data in the packet. */
686         rname_len = -1;
687       }
688       if (fd != NULL)
689         col_append_fstr(fd, COL_INFO, " %s %s", type_name, mname);
690       if (dns_tree != NULL) {
691         trr = proto_tree_add_text(dns_tree, offset, (dptr - data_start) + data_len,
692                      "%s: type %s, class %s, mname %s",
693                      name, type_name, class_name, mname);
694         rr_tree = add_rr_to_tree(trr, ett_dns_rr, offset, name, name_len,
695                        long_type_name, class_name, ttl, data_len);
696         if (mname_len < 0) {
697           /* We ran past the end of the captured data in the packet. */
698           return 0;
699         }
700         proto_tree_add_text(rr_tree, cur_offset, mname_len, "Primary name server: %s",
701                        mname);
702         cur_offset += mname_len;
703       
704         if (rname_len < 0) {
705           /* We ran past the end of the captured data in the packet. */
706           return 0;
707         }
708         proto_tree_add_text(rr_tree, cur_offset, rname_len, "Responsible authority's mailbox: %s",
709                        rname);
710         cur_offset += rname_len;
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         serial = pntohl(&pd[cur_offset]);
717         proto_tree_add_text(rr_tree, cur_offset, 4, "Serial number: %u",
718                        serial);
719         cur_offset += 4;
720
721         if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
722           /* We ran past the end of the captured data in the packet. */
723           return 0;
724         }
725         refresh = pntohl(&pd[cur_offset]);
726         proto_tree_add_text(rr_tree, cur_offset, 4, "Refresh interval: %s",
727                        time_secs_to_str(refresh));
728         cur_offset += 4;
729
730         if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
731           /* We ran past the end of the captured data in the packet. */
732           return 0;
733         }
734         retry = pntohl(&pd[cur_offset]);
735         proto_tree_add_text(rr_tree, cur_offset, 4, "Retry interval: %s",
736                        time_secs_to_str(retry));
737         cur_offset += 4;
738
739         if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
740           /* We ran past the end of the captured data in the packet. */
741           return 0;
742         }
743         expire = pntohl(&pd[cur_offset]);
744         proto_tree_add_text(rr_tree, cur_offset, 4, "Expiration limit: %s",
745                        time_secs_to_str(expire));
746         cur_offset += 4;
747
748         if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
749           /* We ran past the end of the captured data in the packet. */
750           return 0;
751         }
752         minimum = pntohl(&pd[cur_offset]);
753         proto_tree_add_text(rr_tree, cur_offset, 4, "Minimum TTL: %s",
754                        time_secs_to_str(minimum));
755       }
756     }
757     break;
758
759   case T_PTR:
760     {
761       char pname[MAXDNAME];
762       int pname_len;
763       
764       pname_len = get_dns_name(pd, cur_offset, dns_data_offset, pname, sizeof(pname));
765       if (fd != NULL)
766         col_append_fstr(fd, COL_INFO, " %s %s", type_name, pname);
767       if (dns_tree != NULL) {
768         trr = proto_tree_add_text(dns_tree, offset, (dptr - data_start) + data_len,
769                      "%s: type %s, class %s, ptr %s",
770                      name, type_name, class_name, pname);
771         rr_tree = add_rr_to_tree(trr, ett_dns_rr, offset, name, name_len,
772                        long_type_name, class_name, ttl, data_len);
773         if (pname_len < 0) {
774           /* We ran past the end of the captured data in the packet. */
775           return 0;
776         }
777         proto_tree_add_text(rr_tree, cur_offset, pname_len, "Domain name: %s",
778                         pname);
779       }
780       break;
781     }
782     break;
783
784
785   case T_HINFO:
786     {
787       int cpu_offset;
788       int cpu_len;
789       int os_offset;
790       int os_len;
791
792       cpu_offset = cur_offset;
793       if (!BYTES_ARE_IN_FRAME(cpu_offset, 1)) {
794         /* We ran past the end of the captured data in the packet. */
795         if (dns_tree != NULL) {
796           trr = proto_tree_add_text(dns_tree, offset, (dptr - data_start) + data_len,
797                        "%s: type %s, class %s, <CPU goes past end of captured data in packet>",
798                        name, type_name, class_name);
799           rr_tree = add_rr_to_tree(trr, ett_dns_rr, offset, name, name_len,
800                        long_type_name, class_name, ttl, data_len);
801         }
802         return 0;
803       }
804       cpu_len = pd[cpu_offset];
805       if (!BYTES_ARE_IN_FRAME(cpu_offset + 1, cpu_len)) {
806         /* We ran past the end of the captured data in the packet. */
807         if (dns_tree != NULL) {
808           trr = proto_tree_add_text(dns_tree, offset, (dptr - data_start) + data_len,
809                        "%s: type %s, class %s, <CPU goes past end of captured data in packet>",
810                        name, type_name, class_name);
811           rr_tree = add_rr_to_tree(trr, ett_dns_rr, offset, name, name_len,
812                        long_type_name, class_name, ttl, data_len);
813         }
814         return 0;
815       }
816       os_offset = cpu_offset + 1 + cpu_len;
817       if (!BYTES_ARE_IN_FRAME(os_offset, 1)) {
818         /* We ran past the end of the captured data in the packet. */
819         if (dns_tree != NULL) {
820           trr = proto_tree_add_text(dns_tree, offset, (dptr - data_start) + data_len,
821                        "%s: type %s, class %s, CPU %.*s, <OS goes past end of captured data in packet>",
822                        name, type_name, class_name, cpu_len, &pd[cpu_offset + 1]);
823           rr_tree = add_rr_to_tree(trr, ett_dns_rr, offset, name, name_len,
824                        long_type_name, class_name, ttl, data_len);
825         }
826         return 0;
827       }
828       os_len = pd[os_offset];
829       if (!BYTES_ARE_IN_FRAME(os_offset + 1, os_len)) {
830         /* We ran past the end of the captured data in the packet. */
831         if (dns_tree != NULL) {
832           trr = proto_tree_add_text(dns_tree, offset, (dptr - data_start) + data_len,
833                        "%s: type %s, class %s, CPU %*.s, <OS goes past end of captured data in packet>",
834                        name, type_name, class_name, cpu_len, &pd[cpu_offset + 1]);
835           rr_tree = add_rr_to_tree(trr, ett_dns_rr, offset, name, name_len,
836                        long_type_name, class_name, ttl, data_len);
837         }
838         return 0;
839       }
840       if (fd != NULL)
841         col_append_fstr(fd, COL_INFO, " %s %.*s %.*s", type_name, cpu_len,
842             &pd[cpu_offset + 1], os_len, &pd[os_offset + 1]);
843       if (dns_tree != NULL) {
844         trr = proto_tree_add_text(dns_tree, offset, (dptr - data_start) + data_len,
845                      "%s: type %s, class %s, CPU %.*s, OS %.*s",
846                      name, type_name, class_name,
847                      cpu_len, &pd[cpu_offset + 1], os_len, &pd[os_offset + 1]);
848         rr_tree = add_rr_to_tree(trr, ett_dns_rr, offset, name, name_len,
849                        long_type_name, class_name, ttl, data_len);
850         proto_tree_add_text(rr_tree, cpu_offset, 1 + cpu_len, "CPU: %.*s",
851                         cpu_len, &pd[cpu_offset + 1]);
852         proto_tree_add_text(rr_tree, os_offset, 1 + os_len, "OS: %.*s",
853                         os_len, &pd[os_offset + 1]);
854       }
855       break;
856     }
857     break;
858
859   case T_MX:
860     {
861       guint16 preference = 0;
862       char mx_name[MAXDNAME];
863       int mx_name_len;
864       
865       if (!BYTES_ARE_IN_FRAME(cur_offset, 2)) {
866         /* We ran past the end of the captured data in the packet. */
867         if (dns_tree != NULL) {
868           trr = proto_tree_add_text(dns_tree, offset, (dptr - data_start) + data_len,
869                        "%s: type %s, class %s, <preference goes past end of captured data in packet>",
870                        name, type_name, class_name);
871           rr_tree = add_rr_to_tree(trr, ett_dns_rr, offset, name, name_len,
872                        long_type_name, class_name, ttl, data_len);
873         }
874         return 0;
875       }
876       preference = pntohs(&pd[cur_offset]);
877       mx_name_len = get_dns_name(pd, cur_offset + 2, dns_data_offset, mx_name, sizeof(mx_name));
878       if (mx_name_len < 0) {
879         /* We ran past the end of the captured data in the packet. */
880         if (dns_tree != NULL) {
881           trr = proto_tree_add_text(dns_tree, offset, (dptr - data_start) + data_len,
882                        "%s: type %s, class %s, preference %u, <mx goes past end of captured data in packet>",
883                        name, type_name, class_name, preference);
884           rr_tree = add_rr_to_tree(trr, ett_dns_rr, offset, name, name_len,
885                        long_type_name, class_name, ttl, data_len);
886         }
887         return 0;
888       }
889       if (fd != NULL)
890         col_append_fstr(fd, COL_INFO, " %s %u %s", type_name, preference, mx_name);
891       if (dns_tree != NULL) {
892         trr = proto_tree_add_text(dns_tree, offset, (dptr - data_start) + data_len,
893                        "%s: type %s, class %s, preference %u, mx %s",
894                        name, type_name, class_name, preference, mx_name);
895         rr_tree = add_rr_to_tree(trr, ett_dns_rr, offset, name, name_len,
896                        long_type_name, class_name, ttl, data_len);
897         proto_tree_add_text(rr_tree, cur_offset, 2, "Preference: %u", preference);
898         proto_tree_add_text(rr_tree, cur_offset + 2, mx_name_len, "Mail exchange: %s",
899                         mx_name);
900       }
901     }
902     break;
903       
904   case T_LOC:
905     {
906       if (fd != NULL)
907         col_append_fstr(fd, COL_INFO, " %s", type_name);
908       if (dns_tree != NULL) {
909         trr = proto_tree_add_text(dns_tree, offset, (dptr - data_start) + data_len,
910                      "%s: type %s, class %s",
911                      name, type_name, class_name);
912         rr_tree = add_rr_to_tree(trr, ett_dns_rr, offset, name, name_len,
913                        long_type_name, class_name, ttl, data_len);
914         if (!BYTES_ARE_IN_FRAME(cur_offset, 1)) {
915           /* We ran past the end of the captured data in the packet. */
916           return 0;
917         }
918         proto_tree_add_text(rr_tree, cur_offset, 1, "Version: %u", pd[cur_offset]);
919         if (pd[cur_offset] == 0) {
920           /* Version 0, the only version RFC 1876 discusses. */
921           cur_offset++;
922
923           if (!BYTES_ARE_IN_FRAME(cur_offset, 1)) {
924             /* We ran past the end of the captured data in the packet. */
925             return 0;
926           }
927           proto_tree_add_text(rr_tree, cur_offset, 1, "Size: %g m",
928                                 rfc1867_size(pd[cur_offset]));
929           cur_offset++;
930
931           if (!BYTES_ARE_IN_FRAME(cur_offset, 1)) {
932             /* We ran past the end of the captured data in the packet. */
933             return 0;
934           }
935           proto_tree_add_text(rr_tree, cur_offset, 1, "Horizontal precision: %g m",
936                                 rfc1867_size(pd[cur_offset]));
937           cur_offset++;
938
939           if (!BYTES_ARE_IN_FRAME(cur_offset, 1)) {
940             /* We ran past the end of the captured data in the packet. */
941             return 0;
942           }
943           proto_tree_add_text(rr_tree, cur_offset, 1, "Vertical precision: %g m",
944                                 rfc1867_size(pd[cur_offset]));
945           cur_offset++;
946
947           if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
948             /* We ran past the end of the captured data in the packet. */
949             return 0;
950           }
951           proto_tree_add_text(rr_tree, cur_offset, 4, "Latitude: %s",
952                                 rfc1867_angle(&pd[cur_offset], "NS"));
953           cur_offset += 4;
954
955           if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
956             /* We ran past the end of the captured data in the packet. */
957             return 0;
958           }
959           proto_tree_add_text(rr_tree, cur_offset, 4, "Longitude: %s",
960                                 rfc1867_angle(&pd[cur_offset], "EW"));
961           cur_offset += 4;
962
963           if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
964             /* We ran past the end of the captured data in the packet. */
965             return 0;
966           }
967           proto_tree_add_text(rr_tree, cur_offset, 4, "Altitude: %g m",
968                                 (pntohl(&pd[cur_offset]) - 10000000)/100.0);
969         } else
970           proto_tree_add_text(rr_tree, cur_offset, data_len, "Data");
971       }
972       break;
973     }
974     break;
975       
976     /* TODO: parse more record types */
977
978   default:
979     if (fd != NULL)
980       col_append_fstr(fd, COL_INFO, " %s", type_name);
981     if (dns_tree != NULL) {
982       trr = proto_tree_add_text(dns_tree, offset, (dptr - data_start) + data_len,
983                      "%s: type %s, class %s",
984                      name, type_name, class_name);
985       rr_tree = add_rr_to_tree(trr, ett_dns_rr, offset, name, name_len,
986                        long_type_name, class_name, ttl, data_len);
987       proto_tree_add_text(rr_tree, cur_offset, data_len, "Data");
988     }
989   }
990   
991   dptr += data_len;
992         
993   return dptr - data_start;
994 }
995
996 static int
997 dissect_query_records(const u_char *pd, int cur_off, int dns_data_offset,
998     int count, frame_data *fd, proto_tree *dns_tree)
999 {
1000   int start_off, add_off;
1001   proto_tree *qatree = NULL;
1002   proto_item *ti = NULL;
1003   
1004   start_off = cur_off;
1005   if (dns_tree) {
1006     ti = proto_tree_add_text(dns_tree, start_off, 0, "Queries");
1007     qatree = proto_item_add_subtree(ti, ett_dns_qry);
1008   }
1009   while (count-- > 0) {
1010     add_off = dissect_dns_query(pd, cur_off, dns_data_offset, fd, qatree);
1011     if (add_off <= 0) {
1012       /* We ran past the end of the captured data in the packet. */
1013       break;
1014     }
1015     cur_off += add_off;
1016   }
1017   if (ti)
1018     proto_item_set_len(ti, cur_off - start_off);
1019
1020   return cur_off - start_off;
1021 }
1022
1023 static int
1024 dissect_answer_records(const u_char *pd, int cur_off, int dns_data_offset,
1025     int count, frame_data *fd, proto_tree *dns_tree, char *name)
1026 {
1027   int start_off, add_off;
1028   proto_tree *qatree = NULL;
1029   proto_item *ti = NULL;
1030   
1031   start_off = cur_off;
1032   if (dns_tree) {
1033     ti = proto_tree_add_text(dns_tree, start_off, 0, name);
1034     qatree = proto_item_add_subtree(ti, ett_dns_ans);
1035   }
1036   while (count-- > 0) {
1037     add_off = dissect_dns_answer(pd, cur_off, dns_data_offset, fd, qatree);
1038     if (add_off <= 0) {
1039       /* We ran past the end of the captured data in the packet. */
1040       break;
1041     }
1042     cur_off += add_off;
1043   }
1044   if (ti)
1045     proto_item_set_len(ti, cur_off - start_off);
1046
1047   return cur_off - start_off;
1048 }
1049
1050 void
1051 dissect_dns(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
1052 {
1053   int dns_data_offset;
1054   proto_tree *dns_tree = NULL, *field_tree;
1055   proto_item *ti, *tf;
1056   guint16    id, flags, quest, ans, auth, add;
1057   char buf[128+1];
1058   int cur_off;
1059   static const value_string opcode_vals[] = {
1060                   { OPCODE_QUERY,  "Standard query"        },
1061                   { OPCODE_IQUERY, "Inverse query"         },
1062                   { OPCODE_STATUS, "Server status request" },
1063                   { 0,              NULL                   } };
1064   static const value_string rcode_vals[] = {
1065                   { RCODE_NOERROR,   "No error"        },
1066                   { RCODE_FMTERROR,  "Format error"    },
1067                   { RCODE_SERVFAIL,  "Server failure"  },
1068                   { RCODE_NAMEERROR, "Name error"      },
1069                   { RCODE_NOTIMPL,   "Not implemented" },
1070                   { RCODE_REFUSED,   "Refused"         },
1071                   { 0,               NULL              } };
1072
1073   dns_data_offset = offset;
1074
1075   if (check_col(fd, COL_PROTOCOL))
1076     col_add_str(fd, COL_PROTOCOL, "DNS (UDP)");
1077
1078   if (pi.captured_len < DNS_HDRLEN) {
1079     col_add_str(fd, COL_INFO, "Short DNS packet");
1080     dissect_data(pd, offset, fd, tree);
1081     return;
1082   }
1083
1084   /* To do: check for errs, etc. */
1085   id    = pntohs(&pd[offset + DNS_ID]);
1086   flags = pntohs(&pd[offset + DNS_FLAGS]);
1087   quest = pntohs(&pd[offset + DNS_QUEST]);
1088   ans   = pntohs(&pd[offset + DNS_ANS]);
1089   auth  = pntohs(&pd[offset + DNS_AUTH]);
1090   add   = pntohs(&pd[offset + DNS_ADD]);
1091
1092   if (check_col(fd, COL_INFO)) {
1093     col_add_fstr(fd, COL_INFO, "%s%s",
1094                 val_to_str(flags & F_OPCODE, opcode_vals,
1095                            "Unknown operation (%x)"),
1096                 (flags & F_RESPONSE) ? " response" : "");
1097   } else {
1098     /* Set "fd" to NULL; we pass a NULL "fd" to the query and answer
1099        dissectors, as a way of saying that they shouldn't add stuff
1100        to the COL_INFO column (a call to "check_col(fd, COL_INFO)"
1101        is more expensive than a check that a pointer isn't NULL). */
1102     fd = NULL;
1103   }
1104   
1105   if (tree) {
1106     ti = proto_tree_add_item_format(tree, proto_dns, offset, 4, NULL,
1107                           (flags & F_RESPONSE) ? "DNS response" : "DNS query");
1108     
1109     dns_tree = proto_item_add_subtree(ti, ett_dns);
1110
1111     if (flags & F_RESPONSE)
1112       proto_tree_add_item_hidden(dns_tree, hf_dns_response, offset, 4, 1);
1113     else
1114       proto_tree_add_item_hidden(dns_tree, hf_dns_query, offset, 4, 1);
1115
1116     proto_tree_add_item(dns_tree, hf_dns_transaction_id, 
1117                         offset + DNS_ID, 2, id);
1118
1119     strcpy(buf, val_to_str(flags & F_OPCODE, opcode_vals, "Unknown operation"));
1120     if (flags & F_RESPONSE) {
1121       strcat(buf, " response");
1122       strcat(buf, ", ");
1123       strcat(buf, val_to_str(flags & F_RCODE, rcode_vals,
1124             "Unknown error"));
1125     }
1126     tf = proto_tree_add_item_format(dns_tree, hf_dns_flags, 
1127                                     offset + DNS_FLAGS, 2, 
1128                                     flags,
1129                                     "Flags: 0x%04x (%s)",
1130                                     flags, buf);
1131     field_tree = proto_item_add_subtree(tf, ett_dns_flags);
1132     proto_tree_add_text(field_tree, offset + DNS_FLAGS, 2, "%s",
1133        decode_boolean_bitfield(flags, F_RESPONSE,
1134             2*8, "Response", "Query"));
1135     proto_tree_add_text(field_tree, offset + DNS_FLAGS, 2, "%s",
1136        decode_enumerated_bitfield(flags, F_OPCODE,
1137             2*8, opcode_vals, "%s"));
1138     if (flags & F_RESPONSE) {
1139       proto_tree_add_text(field_tree, offset + DNS_FLAGS, 2, "%s",
1140          decode_boolean_bitfield(flags, F_AUTHORITATIVE,
1141               2*8,
1142               "Server is an authority for domain",
1143               "Server isn't an authority for domain"));
1144     }
1145     proto_tree_add_text(field_tree, offset + DNS_FLAGS, 2, "%s",
1146        decode_boolean_bitfield(flags, F_TRUNCATED,
1147             2*8,
1148             "Message is truncated",
1149             "Message is not truncated"));
1150     proto_tree_add_text(field_tree, offset + DNS_FLAGS, 2, "%s",
1151        decode_boolean_bitfield(flags, F_RECDESIRED,
1152             2*8,
1153             "Do query recursively",
1154             "Don't do query recursively"));
1155     if (flags & F_RESPONSE) {
1156       proto_tree_add_text(field_tree, offset + DNS_FLAGS, 2, "%s",
1157          decode_boolean_bitfield(flags, F_RECAVAIL,
1158               2*8,
1159               "Server can do recursive queries",
1160               "Server can't do recursive queries"));
1161       proto_tree_add_text(field_tree, offset + DNS_FLAGS, 2, "%s",
1162          decode_enumerated_bitfield(flags, F_RCODE,
1163               2*8, rcode_vals, "%s"));
1164     }
1165     proto_tree_add_item(dns_tree, hf_dns_count_questions, 
1166                         offset + DNS_QUEST, 2, quest);
1167     proto_tree_add_item(dns_tree, hf_dns_count_answers, 
1168                         offset + DNS_ANS, 2, ans);
1169     proto_tree_add_item(dns_tree, hf_dns_count_auth_rr, 
1170                         offset + DNS_AUTH, 2, auth);
1171     proto_tree_add_item(dns_tree, hf_dns_count_add_rr, 
1172                         offset + DNS_ADD, 2, add);
1173
1174   }
1175   cur_off = offset + DNS_HDRLEN;
1176
1177   if (quest > 0) {
1178     /* If this is a response, don't add information about the queries
1179        to the summary, just add information about the answers. */
1180     cur_off += dissect_query_records(pd, cur_off, dns_data_offset, quest,
1181                                         (!(flags & F_RESPONSE) ? fd : NULL),
1182                                         dns_tree);
1183   }
1184     
1185   if (ans > 0) {
1186     /* If this is a request, don't add information about the answers
1187        to the summary, just add information about the queries. */
1188     cur_off += dissect_answer_records(pd, cur_off, dns_data_offset, ans,
1189                                         ((flags & F_RESPONSE) ? fd : NULL),
1190                                         dns_tree, "Answers");
1191   }
1192     
1193   if (tree) {
1194     /* Don't add information about the authoritative name servers, or the
1195        additional records, to the summary. */
1196     if (auth > 0)
1197       cur_off += dissect_answer_records(pd, cur_off, dns_data_offset, auth,
1198           NULL, dns_tree, "Authoritative nameservers");
1199
1200     if (add > 0)
1201       cur_off += dissect_answer_records(pd, cur_off, dns_data_offset, add,
1202           NULL, dns_tree, "Additional records");
1203   }
1204 }
1205
1206 void
1207 proto_register_dns(void)
1208 {
1209   static hf_register_info hf[] = {
1210     { &hf_dns_response,
1211       { "Response",             "dns.response",  
1212         FT_BOOLEAN, BASE_NONE, NULL, 0x0,
1213         "TRUE if DNS response" }},
1214     { &hf_dns_query,
1215       { "Query",                "dns.query",  
1216         FT_BOOLEAN, BASE_NONE, NULL, 0x0,
1217         "TRUE if DNS query" }},
1218     { &hf_dns_flags,
1219       { "Flags",                "dns.flags",  
1220         FT_UINT16, BASE_HEX, NULL, 0x0,
1221         "" }},
1222     { &hf_dns_transaction_id,
1223       { "Transaction ID",       "dns.id",  
1224         FT_UINT16, BASE_HEX, NULL, 0x0,
1225         "Identification of transaction" }},
1226     { &hf_dns_count_questions,
1227       { "Questions",            "dns.count.queries",  
1228         FT_UINT16, BASE_DEC, NULL, 0x0,
1229         "Number of queries in packet" }},
1230     { &hf_dns_count_answers,
1231       { "Answer RRs",           "dns.count.answers",  
1232         FT_UINT16, BASE_DEC, NULL, 0x0,
1233         "Number of answers in packet" }},
1234     { &hf_dns_count_auth_rr,
1235       { "Authority RRs",        "dns.count.auth_rr",  
1236         FT_UINT16, BASE_DEC, NULL, 0x0,
1237         "Number of authoritative records in packet" }},
1238     { &hf_dns_count_add_rr,
1239       { "Additional RRs",       "dns.count.add_rr",  
1240         FT_UINT16, BASE_DEC, NULL, 0x0,
1241         "Number of additional records in packet" }}
1242   };
1243   static gint *ett[] = {
1244     &ett_dns,
1245     &ett_dns_qd,
1246     &ett_dns_rr,
1247     &ett_dns_qry,
1248     &ett_dns_ans,
1249     &ett_dns_flags,
1250   };
1251
1252   proto_dns = proto_register_protocol("Domain Name Service", "dns");
1253   proto_register_field_array(proto_dns, hf, array_length(hf));
1254   proto_register_subtree_array(ett, array_length(ett));
1255 }