2 * Routines for DNS packet disassembly
4 * $Id: packet-dns.c,v 1.24 1999/10/07 09:21:36 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 *pd, int offset, int dns_data_offset,
294 char *name, int maxname)
296 const u_char *dp = pd + offset;
297 const u_char *dptr = dp;
302 maxname--; /* reserve space for the trailing '\0' */
304 if (!BYTES_ARE_IN_FRAME(offset, 1))
306 component_len = *dp++;
308 if (component_len == 0)
310 switch (component_len & 0xc0) {
315 /* Not the first component - put in a '.'. */
321 if (!BYTES_ARE_IN_FRAME(offset, component_len))
323 while (component_len > 0) {
336 goto error; /* error */
340 /* XXX - check to make sure we aren't looping, by keeping track
341 of how many characters are in the DNS packet, and of how many
342 characters we've looked at, and quitting if the latter
343 becomes bigger than the former. */
344 if (!BYTES_ARE_IN_FRAME(offset, 1))
346 offset = dns_data_offset + (((component_len & ~0xc0) << 8) | (*dp++));
347 /* If "len" is negative, we are still working on the original name,
348 not something pointed to by a pointer, and so we should set "len"
349 to the length of the original name. */
353 break; /* now continue processing from there */
359 /* If "len" is negative, we haven't seen a pointer, and thus haven't
360 set the length, so set it. */
363 /* Zero-length name means "root server" */
365 strcpy(name, "<Root>");
369 /* We ran past the end of the captured data in the packet. */
370 strcpy(name, "<Name goes past end of captured data in packet>");
371 /* If "len" is negative, we haven't seen a pointer, and thus haven't
372 set the length, so set it. */
380 get_dns_name_type_class(const u_char *pd, int offset, int dns_data_offset,
381 char *name_ret, int *name_len_ret, int *type_ret, int *class_ret)
388 int start_offset = offset;
390 name_len = get_dns_name(pd, offset, dns_data_offset, name, sizeof(name));
393 if (!BYTES_ARE_IN_FRAME(offset, 2)) {
394 /* We ran past the end of the captured data in the packet. */
397 type = pntohs(&pd[offset]);
400 if (!BYTES_ARE_IN_FRAME(offset, 2)) {
401 /* We ran past the end of the captured data in the packet. */
404 class = pntohs(&pd[offset]);
407 strcpy (name_ret, name);
410 *name_len_ret = name_len;
412 len = offset - start_offset;
417 rfc1867_size(u_char val)
422 size = (val & 0xF0) >> 4;
423 exponent = (val & 0x0F);
424 while (exponent != 0) {
428 return size / 100; /* return size in meters, not cm */
432 rfc1867_angle(const u_char *dptr, const char *nsew)
436 guint32 degrees, minutes, secs, tsecs;
437 static char buf[10+1+3+1 + 2+1+3+1 + 2+1+3+1+3+1 + 1 + 1];
439 angle = pntohl(dptr);
441 if (angle < 0x80000000U) {
442 angle = 0x80000000U - angle;
445 angle = angle - 0x80000000U;
448 tsecs = angle % 1000;
449 angle = angle / 1000;
452 minutes = angle % 60;
453 degrees = angle / 60;
454 sprintf(buf, "%u deg %u min %u.%03u sec %c", degrees, minutes, secs,
460 dissect_dns_query(const u_char *pd, int offset, int dns_data_offset,
461 proto_tree *dns_tree)
470 char *long_type_name;
472 const u_char *data_start;
476 data_start = dptr = pd + offset;
478 len = get_dns_name_type_class(pd, offset, dns_data_offset, name, &name_len,
481 /* We ran past the end of the data in the packet. */
486 type_name = dns_type_name(type);
487 class_name = dns_class_name(class);
488 long_type_name = dns_long_type_name(type);
490 tq = proto_tree_add_text(dns_tree, offset, len, "%s: type %s, class %s",
491 name, type_name, class_name);
492 q_tree = proto_item_add_subtree(tq, ETT_DNS_QD);
494 proto_tree_add_text(q_tree, offset, name_len, "Name: %s", name);
497 proto_tree_add_text(q_tree, offset, 2, "Type: %s", long_type_name);
500 proto_tree_add_text(q_tree, offset, 2, "Class: %s", class_name);
503 return dptr - data_start;
508 add_rr_to_tree(proto_item *trr, int rr_type, int offset, const char *name,
509 int namelen, const char *type_name, const char *class_name, u_int ttl,
514 rr_tree = proto_item_add_subtree(trr, rr_type);
515 proto_tree_add_text(rr_tree, offset, namelen, "Name: %s", name);
517 proto_tree_add_text(rr_tree, offset, 2, "Type: %s", type_name);
519 proto_tree_add_text(rr_tree, offset, 2, "Class: %s", class_name);
521 proto_tree_add_text(rr_tree, offset, 4, "Time to live: %s",
522 time_secs_to_str(ttl));
524 proto_tree_add_text(rr_tree, offset, 2, "Data length: %u", data_len);
529 dissect_dns_answer(const u_char *pd, int offset, int dns_data_offset,
530 proto_tree *dns_tree)
539 char *long_type_name;
542 const u_char *data_start;
548 data_start = dptr = pd + offset;
551 len = get_dns_name_type_class(pd, offset, dns_data_offset, name, &name_len,
554 /* We ran past the end of the captured data in the packet. */
560 type_name = dns_type_name(type);
561 class_name = dns_class_name(class);
562 long_type_name = dns_long_type_name(type);
564 if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
565 /* We ran past the end of the captured data in the packet. */
572 if (!BYTES_ARE_IN_FRAME(cur_offset, 2)) {
573 /* We ran past the end of the captured data in the packet. */
576 data_len = pntohs(dptr);
582 trr = proto_tree_add_text(dns_tree, offset, (dptr - data_start) + data_len,
583 "%s: type %s, class %s, addr %s",
584 name, type_name, class_name,
585 ip_to_str((guint8 *)dptr));
586 rr_tree = add_rr_to_tree(trr, ETT_DNS_RR, offset, name, name_len,
587 long_type_name, class_name, ttl, data_len);
588 if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
589 /* We ran past the end of the captured data in the packet. */
592 proto_tree_add_text(rr_tree, cur_offset, 4, "Addr: %s",
593 ip_to_str((guint8 *)dptr));
598 char ns_name[MAXDNAME];
601 ns_name_len = get_dns_name(pd, cur_offset, dns_data_offset, ns_name, sizeof(ns_name));
602 trr = proto_tree_add_text(dns_tree, offset, (dptr - data_start) + data_len,
603 "%s: type %s, class %s, ns %s",
604 name, type_name, class_name, ns_name);
605 rr_tree = add_rr_to_tree(trr, ETT_DNS_RR, offset, name, name_len,
606 long_type_name, class_name, ttl, data_len);
607 if (ns_name_len < 0) {
608 /* We ran past the end of the captured data in the packet. */
611 proto_tree_add_text(rr_tree, cur_offset, ns_name_len, "Name server: %s",
618 char cname[MAXDNAME];
621 cname_len = get_dns_name(pd, cur_offset, dns_data_offset, cname, sizeof(cname));
622 trr = proto_tree_add_text(dns_tree, offset, (dptr - data_start) + data_len,
623 "%s: type %s, class %s, cname %s",
624 name, type_name, class_name, cname);
625 rr_tree = add_rr_to_tree(trr, ETT_DNS_RR, offset, name, name_len,
626 long_type_name, class_name, ttl, data_len);
628 /* We ran past the end of the captured data in the packet. */
631 proto_tree_add_text(rr_tree, cur_offset, cname_len, "Primary name: %s",
638 char mname[MAXDNAME];
640 char rname[MAXDNAME];
648 mname_len = get_dns_name(pd, cur_offset, dns_data_offset, mname, sizeof(mname));
650 rname_len = get_dns_name(pd, cur_offset + mname_len, dns_data_offset, rname, sizeof(rname));
652 /* We ran past the end of the captured data in the packet. */
655 trr = proto_tree_add_text(dns_tree, offset, (dptr - data_start) + data_len,
656 "%s: type %s, class %s, mname %s",
657 name, type_name, class_name, mname);
658 rr_tree = add_rr_to_tree(trr, ETT_DNS_RR, offset, name, name_len,
659 long_type_name, class_name, ttl, data_len);
661 /* We ran past the end of the captured data in the packet. */
664 proto_tree_add_text(rr_tree, cur_offset, mname_len, "Primary name server: %s",
666 cur_offset += mname_len;
669 /* We ran past the end of the captured data in the packet. */
672 proto_tree_add_text(rr_tree, cur_offset, rname_len, "Responsible authority's mailbox: %s",
674 cur_offset += rname_len;
676 if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
677 /* We ran past the end of the captured data in the packet. */
680 serial = pntohl(&pd[cur_offset]);
681 proto_tree_add_text(rr_tree, cur_offset, 4, "Serial number: %u",
685 if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
686 /* We ran past the end of the captured data in the packet. */
689 refresh = pntohl(&pd[cur_offset]);
690 proto_tree_add_text(rr_tree, cur_offset, 4, "Refresh interval: %s",
691 time_secs_to_str(refresh));
694 if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
695 /* We ran past the end of the captured data in the packet. */
698 retry = pntohl(&pd[cur_offset]);
699 proto_tree_add_text(rr_tree, cur_offset, 4, "Retry interval: %s",
700 time_secs_to_str(retry));
703 if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
704 /* We ran past the end of the captured data in the packet. */
707 expire = pntohl(&pd[cur_offset]);
708 proto_tree_add_text(rr_tree, cur_offset, 4, "Expiration limit: %s",
709 time_secs_to_str(expire));
712 if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
713 /* We ran past the end of the captured data in the packet. */
716 minimum = pntohl(&pd[cur_offset]);
717 proto_tree_add_text(rr_tree, cur_offset, 4, "Minimum TTL: %s",
718 time_secs_to_str(minimum));
724 char pname[MAXDNAME];
727 pname_len = get_dns_name(pd, cur_offset, dns_data_offset, pname, sizeof(pname));
728 trr = proto_tree_add_text(dns_tree, offset, (dptr - data_start) + data_len,
729 "%s: type %s, class %s, ptr %s",
730 name, type_name, class_name, pname);
731 rr_tree = add_rr_to_tree(trr, ETT_DNS_RR, offset, name, name_len,
732 long_type_name, class_name, ttl, data_len);
734 /* We ran past the end of the captured data in the packet. */
737 proto_tree_add_text(rr_tree, cur_offset, pname_len, "Domain name: %s",
745 guint16 preference = 0;
746 char mx_name[MAXDNAME];
749 mx_name_len = get_dns_name(pd, cur_offset + 2, dns_data_offset, mx_name, sizeof(mx_name));
750 if (!BYTES_ARE_IN_FRAME(cur_offset, 2)) {
751 /* We ran past the end of the captured data in the packet. */
752 trr = proto_tree_add_text(dns_tree, offset, (dptr - data_start) + data_len,
753 "%s: type %s, class %s, <preference goes past end of captured data in packet>",
754 name, type_name, class_name, preference, mx_name);
756 preference = pntohs(&pd[cur_offset]);
757 trr = proto_tree_add_text(dns_tree, offset, (dptr - data_start) + data_len,
758 "%s: type %s, class %s, preference %u, mx %s",
759 name, type_name, class_name, preference, mx_name);
761 rr_tree = add_rr_to_tree(trr, ETT_DNS_RR, offset, name, name_len,
762 long_type_name, class_name, ttl, data_len);
763 if (!BYTES_ARE_IN_FRAME(cur_offset, 2)) {
764 /* We ran past the end of the captured data in the packet. */
767 proto_tree_add_text(rr_tree, cur_offset, 2, "Preference: %u", preference);
768 if (mx_name_len < 0) {
769 /* We ran past the end of the captured data in the packet. */
772 proto_tree_add_text(rr_tree, cur_offset + 2, mx_name_len, "Mail exchange: %s",
779 trr = proto_tree_add_text(dns_tree, offset, (dptr - data_start) + data_len,
780 "%s: type %s, class %s",
781 name, type_name, class_name);
782 rr_tree = add_rr_to_tree(trr, ETT_DNS_RR, offset, name, name_len,
783 long_type_name, class_name, ttl, data_len);
784 if (!BYTES_ARE_IN_FRAME(cur_offset, 1)) {
785 /* We ran past the end of the captured data in the packet. */
788 proto_tree_add_text(rr_tree, cur_offset, 1, "Version: %u", pd[cur_offset]);
789 if (pd[cur_offset] == 0) {
790 /* Version 0, the only version RFC 1876 discusses. */
793 if (!BYTES_ARE_IN_FRAME(cur_offset, 1)) {
794 /* We ran past the end of the captured data in the packet. */
797 proto_tree_add_text(rr_tree, cur_offset, 1, "Size: %g m",
798 rfc1867_size(pd[cur_offset]));
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, "Horizontal precision: %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, "Vertical precision: %g m",
814 rfc1867_size(pd[cur_offset]));
817 if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
818 /* We ran past the end of the captured data in the packet. */
821 proto_tree_add_text(rr_tree, cur_offset, 4, "Latitude: %s",
822 rfc1867_angle(&pd[cur_offset], "NS"));
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, "Longitude: %s",
830 rfc1867_angle(&pd[cur_offset], "EW"));
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, "Altitude: %g m",
838 (pntohl(&pd[cur_offset]) - 10000000)/100.0);
840 proto_tree_add_text(rr_tree, cur_offset, data_len, "Data");
845 /* TODO: parse more record types */
848 trr = proto_tree_add_text(dns_tree, offset, (dptr - data_start) + data_len,
849 "%s: type %s, class %s",
850 name, type_name, class_name);
851 rr_tree = add_rr_to_tree(trr, ETT_DNS_RR, offset, name, name_len,
852 long_type_name, class_name, ttl, data_len);
853 proto_tree_add_text(rr_tree, cur_offset, data_len, "Data");
858 return dptr - data_start;
862 dissect_query_records(const u_char *pd, int cur_off, int dns_data_offset,
863 int count, proto_tree *dns_tree)
865 int start_off, add_off;
870 ti = proto_tree_add_text(dns_tree, start_off, 0, "Queries");
871 qatree = proto_item_add_subtree(ti, ETT_DNS_QRY);
872 while (count-- > 0) {
873 add_off = dissect_dns_query(pd, cur_off, dns_data_offset, qatree);
875 /* We ran past the end of the captured data in the packet. */
880 proto_item_set_len(ti, cur_off - start_off);
882 return cur_off - start_off;
886 dissect_answer_records(const u_char *pd, int cur_off, int dns_data_offset,
887 int count, proto_tree *dns_tree, char *name)
889 int start_off, add_off;
894 ti = proto_tree_add_text(dns_tree, start_off, 0, name);
895 qatree = proto_item_add_subtree(ti, ETT_DNS_ANS);
896 while (count-- > 0) {
897 add_off = dissect_dns_answer(pd, cur_off, dns_data_offset, qatree);
899 /* We ran past the end of the captured data in the packet. */
904 proto_item_set_len(ti, cur_off - start_off);
906 return cur_off - start_off;
910 dissect_dns(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
913 proto_tree *dns_tree, *field_tree;
915 guint16 id, flags, quest, ans, auth, add;
918 static const value_string opcode_vals[] = {
919 { OPCODE_QUERY, "Standard query" },
920 { OPCODE_IQUERY, "Inverse query" },
921 { OPCODE_STATUS, "Server status request" },
923 static const value_string rcode_vals[] = {
924 { RCODE_NOERROR, "No error" },
925 { RCODE_FMTERROR, "Format error" },
926 { RCODE_SERVFAIL, "Server failure" },
927 { RCODE_NAMEERROR, "Name error" },
928 { RCODE_NOTIMPL, "Not implemented" },
929 { RCODE_REFUSED, "Refused" },
932 dns_data_offset = offset;
934 if (check_col(fd, COL_PROTOCOL))
935 col_add_str(fd, COL_PROTOCOL, "DNS (UDP)");
937 if (pi.captured_len < DNS_HDRLEN) {
938 col_add_str(fd, COL_INFO, "Short DNS packet");
939 dissect_data(pd, offset, fd, tree);
943 /* To do: check for errs, etc. */
944 id = pntohs(&pd[offset + DNS_ID]);
945 flags = pntohs(&pd[offset + DNS_FLAGS]);
946 quest = pntohs(&pd[offset + DNS_QUEST]);
947 ans = pntohs(&pd[offset + DNS_ANS]);
948 auth = pntohs(&pd[offset + DNS_AUTH]);
949 add = pntohs(&pd[offset + DNS_ADD]);
951 if (check_col(fd, COL_INFO)) {
952 col_add_fstr(fd, COL_INFO, "%s%s",
953 val_to_str(flags & F_OPCODE, opcode_vals,
954 "Unknown operation (%x)"),
955 (flags & F_RESPONSE) ? " response" : "");
959 ti = proto_tree_add_item_format(tree, proto_dns, offset, 4, NULL,
960 (flags & F_RESPONSE) ? "DNS response" : "DNS query");
962 dns_tree = proto_item_add_subtree(ti, ETT_DNS);
964 proto_tree_add_text(dns_tree, offset + DNS_ID, 2, "Transaction ID: 0x%04x",
967 strcpy(buf, val_to_str(flags & F_OPCODE, opcode_vals, "Unknown operation"));
968 if (flags & F_RESPONSE) {
969 strcat(buf, " response");
971 strcat(buf, val_to_str(flags & F_RCODE, rcode_vals,
974 tf = proto_tree_add_text(dns_tree, offset + DNS_FLAGS, 2, "Flags: 0x%04x (%s)",
976 field_tree = proto_item_add_subtree(tf, ETT_DNS_FLAGS);
977 proto_tree_add_text(field_tree, offset + DNS_FLAGS, 2, "%s",
978 decode_boolean_bitfield(flags, F_RESPONSE,
979 2*8, "Response", "Query"));
980 proto_tree_add_text(field_tree, offset + DNS_FLAGS, 2, "%s",
981 decode_enumerated_bitfield(flags, F_OPCODE,
982 2*8, opcode_vals, "%s"));
983 if (flags & F_RESPONSE) {
984 proto_tree_add_text(field_tree, offset + DNS_FLAGS, 2, "%s",
985 decode_boolean_bitfield(flags, F_AUTHORITATIVE,
987 "Server is an authority for domain",
988 "Server isn't an authority for domain"));
990 proto_tree_add_text(field_tree, offset + DNS_FLAGS, 2, "%s",
991 decode_boolean_bitfield(flags, F_TRUNCATED,
993 "Message is truncated",
994 "Message is not truncated"));
995 proto_tree_add_text(field_tree, offset + DNS_FLAGS, 2, "%s",
996 decode_boolean_bitfield(flags, F_RECDESIRED,
998 "Do query recursively",
999 "Don't do query recursively"));
1000 if (flags & F_RESPONSE) {
1001 proto_tree_add_text(field_tree, offset + DNS_FLAGS, 2, "%s",
1002 decode_boolean_bitfield(flags, F_RECAVAIL,
1004 "Server can do recursive queries",
1005 "Server can't do recursive queries"));
1006 proto_tree_add_text(field_tree, offset + DNS_FLAGS, 2, "%s",
1007 decode_enumerated_bitfield(flags, F_RCODE,
1008 2*8, rcode_vals, "%s"));
1010 proto_tree_add_text(dns_tree, offset + DNS_QUEST, 2, "Questions: %d", quest);
1011 proto_tree_add_text(dns_tree, offset + DNS_ANS, 2, "Answer RRs: %d", ans);
1012 proto_tree_add_text(dns_tree, offset + DNS_AUTH, 2, "Authority RRs: %d", auth);
1013 proto_tree_add_text(dns_tree, offset + DNS_ADD, 2, "Additional RRs: %d", add);
1015 cur_off = offset + DNS_HDRLEN;
1018 cur_off += dissect_query_records(pd, cur_off, dns_data_offset, quest,
1022 cur_off += dissect_answer_records(pd, cur_off, dns_data_offset, ans,
1023 dns_tree, "Answers");
1026 cur_off += dissect_answer_records(pd, cur_off, dns_data_offset, auth,
1027 dns_tree, "Authoritative nameservers");
1030 cur_off += dissect_answer_records(pd, cur_off, dns_data_offset, add,
1031 dns_tree, "Additional records");
1036 proto_register_dns(void)
1038 /* static hf_register_info hf[] = {
1040 { "Name", "dns.abbreviation", TYPE, VALS_POINTER }},
1043 proto_dns = proto_register_protocol("Domain Name Service", "dns");
1044 /* proto_register_field_array(proto_dns, hf, array_length(hf));*/