/* packet-dns.c
* Routines for DNS packet disassembly
*
- * $Id: packet-dns.c,v 1.27 1999/11/10 06:01:21 guy Exp $
+ * $Id: packet-dns.c,v 1.33 1999/12/29 10:36:13 guy Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@zing.org>
static int hf_dns_count_auth_rr = -1;
static int hf_dns_count_add_rr = -1;
+static gint ett_dns = -1;
+static gint ett_dns_qd = -1;
+static gint ett_dns_rr = -1;
+static gint ett_dns_qry = -1;
+static gint ett_dns_ans = -1;
+static gint ett_dns_flags = -1;
+static gint ett_t_key_flags = -1;
+
/* DNS structs and definitions */
/* Offsets of fields in the DNS header. */
/* See RFC 1035 for all RR types for which no RFC is listed. */
static char *
-dns_type_name (int type)
+dns_type_name (u_int type)
{
char *type_names[36] = {
"unused",
case 255:
return "ANY";
}
-
+
return "unknown";
}
static char *
-dns_long_type_name (int type)
+dns_long_type_name (u_int type)
{
char *type_names[36] = {
"unused",
if (dns_tree != NULL) {
tq = proto_tree_add_text(dns_tree, offset, len, "%s: type %s, class %s",
name, type_name, class_name);
- q_tree = proto_item_add_subtree(tq, ETT_DNS_QD);
+ q_tree = proto_item_add_subtree(tq, ett_dns_qd);
proto_tree_add_text(q_tree, offset, name_len, "Name: %s", name);
offset += name_len;
return rr_tree;
}
+/*
+ * SIG and KEY RR algorithms.
+ */
+#define DNS_ALGO_MD5 1 /* MD5/RSA */
+#define DNS_ALGO_EDATE 253 /* Expiration date */
+#define DNS_ALGO_PRIVATE 254 /* Private use */
+
+static const value_string algo_vals[] = {
+ { DNS_ALGO_MD5, "MD5/RSA" },
+ { DNS_ALGO_EDATE, "Expiration date" },
+ { DNS_ALGO_PRIVATE, "Private use" },
+ { 0, NULL }
+};
+
static int
dissect_dns_answer(const u_char *pd, int offset, int dns_data_offset,
frame_data *fd, proto_tree *dns_tree)
"%s: type %s, class %s, addr %s",
name, type_name, class_name,
ip_to_str((guint8 *)dptr));
- rr_tree = add_rr_to_tree(trr, ETT_DNS_RR, offset, name, name_len,
+ rr_tree = add_rr_to_tree(trr, ett_dns_rr, offset, name, name_len,
long_type_name, class_name, ttl, data_len);
if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
/* We ran past the end of the captured data in the packet. */
trr = proto_tree_add_text(dns_tree, offset, (dptr - data_start) + data_len,
"%s: type %s, class %s, ns %s",
name, type_name, class_name, ns_name);
- rr_tree = add_rr_to_tree(trr, ETT_DNS_RR, offset, name, name_len,
+ rr_tree = add_rr_to_tree(trr, ett_dns_rr, offset, name, name_len,
long_type_name, class_name, ttl, data_len);
if (ns_name_len < 0) {
/* We ran past the end of the captured data in the packet. */
trr = proto_tree_add_text(dns_tree, offset, (dptr - data_start) + data_len,
"%s: type %s, class %s, cname %s",
name, type_name, class_name, cname);
- rr_tree = add_rr_to_tree(trr, ETT_DNS_RR, offset, name, name_len,
+ rr_tree = add_rr_to_tree(trr, ett_dns_rr, offset, name, name_len,
long_type_name, class_name, ttl, data_len);
if (cname_len < 0) {
/* We ran past the end of the captured data in the packet. */
trr = proto_tree_add_text(dns_tree, offset, (dptr - data_start) + data_len,
"%s: type %s, class %s, mname %s",
name, type_name, class_name, mname);
- rr_tree = add_rr_to_tree(trr, ETT_DNS_RR, offset, name, name_len,
+ rr_tree = add_rr_to_tree(trr, ett_dns_rr, offset, name, name_len,
long_type_name, class_name, ttl, data_len);
if (mname_len < 0) {
/* We ran past the end of the captured data in the packet. */
trr = proto_tree_add_text(dns_tree, offset, (dptr - data_start) + data_len,
"%s: type %s, class %s, ptr %s",
name, type_name, class_name, pname);
- rr_tree = add_rr_to_tree(trr, ETT_DNS_RR, offset, name, name_len,
+ rr_tree = add_rr_to_tree(trr, ett_dns_rr, offset, name, name_len,
long_type_name, class_name, ttl, data_len);
if (pname_len < 0) {
/* We ran past the end of the captured data in the packet. */
}
break;
+ case T_HINFO:
+ {
+ int cpu_offset;
+ int cpu_len;
+ int os_offset;
+ int os_len;
+
+ cpu_offset = cur_offset;
+ if (!BYTES_ARE_IN_FRAME(cpu_offset, 1)) {
+ /* We ran past the end of the captured data in the packet. */
+ if (dns_tree != NULL) {
+ trr = proto_tree_add_text(dns_tree, offset, (dptr - data_start) + data_len,
+ "%s: type %s, class %s, <CPU goes past end of captured data in packet>",
+ name, type_name, class_name);
+ rr_tree = add_rr_to_tree(trr, ett_dns_rr, offset, name, name_len,
+ long_type_name, class_name, ttl, data_len);
+ }
+ return 0;
+ }
+ cpu_len = pd[cpu_offset];
+ if (!BYTES_ARE_IN_FRAME(cpu_offset + 1, cpu_len)) {
+ /* We ran past the end of the captured data in the packet. */
+ if (dns_tree != NULL) {
+ trr = proto_tree_add_text(dns_tree, offset, (dptr - data_start) + data_len,
+ "%s: type %s, class %s, <CPU goes past end of captured data in packet>",
+ name, type_name, class_name);
+ rr_tree = add_rr_to_tree(trr, ett_dns_rr, offset, name, name_len,
+ long_type_name, class_name, ttl, data_len);
+ }
+ return 0;
+ }
+ os_offset = cpu_offset + 1 + cpu_len;
+ if (!BYTES_ARE_IN_FRAME(os_offset, 1)) {
+ /* We ran past the end of the captured data in the packet. */
+ if (dns_tree != NULL) {
+ trr = proto_tree_add_text(dns_tree, offset, (dptr - data_start) + data_len,
+ "%s: type %s, class %s, CPU %.*s, <OS goes past end of captured data in packet>",
+ name, type_name, class_name, cpu_len, &pd[cpu_offset + 1]);
+ rr_tree = add_rr_to_tree(trr, ett_dns_rr, offset, name, name_len,
+ long_type_name, class_name, ttl, data_len);
+ }
+ return 0;
+ }
+ os_len = pd[os_offset];
+ if (!BYTES_ARE_IN_FRAME(os_offset + 1, os_len)) {
+ /* We ran past the end of the captured data in the packet. */
+ if (dns_tree != NULL) {
+ trr = proto_tree_add_text(dns_tree, offset, (dptr - data_start) + data_len,
+ "%s: type %s, class %s, CPU %*.s, <OS goes past end of captured data in packet>",
+ name, type_name, class_name, cpu_len, &pd[cpu_offset + 1]);
+ rr_tree = add_rr_to_tree(trr, ett_dns_rr, offset, name, name_len,
+ long_type_name, class_name, ttl, data_len);
+ }
+ return 0;
+ }
+ if (fd != NULL)
+ col_append_fstr(fd, COL_INFO, " %s %.*s %.*s", type_name, cpu_len,
+ &pd[cpu_offset + 1], os_len, &pd[os_offset + 1]);
+ if (dns_tree != NULL) {
+ trr = proto_tree_add_text(dns_tree, offset, (dptr - data_start) + data_len,
+ "%s: type %s, class %s, CPU %.*s, OS %.*s",
+ name, type_name, class_name,
+ cpu_len, &pd[cpu_offset + 1], os_len, &pd[os_offset + 1]);
+ rr_tree = add_rr_to_tree(trr, ett_dns_rr, offset, name, name_len,
+ long_type_name, class_name, ttl, data_len);
+ proto_tree_add_text(rr_tree, cpu_offset, 1 + cpu_len, "CPU: %.*s",
+ cpu_len, &pd[cpu_offset + 1]);
+ proto_tree_add_text(rr_tree, os_offset, 1 + os_len, "OS: %.*s",
+ os_len, &pd[os_offset + 1]);
+ }
+ break;
+ }
+ break;
+
case T_MX:
{
guint16 preference = 0;
trr = proto_tree_add_text(dns_tree, offset, (dptr - data_start) + data_len,
"%s: type %s, class %s, <preference goes past end of captured data in packet>",
name, type_name, class_name);
- rr_tree = add_rr_to_tree(trr, ETT_DNS_RR, offset, name, name_len,
+ rr_tree = add_rr_to_tree(trr, ett_dns_rr, offset, name, name_len,
long_type_name, class_name, ttl, data_len);
}
return 0;
trr = proto_tree_add_text(dns_tree, offset, (dptr - data_start) + data_len,
"%s: type %s, class %s, preference %u, <mx goes past end of captured data in packet>",
name, type_name, class_name, preference);
- rr_tree = add_rr_to_tree(trr, ETT_DNS_RR, offset, name, name_len,
+ rr_tree = add_rr_to_tree(trr, ett_dns_rr, offset, name, name_len,
long_type_name, class_name, ttl, data_len);
}
return 0;
trr = proto_tree_add_text(dns_tree, offset, (dptr - data_start) + data_len,
"%s: type %s, class %s, preference %u, mx %s",
name, type_name, class_name, preference, mx_name);
- rr_tree = add_rr_to_tree(trr, ETT_DNS_RR, offset, name, name_len,
+ rr_tree = add_rr_to_tree(trr, ett_dns_rr, offset, name, name_len,
long_type_name, class_name, ttl, data_len);
proto_tree_add_text(rr_tree, cur_offset, 2, "Preference: %u", preference);
proto_tree_add_text(rr_tree, cur_offset + 2, mx_name_len, "Mail exchange: %s",
}
}
break;
-
+
+ case T_SIG:
+ {
+ int rr_len = data_len;
+ struct timeval unixtime;
+ char signer_name[MAXDNAME];
+ int signer_name_len;
+
+ if (fd != NULL)
+ col_append_fstr(fd, COL_INFO, " %s", type_name);
+ if (dns_tree != NULL) {
+ trr = proto_tree_add_text(dns_tree, offset, (dptr - data_start) + data_len,
+ "%s: type %s, class %s",
+ name, type_name, class_name);
+ rr_tree = add_rr_to_tree(trr, ett_dns_rr, offset, name, name_len,
+ long_type_name, class_name, ttl, data_len);
+
+ if (!BYTES_ARE_IN_FRAME(cur_offset, 2)) {
+ /* We ran past the end of the captured data in the packet. */
+ return 0;
+ }
+ proto_tree_add_text(rr_tree, cur_offset, 2, "Type covered: %s (%s)",
+ dns_type_name(pntohs(&pd[cur_offset])),
+ dns_long_type_name(pntohs(&pd[cur_offset])));
+ cur_offset += 2;
+ rr_len -= 2;
+
+ if (!BYTES_ARE_IN_FRAME(cur_offset, 1)) {
+ /* We ran past the end of the captured data in the packet. */
+ return 0;
+ }
+ proto_tree_add_text(rr_tree, cur_offset, 1, "Algorithm: %s",
+ val_to_str(pd[cur_offset], algo_vals,
+ "Unknown (0x%02X)"));
+ cur_offset += 1;
+ rr_len -= 1;
+
+ if (!BYTES_ARE_IN_FRAME(cur_offset, 1)) {
+ /* We ran past the end of the captured data in the packet. */
+ return 0;
+ }
+ proto_tree_add_text(rr_tree, cur_offset, 1, "Labels: %u",
+ pd[cur_offset]);
+ cur_offset += 1;
+ rr_len -= 1;
+
+ if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
+ /* We ran past the end of the captured data in the packet. */
+ return 0;
+ }
+ proto_tree_add_text(rr_tree, cur_offset, 4, "Original TTL: %s",
+ time_secs_to_str(pntohl(&pd[cur_offset])));
+ cur_offset += 4;
+ rr_len -= 4;
+
+ if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
+ /* We ran past the end of the captured data in the packet. */
+ return 0;
+ }
+ unixtime.tv_sec = pntohl(&pd[cur_offset]);
+ unixtime.tv_usec = 0;
+ proto_tree_add_text(rr_tree, cur_offset, 4, "Signature expiration: %s",
+ abs_time_to_str(&unixtime));
+ cur_offset += 4;
+ rr_len -= 4;
+
+ if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
+ /* We ran past the end of the captured data in the packet. */
+ return 0;
+ }
+ unixtime.tv_sec = pntohl(&pd[cur_offset]);
+ unixtime.tv_usec = 0;
+ proto_tree_add_text(rr_tree, cur_offset, 4, "Time signed: %s",
+ abs_time_to_str(&unixtime));
+ cur_offset += 4;
+ rr_len -= 4;
+
+ if (!BYTES_ARE_IN_FRAME(cur_offset, 2)) {
+ /* We ran past the end of the captured data in the packet. */
+ return 0;
+ }
+ proto_tree_add_text(rr_tree, cur_offset, 2, "Key footprint: 0x%04x",
+ pntohs(&pd[cur_offset]));
+ cur_offset += 2;
+ rr_len -= 2;
+
+ signer_name_len = get_dns_name(pd, cur_offset, dns_data_offset, signer_name, sizeof(signer_name));
+ if (signer_name_len < 0) {
+ /* We ran past the end of the captured data in the packet. */
+ return 0;
+ }
+ proto_tree_add_text(rr_tree, cur_offset, signer_name_len,
+ "Signer's name: %s", signer_name);
+ cur_offset += signer_name_len;
+ rr_len -= signer_name_len;
+
+ proto_tree_add_text(rr_tree, cur_offset, rr_len, "Signature");
+ }
+ }
+ break;
+
+ case T_KEY:
+ {
+ int rr_len = data_len;
+ guint16 flags;
+ proto_item *tf;
+ proto_tree *flags_tree;
+
+ if (fd != NULL)
+ col_append_fstr(fd, COL_INFO, " %s", type_name);
+ if (dns_tree != NULL) {
+ trr = proto_tree_add_text(dns_tree, offset, (dptr - data_start) + data_len,
+ "%s: type %s, class %s",
+ name, type_name, class_name);
+ rr_tree = add_rr_to_tree(trr, ett_dns_rr, offset, name, name_len,
+ long_type_name, class_name, ttl, data_len);
+
+ if (!BYTES_ARE_IN_FRAME(cur_offset, 2)) {
+ /* We ran past the end of the captured data in the packet. */
+ return 0;
+ }
+ flags = pntohs(&pd[cur_offset]);
+ tf = proto_tree_add_text(rr_tree, cur_offset, 2, "Flags: 0x%04X", flags);
+ flags_tree = proto_item_add_subtree(tf, ett_t_key_flags);
+ proto_tree_add_text(flags_tree, cur_offset, 2, "%s",
+ decode_boolean_bitfield(flags, 0x8000,
+ 2*8, "Key prohibited for authentication",
+ "Key allowed for authentication"));
+ proto_tree_add_text(flags_tree, cur_offset, 2, "%s",
+ decode_boolean_bitfield(flags, 0x4000,
+ 2*8, "Key prohibited for confidentiality",
+ "Key allowed for confidentiality"));
+ if ((flags & 0xC000) != 0xC000) {
+ /* We have a key */
+ proto_tree_add_text(flags_tree, cur_offset, 2, "%s",
+ decode_boolean_bitfield(flags, 0x2000,
+ 2*8, "Key is experimental or optional",
+ "Key is required"));
+ proto_tree_add_text(flags_tree, cur_offset, 2, "%s",
+ decode_boolean_bitfield(flags, 0x0400,
+ 2*8, "Key is associated with a user",
+ "Key is not associated with a user"));
+ proto_tree_add_text(flags_tree, cur_offset, 2, "%s",
+ decode_boolean_bitfield(flags, 0x0200,
+ 2*8, "Key is associated with the named entity",
+ "Key is not associated with the named entity"));
+ proto_tree_add_text(flags_tree, cur_offset, 2, "%s",
+ decode_boolean_bitfield(flags, 0x0100,
+ 2*8, "This is the zone key for the specified zone",
+ "This is not a zone key"));
+ proto_tree_add_text(flags_tree, cur_offset, 2, "%s",
+ decode_boolean_bitfield(flags, 0x0080,
+ 2*8, "Key is valid for use with IPSEC",
+ "Key is not valid for use with IPSEC"));
+ proto_tree_add_text(flags_tree, cur_offset, 2, "%s",
+ decode_boolean_bitfield(flags, 0x0040,
+ 2*8, "Key is valid for use with MIME security multiparts",
+ "Key is not valid for use with MIME security multiparts"));
+ proto_tree_add_text(flags_tree, cur_offset, 2, "%s",
+ decode_numeric_bitfield(flags, 0x000F,
+ 2*8, "Signatory = %u"));
+ }
+ cur_offset += 2;
+ rr_len -= 2;
+
+ if (!BYTES_ARE_IN_FRAME(cur_offset, 1)) {
+ /* We ran past the end of the captured data in the packet. */
+ return 0;
+ }
+ proto_tree_add_text(rr_tree, cur_offset, 1, "Protocol: %u",
+ pd[cur_offset]);
+ cur_offset += 1;
+ rr_len -= 1;
+
+ if (!BYTES_ARE_IN_FRAME(cur_offset, 1)) {
+ /* We ran past the end of the captured data in the packet. */
+ return 0;
+ }
+ proto_tree_add_text(rr_tree, cur_offset, 1, "Algorithm: %s",
+ val_to_str(pd[cur_offset], algo_vals,
+ "Unknown (0x%02X)"));
+ cur_offset += 1;
+ rr_len -= 1;
+
+ proto_tree_add_text(rr_tree, cur_offset, rr_len, "Public key");
+ }
+ }
+ break;
+
+ case T_AAAA:
+ if (fd != NULL) {
+ col_append_fstr(fd, COL_INFO, " %s %s", type_name,
+ ip6_to_str((struct e_in6_addr *)dptr));
+ }
+ if (dns_tree != NULL) {
+ trr = proto_tree_add_text(dns_tree, offset, (dptr - data_start) + data_len,
+ "%s: type %s, class %s, addr %s",
+ name, type_name, class_name,
+ ip6_to_str((struct e_in6_addr *)dptr));
+ rr_tree = add_rr_to_tree(trr, ett_dns_rr, offset, name, name_len,
+ long_type_name, class_name, ttl, data_len);
+ if (!BYTES_ARE_IN_FRAME(cur_offset, 16)) {
+ /* We ran past the end of the captured data in the packet. */
+ return 0;
+ }
+ proto_tree_add_text(rr_tree, cur_offset, 16, "Addr: %s",
+ ip6_to_str((struct e_in6_addr *)dptr));
+ }
+ break;
+
case T_LOC:
{
if (fd != NULL)
trr = proto_tree_add_text(dns_tree, offset, (dptr - data_start) + data_len,
"%s: type %s, class %s",
name, type_name, class_name);
- rr_tree = add_rr_to_tree(trr, ETT_DNS_RR, offset, name, name_len,
+ rr_tree = add_rr_to_tree(trr, ett_dns_rr, offset, name, name_len,
long_type_name, class_name, ttl, data_len);
if (!BYTES_ARE_IN_FRAME(cur_offset, 1)) {
/* We ran past the end of the captured data in the packet. */
}
break;
+ case T_NXT:
+ {
+ int rr_len = data_len;
+ char next_domain_name[MAXDNAME];
+ int next_domain_name_len;
+ int rr_type;
+ guint8 bits;
+ int mask;
+ int i;
+
+ next_domain_name_len = get_dns_name(pd, cur_offset, dns_data_offset,
+ next_domain_name, sizeof(next_domain_name));
+ if (fd != NULL)
+ col_append_fstr(fd, COL_INFO, " %s %s", type_name, next_domain_name);
+ if (dns_tree != NULL) {
+ trr = proto_tree_add_text(dns_tree, offset, (dptr - data_start) + data_len,
+ "%s: type %s, class %s, next domain name %s",
+ name, type_name, class_name, next_domain_name);
+ rr_tree = add_rr_to_tree(trr, ett_dns_rr, offset, name, name_len,
+ long_type_name, class_name, ttl, data_len);
+ if (next_domain_name_len < 0) {
+ /* We ran past the end of the captured data in the packet. */
+ return 0;
+ }
+ proto_tree_add_text(rr_tree, cur_offset, next_domain_name_len,
+ "Next domain name: %s", next_domain_name);
+ cur_offset += next_domain_name_len;
+ rr_len -= next_domain_name_len;
+ rr_type = 0;
+ while (rr_len != 0) {
+ bits = pd[cur_offset];
+ mask = 1<<8;
+ for (i = 0; i < 8; i++) {
+ if (bits & mask) {
+ proto_tree_add_text(rr_tree, cur_offset, 1,
+ "RR type in bit map: %s (%s)",
+ dns_type_name(rr_type),
+ dns_long_type_name(rr_type));
+ }
+ mask >>= 1;
+ rr_type++;
+ }
+ cur_offset += 1;
+ rr_len -= 1;
+ }
+ }
+ }
+ break;
+
/* TODO: parse more record types */
default:
trr = proto_tree_add_text(dns_tree, offset, (dptr - data_start) + data_len,
"%s: type %s, class %s",
name, type_name, class_name);
- rr_tree = add_rr_to_tree(trr, ETT_DNS_RR, offset, name, name_len,
+ rr_tree = add_rr_to_tree(trr, ett_dns_rr, offset, name, name_len,
long_type_name, class_name, ttl, data_len);
proto_tree_add_text(rr_tree, cur_offset, data_len, "Data");
}
+ break;
}
dptr += data_len;
start_off = cur_off;
if (dns_tree) {
ti = proto_tree_add_text(dns_tree, start_off, 0, "Queries");
- qatree = proto_item_add_subtree(ti, ETT_DNS_QRY);
+ qatree = proto_item_add_subtree(ti, ett_dns_qry);
}
while (count-- > 0) {
add_off = dissect_dns_query(pd, cur_off, dns_data_offset, fd, qatree);
start_off = cur_off;
if (dns_tree) {
ti = proto_tree_add_text(dns_tree, start_off, 0, name);
- qatree = proto_item_add_subtree(ti, ETT_DNS_ANS);
+ qatree = proto_item_add_subtree(ti, ett_dns_ans);
}
while (count-- > 0) {
add_off = dissect_dns_answer(pd, cur_off, dns_data_offset, fd, qatree);
dns_data_offset = offset;
if (check_col(fd, COL_PROTOCOL))
- col_add_str(fd, COL_PROTOCOL, "DNS (UDP)");
+ col_add_str(fd, COL_PROTOCOL, "DNS");
if (pi.captured_len < DNS_HDRLEN) {
col_add_str(fd, COL_INFO, "Short DNS packet");
add = pntohs(&pd[offset + DNS_ADD]);
if (check_col(fd, COL_INFO)) {
- col_add_fstr(fd, COL_INFO, "%s%s",
- val_to_str(flags & F_OPCODE, opcode_vals,
- "Unknown operation (%x)"),
- (flags & F_RESPONSE) ? " response" : "");
+ strcpy(buf, val_to_str(flags & F_OPCODE, opcode_vals, "Unknown operation (%x)"));
+ if (flags & F_RESPONSE) {
+ strcat(buf, " response");
+ if ((flags & F_RCODE) != RCODE_NOERROR) {
+ strcat(buf, ", ");
+ strcat(buf, val_to_str(flags & F_RCODE, rcode_vals,
+ "Unknown error (%x)"));
+ }
+ }
+ col_add_str(fd, COL_INFO, buf);
} else {
/* Set "fd" to NULL; we pass a NULL "fd" to the query and answer
dissectors, as a way of saying that they shouldn't add stuff
if (tree) {
ti = proto_tree_add_item_format(tree, proto_dns, offset, 4, NULL,
- (flags & F_RESPONSE) ? "DNS response" : "DNS query");
+ "Domain Name System (%s)", (flags & F_RESPONSE) ? "response" : "query");
- dns_tree = proto_item_add_subtree(ti, ETT_DNS);
+ dns_tree = proto_item_add_subtree(ti, ett_dns);
if (flags & F_RESPONSE)
proto_tree_add_item_hidden(dns_tree, hf_dns_response, offset, 4, 1);
flags,
"Flags: 0x%04x (%s)",
flags, buf);
- field_tree = proto_item_add_subtree(tf, ETT_DNS_FLAGS);
+ field_tree = proto_item_add_subtree(tf, ett_dns_flags);
proto_tree_add_text(field_tree, offset + DNS_FLAGS, 2, "%s",
decode_boolean_bitfield(flags, F_RESPONSE,
2*8, "Response", "Query"));
FT_UINT16, BASE_DEC, NULL, 0x0,
"Number of additional records in packet" }}
};
+ static gint *ett[] = {
+ &ett_dns,
+ &ett_dns_qd,
+ &ett_dns_rr,
+ &ett_dns_qry,
+ &ett_dns_ans,
+ &ett_dns_flags,
+ &ett_t_key_flags,
+ };
proto_dns = proto_register_protocol("Domain Name Service", "dns");
proto_register_field_array(proto_dns, hf, array_length(hf));
-
+ proto_register_subtree_array(ett, array_length(ett));
}