2 * Routines for DNS packet disassembly
4 * $Id: packet-dns.c,v 1.30 1999/11/27 07:46:44 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;
44 static int hf_dns_response = -1;
45 static int hf_dns_query = -1;
46 static int hf_dns_flags = -1;
47 static int hf_dns_transaction_id = -1;
48 static int hf_dns_count_questions = -1;
49 static int hf_dns_count_answers = -1;
50 static int hf_dns_count_auth_rr = -1;
51 static int hf_dns_count_add_rr = -1;
53 static gint ett_dns = -1;
54 static gint ett_dns_qd = -1;
55 static gint ett_dns_rr = -1;
56 static gint ett_dns_qry = -1;
57 static gint ett_dns_ans = -1;
58 static gint ett_dns_flags = -1;
60 /* DNS structs and definitions */
62 /* Offsets of fields in the DNS header. */
70 /* Length of DNS header. */
74 #define T_A 1 /* host address */
75 #define T_NS 2 /* authoritative name server */
76 #define T_MD 3 /* mail destination (obsolete) */
77 #define T_MF 4 /* mail forwarder (obsolete) */
78 #define T_CNAME 5 /* canonical name */
79 #define T_SOA 6 /* start of authority zone */
80 #define T_MB 7 /* mailbox domain name (experimental) */
81 #define T_MG 8 /* mail group member (experimental) */
82 #define T_MR 9 /* mail rename domain name (experimental) */
83 #define T_NULL 10 /* null RR (experimental) */
84 #define T_WKS 11 /* well known service */
85 #define T_PTR 12 /* domain name pointer */
86 #define T_HINFO 13 /* host information */
87 #define T_MINFO 14 /* mailbox or mail list information */
88 #define T_MX 15 /* mail routing information */
89 #define T_TXT 16 /* text strings */
90 #define T_RP 17 /* responsible person (RFC 1183) */
91 #define T_AFSDB 18 /* AFS data base location (RFC 1183) */
92 #define T_X25 19 /* X.25 address (RFC 1183) */
93 #define T_ISDN 20 /* ISDN address (RFC 1183) */
94 #define T_RT 21 /* route-through (RFC 1183) */
95 #define T_NSAP 22 /* OSI NSAP (RFC 1706) */
96 #define T_NSAP_PTR 23 /* PTR equivalent for OSI NSAP (RFC 1348 - obsolete) */
97 #define T_SIG 24 /* digital signature (RFC 2065) */
98 #define T_KEY 25 /* public key (RFC 2065) */
99 #define T_PX 26 /* pointer to X.400/RFC822 mapping info (RFC 1664) */
100 #define T_GPOS 27 /* geographical position (RFC 1712) */
101 #define T_AAAA 28 /* IPv6 address (RFC 1886) */
102 #define T_LOC 29 /* geographical location (RFC 1876) */
103 #define T_NXT 30 /* "next" name (RFC 2065) */
104 #define T_EID 31 /* ??? (Nimrod?) */
105 #define T_NIMLOC 32 /* ??? (Nimrod?) */
106 #define T_SRV 33 /* service location (RFC 2052) */
107 #define T_ATMA 34 /* ??? */
108 #define T_NAPTR 35 /* naming authority pointer (RFC 2168) */
110 /* Bit fields in the flags */
111 #define F_RESPONSE (1<<15) /* packet is response */
112 #define F_OPCODE (0xF<<11) /* query opcode */
113 #define F_AUTHORITATIVE (1<<10) /* response is authoritative */
114 #define F_TRUNCATED (1<<9) /* response is truncated */
115 #define F_RECDESIRED (1<<8) /* recursion desired */
116 #define F_RECAVAIL (1<<7) /* recursion available */
117 #define F_RCODE (0xF<<0) /* reply code */
120 #define OPCODE_QUERY (0<<11) /* standard query */
121 #define OPCODE_IQUERY (1<<11) /* inverse query */
122 #define OPCODE_STATUS (2<<11) /* server status request */
125 #define RCODE_NOERROR (0<<0)
126 #define RCODE_FMTERROR (1<<0)
127 #define RCODE_SERVFAIL (2<<0)
128 #define RCODE_NAMEERROR (3<<0)
129 #define RCODE_NOTIMPL (4<<0)
130 #define RCODE_REFUSED (5<<0)
132 /* See RFC 1035 for all RR types for which no RFC is listed. */
134 dns_type_name (int type)
136 char *type_names[36] = {
155 "AFSDB", /* RFC 1183 */
156 "X25", /* RFC 1183 */
157 "ISDN", /* RFC 1183 */
159 "NSAP", /* RFC 1706 */
160 "NSAP-PTR", /* RFC 1348 */
161 "SIG", /* RFC 2065 */
162 "KEY", /* RFC 2065 */
164 "GPOS", /* RFC 1712 */
165 "AAAA", /* RFC 1886 */
166 "LOC", /* RFC 1876 */
167 "NXT", /* RFC 2065 */
170 "SRV", /* RFC 2052 */
172 "NAPTR" /* RFC 2168 */
176 return type_names[type];
193 return "IXFR"; /* RFC 1995 */
209 dns_long_type_name (int type)
211 char *type_names[36] = {
214 "Authoritative name server",
217 "Canonical name for an alias",
218 "Start of zone of authority",
219 "Mailbox domain name",
221 "Mail rename domain name",
222 "Null resource record",
223 "Well-known service description",
224 "Domain name pointer",
226 "Mailbox or mail list information",
229 "Responsible person", /* RFC 1183 */
230 "AFS data base location", /* RFC 1183 */
231 "X.25 address", /* RFC 1183 */
232 "ISDN number", /* RFC 1183 */
233 "Route through", /* RFC 1183 */
234 "OSI NSAP", /* RFC 1706 */
235 "OSI NSAP name pointer", /* RFC 1348 */
236 "Signature", /* RFC 2065 */
237 "Public key", /* RFC 2065 */
238 "Pointer to X.400/RFC822 mapping info", /* RFC 1664 */
239 "Geographical position", /* RFC 1712 */
240 "IPv6 address", /* RFC 1886 */
241 "Location", /* RFC 1876 */
242 "Next", /* RFC 2065 */
245 "Service location", /* RFC 2052 */
247 "Naming authority pointer" /* RFC 2168 */
249 static char unkbuf[7+1+2+1+4+1+1+10+1+1]; /* "Unknown RR type (%d)" */
252 return type_names[type];
269 return "Request for incremental zone transfer"; /* RFC 1995 */
271 return "Request for full zone transfer";
273 return "Request for mailbox-related records";
275 return "Request for mail agent resource records";
277 return "Request for all records";
280 sprintf(unkbuf, "Unknown RR type (%d)", type);
286 dns_class_name(int class)
295 class_name = "chaos";
298 class_name = "hesiod";
301 class_name = "unknown";
308 get_dns_name(const u_char *pd, int offset, int dns_data_offset,
309 char *name, int maxname)
311 const u_char *dp = pd + offset;
312 const u_char *dptr = dp;
317 maxname--; /* reserve space for the trailing '\0' */
319 if (!BYTES_ARE_IN_FRAME(offset, 1))
321 component_len = *dp++;
323 if (component_len == 0)
325 switch (component_len & 0xc0) {
330 /* Not the first component - put in a '.'. */
336 if (!BYTES_ARE_IN_FRAME(offset, component_len))
338 while (component_len > 0) {
351 goto error; /* error */
355 /* XXX - check to make sure we aren't looping, by keeping track
356 of how many characters are in the DNS packet, and of how many
357 characters we've looked at, and quitting if the latter
358 becomes bigger than the former. */
359 if (!BYTES_ARE_IN_FRAME(offset, 1))
361 offset = dns_data_offset + (((component_len & ~0xc0) << 8) | (*dp++));
362 /* If "len" is negative, we are still working on the original name,
363 not something pointed to by a pointer, and so we should set "len"
364 to the length of the original name. */
368 break; /* now continue processing from there */
374 /* If "len" is negative, we haven't seen a pointer, and thus haven't
375 set the length, so set it. */
378 /* Zero-length name means "root server" */
380 strcpy(name, "<Root>");
384 /* We ran past the end of the captured data in the packet. */
385 strcpy(name, "<Name goes past end of captured data in packet>");
386 /* If "len" is negative, we haven't seen a pointer, and thus haven't
387 set the length, so set it. */
395 get_dns_name_type_class(const u_char *pd, int offset, int dns_data_offset,
396 char *name_ret, int *name_len_ret, int *type_ret, int *class_ret)
403 int start_offset = offset;
405 name_len = get_dns_name(pd, offset, dns_data_offset, name, sizeof(name));
408 if (!BYTES_ARE_IN_FRAME(offset, 2)) {
409 /* We ran past the end of the captured data in the packet. */
412 type = pntohs(&pd[offset]);
415 if (!BYTES_ARE_IN_FRAME(offset, 2)) {
416 /* We ran past the end of the captured data in the packet. */
419 class = pntohs(&pd[offset]);
422 strcpy (name_ret, name);
425 *name_len_ret = name_len;
427 len = offset - start_offset;
432 rfc1867_size(u_char val)
437 size = (val & 0xF0) >> 4;
438 exponent = (val & 0x0F);
439 while (exponent != 0) {
443 return size / 100; /* return size in meters, not cm */
447 rfc1867_angle(const u_char *dptr, const char *nsew)
451 guint32 degrees, minutes, secs, tsecs;
452 static char buf[10+1+3+1 + 2+1+3+1 + 2+1+3+1+3+1 + 1 + 1];
454 angle = pntohl(dptr);
456 if (angle < 0x80000000U) {
457 angle = 0x80000000U - angle;
460 angle = angle - 0x80000000U;
463 tsecs = angle % 1000;
464 angle = angle / 1000;
467 minutes = angle % 60;
468 degrees = angle / 60;
469 sprintf(buf, "%u deg %u min %u.%03u sec %c", degrees, minutes, secs,
475 dissect_dns_query(const u_char *pd, int offset, int dns_data_offset,
476 frame_data *fd, proto_tree *dns_tree)
485 char *long_type_name;
487 const u_char *data_start;
491 data_start = dptr = pd + offset;
493 len = get_dns_name_type_class(pd, offset, dns_data_offset, name, &name_len,
496 /* We ran past the end of the data in the packet. */
501 type_name = dns_type_name(type);
502 class_name = dns_class_name(class);
503 long_type_name = dns_long_type_name(type);
506 col_append_fstr(fd, COL_INFO, " %s %s", type_name, name);
507 if (dns_tree != NULL) {
508 tq = proto_tree_add_text(dns_tree, offset, len, "%s: type %s, class %s",
509 name, type_name, class_name);
510 q_tree = proto_item_add_subtree(tq, ett_dns_qd);
512 proto_tree_add_text(q_tree, offset, name_len, "Name: %s", name);
515 proto_tree_add_text(q_tree, offset, 2, "Type: %s", long_type_name);
518 proto_tree_add_text(q_tree, offset, 2, "Class: %s", class_name);
522 return dptr - data_start;
527 add_rr_to_tree(proto_item *trr, int rr_type, int offset, const char *name,
528 int namelen, const char *type_name, const char *class_name, u_int ttl,
533 rr_tree = proto_item_add_subtree(trr, rr_type);
534 proto_tree_add_text(rr_tree, offset, namelen, "Name: %s", name);
536 proto_tree_add_text(rr_tree, offset, 2, "Type: %s", type_name);
538 proto_tree_add_text(rr_tree, offset, 2, "Class: %s", class_name);
540 proto_tree_add_text(rr_tree, offset, 4, "Time to live: %s",
541 time_secs_to_str(ttl));
543 proto_tree_add_text(rr_tree, offset, 2, "Data length: %u", data_len);
548 dissect_dns_answer(const u_char *pd, int offset, int dns_data_offset,
549 frame_data *fd, proto_tree *dns_tree)
558 char *long_type_name;
561 const u_char *data_start;
567 data_start = dptr = pd + offset;
570 len = get_dns_name_type_class(pd, offset, dns_data_offset, name, &name_len,
573 /* We ran past the end of the captured data in the packet. */
579 type_name = dns_type_name(type);
580 class_name = dns_class_name(class);
581 long_type_name = dns_long_type_name(type);
583 if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
584 /* We ran past the end of the captured data in the packet. */
591 if (!BYTES_ARE_IN_FRAME(cur_offset, 2)) {
592 /* We ran past the end of the captured data in the packet. */
595 data_len = pntohs(dptr);
602 col_append_fstr(fd, COL_INFO, " %s %s", type_name,
603 ip_to_str((guint8 *)dptr));
605 if (dns_tree != NULL) {
606 trr = proto_tree_add_text(dns_tree, offset, (dptr - data_start) + data_len,
607 "%s: type %s, class %s, addr %s",
608 name, type_name, class_name,
609 ip_to_str((guint8 *)dptr));
610 rr_tree = add_rr_to_tree(trr, ett_dns_rr, offset, name, name_len,
611 long_type_name, class_name, ttl, data_len);
612 if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
613 /* We ran past the end of the captured data in the packet. */
616 proto_tree_add_text(rr_tree, cur_offset, 4, "Addr: %s",
617 ip_to_str((guint8 *)dptr));
623 char ns_name[MAXDNAME];
626 ns_name_len = get_dns_name(pd, cur_offset, dns_data_offset, ns_name, sizeof(ns_name));
628 col_append_fstr(fd, COL_INFO, " %s %s", type_name, ns_name);
629 if (dns_tree != NULL) {
630 trr = proto_tree_add_text(dns_tree, offset, (dptr - data_start) + data_len,
631 "%s: type %s, class %s, ns %s",
632 name, type_name, class_name, ns_name);
633 rr_tree = add_rr_to_tree(trr, ett_dns_rr, offset, name, name_len,
634 long_type_name, class_name, ttl, data_len);
635 if (ns_name_len < 0) {
636 /* We ran past the end of the captured data in the packet. */
639 proto_tree_add_text(rr_tree, cur_offset, ns_name_len, "Name server: %s",
647 char cname[MAXDNAME];
650 cname_len = get_dns_name(pd, cur_offset, dns_data_offset, cname, sizeof(cname));
652 col_append_fstr(fd, COL_INFO, " %s %s", type_name, cname);
653 if (dns_tree != NULL) {
654 trr = proto_tree_add_text(dns_tree, offset, (dptr - data_start) + data_len,
655 "%s: type %s, class %s, cname %s",
656 name, type_name, class_name, cname);
657 rr_tree = add_rr_to_tree(trr, ett_dns_rr, offset, name, name_len,
658 long_type_name, class_name, ttl, data_len);
660 /* We ran past the end of the captured data in the packet. */
663 proto_tree_add_text(rr_tree, cur_offset, cname_len, "Primary name: %s",
671 char mname[MAXDNAME];
673 char rname[MAXDNAME];
681 mname_len = get_dns_name(pd, cur_offset, dns_data_offset, mname, sizeof(mname));
683 rname_len = get_dns_name(pd, cur_offset + mname_len, dns_data_offset, rname, sizeof(rname));
685 /* We ran past the end of the captured data in the packet. */
689 col_append_fstr(fd, COL_INFO, " %s %s", type_name, mname);
690 if (dns_tree != NULL) {
691 trr = proto_tree_add_text(dns_tree, offset, (dptr - data_start) + data_len,
692 "%s: type %s, class %s, mname %s",
693 name, type_name, class_name, mname);
694 rr_tree = add_rr_to_tree(trr, ett_dns_rr, offset, name, name_len,
695 long_type_name, class_name, ttl, data_len);
697 /* We ran past the end of the captured data in the packet. */
700 proto_tree_add_text(rr_tree, cur_offset, mname_len, "Primary name server: %s",
702 cur_offset += mname_len;
705 /* We ran past the end of the captured data in the packet. */
708 proto_tree_add_text(rr_tree, cur_offset, rname_len, "Responsible authority's mailbox: %s",
710 cur_offset += rname_len;
712 if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
713 /* We ran past the end of the captured data in the packet. */
716 serial = pntohl(&pd[cur_offset]);
717 proto_tree_add_text(rr_tree, cur_offset, 4, "Serial number: %u",
721 if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
722 /* We ran past the end of the captured data in the packet. */
725 refresh = pntohl(&pd[cur_offset]);
726 proto_tree_add_text(rr_tree, cur_offset, 4, "Refresh interval: %s",
727 time_secs_to_str(refresh));
730 if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
731 /* We ran past the end of the captured data in the packet. */
734 retry = pntohl(&pd[cur_offset]);
735 proto_tree_add_text(rr_tree, cur_offset, 4, "Retry interval: %s",
736 time_secs_to_str(retry));
739 if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
740 /* We ran past the end of the captured data in the packet. */
743 expire = pntohl(&pd[cur_offset]);
744 proto_tree_add_text(rr_tree, cur_offset, 4, "Expiration limit: %s",
745 time_secs_to_str(expire));
748 if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
749 /* We ran past the end of the captured data in the packet. */
752 minimum = pntohl(&pd[cur_offset]);
753 proto_tree_add_text(rr_tree, cur_offset, 4, "Minimum TTL: %s",
754 time_secs_to_str(minimum));
761 char pname[MAXDNAME];
764 pname_len = get_dns_name(pd, cur_offset, dns_data_offset, pname, sizeof(pname));
766 col_append_fstr(fd, COL_INFO, " %s %s", type_name, pname);
767 if (dns_tree != NULL) {
768 trr = proto_tree_add_text(dns_tree, offset, (dptr - data_start) + data_len,
769 "%s: type %s, class %s, ptr %s",
770 name, type_name, class_name, pname);
771 rr_tree = add_rr_to_tree(trr, ett_dns_rr, offset, name, name_len,
772 long_type_name, class_name, ttl, data_len);
774 /* We ran past the end of the captured data in the packet. */
777 proto_tree_add_text(rr_tree, cur_offset, pname_len, "Domain name: %s",
792 cpu_offset = cur_offset;
793 if (!BYTES_ARE_IN_FRAME(cpu_offset, 1)) {
794 /* We ran past the end of the captured data in the packet. */
795 if (dns_tree != NULL) {
796 trr = proto_tree_add_text(dns_tree, offset, (dptr - data_start) + data_len,
797 "%s: type %s, class %s, <CPU goes past end of captured data in packet>",
798 name, type_name, class_name);
799 rr_tree = add_rr_to_tree(trr, ett_dns_rr, offset, name, name_len,
800 long_type_name, class_name, ttl, data_len);
804 cpu_len = pd[cpu_offset];
805 if (!BYTES_ARE_IN_FRAME(cpu_offset + 1, cpu_len)) {
806 /* We ran past the end of the captured data in the packet. */
807 if (dns_tree != NULL) {
808 trr = proto_tree_add_text(dns_tree, offset, (dptr - data_start) + data_len,
809 "%s: type %s, class %s, <CPU goes past end of captured data in packet>",
810 name, type_name, class_name);
811 rr_tree = add_rr_to_tree(trr, ett_dns_rr, offset, name, name_len,
812 long_type_name, class_name, ttl, data_len);
816 os_offset = cpu_offset + 1 + cpu_len;
817 if (!BYTES_ARE_IN_FRAME(os_offset, 1)) {
818 /* We ran past the end of the captured data in the packet. */
819 if (dns_tree != NULL) {
820 trr = proto_tree_add_text(dns_tree, offset, (dptr - data_start) + data_len,
821 "%s: type %s, class %s, CPU %.*s, <OS goes past end of captured data in packet>",
822 name, type_name, class_name, cpu_len, &pd[cpu_offset + 1]);
823 rr_tree = add_rr_to_tree(trr, ett_dns_rr, offset, name, name_len,
824 long_type_name, class_name, ttl, data_len);
828 os_len = pd[os_offset];
829 if (!BYTES_ARE_IN_FRAME(os_offset + 1, os_len)) {
830 /* We ran past the end of the captured data in the packet. */
831 if (dns_tree != NULL) {
832 trr = proto_tree_add_text(dns_tree, offset, (dptr - data_start) + data_len,
833 "%s: type %s, class %s, CPU %*.s, <OS goes past end of captured data in packet>",
834 name, type_name, class_name, cpu_len, &pd[cpu_offset + 1]);
835 rr_tree = add_rr_to_tree(trr, ett_dns_rr, offset, name, name_len,
836 long_type_name, class_name, ttl, data_len);
841 col_append_fstr(fd, COL_INFO, " %s %.*s %.*s", type_name, cpu_len,
842 &pd[cpu_offset + 1], os_len, &pd[os_offset + 1]);
843 if (dns_tree != NULL) {
844 trr = proto_tree_add_text(dns_tree, offset, (dptr - data_start) + data_len,
845 "%s: type %s, class %s, CPU %.*s, OS %.*s",
846 name, type_name, class_name,
847 cpu_len, &pd[cpu_offset + 1], os_len, &pd[os_offset + 1]);
848 rr_tree = add_rr_to_tree(trr, ett_dns_rr, offset, name, name_len,
849 long_type_name, class_name, ttl, data_len);
850 proto_tree_add_text(rr_tree, cpu_offset, 1 + cpu_len, "CPU: %.*s",
851 cpu_len, &pd[cpu_offset + 1]);
852 proto_tree_add_text(rr_tree, os_offset, 1 + os_len, "OS: %.*s",
853 os_len, &pd[os_offset + 1]);
861 guint16 preference = 0;
862 char mx_name[MAXDNAME];
865 if (!BYTES_ARE_IN_FRAME(cur_offset, 2)) {
866 /* We ran past the end of the captured data in the packet. */
867 if (dns_tree != NULL) {
868 trr = proto_tree_add_text(dns_tree, offset, (dptr - data_start) + data_len,
869 "%s: type %s, class %s, <preference goes past end of captured data in packet>",
870 name, type_name, class_name);
871 rr_tree = add_rr_to_tree(trr, ett_dns_rr, offset, name, name_len,
872 long_type_name, class_name, ttl, data_len);
876 preference = pntohs(&pd[cur_offset]);
877 mx_name_len = get_dns_name(pd, cur_offset + 2, dns_data_offset, mx_name, sizeof(mx_name));
878 if (mx_name_len < 0) {
879 /* We ran past the end of the captured data in the packet. */
880 if (dns_tree != NULL) {
881 trr = proto_tree_add_text(dns_tree, offset, (dptr - data_start) + data_len,
882 "%s: type %s, class %s, preference %u, <mx goes past end of captured data in packet>",
883 name, type_name, class_name, preference);
884 rr_tree = add_rr_to_tree(trr, ett_dns_rr, offset, name, name_len,
885 long_type_name, class_name, ttl, data_len);
890 col_append_fstr(fd, COL_INFO, " %s %u %s", type_name, preference, mx_name);
891 if (dns_tree != NULL) {
892 trr = proto_tree_add_text(dns_tree, offset, (dptr - data_start) + data_len,
893 "%s: type %s, class %s, preference %u, mx %s",
894 name, type_name, class_name, preference, mx_name);
895 rr_tree = add_rr_to_tree(trr, ett_dns_rr, offset, name, name_len,
896 long_type_name, class_name, ttl, data_len);
897 proto_tree_add_text(rr_tree, cur_offset, 2, "Preference: %u", preference);
898 proto_tree_add_text(rr_tree, cur_offset + 2, mx_name_len, "Mail exchange: %s",
906 col_append_fstr(fd, COL_INFO, " %s %s", type_name,
907 ip6_to_str((struct e_in6_addr *)dptr));
909 if (dns_tree != NULL) {
910 trr = proto_tree_add_text(dns_tree, offset, (dptr - data_start) + data_len,
911 "%s: type %s, class %s, addr %s",
912 name, type_name, class_name,
913 ip6_to_str((struct e_in6_addr *)dptr));
914 rr_tree = add_rr_to_tree(trr, ett_dns_rr, offset, name, name_len,
915 long_type_name, class_name, ttl, data_len);
916 if (!BYTES_ARE_IN_FRAME(cur_offset, 16)) {
917 /* We ran past the end of the captured data in the packet. */
920 proto_tree_add_text(rr_tree, cur_offset, 16, "Addr: %s",
921 ip6_to_str((struct e_in6_addr *)dptr));
928 col_append_fstr(fd, COL_INFO, " %s", type_name);
929 if (dns_tree != NULL) {
930 trr = proto_tree_add_text(dns_tree, offset, (dptr - data_start) + data_len,
931 "%s: type %s, class %s",
932 name, type_name, class_name);
933 rr_tree = add_rr_to_tree(trr, ett_dns_rr, offset, name, name_len,
934 long_type_name, class_name, ttl, data_len);
935 if (!BYTES_ARE_IN_FRAME(cur_offset, 1)) {
936 /* We ran past the end of the captured data in the packet. */
939 proto_tree_add_text(rr_tree, cur_offset, 1, "Version: %u", pd[cur_offset]);
940 if (pd[cur_offset] == 0) {
941 /* Version 0, the only version RFC 1876 discusses. */
944 if (!BYTES_ARE_IN_FRAME(cur_offset, 1)) {
945 /* We ran past the end of the captured data in the packet. */
948 proto_tree_add_text(rr_tree, cur_offset, 1, "Size: %g m",
949 rfc1867_size(pd[cur_offset]));
952 if (!BYTES_ARE_IN_FRAME(cur_offset, 1)) {
953 /* We ran past the end of the captured data in the packet. */
956 proto_tree_add_text(rr_tree, cur_offset, 1, "Horizontal precision: %g m",
957 rfc1867_size(pd[cur_offset]));
960 if (!BYTES_ARE_IN_FRAME(cur_offset, 1)) {
961 /* We ran past the end of the captured data in the packet. */
964 proto_tree_add_text(rr_tree, cur_offset, 1, "Vertical precision: %g m",
965 rfc1867_size(pd[cur_offset]));
968 if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
969 /* We ran past the end of the captured data in the packet. */
972 proto_tree_add_text(rr_tree, cur_offset, 4, "Latitude: %s",
973 rfc1867_angle(&pd[cur_offset], "NS"));
976 if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
977 /* We ran past the end of the captured data in the packet. */
980 proto_tree_add_text(rr_tree, cur_offset, 4, "Longitude: %s",
981 rfc1867_angle(&pd[cur_offset], "EW"));
984 if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
985 /* We ran past the end of the captured data in the packet. */
988 proto_tree_add_text(rr_tree, cur_offset, 4, "Altitude: %g m",
989 (pntohl(&pd[cur_offset]) - 10000000)/100.0);
991 proto_tree_add_text(rr_tree, cur_offset, data_len, "Data");
997 /* TODO: parse more record types */
1001 col_append_fstr(fd, COL_INFO, " %s", type_name);
1002 if (dns_tree != NULL) {
1003 trr = proto_tree_add_text(dns_tree, offset, (dptr - data_start) + data_len,
1004 "%s: type %s, class %s",
1005 name, type_name, class_name);
1006 rr_tree = add_rr_to_tree(trr, ett_dns_rr, offset, name, name_len,
1007 long_type_name, class_name, ttl, data_len);
1008 proto_tree_add_text(rr_tree, cur_offset, data_len, "Data");
1014 return dptr - data_start;
1018 dissect_query_records(const u_char *pd, int cur_off, int dns_data_offset,
1019 int count, frame_data *fd, proto_tree *dns_tree)
1021 int start_off, add_off;
1022 proto_tree *qatree = NULL;
1023 proto_item *ti = NULL;
1025 start_off = cur_off;
1027 ti = proto_tree_add_text(dns_tree, start_off, 0, "Queries");
1028 qatree = proto_item_add_subtree(ti, ett_dns_qry);
1030 while (count-- > 0) {
1031 add_off = dissect_dns_query(pd, cur_off, dns_data_offset, fd, qatree);
1033 /* We ran past the end of the captured data in the packet. */
1039 proto_item_set_len(ti, cur_off - start_off);
1041 return cur_off - start_off;
1045 dissect_answer_records(const u_char *pd, int cur_off, int dns_data_offset,
1046 int count, frame_data *fd, proto_tree *dns_tree, char *name)
1048 int start_off, add_off;
1049 proto_tree *qatree = NULL;
1050 proto_item *ti = NULL;
1052 start_off = cur_off;
1054 ti = proto_tree_add_text(dns_tree, start_off, 0, name);
1055 qatree = proto_item_add_subtree(ti, ett_dns_ans);
1057 while (count-- > 0) {
1058 add_off = dissect_dns_answer(pd, cur_off, dns_data_offset, fd, qatree);
1060 /* We ran past the end of the captured data in the packet. */
1066 proto_item_set_len(ti, cur_off - start_off);
1068 return cur_off - start_off;
1072 dissect_dns(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
1074 int dns_data_offset;
1075 proto_tree *dns_tree = NULL, *field_tree;
1076 proto_item *ti, *tf;
1077 guint16 id, flags, quest, ans, auth, add;
1080 static const value_string opcode_vals[] = {
1081 { OPCODE_QUERY, "Standard query" },
1082 { OPCODE_IQUERY, "Inverse query" },
1083 { OPCODE_STATUS, "Server status request" },
1085 static const value_string rcode_vals[] = {
1086 { RCODE_NOERROR, "No error" },
1087 { RCODE_FMTERROR, "Format error" },
1088 { RCODE_SERVFAIL, "Server failure" },
1089 { RCODE_NAMEERROR, "Name error" },
1090 { RCODE_NOTIMPL, "Not implemented" },
1091 { RCODE_REFUSED, "Refused" },
1094 dns_data_offset = offset;
1096 if (check_col(fd, COL_PROTOCOL))
1097 col_add_str(fd, COL_PROTOCOL, "DNS (UDP)");
1099 if (pi.captured_len < DNS_HDRLEN) {
1100 col_add_str(fd, COL_INFO, "Short DNS packet");
1101 dissect_data(pd, offset, fd, tree);
1105 /* To do: check for errs, etc. */
1106 id = pntohs(&pd[offset + DNS_ID]);
1107 flags = pntohs(&pd[offset + DNS_FLAGS]);
1108 quest = pntohs(&pd[offset + DNS_QUEST]);
1109 ans = pntohs(&pd[offset + DNS_ANS]);
1110 auth = pntohs(&pd[offset + DNS_AUTH]);
1111 add = pntohs(&pd[offset + DNS_ADD]);
1113 if (check_col(fd, COL_INFO)) {
1114 col_add_fstr(fd, COL_INFO, "%s%s",
1115 val_to_str(flags & F_OPCODE, opcode_vals,
1116 "Unknown operation (%x)"),
1117 (flags & F_RESPONSE) ? " response" : "");
1119 /* Set "fd" to NULL; we pass a NULL "fd" to the query and answer
1120 dissectors, as a way of saying that they shouldn't add stuff
1121 to the COL_INFO column (a call to "check_col(fd, COL_INFO)"
1122 is more expensive than a check that a pointer isn't NULL). */
1127 ti = proto_tree_add_item_format(tree, proto_dns, offset, 4, NULL,
1128 (flags & F_RESPONSE) ? "DNS response" : "DNS query");
1130 dns_tree = proto_item_add_subtree(ti, ett_dns);
1132 if (flags & F_RESPONSE)
1133 proto_tree_add_item_hidden(dns_tree, hf_dns_response, offset, 4, 1);
1135 proto_tree_add_item_hidden(dns_tree, hf_dns_query, offset, 4, 1);
1137 proto_tree_add_item(dns_tree, hf_dns_transaction_id,
1138 offset + DNS_ID, 2, id);
1140 strcpy(buf, val_to_str(flags & F_OPCODE, opcode_vals, "Unknown operation"));
1141 if (flags & F_RESPONSE) {
1142 strcat(buf, " response");
1144 strcat(buf, val_to_str(flags & F_RCODE, rcode_vals,
1147 tf = proto_tree_add_item_format(dns_tree, hf_dns_flags,
1148 offset + DNS_FLAGS, 2,
1150 "Flags: 0x%04x (%s)",
1152 field_tree = proto_item_add_subtree(tf, ett_dns_flags);
1153 proto_tree_add_text(field_tree, offset + DNS_FLAGS, 2, "%s",
1154 decode_boolean_bitfield(flags, F_RESPONSE,
1155 2*8, "Response", "Query"));
1156 proto_tree_add_text(field_tree, offset + DNS_FLAGS, 2, "%s",
1157 decode_enumerated_bitfield(flags, F_OPCODE,
1158 2*8, opcode_vals, "%s"));
1159 if (flags & F_RESPONSE) {
1160 proto_tree_add_text(field_tree, offset + DNS_FLAGS, 2, "%s",
1161 decode_boolean_bitfield(flags, F_AUTHORITATIVE,
1163 "Server is an authority for domain",
1164 "Server isn't an authority for domain"));
1166 proto_tree_add_text(field_tree, offset + DNS_FLAGS, 2, "%s",
1167 decode_boolean_bitfield(flags, F_TRUNCATED,
1169 "Message is truncated",
1170 "Message is not truncated"));
1171 proto_tree_add_text(field_tree, offset + DNS_FLAGS, 2, "%s",
1172 decode_boolean_bitfield(flags, F_RECDESIRED,
1174 "Do query recursively",
1175 "Don't do query recursively"));
1176 if (flags & F_RESPONSE) {
1177 proto_tree_add_text(field_tree, offset + DNS_FLAGS, 2, "%s",
1178 decode_boolean_bitfield(flags, F_RECAVAIL,
1180 "Server can do recursive queries",
1181 "Server can't do recursive queries"));
1182 proto_tree_add_text(field_tree, offset + DNS_FLAGS, 2, "%s",
1183 decode_enumerated_bitfield(flags, F_RCODE,
1184 2*8, rcode_vals, "%s"));
1186 proto_tree_add_item(dns_tree, hf_dns_count_questions,
1187 offset + DNS_QUEST, 2, quest);
1188 proto_tree_add_item(dns_tree, hf_dns_count_answers,
1189 offset + DNS_ANS, 2, ans);
1190 proto_tree_add_item(dns_tree, hf_dns_count_auth_rr,
1191 offset + DNS_AUTH, 2, auth);
1192 proto_tree_add_item(dns_tree, hf_dns_count_add_rr,
1193 offset + DNS_ADD, 2, add);
1196 cur_off = offset + DNS_HDRLEN;
1199 /* If this is a response, don't add information about the queries
1200 to the summary, just add information about the answers. */
1201 cur_off += dissect_query_records(pd, cur_off, dns_data_offset, quest,
1202 (!(flags & F_RESPONSE) ? fd : NULL),
1207 /* If this is a request, don't add information about the answers
1208 to the summary, just add information about the queries. */
1209 cur_off += dissect_answer_records(pd, cur_off, dns_data_offset, ans,
1210 ((flags & F_RESPONSE) ? fd : NULL),
1211 dns_tree, "Answers");
1215 /* Don't add information about the authoritative name servers, or the
1216 additional records, to the summary. */
1218 cur_off += dissect_answer_records(pd, cur_off, dns_data_offset, auth,
1219 NULL, dns_tree, "Authoritative nameservers");
1222 cur_off += dissect_answer_records(pd, cur_off, dns_data_offset, add,
1223 NULL, dns_tree, "Additional records");
1228 proto_register_dns(void)
1230 static hf_register_info hf[] = {
1232 { "Response", "dns.response",
1233 FT_BOOLEAN, BASE_NONE, NULL, 0x0,
1234 "TRUE if DNS response" }},
1236 { "Query", "dns.query",
1237 FT_BOOLEAN, BASE_NONE, NULL, 0x0,
1238 "TRUE if DNS query" }},
1240 { "Flags", "dns.flags",
1241 FT_UINT16, BASE_HEX, NULL, 0x0,
1243 { &hf_dns_transaction_id,
1244 { "Transaction ID", "dns.id",
1245 FT_UINT16, BASE_HEX, NULL, 0x0,
1246 "Identification of transaction" }},
1247 { &hf_dns_count_questions,
1248 { "Questions", "dns.count.queries",
1249 FT_UINT16, BASE_DEC, NULL, 0x0,
1250 "Number of queries in packet" }},
1251 { &hf_dns_count_answers,
1252 { "Answer RRs", "dns.count.answers",
1253 FT_UINT16, BASE_DEC, NULL, 0x0,
1254 "Number of answers in packet" }},
1255 { &hf_dns_count_auth_rr,
1256 { "Authority RRs", "dns.count.auth_rr",
1257 FT_UINT16, BASE_DEC, NULL, 0x0,
1258 "Number of authoritative records in packet" }},
1259 { &hf_dns_count_add_rr,
1260 { "Additional RRs", "dns.count.add_rr",
1261 FT_UINT16, BASE_DEC, NULL, 0x0,
1262 "Number of additional records in packet" }}
1264 static gint *ett[] = {
1273 proto_dns = proto_register_protocol("Domain Name Service", "dns");
1274 proto_register_field_array(proto_dns, hf, array_length(hf));
1275 proto_register_subtree_array(ett, array_length(ett));