2 * Routines for DNS packet disassembly
4 * $Id: packet-dns.c,v 1.17 1999/03/23 03:14:36 gram 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.
30 #ifdef HAVE_SYS_TYPES_H
31 # include <sys/types.h>
40 #include "packet-dns.h"
44 /* DNS structs and definitions */
46 /* Offsets of fields in the DNS header. */
54 /* Length of DNS header. */
58 #define T_A 1 /* host address */
59 #define T_NS 2 /* authoritative name server */
60 #define T_MD 3 /* mail destination (obsolete) */
61 #define T_MF 4 /* mail forwarder (obsolete) */
62 #define T_CNAME 5 /* canonical name */
63 #define T_SOA 6 /* start of authority zone */
64 #define T_MB 7 /* mailbox domain name (experimental) */
65 #define T_MG 8 /* mail group member (experimental) */
66 #define T_MR 9 /* mail rename domain name (experimental) */
67 #define T_NULL 10 /* null RR (experimental) */
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_MINFO 14 /* mailbox or mail list information */
72 #define T_MX 15 /* mail routing information */
73 #define T_TXT 16 /* text strings */
74 #define T_RP 17 /* responsible person (RFC 1183) */
75 #define T_AFSDB 18 /* AFS data base location (RFC 1183) */
76 #define T_X25 19 /* X.25 address (RFC 1183) */
77 #define T_ISDN 20 /* ISDN address (RFC 1183) */
78 #define T_RT 21 /* route-through (RFC 1183) */
79 #define T_NSAP 22 /* OSI NSAP (RFC 1706) */
80 #define T_NSAP_PTR 23 /* PTR equivalent for OSI NSAP (RFC 1348 - obsolete) */
81 #define T_SIG 24 /* digital signature (RFC 2065) */
82 #define T_KEY 25 /* public key (RFC 2065) */
83 #define T_PX 26 /* pointer to X.400/RFC822 mapping info (RFC 1664) */
84 #define T_GPOS 27 /* geographical position (RFC 1712) */
85 #define T_AAAA 28 /* IPv6 address (RFC 1886) */
86 #define T_LOC 29 /* geographical location (RFC 1876) */
87 #define T_NXT 30 /* "next" name (RFC 2065) */
88 #define T_EID 31 /* ??? (Nimrod?) */
89 #define T_NIMLOC 32 /* ??? (Nimrod?) */
90 #define T_SRV 33 /* service location (RFC 2052) */
91 #define T_ATMA 34 /* ??? */
92 #define T_NAPTR 35 /* naming authority pointer (RFC 2168) */
94 /* Bit fields in the flags */
95 #define F_RESPONSE (1<<15) /* packet is response */
96 #define F_OPCODE (0xF<<11) /* query opcode */
97 #define F_AUTHORITATIVE (1<<10) /* response is authoritative */
98 #define F_TRUNCATED (1<<9) /* response is truncated */
99 #define F_RECDESIRED (1<<8) /* recursion desired */
100 #define F_RECAVAIL (1<<7) /* recursion available */
101 #define F_RCODE (0xF<<0) /* reply code */
104 #define OPCODE_QUERY (0<<11) /* standard query */
105 #define OPCODE_IQUERY (1<<11) /* inverse query */
106 #define OPCODE_STATUS (2<<11) /* server status request */
109 #define RCODE_NOERROR (0<<0)
110 #define RCODE_FMTERROR (1<<0)
111 #define RCODE_SERVFAIL (2<<0)
112 #define RCODE_NAMEERROR (3<<0)
113 #define RCODE_NOTIMPL (4<<0)
114 #define RCODE_REFUSED (5<<0)
116 /* See RFC 1035 for all RR types for which no RFC is listed. */
118 dns_type_name (int type)
120 char *type_names[36] = {
139 "AFSDB", /* RFC 1183 */
140 "X25", /* RFC 1183 */
141 "ISDN", /* RFC 1183 */
143 "NSAP", /* RFC 1706 */
144 "NSAP-PTR", /* RFC 1348 */
145 "SIG", /* RFC 2065 */
146 "KEY", /* RFC 2065 */
148 "GPOS", /* RFC 1712 */
149 "AAAA", /* RFC 1886 */
150 "LOC", /* RFC 1876 */
151 "NXT", /* RFC 2065 */
154 "SRV", /* RFC 2052 */
156 "NAPTR" /* RFC 2168 */
160 return type_names[type];
177 return "IXFR"; /* RFC 1995 */
193 dns_long_type_name (int type)
195 char *type_names[36] = {
198 "Authoritative name server",
201 "Canonical name for an alias",
202 "Start of zone of authority",
203 "Mailbox domain name",
205 "Mail rename domain name",
206 "Null resource record",
207 "Well-known service description",
208 "Domain name pointer",
210 "Mailbox or mail list information",
213 "Responsible person", /* RFC 1183 */
214 "AFS data base location", /* RFC 1183 */
215 "X.25 address", /* RFC 1183 */
216 "ISDN number", /* RFC 1183 */
217 "Route through", /* RFC 1183 */
218 "OSI NSAP", /* RFC 1706 */
219 "OSI NSAP name pointer", /* RFC 1348 */
220 "Signature", /* RFC 2065 */
221 "Public key", /* RFC 2065 */
222 "Pointer to X.400/RFC822 mapping info", /* RFC 1664 */
223 "Geographical position", /* RFC 1712 */
224 "IPv6 address", /* RFC 1886 */
225 "Location", /* RFC 1876 */
226 "Next", /* RFC 2065 */
229 "Service location", /* RFC 2052 */
231 "Naming authority pointer" /* RFC 2168 */
233 static char unkbuf[7+1+2+1+4+1+1+10+1+1]; /* "Unknown RR type (%d)" */
236 return type_names[type];
253 return "Request for incremental zone transfer"; /* RFC 1995 */
255 return "Request for full zone transfer";
257 return "Request for mailbox-related records";
259 return "Request for mail agent resource records";
261 return "Request for all records";
264 sprintf(unkbuf, "Unknown RR type (%d)", type);
270 dns_class_name(int class)
279 class_name = "chaos";
282 class_name = "hesiod";
285 class_name = "unknown";
293 is_compressed_name(const u_char *foo)
295 return (0xc0 == (*foo & 0xc0));
300 get_compressed_name_offset(const u_char *ptr)
302 return ((*ptr & ~0xc0) << 8) | *(ptr+1);
307 copy_one_name_component(const u_char *dataptr, char *nameptr)
312 len = n = *dataptr++;
317 *nameptr++ = *dataptr++;
324 copy_name_component_rec(const u_char *dns_data_ptr, const u_char *dataptr,
325 char *nameptr, int *real_string_len)
332 if (is_compressed_name(dataptr)) {
334 offset = get_compressed_name_offset(dataptr);
335 dataptr = dns_data_ptr + offset;
336 copy_name_component_rec(dns_data_ptr, dataptr, nameptr, &str_len);
337 *real_string_len += str_len;
342 str_len = copy_one_name_component(dataptr, nameptr);
343 *real_string_len = str_len;
344 dataptr += str_len + 1;
352 (*real_string_len)++;
356 len += copy_name_component_rec(dns_data_ptr, dataptr, nameptr, &str_len);
357 *real_string_len += str_len;
366 get_dns_name(const u_char *dns_data_ptr, const u_char *pd, int offset,
367 char *nameptr, int maxname)
370 const u_char *dataptr = pd + offset;
373 memset (nameptr, 0, maxname);
374 len = copy_name_component_rec(dns_data_ptr, dataptr, nameptr, &str_len);
381 get_dns_name_type_class (const u_char *dns_data_ptr,
394 const u_char *pd_save;
396 name_len = get_dns_name(dns_data_ptr, pd, offset, name, sizeof(name));
406 strcpy (name_ret, name);
409 *name_len_ret = name_len;
417 dissect_dns_query(const u_char *dns_data_ptr, const u_char *pd, int offset,
418 proto_tree *dns_tree)
427 char *long_type_name;
429 const u_char *data_start;
433 data_start = dptr = pd + offset;
435 len = get_dns_name_type_class(dns_data_ptr, pd, offset, name, &name_len,
439 type_name = dns_type_name(type);
440 class_name = dns_class_name(class);
441 long_type_name = dns_long_type_name(type);
443 tq = proto_tree_add_item(dns_tree, offset, len, "%s: type %s, class %s",
444 name, type_name, class_name);
445 q_tree = proto_tree_new();
446 proto_item_add_subtree(tq, q_tree, ETT_DNS_QD);
448 proto_tree_add_item(q_tree, offset, name_len, "Name: %s", name);
451 proto_tree_add_item(q_tree, offset, 2, "Type: %s", long_type_name);
454 proto_tree_add_item(q_tree, offset, 2, "Class: %s", class_name);
457 return dptr - data_start;
462 add_rr_to_tree(proto_item *trr, int rr_type, int offset, const char *name,
463 int namelen, const char *type_name, const char *class_name, u_int ttl,
468 rr_tree = proto_tree_new();
469 proto_item_add_subtree(trr, rr_tree, rr_type);
470 proto_tree_add_item(rr_tree, offset, namelen, "Name: %s", name);
472 proto_tree_add_item(rr_tree, offset, 2, "Type: %s", type_name);
474 proto_tree_add_item(rr_tree, offset, 2, "Class: %s", class_name);
476 proto_tree_add_item(rr_tree, offset, 4, "Time to live: %s",
477 time_secs_to_str(ttl));
479 proto_tree_add_item(rr_tree, offset, 2, "Data length: %u", data_len);
484 dissect_dns_answer(const u_char *dns_data_ptr, const u_char *pd, int offset,
485 proto_tree *dns_tree)
494 char *long_type_name;
496 const u_char *data_start;
502 data_start = dptr = pd + offset;
504 len = get_dns_name_type_class(dns_data_ptr, pd, offset, name, &name_len,
508 type_name = dns_type_name(type);
509 class_name = dns_class_name(class);
510 long_type_name = dns_long_type_name(type);
515 data_len = pntohs(dptr);
519 case T_A: /* "A" record */
520 trr = proto_tree_add_item(dns_tree, offset, (dptr - data_start) + data_len,
521 "%s: type %s, class %s, addr %s",
522 name, type_name, class_name,
523 ip_to_str((guint8 *)dptr));
524 rr_tree = add_rr_to_tree(trr, ETT_DNS_RR, offset, name, name_len,
525 long_type_name, class_name, ttl, data_len);
526 offset += (dptr - data_start);
527 proto_tree_add_item(rr_tree, offset, 4, "Addr: %s",
528 ip_to_str((guint8 *)dptr));
531 case T_NS: /* "NS" record */
533 char ns_name[MAXDNAME];
536 ns_name_len = get_dns_name(dns_data_ptr, dptr, 0, ns_name, sizeof(ns_name));
537 trr = proto_tree_add_item(dns_tree, offset, (dptr - data_start) + data_len,
538 "%s: type %s, class %s, ns %s",
539 name, type_name, class_name, ns_name);
540 rr_tree = add_rr_to_tree(trr, ETT_DNS_RR, offset, name, name_len,
541 long_type_name, class_name, ttl, data_len);
542 offset += (dptr - data_start);
543 proto_tree_add_item(rr_tree, offset, ns_name_len, "Name server: %s", ns_name);
547 case T_CNAME: /* "CNAME" record */
549 char cname[MAXDNAME];
552 cname_len = get_dns_name(dns_data_ptr, dptr, 0, cname, sizeof(cname));
553 trr = proto_tree_add_item(dns_tree, offset, (dptr - data_start) + data_len,
554 "%s: type %s, class %s, cname %s",
555 name, type_name, class_name, cname);
556 rr_tree = add_rr_to_tree(trr, ETT_DNS_RR, offset, name, name_len,
557 long_type_name, class_name, ttl, data_len);
558 offset += (dptr - data_start);
559 proto_tree_add_item(rr_tree, offset, data_len, "Primary name: %s", cname);
563 case T_PTR: /* "PTR" record */
565 char pname[MAXDNAME];
568 pname_len = get_dns_name(dns_data_ptr, dptr, 0, pname, sizeof(pname));
569 trr = proto_tree_add_item(dns_tree, offset, (dptr - data_start) + data_len,
570 "%s: type %s, class %s, ptr %s",
571 name, type_name, class_name, pname);
572 rr_tree = add_rr_to_tree(trr, ETT_DNS_RR, offset, name, name_len,
573 long_type_name, class_name, ttl, data_len);
574 offset += (dptr - data_start);
575 proto_tree_add_item(rr_tree, offset, data_len, "Domain name: %s", pname);
580 /* TODO: parse more record types */
583 trr = proto_tree_add_item(dns_tree, offset, (dptr - data_start) + data_len,
584 "%s: type %s, class %s",
585 name, type_name, class_name);
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 offset += (dptr - data_start);
589 proto_tree_add_item(rr_tree, offset, data_len, "Data");
594 return dptr - data_start;
598 dissect_query_records(const u_char *dns_data_ptr, int count, const u_char *pd,
599 int cur_off, proto_tree *dns_tree)
606 ti = proto_tree_add_item(dns_tree, start_off, 0, "Queries");
607 qatree = proto_tree_new();
608 proto_item_add_subtree(ti, qatree, ETT_DNS_QRY);
610 cur_off += dissect_dns_query(dns_data_ptr, pd, cur_off, qatree);
611 proto_item_set_len(ti, cur_off - start_off);
613 return cur_off - start_off;
619 dissect_answer_records(const u_char *dns_data_ptr, int count,
620 const u_char *pd, int cur_off, proto_tree *dns_tree,
628 ti = proto_tree_add_item(dns_tree, start_off, 0, name);
629 qatree = proto_tree_new();
630 proto_item_add_subtree(ti, qatree, ETT_DNS_ANS);
632 cur_off += dissect_dns_answer(dns_data_ptr, pd, cur_off, qatree);
633 proto_item_set_len(ti, cur_off - start_off);
635 return cur_off - start_off;
640 dissect_dns(const u_char *pd, int offset, frame_data *fd, proto_tree *tree) {
641 const u_char *dns_data_ptr;
642 proto_tree *dns_tree, *field_tree;
644 guint16 id, flags, quest, ans, auth, add;
647 static const value_string opcode_vals[] = {
648 { OPCODE_QUERY, "Standard query" },
649 { OPCODE_IQUERY, "Inverse query" },
650 { OPCODE_STATUS, "Server status request" },
652 static const value_string rcode_vals[] = {
653 { RCODE_NOERROR, "No error" },
654 { RCODE_FMTERROR, "Format error" },
655 { RCODE_SERVFAIL, "Server failure" },
656 { RCODE_NAMEERROR, "Name error" },
657 { RCODE_NOTIMPL, "Not implemented" },
658 { RCODE_REFUSED, "Refused" },
661 dns_data_ptr = &pd[offset];
663 /* To do: check for runts, errs, etc. */
664 id = pntohs(&pd[offset + DNS_ID]);
665 flags = pntohs(&pd[offset + DNS_FLAGS]);
666 quest = pntohs(&pd[offset + DNS_QUEST]);
667 ans = pntohs(&pd[offset + DNS_ANS]);
668 auth = pntohs(&pd[offset + DNS_AUTH]);
669 add = pntohs(&pd[offset + DNS_ADD]);
671 if (check_col(fd, COL_PROTOCOL))
672 col_add_str(fd, COL_PROTOCOL, "DNS (UDP)");
673 if (check_col(fd, COL_INFO)) {
674 col_add_fstr(fd, COL_INFO, "%s%s",
675 val_to_str(flags & F_OPCODE, opcode_vals,
676 "Unknown operation (%x)"),
677 (flags & F_RESPONSE) ? " response" : "");
681 ti = proto_tree_add_item(tree, offset, 4,
682 (flags & F_RESPONSE) ? "DNS response" : "DNS query");
684 dns_tree = proto_tree_new();
685 proto_item_add_subtree(ti, dns_tree, ETT_DNS);
687 proto_tree_add_item(dns_tree, offset + DNS_ID, 2, "Transaction ID: 0x%04x",
690 strcpy(buf, val_to_str(flags & F_OPCODE, opcode_vals, "Unknown operation"));
691 if (flags & F_RESPONSE) {
692 strcat(buf, " response");
694 strcat(buf, val_to_str(flags & F_RCODE, rcode_vals,
697 tf = proto_tree_add_item(dns_tree, offset + DNS_FLAGS, 2, "Flags: 0x%04x (%s)",
699 field_tree = proto_tree_new();
700 proto_item_add_subtree(tf, field_tree, ETT_DNS_FLAGS);
701 proto_tree_add_item(field_tree, offset + DNS_FLAGS, 2, "%s",
702 decode_boolean_bitfield(flags, F_RESPONSE,
703 2*8, "Response", "Query"));
704 proto_tree_add_item(field_tree, offset + DNS_FLAGS, 2, "%s",
705 decode_enumerated_bitfield(flags, F_OPCODE,
706 2*8, opcode_vals, "%s"));
707 if (flags & F_RESPONSE) {
708 proto_tree_add_item(field_tree, offset + DNS_FLAGS, 2, "%s",
709 decode_boolean_bitfield(flags, F_AUTHORITATIVE,
711 "Server is an authority for domain",
712 "Server isn't an authority for domain"));
714 proto_tree_add_item(field_tree, offset + DNS_FLAGS, 2, "%s",
715 decode_boolean_bitfield(flags, F_TRUNCATED,
717 "Message is truncated",
718 "Message is not truncated"));
719 proto_tree_add_item(field_tree, offset + DNS_FLAGS, 2, "%s",
720 decode_boolean_bitfield(flags, F_RECDESIRED,
722 "Do query recursively",
723 "Don't do query recursively"));
724 if (flags & F_RESPONSE) {
725 proto_tree_add_item(field_tree, offset + DNS_FLAGS, 2, "%s",
726 decode_boolean_bitfield(flags, F_RECAVAIL,
728 "Server can do recursive queries",
729 "Server can't do recursive queries"));
730 proto_tree_add_item(field_tree, offset + DNS_FLAGS, 2, "%s",
731 decode_enumerated_bitfield(flags, F_RCODE,
732 2*8, rcode_vals, "%s"));
734 proto_tree_add_item(dns_tree, offset + DNS_QUEST, 2, "Questions: %d", quest);
735 proto_tree_add_item(dns_tree, offset + DNS_ANS, 2, "Answer RRs: %d", ans);
736 proto_tree_add_item(dns_tree, offset + DNS_AUTH, 2, "Authority RRs: %d", auth);
737 proto_tree_add_item(dns_tree, offset + DNS_ADD, 2, "Additional RRs: %d", add);
739 cur_off = offset + DNS_HDRLEN;
742 cur_off += dissect_query_records(dns_data_ptr, quest, pd, cur_off,
746 cur_off += dissect_answer_records(dns_data_ptr, ans, pd, cur_off,
747 dns_tree, "Answers");
750 cur_off += dissect_answer_records(dns_data_ptr, auth, pd, cur_off,
751 dns_tree, "Authoritative nameservers");
754 cur_off += dissect_answer_records(dns_data_ptr, add, pd, cur_off,
755 dns_tree, "Additional records");