2 * Routines for DNS packet disassembly
4 * $Id: packet-dns.c,v 1.12 1998/12/20 01:47:05 guy Exp $
6 * Ethereal - Network traffic analyzer
7 * By Gerald Combs <gerald@zing.org>
8 * Copyright 1998 Gerald Combs
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.
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.
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.
35 #ifdef HAVE_SYS_TYPES_H
36 # include <sys/types.h>
39 #ifdef HAVE_NETINET_IN_H
40 # include <netinet/in.h>
45 #include "packet-dns.h"
48 /* DNS structs and definitions */
50 typedef struct _e_dns {
60 #define T_A 1 /* host address */
61 #define T_NS 2 /* authoritative server */
62 #define T_CNAME 5 /* canonical name */
63 #define T_SOA 6 /* start of authority zone */
64 #define T_WKS 11 /* well known service */
65 #define T_PTR 12 /* domain name pointer */
66 #define T_HINFO 13 /* host information */
67 #define T_MX 15 /* mail routing information */
68 #define T_TXT 16 /* text strings */
69 #define T_AAAA 28 /* IP6 Address */
73 dns_type_name (int type)
75 char *type_names[36] = {
76 "unused", "A", "NS", "MD", "MF", "CNAME", "SOA", "MB", "MG", "MR",
77 "NULL", "WKS", "PTR", "HINFO", "MINFO", "MX", "TXT", "RP", "AFSDB",
78 "X25", "ISDN", "RT", "NSAP", "NSAP_PTR", "SIG", "KEY", "PX", "GPOS",
79 "AAAA", "LOC", "NXT", "EID", "NIMLOC", "SRV", "ATMA", "NAPTR"
83 return type_names[type];
116 dns_class_name(int class)
125 class_name = "chaos";
128 class_name = "hesiod";
131 class_name = "unknown";
139 is_compressed_name(const u_char *foo)
141 return (0xc0 == (*foo & 0xc0));
146 get_compressed_name_offset(const u_char *ptr)
148 return ((*ptr & ~0xc0) << 8) | *(ptr+1);
153 copy_one_name_component(const u_char *dataptr, char *nameptr)
158 len = n = *dataptr++;
163 *nameptr++ = *dataptr++;
170 copy_name_component_rec(const u_char *dns_data_ptr, const u_char *dataptr,
171 char *nameptr, int *real_string_len)
178 if (is_compressed_name(dataptr)) {
180 offset = get_compressed_name_offset(dataptr);
181 dataptr = dns_data_ptr + offset;
182 copy_name_component_rec(dns_data_ptr, dataptr, nameptr, &str_len);
183 *real_string_len += str_len;
188 str_len = copy_one_name_component(dataptr, nameptr);
189 *real_string_len = str_len;
190 dataptr += str_len + 1;
198 (*real_string_len)++;
202 len += copy_name_component_rec(dns_data_ptr, dataptr, nameptr, &str_len);
203 *real_string_len += str_len;
212 get_dns_name(const u_char *dns_data_ptr, const u_char *pd, int offset,
213 char *nameptr, int maxname)
216 const u_char *dataptr = pd + offset;
219 memset (nameptr, 0, maxname);
220 len = copy_name_component_rec(dns_data_ptr, dataptr, nameptr, &str_len);
227 get_dns_name_type_class (const u_char *dns_data_ptr,
240 const u_char *pd_save;
242 name_len = get_dns_name(dns_data_ptr, pd, offset, name, sizeof(name));
252 strcpy (name_ret, name);
255 *name_len_ret = name_len;
263 dissect_dns_query(const u_char *dns_data_ptr, const u_char *pd, int offset,
274 const u_char *data_start;
275 GtkWidget *q_tree, *tq;
277 data_start = dptr = pd + offset;
279 len = get_dns_name_type_class(dns_data_ptr, pd, offset, name, &name_len,
283 type_name = dns_type_name(type);
284 class_name = dns_class_name(class);
286 tq = add_item_to_tree(dns_tree, offset, len, "%s: type %s, class %s",
287 name, type_name, class_name);
288 q_tree = gtk_tree_new();
289 add_subtree(tq, q_tree, ETT_DNS_QD);
291 add_item_to_tree(q_tree, offset, name_len, "Name: %s", name);
294 add_item_to_tree(q_tree, offset, 2, "Type: %s", type_name);
297 add_item_to_tree(q_tree, offset, 2, "Class: %s", class_name);
300 return dptr - data_start;
305 add_rr_to_tree(GtkWidget *trr, int rr_type, int offset, const char *name,
306 int namelen, const char *type_name, const char *class_name, u_int ttl,
311 rr_tree = gtk_tree_new();
312 add_subtree(trr, rr_tree, rr_type);
313 add_item_to_tree(rr_tree, offset, namelen, "Name: %s", name);
315 add_item_to_tree(rr_tree, offset, 2, "Type: %s", type_name);
317 add_item_to_tree(rr_tree, offset, 2, "Class: %s", class_name);
319 add_item_to_tree(rr_tree, offset, 4, "Time to live: %u", ttl);
321 add_item_to_tree(rr_tree, offset, 2, "Data length: %u", data_len);
326 dissect_dns_answer(const u_char *dns_data_ptr, const u_char *pd, int offset,
337 const u_char *data_start;
340 GtkWidget *rr_tree, *trr;
342 data_start = dptr = pd + offset;
344 len = get_dns_name_type_class(dns_data_ptr, pd, offset, name, &name_len,
348 type_name = dns_type_name(type);
349 class_name = dns_class_name(class);
354 data_len = pntohs(dptr);
358 case T_A: /* "A" record */
359 trr = add_item_to_tree(dns_tree, offset, (dptr - data_start) + data_len,
360 "%s: type %s, class %s, addr %s",
361 name, type_name, class_name,
362 ip_to_str((guint8 *)dptr));
363 rr_tree = add_rr_to_tree(trr, ETT_DNS_RR, offset, name, name_len, type_name,
364 class_name, ttl, data_len);
365 offset += (dptr - data_start);
366 add_item_to_tree(rr_tree, offset, 4, "Addr: %s",
367 ip_to_str((guint8 *)dptr));
370 case T_NS: /* "NS" record */
372 char ns_name[MAXDNAME];
375 ns_name_len = get_dns_name(dns_data_ptr, dptr, 0, ns_name, sizeof(ns_name));
376 trr = add_item_to_tree(dns_tree, offset, (dptr - data_start) + data_len,
377 "%s: type %s, class %s, ns %s",
378 name, type_name, class_name, ns_name);
379 rr_tree = add_rr_to_tree(trr, ETT_DNS_RR, offset, name, name_len,
380 type_name, class_name, ttl, data_len);
381 offset += (dptr - data_start);
382 add_item_to_tree(rr_tree, offset, ns_name_len, "Name server: %s", ns_name);
386 /* TODO: parse more record types */
389 trr = add_item_to_tree(dns_tree, offset, (dptr - data_start) + data_len,
390 "%s: type %s, class %s",
391 name, type_name, class_name);
392 rr_tree = add_rr_to_tree(trr, ETT_DNS_RR, offset, name, name_len, type_name,
393 class_name, ttl, data_len);
394 offset += (dptr - data_start);
395 add_item_to_tree(rr_tree, offset, data_len, "Data");
400 return dptr - data_start;
404 dissect_query_records(const u_char *dns_data_ptr, int count, const u_char *pd,
405 int cur_off, GtkWidget *dns_tree)
408 GtkWidget *qatree, *ti;
411 ti = add_item_to_tree(GTK_WIDGET(dns_tree),
412 start_off, 0, "Queries");
413 qatree = gtk_tree_new();
414 add_subtree(ti, qatree, ETT_DNS_QRY);
416 cur_off += dissect_dns_query(dns_data_ptr, pd, cur_off, qatree);
417 set_item_len(ti, cur_off - start_off);
419 return cur_off - start_off;
425 dissect_answer_records(const u_char *dns_data_ptr, int count,
426 const u_char *pd, int cur_off, GtkWidget *dns_tree,
430 GtkWidget *qatree, *ti;
433 ti = add_item_to_tree(GTK_WIDGET(dns_tree),
435 qatree = gtk_tree_new();
436 add_subtree(ti, qatree, ETT_DNS_ANS);
438 cur_off += dissect_dns_answer(dns_data_ptr, pd, cur_off, qatree);
439 set_item_len(ti, cur_off - start_off);
441 return cur_off - start_off;
446 dissect_dns(const u_char *pd, int offset, frame_data *fd, GtkTree *tree) {
447 const u_char *dns_data_ptr;
449 GtkWidget *dns_tree, *ti;
450 guint16 id, flags, quest, ans, auth, add;
454 dns_data_ptr = &pd[offset];
455 dh = (e_dns *) dns_data_ptr;
457 /* To do: check for runts, errs, etc. */
458 id = ntohs(dh->dns_id);
459 flags = ntohs(dh->dns_flags);
460 quest = ntohs(dh->dns_quest);
461 ans = ntohs(dh->dns_ans);
462 auth = ntohs(dh->dns_auth);
463 add = ntohs(dh->dns_add);
465 query = ! (flags & (1 << 15));
467 if (check_col(fd, COL_PROTOCOL))
468 col_add_str(fd, COL_PROTOCOL, "DNS (UDP)");
469 if (check_col(fd, COL_INFO))
470 col_add_str(fd, COL_INFO, query ? "Query" : "Response");
473 ti = add_item_to_tree(GTK_WIDGET(tree), offset, 4,
474 query ? "DNS query" : "DNS response");
476 dns_tree = gtk_tree_new();
477 add_subtree(ti, dns_tree, ETT_DNS);
479 add_item_to_tree(dns_tree, offset, 2, "ID: 0x%04x", id);
481 add_item_to_tree(dns_tree, offset + 2, 2, "Flags: 0x%04x", flags);
482 add_item_to_tree(dns_tree, offset + 4, 2, "Questions: %d", quest);
483 add_item_to_tree(dns_tree, offset + 6, 2, "Answer RRs: %d", ans);
484 add_item_to_tree(dns_tree, offset + 8, 2, "Authority RRs: %d", auth);
485 add_item_to_tree(dns_tree, offset + 10, 2, "Additional RRs: %d", add);
487 cur_off = offset + 12;
490 cur_off += dissect_query_records(dns_data_ptr, quest, pd, cur_off,
494 cur_off += dissect_answer_records(dns_data_ptr, ans, pd, cur_off,
495 dns_tree, "Answers");
498 cur_off += dissect_answer_records(dns_data_ptr, auth, pd, cur_off,
499 dns_tree, "Authoritative nameservers");
502 cur_off += dissect_answer_records(dns_data_ptr, add, pd, cur_off,
503 dns_tree, "Additional records");