2 * Routines for DNS packet disassembly
4 * $Id: packet-dns.c,v 1.25 1999/10/16 15:08:11 deniel 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 /* DNS structs and definitions */
55 /* Offsets of fields in the DNS header. */
63 /* Length of DNS header. */
67 #define T_A 1 /* host address */
68 #define T_NS 2 /* authoritative name server */
69 #define T_MD 3 /* mail destination (obsolete) */
70 #define T_MF 4 /* mail forwarder (obsolete) */
71 #define T_CNAME 5 /* canonical name */
72 #define T_SOA 6 /* start of authority zone */
73 #define T_MB 7 /* mailbox domain name (experimental) */
74 #define T_MG 8 /* mail group member (experimental) */
75 #define T_MR 9 /* mail rename domain name (experimental) */
76 #define T_NULL 10 /* null RR (experimental) */
77 #define T_WKS 11 /* well known service */
78 #define T_PTR 12 /* domain name pointer */
79 #define T_HINFO 13 /* host information */
80 #define T_MINFO 14 /* mailbox or mail list information */
81 #define T_MX 15 /* mail routing information */
82 #define T_TXT 16 /* text strings */
83 #define T_RP 17 /* responsible person (RFC 1183) */
84 #define T_AFSDB 18 /* AFS data base location (RFC 1183) */
85 #define T_X25 19 /* X.25 address (RFC 1183) */
86 #define T_ISDN 20 /* ISDN address (RFC 1183) */
87 #define T_RT 21 /* route-through (RFC 1183) */
88 #define T_NSAP 22 /* OSI NSAP (RFC 1706) */
89 #define T_NSAP_PTR 23 /* PTR equivalent for OSI NSAP (RFC 1348 - obsolete) */
90 #define T_SIG 24 /* digital signature (RFC 2065) */
91 #define T_KEY 25 /* public key (RFC 2065) */
92 #define T_PX 26 /* pointer to X.400/RFC822 mapping info (RFC 1664) */
93 #define T_GPOS 27 /* geographical position (RFC 1712) */
94 #define T_AAAA 28 /* IPv6 address (RFC 1886) */
95 #define T_LOC 29 /* geographical location (RFC 1876) */
96 #define T_NXT 30 /* "next" name (RFC 2065) */
97 #define T_EID 31 /* ??? (Nimrod?) */
98 #define T_NIMLOC 32 /* ??? (Nimrod?) */
99 #define T_SRV 33 /* service location (RFC 2052) */
100 #define T_ATMA 34 /* ??? */
101 #define T_NAPTR 35 /* naming authority pointer (RFC 2168) */
103 /* Bit fields in the flags */
104 #define F_RESPONSE (1<<15) /* packet is response */
105 #define F_OPCODE (0xF<<11) /* query opcode */
106 #define F_AUTHORITATIVE (1<<10) /* response is authoritative */
107 #define F_TRUNCATED (1<<9) /* response is truncated */
108 #define F_RECDESIRED (1<<8) /* recursion desired */
109 #define F_RECAVAIL (1<<7) /* recursion available */
110 #define F_RCODE (0xF<<0) /* reply code */
113 #define OPCODE_QUERY (0<<11) /* standard query */
114 #define OPCODE_IQUERY (1<<11) /* inverse query */
115 #define OPCODE_STATUS (2<<11) /* server status request */
118 #define RCODE_NOERROR (0<<0)
119 #define RCODE_FMTERROR (1<<0)
120 #define RCODE_SERVFAIL (2<<0)
121 #define RCODE_NAMEERROR (3<<0)
122 #define RCODE_NOTIMPL (4<<0)
123 #define RCODE_REFUSED (5<<0)
125 /* See RFC 1035 for all RR types for which no RFC is listed. */
127 dns_type_name (int type)
129 char *type_names[36] = {
148 "AFSDB", /* RFC 1183 */
149 "X25", /* RFC 1183 */
150 "ISDN", /* RFC 1183 */
152 "NSAP", /* RFC 1706 */
153 "NSAP-PTR", /* RFC 1348 */
154 "SIG", /* RFC 2065 */
155 "KEY", /* RFC 2065 */
157 "GPOS", /* RFC 1712 */
158 "AAAA", /* RFC 1886 */
159 "LOC", /* RFC 1876 */
160 "NXT", /* RFC 2065 */
163 "SRV", /* RFC 2052 */
165 "NAPTR" /* RFC 2168 */
169 return type_names[type];
186 return "IXFR"; /* RFC 1995 */
202 dns_long_type_name (int type)
204 char *type_names[36] = {
207 "Authoritative name server",
210 "Canonical name for an alias",
211 "Start of zone of authority",
212 "Mailbox domain name",
214 "Mail rename domain name",
215 "Null resource record",
216 "Well-known service description",
217 "Domain name pointer",
219 "Mailbox or mail list information",
222 "Responsible person", /* RFC 1183 */
223 "AFS data base location", /* RFC 1183 */
224 "X.25 address", /* RFC 1183 */
225 "ISDN number", /* RFC 1183 */
226 "Route through", /* RFC 1183 */
227 "OSI NSAP", /* RFC 1706 */
228 "OSI NSAP name pointer", /* RFC 1348 */
229 "Signature", /* RFC 2065 */
230 "Public key", /* RFC 2065 */
231 "Pointer to X.400/RFC822 mapping info", /* RFC 1664 */
232 "Geographical position", /* RFC 1712 */
233 "IPv6 address", /* RFC 1886 */
234 "Location", /* RFC 1876 */
235 "Next", /* RFC 2065 */
238 "Service location", /* RFC 2052 */
240 "Naming authority pointer" /* RFC 2168 */
242 static char unkbuf[7+1+2+1+4+1+1+10+1+1]; /* "Unknown RR type (%d)" */
245 return type_names[type];
262 return "Request for incremental zone transfer"; /* RFC 1995 */
264 return "Request for full zone transfer";
266 return "Request for mailbox-related records";
268 return "Request for mail agent resource records";
270 return "Request for all records";
273 sprintf(unkbuf, "Unknown RR type (%d)", type);
279 dns_class_name(int class)
288 class_name = "chaos";
291 class_name = "hesiod";
294 class_name = "unknown";
301 get_dns_name(const u_char *pd, int offset, int dns_data_offset,
302 char *name, int maxname)
304 const u_char *dp = pd + offset;
305 const u_char *dptr = dp;
310 maxname--; /* reserve space for the trailing '\0' */
312 if (!BYTES_ARE_IN_FRAME(offset, 1))
314 component_len = *dp++;
316 if (component_len == 0)
318 switch (component_len & 0xc0) {
323 /* Not the first component - put in a '.'. */
329 if (!BYTES_ARE_IN_FRAME(offset, component_len))
331 while (component_len > 0) {
344 goto error; /* error */
348 /* XXX - check to make sure we aren't looping, by keeping track
349 of how many characters are in the DNS packet, and of how many
350 characters we've looked at, and quitting if the latter
351 becomes bigger than the former. */
352 if (!BYTES_ARE_IN_FRAME(offset, 1))
354 offset = dns_data_offset + (((component_len & ~0xc0) << 8) | (*dp++));
355 /* If "len" is negative, we are still working on the original name,
356 not something pointed to by a pointer, and so we should set "len"
357 to the length of the original name. */
361 break; /* now continue processing from there */
367 /* If "len" is negative, we haven't seen a pointer, and thus haven't
368 set the length, so set it. */
371 /* Zero-length name means "root server" */
373 strcpy(name, "<Root>");
377 /* We ran past the end of the captured data in the packet. */
378 strcpy(name, "<Name goes past end of captured data in packet>");
379 /* If "len" is negative, we haven't seen a pointer, and thus haven't
380 set the length, so set it. */
388 get_dns_name_type_class(const u_char *pd, int offset, int dns_data_offset,
389 char *name_ret, int *name_len_ret, int *type_ret, int *class_ret)
396 int start_offset = offset;
398 name_len = get_dns_name(pd, offset, dns_data_offset, name, sizeof(name));
401 if (!BYTES_ARE_IN_FRAME(offset, 2)) {
402 /* We ran past the end of the captured data in the packet. */
405 type = pntohs(&pd[offset]);
408 if (!BYTES_ARE_IN_FRAME(offset, 2)) {
409 /* We ran past the end of the captured data in the packet. */
412 class = pntohs(&pd[offset]);
415 strcpy (name_ret, name);
418 *name_len_ret = name_len;
420 len = offset - start_offset;
425 rfc1867_size(u_char val)
430 size = (val & 0xF0) >> 4;
431 exponent = (val & 0x0F);
432 while (exponent != 0) {
436 return size / 100; /* return size in meters, not cm */
440 rfc1867_angle(const u_char *dptr, const char *nsew)
444 guint32 degrees, minutes, secs, tsecs;
445 static char buf[10+1+3+1 + 2+1+3+1 + 2+1+3+1+3+1 + 1 + 1];
447 angle = pntohl(dptr);
449 if (angle < 0x80000000U) {
450 angle = 0x80000000U - angle;
453 angle = angle - 0x80000000U;
456 tsecs = angle % 1000;
457 angle = angle / 1000;
460 minutes = angle % 60;
461 degrees = angle / 60;
462 sprintf(buf, "%u deg %u min %u.%03u sec %c", degrees, minutes, secs,
468 dissect_dns_query(const u_char *pd, int offset, int dns_data_offset,
469 proto_tree *dns_tree)
478 char *long_type_name;
480 const u_char *data_start;
484 data_start = dptr = pd + offset;
486 len = get_dns_name_type_class(pd, offset, dns_data_offset, name, &name_len,
489 /* We ran past the end of the data in the packet. */
494 type_name = dns_type_name(type);
495 class_name = dns_class_name(class);
496 long_type_name = dns_long_type_name(type);
498 tq = proto_tree_add_text(dns_tree, offset, len, "%s: type %s, class %s",
499 name, type_name, class_name);
500 q_tree = proto_item_add_subtree(tq, ETT_DNS_QD);
502 proto_tree_add_text(q_tree, offset, name_len, "Name: %s", name);
505 proto_tree_add_text(q_tree, offset, 2, "Type: %s", long_type_name);
508 proto_tree_add_text(q_tree, offset, 2, "Class: %s", class_name);
511 return dptr - data_start;
516 add_rr_to_tree(proto_item *trr, int rr_type, int offset, const char *name,
517 int namelen, const char *type_name, const char *class_name, u_int ttl,
522 rr_tree = proto_item_add_subtree(trr, rr_type);
523 proto_tree_add_text(rr_tree, offset, namelen, "Name: %s", name);
525 proto_tree_add_text(rr_tree, offset, 2, "Type: %s", type_name);
527 proto_tree_add_text(rr_tree, offset, 2, "Class: %s", class_name);
529 proto_tree_add_text(rr_tree, offset, 4, "Time to live: %s",
530 time_secs_to_str(ttl));
532 proto_tree_add_text(rr_tree, offset, 2, "Data length: %u", data_len);
537 dissect_dns_answer(const u_char *pd, int offset, int dns_data_offset,
538 proto_tree *dns_tree)
547 char *long_type_name;
550 const u_char *data_start;
556 data_start = dptr = pd + offset;
559 len = get_dns_name_type_class(pd, offset, dns_data_offset, name, &name_len,
562 /* We ran past the end of the captured data in the packet. */
568 type_name = dns_type_name(type);
569 class_name = dns_class_name(class);
570 long_type_name = dns_long_type_name(type);
572 if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
573 /* We ran past the end of the captured data in the packet. */
580 if (!BYTES_ARE_IN_FRAME(cur_offset, 2)) {
581 /* We ran past the end of the captured data in the packet. */
584 data_len = pntohs(dptr);
590 trr = proto_tree_add_text(dns_tree, offset, (dptr - data_start) + data_len,
591 "%s: type %s, class %s, addr %s",
592 name, type_name, class_name,
593 ip_to_str((guint8 *)dptr));
594 rr_tree = add_rr_to_tree(trr, ETT_DNS_RR, offset, name, name_len,
595 long_type_name, class_name, ttl, data_len);
596 if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
597 /* We ran past the end of the captured data in the packet. */
600 proto_tree_add_text(rr_tree, cur_offset, 4, "Addr: %s",
601 ip_to_str((guint8 *)dptr));
606 char ns_name[MAXDNAME];
609 ns_name_len = get_dns_name(pd, cur_offset, dns_data_offset, ns_name, sizeof(ns_name));
610 trr = proto_tree_add_text(dns_tree, offset, (dptr - data_start) + data_len,
611 "%s: type %s, class %s, ns %s",
612 name, type_name, class_name, ns_name);
613 rr_tree = add_rr_to_tree(trr, ETT_DNS_RR, offset, name, name_len,
614 long_type_name, class_name, ttl, data_len);
615 if (ns_name_len < 0) {
616 /* We ran past the end of the captured data in the packet. */
619 proto_tree_add_text(rr_tree, cur_offset, ns_name_len, "Name server: %s",
626 char cname[MAXDNAME];
629 cname_len = get_dns_name(pd, cur_offset, dns_data_offset, cname, sizeof(cname));
630 trr = proto_tree_add_text(dns_tree, offset, (dptr - data_start) + data_len,
631 "%s: type %s, class %s, cname %s",
632 name, type_name, class_name, cname);
633 rr_tree = add_rr_to_tree(trr, ETT_DNS_RR, offset, name, name_len,
634 long_type_name, class_name, ttl, data_len);
636 /* We ran past the end of the captured data in the packet. */
639 proto_tree_add_text(rr_tree, cur_offset, cname_len, "Primary name: %s",
646 char mname[MAXDNAME];
648 char rname[MAXDNAME];
656 mname_len = get_dns_name(pd, cur_offset, dns_data_offset, mname, sizeof(mname));
658 rname_len = get_dns_name(pd, cur_offset + mname_len, dns_data_offset, rname, sizeof(rname));
660 /* We ran past the end of the captured data in the packet. */
663 trr = proto_tree_add_text(dns_tree, offset, (dptr - data_start) + data_len,
664 "%s: type %s, class %s, mname %s",
665 name, type_name, class_name, mname);
666 rr_tree = add_rr_to_tree(trr, ETT_DNS_RR, offset, name, name_len,
667 long_type_name, class_name, ttl, data_len);
669 /* We ran past the end of the captured data in the packet. */
672 proto_tree_add_text(rr_tree, cur_offset, mname_len, "Primary name server: %s",
674 cur_offset += mname_len;
677 /* We ran past the end of the captured data in the packet. */
680 proto_tree_add_text(rr_tree, cur_offset, rname_len, "Responsible authority's mailbox: %s",
682 cur_offset += rname_len;
684 if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
685 /* We ran past the end of the captured data in the packet. */
688 serial = pntohl(&pd[cur_offset]);
689 proto_tree_add_text(rr_tree, cur_offset, 4, "Serial number: %u",
693 if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
694 /* We ran past the end of the captured data in the packet. */
697 refresh = pntohl(&pd[cur_offset]);
698 proto_tree_add_text(rr_tree, cur_offset, 4, "Refresh interval: %s",
699 time_secs_to_str(refresh));
702 if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
703 /* We ran past the end of the captured data in the packet. */
706 retry = pntohl(&pd[cur_offset]);
707 proto_tree_add_text(rr_tree, cur_offset, 4, "Retry interval: %s",
708 time_secs_to_str(retry));
711 if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
712 /* We ran past the end of the captured data in the packet. */
715 expire = pntohl(&pd[cur_offset]);
716 proto_tree_add_text(rr_tree, cur_offset, 4, "Expiration limit: %s",
717 time_secs_to_str(expire));
720 if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
721 /* We ran past the end of the captured data in the packet. */
724 minimum = pntohl(&pd[cur_offset]);
725 proto_tree_add_text(rr_tree, cur_offset, 4, "Minimum TTL: %s",
726 time_secs_to_str(minimum));
732 char pname[MAXDNAME];
735 pname_len = get_dns_name(pd, cur_offset, dns_data_offset, pname, sizeof(pname));
736 trr = proto_tree_add_text(dns_tree, offset, (dptr - data_start) + data_len,
737 "%s: type %s, class %s, ptr %s",
738 name, type_name, class_name, pname);
739 rr_tree = add_rr_to_tree(trr, ETT_DNS_RR, offset, name, name_len,
740 long_type_name, class_name, ttl, data_len);
742 /* We ran past the end of the captured data in the packet. */
745 proto_tree_add_text(rr_tree, cur_offset, pname_len, "Domain name: %s",
753 guint16 preference = 0;
754 char mx_name[MAXDNAME];
757 mx_name_len = get_dns_name(pd, cur_offset + 2, dns_data_offset, mx_name, sizeof(mx_name));
758 if (!BYTES_ARE_IN_FRAME(cur_offset, 2)) {
759 /* We ran past the end of the captured data in the packet. */
760 trr = proto_tree_add_text(dns_tree, offset, (dptr - data_start) + data_len,
761 "%s: type %s, class %s, <preference goes past end of captured data in packet>",
762 name, type_name, class_name, preference, mx_name);
764 preference = pntohs(&pd[cur_offset]);
765 trr = proto_tree_add_text(dns_tree, offset, (dptr - data_start) + data_len,
766 "%s: type %s, class %s, preference %u, mx %s",
767 name, type_name, class_name, preference, mx_name);
769 rr_tree = add_rr_to_tree(trr, ETT_DNS_RR, offset, name, name_len,
770 long_type_name, class_name, ttl, data_len);
771 if (!BYTES_ARE_IN_FRAME(cur_offset, 2)) {
772 /* We ran past the end of the captured data in the packet. */
775 proto_tree_add_text(rr_tree, cur_offset, 2, "Preference: %u", preference);
776 if (mx_name_len < 0) {
777 /* We ran past the end of the captured data in the packet. */
780 proto_tree_add_text(rr_tree, cur_offset + 2, mx_name_len, "Mail exchange: %s",
787 trr = proto_tree_add_text(dns_tree, offset, (dptr - data_start) + data_len,
788 "%s: type %s, class %s",
789 name, type_name, class_name);
790 rr_tree = add_rr_to_tree(trr, ETT_DNS_RR, offset, name, name_len,
791 long_type_name, class_name, ttl, data_len);
792 if (!BYTES_ARE_IN_FRAME(cur_offset, 1)) {
793 /* We ran past the end of the captured data in the packet. */
796 proto_tree_add_text(rr_tree, cur_offset, 1, "Version: %u", pd[cur_offset]);
797 if (pd[cur_offset] == 0) {
798 /* Version 0, the only version RFC 1876 discusses. */
801 if (!BYTES_ARE_IN_FRAME(cur_offset, 1)) {
802 /* We ran past the end of the captured data in the packet. */
805 proto_tree_add_text(rr_tree, cur_offset, 1, "Size: %g m",
806 rfc1867_size(pd[cur_offset]));
809 if (!BYTES_ARE_IN_FRAME(cur_offset, 1)) {
810 /* We ran past the end of the captured data in the packet. */
813 proto_tree_add_text(rr_tree, cur_offset, 1, "Horizontal precision: %g m",
814 rfc1867_size(pd[cur_offset]));
817 if (!BYTES_ARE_IN_FRAME(cur_offset, 1)) {
818 /* We ran past the end of the captured data in the packet. */
821 proto_tree_add_text(rr_tree, cur_offset, 1, "Vertical precision: %g m",
822 rfc1867_size(pd[cur_offset]));
825 if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
826 /* We ran past the end of the captured data in the packet. */
829 proto_tree_add_text(rr_tree, cur_offset, 4, "Latitude: %s",
830 rfc1867_angle(&pd[cur_offset], "NS"));
833 if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
834 /* We ran past the end of the captured data in the packet. */
837 proto_tree_add_text(rr_tree, cur_offset, 4, "Longitude: %s",
838 rfc1867_angle(&pd[cur_offset], "EW"));
841 if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
842 /* We ran past the end of the captured data in the packet. */
845 proto_tree_add_text(rr_tree, cur_offset, 4, "Altitude: %g m",
846 (pntohl(&pd[cur_offset]) - 10000000)/100.0);
848 proto_tree_add_text(rr_tree, cur_offset, data_len, "Data");
853 /* TODO: parse more record types */
856 trr = proto_tree_add_text(dns_tree, offset, (dptr - data_start) + data_len,
857 "%s: type %s, class %s",
858 name, type_name, class_name);
859 rr_tree = add_rr_to_tree(trr, ETT_DNS_RR, offset, name, name_len,
860 long_type_name, class_name, ttl, data_len);
861 proto_tree_add_text(rr_tree, cur_offset, data_len, "Data");
866 return dptr - data_start;
870 dissect_query_records(const u_char *pd, int cur_off, int dns_data_offset,
871 int count, proto_tree *dns_tree)
873 int start_off, add_off;
878 ti = proto_tree_add_text(dns_tree, start_off, 0, "Queries");
879 qatree = proto_item_add_subtree(ti, ETT_DNS_QRY);
880 while (count-- > 0) {
881 add_off = dissect_dns_query(pd, cur_off, dns_data_offset, qatree);
883 /* We ran past the end of the captured data in the packet. */
888 proto_item_set_len(ti, cur_off - start_off);
890 return cur_off - start_off;
894 dissect_answer_records(const u_char *pd, int cur_off, int dns_data_offset,
895 int count, proto_tree *dns_tree, char *name)
897 int start_off, add_off;
902 ti = proto_tree_add_text(dns_tree, start_off, 0, name);
903 qatree = proto_item_add_subtree(ti, ETT_DNS_ANS);
904 while (count-- > 0) {
905 add_off = dissect_dns_answer(pd, cur_off, dns_data_offset, qatree);
907 /* We ran past the end of the captured data in the packet. */
912 proto_item_set_len(ti, cur_off - start_off);
914 return cur_off - start_off;
918 dissect_dns(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
921 proto_tree *dns_tree, *field_tree;
923 guint16 id, flags, quest, ans, auth, add;
926 static const value_string opcode_vals[] = {
927 { OPCODE_QUERY, "Standard query" },
928 { OPCODE_IQUERY, "Inverse query" },
929 { OPCODE_STATUS, "Server status request" },
931 static const value_string rcode_vals[] = {
932 { RCODE_NOERROR, "No error" },
933 { RCODE_FMTERROR, "Format error" },
934 { RCODE_SERVFAIL, "Server failure" },
935 { RCODE_NAMEERROR, "Name error" },
936 { RCODE_NOTIMPL, "Not implemented" },
937 { RCODE_REFUSED, "Refused" },
940 dns_data_offset = offset;
942 if (check_col(fd, COL_PROTOCOL))
943 col_add_str(fd, COL_PROTOCOL, "DNS (UDP)");
945 if (pi.captured_len < DNS_HDRLEN) {
946 col_add_str(fd, COL_INFO, "Short DNS packet");
947 dissect_data(pd, offset, fd, tree);
951 /* To do: check for errs, etc. */
952 id = pntohs(&pd[offset + DNS_ID]);
953 flags = pntohs(&pd[offset + DNS_FLAGS]);
954 quest = pntohs(&pd[offset + DNS_QUEST]);
955 ans = pntohs(&pd[offset + DNS_ANS]);
956 auth = pntohs(&pd[offset + DNS_AUTH]);
957 add = pntohs(&pd[offset + DNS_ADD]);
959 if (check_col(fd, COL_INFO)) {
960 col_add_fstr(fd, COL_INFO, "%s%s",
961 val_to_str(flags & F_OPCODE, opcode_vals,
962 "Unknown operation (%x)"),
963 (flags & F_RESPONSE) ? " response" : "");
967 ti = proto_tree_add_item_format(tree, proto_dns, offset, 4, NULL,
968 (flags & F_RESPONSE) ? "DNS response" : "DNS query");
970 dns_tree = proto_item_add_subtree(ti, ETT_DNS);
972 if (flags & F_RESPONSE)
973 proto_tree_add_item_hidden(dns_tree, hf_dns_response, offset, 4, 1);
975 proto_tree_add_item_hidden(dns_tree, hf_dns_query, offset, 4, 1);
977 proto_tree_add_item(dns_tree, hf_dns_transaction_id,
978 offset + DNS_ID, 2, id);
980 strcpy(buf, val_to_str(flags & F_OPCODE, opcode_vals, "Unknown operation"));
981 if (flags & F_RESPONSE) {
982 strcat(buf, " response");
984 strcat(buf, val_to_str(flags & F_RCODE, rcode_vals,
987 tf = proto_tree_add_item_format(dns_tree, hf_dns_flags,
988 offset + DNS_FLAGS, 2,
990 "Flags: 0x%04x (%s)",
992 field_tree = proto_item_add_subtree(tf, ETT_DNS_FLAGS);
993 proto_tree_add_text(field_tree, offset + DNS_FLAGS, 2, "%s",
994 decode_boolean_bitfield(flags, F_RESPONSE,
995 2*8, "Response", "Query"));
996 proto_tree_add_text(field_tree, offset + DNS_FLAGS, 2, "%s",
997 decode_enumerated_bitfield(flags, F_OPCODE,
998 2*8, opcode_vals, "%s"));
999 if (flags & F_RESPONSE) {
1000 proto_tree_add_text(field_tree, offset + DNS_FLAGS, 2, "%s",
1001 decode_boolean_bitfield(flags, F_AUTHORITATIVE,
1003 "Server is an authority for domain",
1004 "Server isn't an authority for domain"));
1006 proto_tree_add_text(field_tree, offset + DNS_FLAGS, 2, "%s",
1007 decode_boolean_bitfield(flags, F_TRUNCATED,
1009 "Message is truncated",
1010 "Message is not truncated"));
1011 proto_tree_add_text(field_tree, offset + DNS_FLAGS, 2, "%s",
1012 decode_boolean_bitfield(flags, F_RECDESIRED,
1014 "Do query recursively",
1015 "Don't do query recursively"));
1016 if (flags & F_RESPONSE) {
1017 proto_tree_add_text(field_tree, offset + DNS_FLAGS, 2, "%s",
1018 decode_boolean_bitfield(flags, F_RECAVAIL,
1020 "Server can do recursive queries",
1021 "Server can't do recursive queries"));
1022 proto_tree_add_text(field_tree, offset + DNS_FLAGS, 2, "%s",
1023 decode_enumerated_bitfield(flags, F_RCODE,
1024 2*8, rcode_vals, "%s"));
1026 proto_tree_add_item(dns_tree, hf_dns_count_questions,
1027 offset + DNS_QUEST, 2, quest);
1028 proto_tree_add_item(dns_tree, hf_dns_count_answers,
1029 offset + DNS_ANS, 2, ans);
1030 proto_tree_add_item(dns_tree, hf_dns_count_auth_rr,
1031 offset + DNS_AUTH, 2, auth);
1032 proto_tree_add_item(dns_tree, hf_dns_count_add_rr,
1033 offset + DNS_ADD, 2, add);
1035 cur_off = offset + DNS_HDRLEN;
1038 cur_off += dissect_query_records(pd, cur_off, dns_data_offset, quest,
1042 cur_off += dissect_answer_records(pd, cur_off, dns_data_offset, ans,
1043 dns_tree, "Answers");
1046 cur_off += dissect_answer_records(pd, cur_off, dns_data_offset, auth,
1047 dns_tree, "Authoritative nameservers");
1050 cur_off += dissect_answer_records(pd, cur_off, dns_data_offset, add,
1051 dns_tree, "Additional records");
1056 proto_register_dns(void)
1058 static hf_register_info hf[] = {
1060 { "Response", "dns.response",
1061 FT_BOOLEAN, BASE_NONE, NULL, 0x0,
1062 "TRUE if DNS response" }},
1064 { "Query", "dns.query",
1065 FT_BOOLEAN, BASE_NONE, NULL, 0x0,
1066 "TRUE if DNS query" }},
1068 { "Flags", "dns.flags",
1069 FT_UINT16, BASE_HEX, NULL, 0x0,
1071 { &hf_dns_transaction_id,
1072 { "Transaction ID", "dns.id",
1073 FT_UINT16, BASE_HEX, NULL, 0x0,
1074 "Identification of transaction" }},
1075 { &hf_dns_count_questions,
1076 { "Questions", "dns.count.queries",
1077 FT_UINT16, BASE_DEC, NULL, 0x0,
1078 "Number of queries in packet" }},
1079 { &hf_dns_count_answers,
1080 { "Answer RRs", "dns.count.answers",
1081 FT_UINT16, BASE_DEC, NULL, 0x0,
1082 "Number of answers in packet" }},
1083 { &hf_dns_count_auth_rr,
1084 { "Authority RRs", "dns.count.auth_rr",
1085 FT_UINT16, BASE_DEC, NULL, 0x0,
1086 "Number of authoritative records in packet" }},
1087 { &hf_dns_count_add_rr,
1088 { "Additional RRs", "dns.count.add_rr",
1089 FT_UINT16, BASE_DEC, NULL, 0x0,
1090 "Number of additional records in packet" }}
1093 proto_dns = proto_register_protocol("Domain Name Service", "dns");
1094 proto_register_field_array(proto_dns, hf, array_length(hf));