Add Network Monitor and "iptrace" to the list of capture file formats
[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.15 1999/01/28 21:29:35 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 #include <gtk/gtk.h>
31
32 #include <stdio.h>
33 #include <string.h>
34 #include <memory.h>
35
36 #ifdef HAVE_SYS_TYPES_H
37 # include <sys/types.h>
38 #endif
39
40 #ifdef HAVE_NETINET_IN_H
41 # include <netinet/in.h>
42 #endif
43
44 #include "ethereal.h"
45 #include "packet.h"
46 #include "packet-dns.h"
47 #include "util.h"
48
49
50 /* DNS structs and definitions */
51
52 /* Offsets of fields in the DNS header. */
53 #define DNS_ID          0
54 #define DNS_FLAGS       2
55 #define DNS_QUEST       4
56 #define DNS_ANS 6
57 #define DNS_AUTH        8
58 #define DNS_ADD 10
59
60 /* Length of DNS header. */
61 #define DNS_HDRLEN      12
62
63 /* type values  */
64 #define T_A             1               /* host address */
65 #define T_NS            2               /* authoritative server */
66 #define T_CNAME         5               /* canonical name */
67 #define T_SOA           6               /* start of authority zone */
68 #define T_WKS           11              /* well known service */
69 #define T_PTR           12              /* domain name pointer */
70 #define T_HINFO         13              /* host information */
71 #define T_MX            15              /* mail routing information */
72 #define T_TXT           16              /* text strings */
73 #define T_AAAA          28              /* IP6 Address */
74
75 /* Bit fields in the flags */
76 #define F_RESPONSE      (1<<15)         /* packet is response */
77 #define F_OPCODE        (0xF<<11)       /* query opcode */
78 #define F_AUTHORITATIVE (1<<10)         /* response is authoritative */
79 #define F_TRUNCATED     (1<<9)          /* response is truncated */
80 #define F_RECDESIRED    (1<<8)          /* recursion desired */
81 #define F_RECAVAIL      (1<<7)          /* recursion available */
82 #define F_RCODE         (0xF<<0)        /* reply code */
83
84 /* Opcodes */
85 #define OPCODE_QUERY    (0<<11)         /* standard query */
86 #define OPCODE_IQUERY   (1<<11)         /* inverse query */
87 #define OPCODE_STATUS   (2<<11)         /* server status request */
88
89 /* Reply codes */
90 #define RCODE_NOERROR   (0<<0)
91 #define RCODE_FMTERROR  (1<<0)
92 #define RCODE_SERVFAIL  (2<<0)
93 #define RCODE_NAMEERROR (3<<0)
94 #define RCODE_NOTIMPL   (4<<0)
95 #define RCODE_REFUSED   (5<<0)
96
97 static char *
98 dns_type_name (int type)
99 {
100   char *type_names[36] = {
101     "unused", "A", "NS", "MD", "MF", "CNAME", "SOA", "MB", "MG", "MR",
102     "NULL", "WKS", "PTR", "HINFO", "MINFO", "MX", "TXT", "RP", "AFSDB",
103     "X25", "ISDN", "RT", "NSAP", "NSAP_PTR", "SIG", "KEY", "PX", "GPOS",
104     "AAAA", "LOC", "NXT", "EID", "NIMLOC", "SRV", "ATMA", "NAPTR"
105   };
106   
107   if (type <= 35)
108     return type_names[type];
109   
110   /* special cases */
111   switch (type) 
112     {
113       /* non standard  */
114     case 100:
115       return "UINFO";
116     case 101:
117       return "UID";
118     case 102:
119       return "GID";
120     case 103:
121       return "UNSPEC";
122       
123       /* queries  */
124     case 251:
125       return "IXFR";
126     case 252:
127       return "AXFR";
128     case 253:
129       return "MAILB";
130     case 254:
131       return "MAILA";
132     case 255:
133       return "ANY";
134     }
135   
136   return "unknown";
137 }
138
139
140 char *
141 dns_class_name(int class)
142 {
143   char *class_name;
144   
145   switch (class) {
146   case 1:
147     class_name = "inet";
148     break;
149   case 3:
150     class_name = "chaos";
151     break;
152   case 4:
153     class_name = "hesiod";
154     break;
155   default:
156     class_name = "unknown";
157   }
158
159   return class_name;
160 }
161   
162
163 static int
164 is_compressed_name(const u_char *foo)
165 {
166   return (0xc0 == (*foo & 0xc0));
167 }
168
169
170 static int
171 get_compressed_name_offset(const u_char *ptr)
172 {
173   return ((*ptr & ~0xc0) << 8) | *(ptr+1);
174 }
175
176
177 static int
178 copy_one_name_component(const u_char *dataptr, char *nameptr)
179 {
180   int len;
181   int n;
182   
183   len = n  = *dataptr++;
184   if (0 == len)
185     return 0;
186   
187   while (n-- > 0)
188     *nameptr++ = *dataptr++;
189
190   return len;
191 }
192
193
194 static int
195 copy_name_component_rec(const u_char *dns_data_ptr, const u_char *dataptr,
196   char *nameptr, int *real_string_len)
197 {
198   int len = 0;
199   int str_len;
200   int offset;
201   int compress = 0;
202   
203   if (is_compressed_name(dataptr)) {
204     compress = 1;
205     offset = get_compressed_name_offset(dataptr);
206     dataptr = dns_data_ptr + offset;
207     copy_name_component_rec(dns_data_ptr, dataptr, nameptr, &str_len);
208     *real_string_len += str_len;
209     nameptr += str_len;
210     len = 2;
211   }
212   else {
213     str_len = copy_one_name_component(dataptr, nameptr);
214     *real_string_len = str_len;
215     dataptr += str_len + 1;
216     len     += str_len + 1;
217     nameptr += str_len;
218   }
219
220   if (compress)
221     return len;
222   
223   (*real_string_len)++;
224
225   if (*dataptr > 0) {
226     *nameptr++ = '.';
227     len += copy_name_component_rec(dns_data_ptr, dataptr, nameptr, &str_len);
228     *real_string_len += str_len;
229     return len;
230   }
231
232   return len + 1;
233 }
234
235
236 int
237 get_dns_name(const u_char *dns_data_ptr, const u_char *pd, int offset,
238   char *nameptr, int maxname)
239 {
240   int len;
241   const u_char *dataptr = pd + offset;
242   int str_len = 0;
243
244   memset (nameptr, 0, maxname);
245   len = copy_name_component_rec(dns_data_ptr, dataptr, nameptr, &str_len);
246   
247   return len;
248 }
249
250
251 static int
252 get_dns_name_type_class (const u_char *dns_data_ptr,
253                          const u_char *pd,
254                          int offset,
255                          char *name_ret,
256                          int *name_len_ret,
257                          int *type_ret,
258                          int *class_ret)
259 {
260   int len;
261   int name_len;
262   int type;
263   int class;
264   char name[MAXDNAME];
265   const u_char *pd_save;
266
267   name_len = get_dns_name(dns_data_ptr, pd, offset, name, sizeof(name));
268   pd += offset;
269   pd_save = pd;
270   pd += name_len;
271   
272   type = pntohs(pd);
273   pd += 2;
274   class = pntohs(pd);
275   pd += 2;
276
277   strcpy (name_ret, name);
278   *type_ret = type;
279   *class_ret = class;
280   *name_len_ret = name_len;
281
282   len = pd - pd_save;
283   return len;
284 }
285
286
287 static int
288 dissect_dns_query(const u_char *dns_data_ptr, const u_char *pd, int offset,
289   GtkWidget *dns_tree)
290 {
291   int len;
292   char name[MAXDNAME];
293   int name_len;
294   int type;
295   int class;
296   char *class_name;
297   char *type_name;
298   const u_char *dptr;
299   const u_char *data_start;
300   GtkWidget *q_tree, *tq;
301
302   data_start = dptr = pd + offset;
303
304   len = get_dns_name_type_class(dns_data_ptr, pd, offset, name, &name_len,
305     &type, &class);
306   dptr += len;
307
308   type_name = dns_type_name(type);
309   class_name = dns_class_name(class);
310
311   tq = add_item_to_tree(dns_tree, offset, len, "%s: type %s, class %s", 
312                    name, type_name, class_name);
313   q_tree = gtk_tree_new();
314   add_subtree(tq, q_tree, ETT_DNS_QD);
315
316   add_item_to_tree(q_tree, offset, name_len, "Name: %s", name);
317   offset += name_len;
318
319   add_item_to_tree(q_tree, offset, 2, "Type: %s", type_name);
320   offset += 2;
321
322   add_item_to_tree(q_tree, offset, 2, "Class: %s", class_name);
323   offset += 2;
324   
325   return dptr - data_start;
326 }
327
328
329 GtkWidget *
330 add_rr_to_tree(GtkWidget *trr, int rr_type, int offset, const char *name,
331   int namelen, const char *type_name, const char *class_name, u_int ttl,
332   u_short data_len)
333 {
334   GtkWidget *rr_tree;
335
336   rr_tree = gtk_tree_new();
337   add_subtree(trr, rr_tree, rr_type);
338   add_item_to_tree(rr_tree, offset, namelen, "Name: %s", name);
339   offset += namelen;
340   add_item_to_tree(rr_tree, offset, 2, "Type: %s", type_name);
341   offset += 2;
342   add_item_to_tree(rr_tree, offset, 2, "Class: %s", class_name);
343   offset += 2;
344   add_item_to_tree(rr_tree, offset, 4, "Time to live: %s",
345                                                 time_secs_to_str(ttl));
346   offset += 4;
347   add_item_to_tree(rr_tree, offset, 2, "Data length: %u", data_len);
348   return rr_tree;
349 }
350
351 static int
352 dissect_dns_answer(const u_char *dns_data_ptr, const u_char *pd, int offset,
353   GtkWidget *dns_tree)
354 {
355   int len;
356   char name[MAXDNAME];
357   int name_len;
358   int type;
359   int class;
360   char *class_name;
361   char *type_name;
362   const u_char *dptr;
363   const u_char *data_start;
364   u_int ttl;
365   u_short data_len;
366   GtkWidget *rr_tree, *trr;
367
368   data_start = dptr = pd + offset;
369
370   len = get_dns_name_type_class(dns_data_ptr, pd, offset, name, &name_len,
371     &type, &class);
372   dptr += len;
373
374   type_name = dns_type_name(type);
375   class_name = dns_class_name(class);
376
377   ttl = pntohl(dptr);
378   dptr += 4;
379
380   data_len = pntohs(dptr);
381   dptr += 2;
382
383   switch (type) {
384   case T_A:             /* "A" record */
385     trr = add_item_to_tree(dns_tree, offset, (dptr - data_start) + data_len,
386                      "%s: type %s, class %s, addr %s",
387                      name, type_name, class_name,
388                      ip_to_str((guint8 *)dptr));
389     rr_tree = add_rr_to_tree(trr, ETT_DNS_RR, offset, name, name_len, type_name,
390                      class_name, ttl, data_len);
391     offset += (dptr - data_start);
392     add_item_to_tree(rr_tree, offset, 4, "Addr: %s",
393                      ip_to_str((guint8 *)dptr));
394     break;
395
396   case T_NS:            /* "NS" record */
397     {
398       char ns_name[MAXDNAME];
399       int ns_name_len;
400       
401       ns_name_len = get_dns_name(dns_data_ptr, dptr, 0, ns_name, sizeof(ns_name));
402       trr = add_item_to_tree(dns_tree, offset, (dptr - data_start) + data_len,
403                        "%s: type %s, class %s, ns %s",
404                        name, type_name, class_name, ns_name);
405       rr_tree = add_rr_to_tree(trr, ETT_DNS_RR, offset, name, name_len,
406                        type_name, class_name, ttl, data_len);
407       offset += (dptr - data_start);
408       add_item_to_tree(rr_tree, offset, ns_name_len, "Name server: %s", ns_name);
409     }
410     break;
411
412     /* TODO: parse more record types */
413       
414   default:
415     trr = add_item_to_tree(dns_tree, offset, (dptr - data_start) + data_len,
416                      "%s: type %s, class %s",
417                      name, type_name, class_name);
418     rr_tree = add_rr_to_tree(trr, ETT_DNS_RR, offset, name, name_len, type_name,
419                        class_name, ttl, data_len);
420     offset += (dptr - data_start);
421     add_item_to_tree(rr_tree, offset, data_len, "Data");
422   }
423   
424   dptr += data_len;
425         
426   return dptr - data_start;
427 }
428
429 static int
430 dissect_query_records(const u_char *dns_data_ptr, int count, const u_char *pd, 
431                       int cur_off, GtkWidget *dns_tree)
432 {
433   int start_off;
434   GtkWidget *qatree, *ti;
435   
436   start_off = cur_off;
437   ti = add_item_to_tree(GTK_WIDGET(dns_tree), 
438                         start_off, 0, "Queries");
439   qatree = gtk_tree_new();
440   add_subtree(ti, qatree, ETT_DNS_QRY);
441   while (count-- > 0)
442     cur_off += dissect_dns_query(dns_data_ptr, pd, cur_off, qatree);
443   set_item_len(ti, cur_off - start_off);
444
445   return cur_off - start_off;
446 }
447
448
449
450 static int
451 dissect_answer_records(const u_char *dns_data_ptr, int count,
452                        const u_char *pd, int cur_off, GtkWidget *dns_tree,
453                        char *name)
454 {
455   int start_off;
456   GtkWidget *qatree, *ti;
457   
458   start_off = cur_off;
459   ti = add_item_to_tree(GTK_WIDGET(dns_tree),
460                         start_off, 0, name);
461   qatree = gtk_tree_new();
462   add_subtree(ti, qatree, ETT_DNS_ANS);
463   while (count-- > 0)
464     cur_off += dissect_dns_answer(dns_data_ptr, pd, cur_off, qatree);
465   set_item_len(ti, cur_off - start_off);
466
467   return cur_off - start_off;
468 }
469
470
471 void
472 dissect_dns(const u_char *pd, int offset, frame_data *fd, GtkTree *tree) {
473   const u_char *dns_data_ptr;
474   GtkWidget *dns_tree, *ti, *field_tree, *tf;
475   guint16    id, flags, quest, ans, auth, add;
476   char buf[128+1];
477   int cur_off;
478   static const value_string opcode_vals[] = {
479                   { OPCODE_QUERY,  "Standard query"        },
480                   { OPCODE_IQUERY, "Inverse query"         },
481                   { OPCODE_STATUS, "Server status request" },
482                   { 0,              NULL                   } };
483   static const value_string rcode_vals[] = {
484                   { RCODE_NOERROR,   "No error"        },
485                   { RCODE_FMTERROR,  "Format error"    },
486                   { RCODE_SERVFAIL,  "Server failure"  },
487                   { RCODE_NAMEERROR, "Name error"      },
488                   { RCODE_NOTIMPL,   "Not implemented" },
489                   { RCODE_REFUSED,   "Refused"         },
490                   { 0,               NULL              } };
491
492   dns_data_ptr = &pd[offset];
493
494   /* To do: check for runts, errs, etc. */
495   id    = pntohs(&pd[offset + DNS_ID]);
496   flags = pntohs(&pd[offset + DNS_FLAGS]);
497   quest = pntohs(&pd[offset + DNS_QUEST]);
498   ans   = pntohs(&pd[offset + DNS_ANS]);
499   auth  = pntohs(&pd[offset + DNS_AUTH]);
500   add   = pntohs(&pd[offset + DNS_ADD]);
501   
502   if (check_col(fd, COL_PROTOCOL))
503     col_add_str(fd, COL_PROTOCOL, "DNS (UDP)");
504   if (check_col(fd, COL_INFO)) {
505     col_add_fstr(fd, COL_INFO, "%s%s",
506                 val_to_str(flags & F_OPCODE, opcode_vals,
507                            "Unknown operation (%x)"),
508                 (flags & F_RESPONSE) ? " response" : "");
509   }
510   
511   if (tree) {
512     ti = add_item_to_tree(GTK_WIDGET(tree), offset, 4,
513                           (flags & F_RESPONSE) ? "DNS response" : "DNS query");
514     
515     dns_tree = gtk_tree_new();
516     add_subtree(ti, dns_tree, ETT_DNS);
517     
518     add_item_to_tree(dns_tree, offset + DNS_ID, 2, "Transaction ID: 0x%04x",
519                         id);
520
521     strcpy(buf, val_to_str(flags & F_OPCODE, opcode_vals, "Unknown operation"));
522     if (flags & F_RESPONSE) {
523       strcat(buf, " response");
524       strcat(buf, ", ");
525       strcat(buf, val_to_str(flags & F_RCODE, rcode_vals,
526             "Unknown error"));
527     }
528     tf = add_item_to_tree(dns_tree, offset + DNS_FLAGS, 2, "Flags: 0x%04x (%s)",
529                           flags, buf);
530     field_tree = gtk_tree_new();
531     add_subtree(tf, field_tree, ETT_DNS_FLAGS);
532     add_item_to_tree(field_tree, offset + DNS_FLAGS, 2, "%s",
533        decode_boolean_bitfield(flags, F_RESPONSE,
534             2*8, "Response", "Query"));
535     add_item_to_tree(field_tree, offset + DNS_FLAGS, 2, "%s",
536        decode_enumerated_bitfield(flags, F_OPCODE,
537             2*8, opcode_vals, "%s"));
538     if (flags & F_RESPONSE) {
539       add_item_to_tree(field_tree, offset + DNS_FLAGS, 2, "%s",
540          decode_boolean_bitfield(flags, F_AUTHORITATIVE,
541               2*8,
542               "Server is an authority for domain",
543               "Server isn't an authority for domain"));
544     }
545     add_item_to_tree(field_tree, offset + DNS_FLAGS, 2, "%s",
546        decode_boolean_bitfield(flags, F_TRUNCATED,
547             2*8,
548             "Message is truncated",
549             "Message is not truncated"));
550     add_item_to_tree(field_tree, offset + DNS_FLAGS, 2, "%s",
551        decode_boolean_bitfield(flags, F_RECDESIRED,
552             2*8,
553             "Do query recursively",
554             "Don't do query recursively"));
555     if (flags & F_RESPONSE) {
556       add_item_to_tree(field_tree, offset + DNS_FLAGS, 2, "%s",
557          decode_boolean_bitfield(flags, F_RECAVAIL,
558               2*8,
559               "Server can do recursive queries",
560               "Server can't do recursive queries"));
561       add_item_to_tree(field_tree, offset + DNS_FLAGS, 2, "%s",
562          decode_enumerated_bitfield(flags, F_RCODE,
563               2*8, rcode_vals, "%s"));
564     }
565     add_item_to_tree(dns_tree, offset + DNS_QUEST, 2, "Questions: %d", quest);
566     add_item_to_tree(dns_tree, offset + DNS_ANS, 2, "Answer RRs: %d", ans);
567     add_item_to_tree(dns_tree, offset + DNS_AUTH, 2, "Authority RRs: %d", auth);
568     add_item_to_tree(dns_tree, offset + DNS_ADD, 2, "Additional RRs: %d", add);
569
570     cur_off = offset + DNS_HDRLEN;
571     
572     if (quest > 0)
573       cur_off += dissect_query_records(dns_data_ptr, quest, pd, cur_off,
574                                         dns_tree);
575     
576     if (ans > 0)
577       cur_off += dissect_answer_records(dns_data_ptr, ans, pd, cur_off,
578           dns_tree, "Answers");
579     
580     if (auth > 0)
581       cur_off += dissect_answer_records(dns_data_ptr, auth, pd, cur_off,
582           dns_tree, "Authoritative nameservers");
583
584     if (add > 0)
585       cur_off += dissect_answer_records(dns_data_ptr, add, pd, cur_off,
586           dns_tree, "Additional records");
587   }
588 }