2 * Routines for DNS packet disassembly
4 * $Id: packet-dns.c,v 1.20 1999/07/29 05:46:53 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"
43 static int proto_dns = -1;
45 /* DNS structs and definitions */
47 /* Offsets of fields in the DNS header. */
55 /* Length of DNS header. */
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) */
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 */
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 */
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)
117 /* See RFC 1035 for all RR types for which no RFC is listed. */
119 dns_type_name (int type)
121 char *type_names[36] = {
140 "AFSDB", /* RFC 1183 */
141 "X25", /* RFC 1183 */
142 "ISDN", /* RFC 1183 */
144 "NSAP", /* RFC 1706 */
145 "NSAP-PTR", /* RFC 1348 */
146 "SIG", /* RFC 2065 */
147 "KEY", /* RFC 2065 */
149 "GPOS", /* RFC 1712 */
150 "AAAA", /* RFC 1886 */
151 "LOC", /* RFC 1876 */
152 "NXT", /* RFC 2065 */
155 "SRV", /* RFC 2052 */
157 "NAPTR" /* RFC 2168 */
161 return type_names[type];
178 return "IXFR"; /* RFC 1995 */
194 dns_long_type_name (int type)
196 char *type_names[36] = {
199 "Authoritative name server",
202 "Canonical name for an alias",
203 "Start of zone of authority",
204 "Mailbox domain name",
206 "Mail rename domain name",
207 "Null resource record",
208 "Well-known service description",
209 "Domain name pointer",
211 "Mailbox or mail list information",
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 */
230 "Service location", /* RFC 2052 */
232 "Naming authority pointer" /* RFC 2168 */
234 static char unkbuf[7+1+2+1+4+1+1+10+1+1]; /* "Unknown RR type (%d)" */
237 return type_names[type];
254 return "Request for incremental zone transfer"; /* RFC 1995 */
256 return "Request for full zone transfer";
258 return "Request for mailbox-related records";
260 return "Request for mail agent resource records";
262 return "Request for all records";
265 sprintf(unkbuf, "Unknown RR type (%d)", type);
271 dns_class_name(int class)
280 class_name = "chaos";
283 class_name = "hesiod";
286 class_name = "unknown";
293 get_dns_name(const u_char *dns_data_ptr, const u_char *dptr, char *name,
296 const u_char *dp = dptr;
302 maxname--; /* reserve space for the trailing '\0' */
303 while ((component_len = *dp++) != 0) {
304 switch (component_len & 0xc0) {
309 /* Not the first component - put in a '.'. */
315 while (component_len > 0) {
327 goto error; /* error */
331 /* XXX - check to make sure we aren't looping, by keeping track
332 of how many characters are in the DNS packet, and of how many
333 characters we've looked at, and quitting if the latter
334 becomes bigger than the former. */
335 offset = ((component_len & ~0xc0) << 8) | *dp++;
336 /* If "len" is negative, we are still working on the original name,
337 not something pointed to by a pointer, and so we should set "len"
338 to the length of the original name. */
341 dp = dns_data_ptr + offset;
342 break; /* now continue processing from there */
348 /* If "len" is negative, we haven't seen a pointer, and thus haven't
349 set the length, so set it. */
352 /* Zero-length name means "root server" */
354 strcpy(name, "<Root>");
360 get_dns_name_type_class (const u_char *dns_data_ptr,
372 const u_char *dptr_save;
374 name_len = get_dns_name(dns_data_ptr, dptr, name, sizeof(name));
380 class = pntohs(dptr);
383 strcpy (name_ret, name);
386 *name_len_ret = name_len;
388 len = dptr - dptr_save;
394 dissect_dns_query(const u_char *dns_data_ptr, const u_char *pd, int offset,
395 proto_tree *dns_tree)
404 char *long_type_name;
406 const u_char *data_start;
410 data_start = dptr = pd + offset;
412 len = get_dns_name_type_class(dns_data_ptr, dptr, name, &name_len,
416 type_name = dns_type_name(type);
417 class_name = dns_class_name(class);
418 long_type_name = dns_long_type_name(type);
420 tq = proto_tree_add_text(dns_tree, offset, len, "%s: type %s, class %s",
421 name, type_name, class_name);
422 q_tree = proto_item_add_subtree(tq, ETT_DNS_QD);
424 proto_tree_add_text(q_tree, offset, name_len, "Name: %s", name);
427 proto_tree_add_text(q_tree, offset, 2, "Type: %s", long_type_name);
430 proto_tree_add_text(q_tree, offset, 2, "Class: %s", class_name);
433 return dptr - data_start;
438 add_rr_to_tree(proto_item *trr, int rr_type, int offset, const char *name,
439 int namelen, const char *type_name, const char *class_name, u_int ttl,
444 rr_tree = proto_item_add_subtree(trr, rr_type);
445 proto_tree_add_text(rr_tree, offset, namelen, "Name: %s", name);
447 proto_tree_add_text(rr_tree, offset, 2, "Type: %s", type_name);
449 proto_tree_add_text(rr_tree, offset, 2, "Class: %s", class_name);
451 proto_tree_add_text(rr_tree, offset, 4, "Time to live: %s",
452 time_secs_to_str(ttl));
454 proto_tree_add_text(rr_tree, offset, 2, "Data length: %u", data_len);
459 dissect_dns_answer(const u_char *dns_data_ptr, const u_char *pd, int offset,
460 proto_tree *dns_tree)
469 char *long_type_name;
471 const u_char *data_start;
478 data_start = dptr = pd + offset;
480 len = get_dns_name_type_class(dns_data_ptr, dptr, name, &name_len,
484 type_name = dns_type_name(type);
485 class_name = dns_class_name(class);
486 long_type_name = dns_long_type_name(type);
491 data_len = pntohs(dptr);
496 trr = proto_tree_add_text(dns_tree, offset, (dptr - data_start) + data_len,
497 "%s: type %s, class %s, addr %s",
498 name, type_name, class_name,
499 ip_to_str((guint8 *)dptr));
500 rr_tree = add_rr_to_tree(trr, ETT_DNS_RR, offset, name, name_len,
501 long_type_name, class_name, ttl, data_len);
502 offset += (dptr - data_start);
503 proto_tree_add_text(rr_tree, offset, 4, "Addr: %s",
504 ip_to_str((guint8 *)dptr));
509 char ns_name[MAXDNAME];
512 ns_name_len = get_dns_name(dns_data_ptr, dptr, ns_name, sizeof(ns_name));
513 trr = proto_tree_add_text(dns_tree, offset, (dptr - data_start) + data_len,
514 "%s: type %s, class %s, ns %s",
515 name, type_name, class_name, ns_name);
516 rr_tree = add_rr_to_tree(trr, ETT_DNS_RR, offset, name, name_len,
517 long_type_name, class_name, ttl, data_len);
518 offset += (dptr - data_start);
519 proto_tree_add_text(rr_tree, offset, ns_name_len, "Name server: %s", ns_name);
525 char cname[MAXDNAME];
528 cname_len = get_dns_name(dns_data_ptr, dptr, cname, sizeof(cname));
529 trr = proto_tree_add_text(dns_tree, offset, (dptr - data_start) + data_len,
530 "%s: type %s, class %s, cname %s",
531 name, type_name, class_name, cname);
532 rr_tree = add_rr_to_tree(trr, ETT_DNS_RR, offset, name, name_len,
533 long_type_name, class_name, ttl, data_len);
534 offset += (dptr - data_start);
535 proto_tree_add_text(rr_tree, offset, cname_len, "Primary name: %s", cname);
541 char mname[MAXDNAME];
543 char rname[MAXDNAME];
552 mname_len = get_dns_name(dns_data_ptr, rrptr, mname, sizeof(mname));
554 trr = proto_tree_add_text(dns_tree, offset, (dptr - data_start) + data_len,
555 "%s: type %s, class %s, mname %s",
556 name, type_name, class_name, mname);
557 rr_tree = add_rr_to_tree(trr, ETT_DNS_RR, offset, name, name_len,
558 long_type_name, class_name, ttl, data_len);
559 offset += (dptr - data_start);
560 proto_tree_add_text(rr_tree, offset, mname_len, "Primary name server: %s",
563 rname_len = get_dns_name(dns_data_ptr, rrptr, rname, sizeof(rname));
564 proto_tree_add_text(rr_tree, offset, rname_len, "Responsible authority's mailbox: %s",
568 serial = pntohl(rrptr);
569 proto_tree_add_text(rr_tree, offset, 4, "Serial number: %u",
573 refresh = pntohl(rrptr);
574 proto_tree_add_text(rr_tree, offset, 4, "Refresh interval: %s",
575 time_secs_to_str(refresh));
578 retry = pntohl(rrptr);
579 proto_tree_add_text(rr_tree, offset, 4, "Retry interval: %s",
580 time_secs_to_str(retry));
583 expire = pntohl(rrptr);
584 proto_tree_add_text(rr_tree, offset, 4, "Expiration limit: %s",
585 time_secs_to_str(expire));
588 minimum = pntohl(rrptr);
589 proto_tree_add_text(rr_tree, offset, 4, "Minimum TTL: %s",
590 time_secs_to_str(minimum));
596 char pname[MAXDNAME];
599 pname_len = get_dns_name(dns_data_ptr, dptr, pname, sizeof(pname));
600 trr = proto_tree_add_text(dns_tree, offset, (dptr - data_start) + data_len,
601 "%s: type %s, class %s, ptr %s",
602 name, type_name, class_name, pname);
603 rr_tree = add_rr_to_tree(trr, ETT_DNS_RR, offset, name, name_len,
604 long_type_name, class_name, ttl, data_len);
605 offset += (dptr - data_start);
606 proto_tree_add_text(rr_tree, offset, pname_len, "Domain name: %s", pname);
611 /* TODO: parse more record types */
614 trr = proto_tree_add_text(dns_tree, offset, (dptr - data_start) + data_len,
615 "%s: type %s, class %s",
616 name, type_name, class_name);
617 rr_tree = add_rr_to_tree(trr, ETT_DNS_RR, offset, name, name_len,
618 long_type_name, class_name, ttl, data_len);
619 offset += (dptr - data_start);
620 proto_tree_add_text(rr_tree, offset, data_len, "Data");
625 return dptr - data_start;
629 dissect_query_records(const u_char *dns_data_ptr, int count, const u_char *pd,
630 int cur_off, proto_tree *dns_tree)
637 ti = proto_tree_add_text(dns_tree, start_off, 0, "Queries");
638 qatree = proto_item_add_subtree(ti, ETT_DNS_QRY);
640 cur_off += dissect_dns_query(dns_data_ptr, pd, cur_off, qatree);
641 proto_item_set_len(ti, cur_off - start_off);
643 return cur_off - start_off;
649 dissect_answer_records(const u_char *dns_data_ptr, int count,
650 const u_char *pd, int cur_off, proto_tree *dns_tree,
658 ti = proto_tree_add_text(dns_tree, start_off, 0, name);
659 qatree = proto_item_add_subtree(ti, ETT_DNS_ANS);
661 cur_off += dissect_dns_answer(dns_data_ptr, pd, cur_off, qatree);
662 proto_item_set_len(ti, cur_off - start_off);
664 return cur_off - start_off;
669 dissect_dns(const u_char *pd, int offset, frame_data *fd, proto_tree *tree) {
670 const u_char *dns_data_ptr;
671 proto_tree *dns_tree, *field_tree;
673 guint16 id, flags, quest, ans, auth, add;
676 static const value_string opcode_vals[] = {
677 { OPCODE_QUERY, "Standard query" },
678 { OPCODE_IQUERY, "Inverse query" },
679 { OPCODE_STATUS, "Server status request" },
681 static const value_string rcode_vals[] = {
682 { RCODE_NOERROR, "No error" },
683 { RCODE_FMTERROR, "Format error" },
684 { RCODE_SERVFAIL, "Server failure" },
685 { RCODE_NAMEERROR, "Name error" },
686 { RCODE_NOTIMPL, "Not implemented" },
687 { RCODE_REFUSED, "Refused" },
690 dns_data_ptr = &pd[offset];
692 /* To do: check for runts, errs, etc. */
693 id = pntohs(&pd[offset + DNS_ID]);
694 flags = pntohs(&pd[offset + DNS_FLAGS]);
695 quest = pntohs(&pd[offset + DNS_QUEST]);
696 ans = pntohs(&pd[offset + DNS_ANS]);
697 auth = pntohs(&pd[offset + DNS_AUTH]);
698 add = pntohs(&pd[offset + DNS_ADD]);
700 if (check_col(fd, COL_PROTOCOL))
701 col_add_str(fd, COL_PROTOCOL, "DNS (UDP)");
702 if (check_col(fd, COL_INFO)) {
703 col_add_fstr(fd, COL_INFO, "%s%s",
704 val_to_str(flags & F_OPCODE, opcode_vals,
705 "Unknown operation (%x)"),
706 (flags & F_RESPONSE) ? " response" : "");
710 ti = proto_tree_add_item_format(tree, proto_dns, offset, 4, NULL,
711 (flags & F_RESPONSE) ? "DNS response" : "DNS query");
713 dns_tree = proto_item_add_subtree(ti, ETT_DNS);
715 proto_tree_add_text(dns_tree, offset + DNS_ID, 2, "Transaction ID: 0x%04x",
718 strcpy(buf, val_to_str(flags & F_OPCODE, opcode_vals, "Unknown operation"));
719 if (flags & F_RESPONSE) {
720 strcat(buf, " response");
722 strcat(buf, val_to_str(flags & F_RCODE, rcode_vals,
725 tf = proto_tree_add_text(dns_tree, offset + DNS_FLAGS, 2, "Flags: 0x%04x (%s)",
727 field_tree = proto_item_add_subtree(tf, ETT_DNS_FLAGS);
728 proto_tree_add_text(field_tree, offset + DNS_FLAGS, 2, "%s",
729 decode_boolean_bitfield(flags, F_RESPONSE,
730 2*8, "Response", "Query"));
731 proto_tree_add_text(field_tree, offset + DNS_FLAGS, 2, "%s",
732 decode_enumerated_bitfield(flags, F_OPCODE,
733 2*8, opcode_vals, "%s"));
734 if (flags & F_RESPONSE) {
735 proto_tree_add_text(field_tree, offset + DNS_FLAGS, 2, "%s",
736 decode_boolean_bitfield(flags, F_AUTHORITATIVE,
738 "Server is an authority for domain",
739 "Server isn't an authority for domain"));
741 proto_tree_add_text(field_tree, offset + DNS_FLAGS, 2, "%s",
742 decode_boolean_bitfield(flags, F_TRUNCATED,
744 "Message is truncated",
745 "Message is not truncated"));
746 proto_tree_add_text(field_tree, offset + DNS_FLAGS, 2, "%s",
747 decode_boolean_bitfield(flags, F_RECDESIRED,
749 "Do query recursively",
750 "Don't do query recursively"));
751 if (flags & F_RESPONSE) {
752 proto_tree_add_text(field_tree, offset + DNS_FLAGS, 2, "%s",
753 decode_boolean_bitfield(flags, F_RECAVAIL,
755 "Server can do recursive queries",
756 "Server can't do recursive queries"));
757 proto_tree_add_text(field_tree, offset + DNS_FLAGS, 2, "%s",
758 decode_enumerated_bitfield(flags, F_RCODE,
759 2*8, rcode_vals, "%s"));
761 proto_tree_add_text(dns_tree, offset + DNS_QUEST, 2, "Questions: %d", quest);
762 proto_tree_add_text(dns_tree, offset + DNS_ANS, 2, "Answer RRs: %d", ans);
763 proto_tree_add_text(dns_tree, offset + DNS_AUTH, 2, "Authority RRs: %d", auth);
764 proto_tree_add_text(dns_tree, offset + DNS_ADD, 2, "Additional RRs: %d", add);
766 cur_off = offset + DNS_HDRLEN;
769 cur_off += dissect_query_records(dns_data_ptr, quest, pd, cur_off,
773 cur_off += dissect_answer_records(dns_data_ptr, ans, pd, cur_off,
774 dns_tree, "Answers");
777 cur_off += dissect_answer_records(dns_data_ptr, auth, pd, cur_off,
778 dns_tree, "Authoritative nameservers");
781 cur_off += dissect_answer_records(dns_data_ptr, add, pd, cur_off,
782 dns_tree, "Additional records");
787 proto_register_dns(void)
789 /* static hf_register_info hf[] = {
791 { "Name", "dns.abbreviation", TYPE, VALS_POINTER }},
794 proto_dns = proto_register_protocol("Domain Name Service", "dns");
795 /* proto_register_field_array(proto_dns, hf, array_length(hf));*/