2 * Routines for DNS packet disassembly
4 * $Id: packet-dns.c,v 1.21 1999/09/21 07:15:38 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.
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;
393 rfc1867_size(const u_char *dptr)
398 size = (*dptr & 0xF0) >> 4;
399 exponent = (*dptr & 0x0F);
400 while (exponent != 0) {
404 return size / 100; /* return size in meters, not cm */
408 rfc1867_angle(const u_char *dptr, const char *nsew)
412 guint32 degrees, minutes, secs, tsecs;
413 static char buf[10+1+3+1 + 2+1+3+1 + 2+1+3+1+3+1 + 1 + 1];
415 angle = pntohl(dptr);
417 if (angle < 0x80000000U) {
418 angle = 0x80000000U - angle;
421 angle = angle - 0x80000000U;
424 tsecs = angle % 1000;
425 angle = angle / 1000;
428 minutes = angle % 60;
429 degrees = angle / 60;
430 sprintf(buf, "%u deg %u min %u.%03u sec %c", degrees, minutes, secs,
436 dissect_dns_query(const u_char *dns_data_ptr, const u_char *pd, int offset,
437 proto_tree *dns_tree)
446 char *long_type_name;
448 const u_char *data_start;
452 data_start = dptr = pd + offset;
454 len = get_dns_name_type_class(dns_data_ptr, dptr, name, &name_len,
458 type_name = dns_type_name(type);
459 class_name = dns_class_name(class);
460 long_type_name = dns_long_type_name(type);
462 tq = proto_tree_add_text(dns_tree, offset, len, "%s: type %s, class %s",
463 name, type_name, class_name);
464 q_tree = proto_item_add_subtree(tq, ETT_DNS_QD);
466 proto_tree_add_text(q_tree, offset, name_len, "Name: %s", name);
469 proto_tree_add_text(q_tree, offset, 2, "Type: %s", long_type_name);
472 proto_tree_add_text(q_tree, offset, 2, "Class: %s", class_name);
475 return dptr - data_start;
480 add_rr_to_tree(proto_item *trr, int rr_type, int offset, const char *name,
481 int namelen, const char *type_name, const char *class_name, u_int ttl,
486 rr_tree = proto_item_add_subtree(trr, rr_type);
487 proto_tree_add_text(rr_tree, offset, namelen, "Name: %s", name);
489 proto_tree_add_text(rr_tree, offset, 2, "Type: %s", type_name);
491 proto_tree_add_text(rr_tree, offset, 2, "Class: %s", class_name);
493 proto_tree_add_text(rr_tree, offset, 4, "Time to live: %s",
494 time_secs_to_str(ttl));
496 proto_tree_add_text(rr_tree, offset, 2, "Data length: %u", data_len);
501 dissect_dns_answer(const u_char *dns_data_ptr, const u_char *pd, int offset,
502 proto_tree *dns_tree)
511 char *long_type_name;
513 const u_char *data_start;
520 data_start = dptr = pd + offset;
522 len = get_dns_name_type_class(dns_data_ptr, dptr, name, &name_len,
526 type_name = dns_type_name(type);
527 class_name = dns_class_name(class);
528 long_type_name = dns_long_type_name(type);
533 data_len = pntohs(dptr);
538 trr = proto_tree_add_text(dns_tree, offset, (dptr - data_start) + data_len,
539 "%s: type %s, class %s, addr %s",
540 name, type_name, class_name,
541 ip_to_str((guint8 *)dptr));
542 rr_tree = add_rr_to_tree(trr, ETT_DNS_RR, offset, name, name_len,
543 long_type_name, class_name, ttl, data_len);
544 offset += (dptr - data_start);
545 proto_tree_add_text(rr_tree, offset, 4, "Addr: %s",
546 ip_to_str((guint8 *)dptr));
551 char ns_name[MAXDNAME];
554 ns_name_len = get_dns_name(dns_data_ptr, dptr, ns_name, sizeof(ns_name));
555 trr = proto_tree_add_text(dns_tree, offset, (dptr - data_start) + data_len,
556 "%s: type %s, class %s, ns %s",
557 name, type_name, class_name, ns_name);
558 rr_tree = add_rr_to_tree(trr, ETT_DNS_RR, offset, name, name_len,
559 long_type_name, class_name, ttl, data_len);
560 offset += (dptr - data_start);
561 proto_tree_add_text(rr_tree, offset, ns_name_len, "Name server: %s", ns_name);
567 char cname[MAXDNAME];
570 cname_len = get_dns_name(dns_data_ptr, dptr, cname, sizeof(cname));
571 trr = proto_tree_add_text(dns_tree, offset, (dptr - data_start) + data_len,
572 "%s: type %s, class %s, cname %s",
573 name, type_name, class_name, cname);
574 rr_tree = add_rr_to_tree(trr, ETT_DNS_RR, offset, name, name_len,
575 long_type_name, class_name, ttl, data_len);
576 offset += (dptr - data_start);
577 proto_tree_add_text(rr_tree, offset, cname_len, "Primary name: %s", cname);
583 char mname[MAXDNAME];
585 char rname[MAXDNAME];
594 mname_len = get_dns_name(dns_data_ptr, rrptr, mname, sizeof(mname));
596 trr = proto_tree_add_text(dns_tree, offset, (dptr - data_start) + data_len,
597 "%s: type %s, class %s, mname %s",
598 name, type_name, class_name, mname);
599 rr_tree = add_rr_to_tree(trr, ETT_DNS_RR, offset, name, name_len,
600 long_type_name, class_name, ttl, data_len);
601 offset += (dptr - data_start);
602 proto_tree_add_text(rr_tree, offset, mname_len, "Primary name server: %s",
605 rname_len = get_dns_name(dns_data_ptr, rrptr, rname, sizeof(rname));
606 proto_tree_add_text(rr_tree, offset, rname_len, "Responsible authority's mailbox: %s",
610 serial = pntohl(rrptr);
611 proto_tree_add_text(rr_tree, offset, 4, "Serial number: %u",
615 refresh = pntohl(rrptr);
616 proto_tree_add_text(rr_tree, offset, 4, "Refresh interval: %s",
617 time_secs_to_str(refresh));
620 retry = pntohl(rrptr);
621 proto_tree_add_text(rr_tree, offset, 4, "Retry interval: %s",
622 time_secs_to_str(retry));
625 expire = pntohl(rrptr);
626 proto_tree_add_text(rr_tree, offset, 4, "Expiration limit: %s",
627 time_secs_to_str(expire));
630 minimum = pntohl(rrptr);
631 proto_tree_add_text(rr_tree, offset, 4, "Minimum TTL: %s",
632 time_secs_to_str(minimum));
638 char pname[MAXDNAME];
641 pname_len = get_dns_name(dns_data_ptr, dptr, pname, sizeof(pname));
642 trr = proto_tree_add_text(dns_tree, offset, (dptr - data_start) + data_len,
643 "%s: type %s, class %s, ptr %s",
644 name, type_name, class_name, pname);
645 rr_tree = add_rr_to_tree(trr, ETT_DNS_RR, offset, name, name_len,
646 long_type_name, class_name, ttl, data_len);
647 offset += (dptr - data_start);
648 proto_tree_add_text(rr_tree, offset, pname_len, "Domain name: %s", pname);
656 char mx_name[MAXDNAME];
660 preference = pntohs(rrptr);
662 mx_name_len = get_dns_name(dns_data_ptr, rrptr, mx_name, sizeof(mx_name));
663 trr = proto_tree_add_text(dns_tree, offset, (dptr - data_start) + data_len,
664 "%s: type %s, class %s, preference %u, mx %s",
665 name, type_name, class_name, preference, mx_name);
666 rr_tree = add_rr_to_tree(trr, ETT_DNS_RR, offset, name, name_len,
667 long_type_name, class_name, ttl, data_len);
668 offset += (dptr - data_start);
669 proto_tree_add_text(rr_tree, offset, 2, "Preference: %u", preference);
671 proto_tree_add_text(rr_tree, offset, mx_name_len, "Mail exchange: %s", mx_name);
678 trr = proto_tree_add_text(dns_tree, offset, (dptr - data_start) + data_len,
679 "%s: type %s, class %s",
680 name, type_name, class_name);
681 rr_tree = add_rr_to_tree(trr, ETT_DNS_RR, offset, name, name_len,
682 long_type_name, class_name, ttl, data_len);
683 offset += (dptr - data_start);
684 proto_tree_add_text(rr_tree, offset, 1, "Version: %u", *dptr);
686 /* Version 0, the only version RFC 1876 discusses. */
689 proto_tree_add_text(rr_tree, offset, 1, "Size: %g m",
690 rfc1867_size(rrptr));
693 proto_tree_add_text(rr_tree, offset, 1, "Horizontal precision: %g m",
694 rfc1867_size(rrptr));
697 proto_tree_add_text(rr_tree, offset, 1, "Vertical precision: %g m",
698 rfc1867_size(rrptr));
701 proto_tree_add_text(rr_tree, offset, 4, "Latitude: %s",
702 rfc1867_angle(rrptr, "NS"));
705 proto_tree_add_text(rr_tree, offset, 4, "Longitude: %s",
706 rfc1867_angle(rrptr, "EW"));
709 proto_tree_add_text(rr_tree, offset, 4, "Altitude: %g m",
710 (pntohl(rrptr) - 10000000)/100.0);
712 proto_tree_add_text(rr_tree, offset, data_len, "Data");
717 /* TODO: parse more record types */
720 trr = proto_tree_add_text(dns_tree, offset, (dptr - data_start) + data_len,
721 "%s: type %s, class %s",
722 name, type_name, class_name);
723 rr_tree = add_rr_to_tree(trr, ETT_DNS_RR, offset, name, name_len,
724 long_type_name, class_name, ttl, data_len);
725 offset += (dptr - data_start);
726 proto_tree_add_text(rr_tree, offset, data_len, "Data");
731 return dptr - data_start;
735 dissect_query_records(const u_char *dns_data_ptr, int count, const u_char *pd,
736 int cur_off, proto_tree *dns_tree)
743 ti = proto_tree_add_text(dns_tree, start_off, 0, "Queries");
744 qatree = proto_item_add_subtree(ti, ETT_DNS_QRY);
746 cur_off += dissect_dns_query(dns_data_ptr, pd, cur_off, qatree);
747 proto_item_set_len(ti, cur_off - start_off);
749 return cur_off - start_off;
755 dissect_answer_records(const u_char *dns_data_ptr, int count,
756 const u_char *pd, int cur_off, proto_tree *dns_tree,
764 ti = proto_tree_add_text(dns_tree, start_off, 0, name);
765 qatree = proto_item_add_subtree(ti, ETT_DNS_ANS);
767 cur_off += dissect_dns_answer(dns_data_ptr, pd, cur_off, qatree);
768 proto_item_set_len(ti, cur_off - start_off);
770 return cur_off - start_off;
775 dissect_dns(const u_char *pd, int offset, frame_data *fd, proto_tree *tree) {
776 const u_char *dns_data_ptr;
777 proto_tree *dns_tree, *field_tree;
779 guint16 id, flags, quest, ans, auth, add;
782 static const value_string opcode_vals[] = {
783 { OPCODE_QUERY, "Standard query" },
784 { OPCODE_IQUERY, "Inverse query" },
785 { OPCODE_STATUS, "Server status request" },
787 static const value_string rcode_vals[] = {
788 { RCODE_NOERROR, "No error" },
789 { RCODE_FMTERROR, "Format error" },
790 { RCODE_SERVFAIL, "Server failure" },
791 { RCODE_NAMEERROR, "Name error" },
792 { RCODE_NOTIMPL, "Not implemented" },
793 { RCODE_REFUSED, "Refused" },
796 dns_data_ptr = &pd[offset];
798 /* To do: check for runts, errs, etc. */
799 id = pntohs(&pd[offset + DNS_ID]);
800 flags = pntohs(&pd[offset + DNS_FLAGS]);
801 quest = pntohs(&pd[offset + DNS_QUEST]);
802 ans = pntohs(&pd[offset + DNS_ANS]);
803 auth = pntohs(&pd[offset + DNS_AUTH]);
804 add = pntohs(&pd[offset + DNS_ADD]);
806 if (check_col(fd, COL_PROTOCOL))
807 col_add_str(fd, COL_PROTOCOL, "DNS (UDP)");
808 if (check_col(fd, COL_INFO)) {
809 col_add_fstr(fd, COL_INFO, "%s%s",
810 val_to_str(flags & F_OPCODE, opcode_vals,
811 "Unknown operation (%x)"),
812 (flags & F_RESPONSE) ? " response" : "");
816 ti = proto_tree_add_item_format(tree, proto_dns, offset, 4, NULL,
817 (flags & F_RESPONSE) ? "DNS response" : "DNS query");
819 dns_tree = proto_item_add_subtree(ti, ETT_DNS);
821 proto_tree_add_text(dns_tree, offset + DNS_ID, 2, "Transaction ID: 0x%04x",
824 strcpy(buf, val_to_str(flags & F_OPCODE, opcode_vals, "Unknown operation"));
825 if (flags & F_RESPONSE) {
826 strcat(buf, " response");
828 strcat(buf, val_to_str(flags & F_RCODE, rcode_vals,
831 tf = proto_tree_add_text(dns_tree, offset + DNS_FLAGS, 2, "Flags: 0x%04x (%s)",
833 field_tree = proto_item_add_subtree(tf, ETT_DNS_FLAGS);
834 proto_tree_add_text(field_tree, offset + DNS_FLAGS, 2, "%s",
835 decode_boolean_bitfield(flags, F_RESPONSE,
836 2*8, "Response", "Query"));
837 proto_tree_add_text(field_tree, offset + DNS_FLAGS, 2, "%s",
838 decode_enumerated_bitfield(flags, F_OPCODE,
839 2*8, opcode_vals, "%s"));
840 if (flags & F_RESPONSE) {
841 proto_tree_add_text(field_tree, offset + DNS_FLAGS, 2, "%s",
842 decode_boolean_bitfield(flags, F_AUTHORITATIVE,
844 "Server is an authority for domain",
845 "Server isn't an authority for domain"));
847 proto_tree_add_text(field_tree, offset + DNS_FLAGS, 2, "%s",
848 decode_boolean_bitfield(flags, F_TRUNCATED,
850 "Message is truncated",
851 "Message is not truncated"));
852 proto_tree_add_text(field_tree, offset + DNS_FLAGS, 2, "%s",
853 decode_boolean_bitfield(flags, F_RECDESIRED,
855 "Do query recursively",
856 "Don't do query recursively"));
857 if (flags & F_RESPONSE) {
858 proto_tree_add_text(field_tree, offset + DNS_FLAGS, 2, "%s",
859 decode_boolean_bitfield(flags, F_RECAVAIL,
861 "Server can do recursive queries",
862 "Server can't do recursive queries"));
863 proto_tree_add_text(field_tree, offset + DNS_FLAGS, 2, "%s",
864 decode_enumerated_bitfield(flags, F_RCODE,
865 2*8, rcode_vals, "%s"));
867 proto_tree_add_text(dns_tree, offset + DNS_QUEST, 2, "Questions: %d", quest);
868 proto_tree_add_text(dns_tree, offset + DNS_ANS, 2, "Answer RRs: %d", ans);
869 proto_tree_add_text(dns_tree, offset + DNS_AUTH, 2, "Authority RRs: %d", auth);
870 proto_tree_add_text(dns_tree, offset + DNS_ADD, 2, "Additional RRs: %d", add);
872 cur_off = offset + DNS_HDRLEN;
875 cur_off += dissect_query_records(dns_data_ptr, quest, pd, cur_off,
879 cur_off += dissect_answer_records(dns_data_ptr, ans, pd, cur_off,
880 dns_tree, "Answers");
883 cur_off += dissect_answer_records(dns_data_ptr, auth, pd, cur_off,
884 dns_tree, "Authoritative nameservers");
887 cur_off += dissect_answer_records(dns_data_ptr, add, pd, cur_off,
888 dns_tree, "Additional records");
893 proto_register_dns(void)
895 /* static hf_register_info hf[] = {
897 { "Name", "dns.abbreviation", TYPE, VALS_POINTER }},
900 proto_dns = proto_register_protocol("Domain Name Service", "dns");
901 /* proto_register_field_array(proto_dns, hf, array_length(hf));*/