/* packet-nbns.c
- * Routines for NetBIOS Name Service, Datagram Service, and Session Service
- * packet disassembly (the name dates back to when it had only NBNS)
- * Gilbert Ramirez <gram@verdict.uthscsa.edu>
- * Much stuff added by Guy Harris <guy@netapp.com>
+ * Routines for NetBIOS-over-TCP packet disassembly (the name dates back
+ * to when it had only NBNS)
+ * Gilbert Ramirez <gram@xiexie.org>
+ * Much stuff added by Guy Harris <guy@alum.mit.edu>
*
- * $Id: packet-nbns.c,v 1.17 1999/05/10 20:02:57 guy Exp $
+ * $Id: packet-nbns.c,v 1.38 2000/03/12 04:47:42 gram Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@zing.org>
#include <stdio.h>
#include <string.h>
#include <glib.h>
+
#include "packet.h"
#include "packet-dns.h"
-#include "util.h"
+#include "packet-netbios.h"
+#include "packet-smb.h"
+
+static int proto_nbns = -1;
+static int hf_nbns_response = -1;
+static int hf_nbns_query = -1;
+static int hf_nbns_transaction_id = -1;
+static int hf_nbns_count_questions = -1;
+static int hf_nbns_count_answers = -1;
+static int hf_nbns_count_auth_rr = -1;
+static int hf_nbns_count_add_rr = -1;
+
+static gint ett_nbns = -1;
+static gint ett_nbns_qd = -1;
+static gint ett_nbns_flags = -1;
+static gint ett_nbns_nb_flags = -1;
+static gint ett_nbns_name_flags = -1;
+static gint ett_nbns_rr = -1;
+static gint ett_nbns_qry = -1;
+static gint ett_nbns_ans = -1;
+
+static int proto_nbdgm = -1;
+static int hf_nbdgm_type = -1;
+static int hf_nbdgm_fragment = -1;
+static int hf_nbdgm_first = -1;
+static int hf_nbdgm_node_type = -1;
+static int hf_nbdgm_datagram_id = -1;
+static int hf_nbdgm_src_ip = -1;
+static int hf_nbdgm_src_port = -1;
+
+static gint ett_nbdgm = -1;
+
+static int proto_nbss = -1;
+static int hf_nbss_type = -1;
+static int hf_nbss_flags = -1;
+
+static gint ett_nbss = -1;
+static gint ett_nbss_flags = -1;
/* Packet structure taken from RFC 1002. See also RFC 1001.
* Opcode, flags, and rcode treated as "flags", similarly to DNS,
return "unknown";
}
-/* "Canonicalize" a 16-character NetBIOS name by:
- *
- * removing and saving the last byte;
- *
- * stripping trailing blanks;
- *
- * appending the trailing byte, as a hex number, in square brackets. */
-static char *
-canonicalize_netbios_name(char *nbname)
-{
- char *pnbname;
- u_char lastchar;
-
- /* Get the last character of the name, as it's a special number
- * indicating the type of the name, rather than part of the name
- * *per se*. */
- pnbname = nbname + 15; /* point to the 16th character */
- lastchar = *(unsigned char *)pnbname;
-
- /* Now strip off any trailing blanks used to pad it to
- * 16 bytes. */
- while (pnbname > &nbname[0]) {
- if (*(pnbname - 1) != ' ')
- break; /* found non-blank character */
- pnbname--; /* blank - skip over it */
- }
-
- /* Replace the last character with its hex value, in square
- * brackets, to make it easier to tell what it is. */
- sprintf(pnbname, "[%02X]", lastchar);
- pnbname += 4;
- return pnbname;
-}
-
static int
-get_nbns_name(const u_char *nbns_data_ptr, const u_char *pd,
- int offset, char *name_ret)
+get_nbns_name(const u_char *pd, int offset, int nbns_data_offset,
+ char *name_ret, int *name_type_ret)
{
int name_len;
char name[MAXDNAME];
- char nbname[MAXDNAME+4]; /* 4 for [<last char>] */
+ char nbname[NETBIOS_NAME_LEN];
char *pname, *pnbname, cname, cnbname;
+ int name_type;
+
+ name_len = get_dns_name(pd, offset, nbns_data_offset, name,
+ sizeof(name));
- name_len = get_dns_name(nbns_data_ptr, pd, offset, name, sizeof(name));
-
/* OK, now undo the first-level encoding. */
pname = &name[0];
pnbname = &nbname[0];
cnbname |= cname;
pname++;
- /* Store the character. */
- *pnbname++ = cnbname;
+ /* Do we have room to store the character? */
+ if (pnbname < &nbname[NETBIOS_NAME_LEN]) {
+ /* Yes - store the character. */
+ *pnbname = cnbname;
+ }
+
+ /* We bump the pointer even if it's past the end of the
+ name, so we keep track of how long the name is. */
+ pnbname++;
}
/* NetBIOS names are supposed to be exactly 16 bytes long. */
- if (pnbname - nbname == 16) {
- /* This one is; canonicalize its name. */
- pnbname = canonicalize_netbios_name(nbname);
- } else {
+ if (pnbname - nbname != NETBIOS_NAME_LEN) {
+ /* It's not. */
sprintf(nbname, "Illegal NetBIOS name (%ld bytes long)",
(long)(pnbname - nbname));
goto bad;
}
+
+ /* This one is; make its name printable. */
+ name_type = process_netbios_name(nbname, name_ret);
+ name_ret += strlen(name_ret);
+ sprintf(name_ret, "<%02x>", name_type);
+ name_ret += 4;
if (cname == '.') {
/* We have a scope ID, starting at "pname"; append that to
* the decoded host name. */
- strcpy(pnbname, pname);
- } else {
- /* Terminate the decoded host name. */
- *pnbname = '\0';
+ strcpy(name_ret, pname);
}
+ if (name_type_ret != NULL)
+ *name_type_ret = name_type;
+ return name_len;
bad:
+ if (name_type_ret != NULL)
+ *name_type_ret = -1;
strcpy (name_ret, nbname);
return name_len;
}
static int
-get_nbns_name_type_class(const u_char *nbns_data_ptr, const u_char *pd,
- int offset, char *name_ret, int *name_len_ret, int *type_ret,
+get_nbns_name_type_class(const u_char *pd, int offset, int nbns_data_offset,
+ char *name_ret, int *name_len_ret, int *name_type_ret, int *type_ret,
int *class_ret)
{
int name_len;
int type;
int class;
- name_len = get_nbns_name(nbns_data_ptr, pd, offset, name_ret);
+ name_len = get_nbns_name(pd, offset, nbns_data_offset, name_ret,
+ name_type_ret);
offset += name_len;
+ if (!BYTES_ARE_IN_FRAME(offset, 2)) {
+ /* We ran past the end of the captured data in the packet. */
+ return -1;
+ }
type = pntohs(&pd[offset]);
offset += 2;
+
+ if (!BYTES_ARE_IN_FRAME(offset, 2)) {
+ /* We ran past the end of the captured data in the packet. */
+ return -1;
+ }
class = pntohs(&pd[offset]);
*type_ret = type;
return name_len + 4;
}
+static void
+add_name_and_type(proto_tree *tree, int offset, int len, char *tag,
+ char *name, int name_type)
+{
+ if (name_type != -1) {
+ proto_tree_add_text(tree, offset, len, "%s: %s (%s)",
+ tag, name, netbios_name_type_descr(name_type));
+ } else {
+ proto_tree_add_text(tree, offset, len, "%s: %s",
+ tag, name);
+ }
+}
static int
-dissect_nbns_query(const u_char *nbns_data_ptr, const u_char *pd, int offset,
- proto_tree *nbns_tree)
+dissect_nbns_query(const u_char *pd, int offset, int nbns_data_offset,
+ frame_data *fd, proto_tree *nbns_tree)
{
int len;
- char name[MAXDNAME];
+ char name[(NETBIOS_NAME_LEN - 1)*4 + MAXDNAME];
int name_len;
+ int name_type;
int type;
int class;
char *class_name;
data_start = dptr = pd + offset;
- len = get_nbns_name_type_class(nbns_data_ptr, pd, offset, name,
- &name_len, &type, &class);
+ len = get_nbns_name_type_class(pd, offset, nbns_data_offset, name,
+ &name_len, &name_type, &type, &class);
+ if (len < 0) {
+ /* We ran past the end of the data in the packet. */
+ return 0;
+ }
dptr += len;
type_name = nbns_type_name(type);
class_name = dns_class_name(class);
- tq = proto_tree_add_item(nbns_tree, offset, len, "%s: type %s, class %s",
- name, type_name, class_name);
- q_tree = proto_tree_new();
- proto_item_add_subtree(tq, q_tree, ETT_NBNS_QD);
+ if (fd != NULL)
+ col_append_fstr(fd, COL_INFO, " %s %s", type_name, name);
+ if (nbns_tree != NULL) {
+ tq = proto_tree_add_text(nbns_tree, offset, len,
+ "%s: type %s, class %s", name, type_name, class_name);
+ q_tree = proto_item_add_subtree(tq, ett_nbns_qd);
- proto_tree_add_item(q_tree, offset, name_len, "Name: %s", name);
- offset += name_len;
+ add_name_and_type(q_tree, offset, name_len, "Name", name,
+ name_type);
+ offset += name_len;
- proto_tree_add_item(q_tree, offset, 2, "Type: %s", type_name);
- offset += 2;
+ proto_tree_add_text(q_tree, offset, 2, "Type: %s", type_name);
+ offset += 2;
- proto_tree_add_item(q_tree, offset, 2, "Class: %s", class_name);
- offset += 2;
+ proto_tree_add_text(q_tree, offset, 2, "Class: %s", class_name);
+ offset += 2;
+ }
return dptr - data_start;
}
strcat(buf, val_to_str(flags & F_RCODE, rcode_vals,
"Unknown error"));
}
- tf = proto_tree_add_item(nbns_tree, offset, 2,
+ tf = proto_tree_add_text(nbns_tree, offset, 2,
"Flags: 0x%04x (%s)", flags, buf);
- field_tree = proto_tree_new();
- proto_item_add_subtree(tf, field_tree, ETT_NBNS_FLAGS);
- proto_tree_add_item(field_tree, offset, 2, "%s",
+ field_tree = proto_item_add_subtree(tf, ett_nbns_flags);
+ proto_tree_add_text(field_tree, offset, 2, "%s",
decode_boolean_bitfield(flags, F_RESPONSE,
2*8, "Response", "Query"));
- proto_tree_add_item(field_tree, offset, 2, "%s",
+ proto_tree_add_text(field_tree, offset, 2, "%s",
decode_enumerated_bitfield(flags, F_OPCODE,
2*8, opcode_vals, "%s"));
if (flags & F_RESPONSE) {
- proto_tree_add_item(field_tree, offset, 2,
+ proto_tree_add_text(field_tree, offset, 2,
"%s",
decode_boolean_bitfield(flags, F_AUTHORITATIVE,
2*8,
"Server is an authority for domain",
"Server isn't an authority for domain"));
}
- proto_tree_add_item(field_tree, offset, 2, "%s",
+ proto_tree_add_text(field_tree, offset, 2, "%s",
decode_boolean_bitfield(flags, F_TRUNCATED,
2*8,
"Message is truncated",
"Message is not truncated"));
- proto_tree_add_item(field_tree, offset, 2, "%s",
+ proto_tree_add_text(field_tree, offset, 2, "%s",
decode_boolean_bitfield(flags, F_RECDESIRED,
2*8,
"Do query recursively",
"Don't do query recursively"));
if (flags & F_RESPONSE) {
- proto_tree_add_item(field_tree, offset, 2,
+ proto_tree_add_text(field_tree, offset, 2,
"%s",
decode_boolean_bitfield(flags, F_RECAVAIL,
2*8,
"Server can do recursive queries",
"Server can't do recursive queries"));
}
- proto_tree_add_item(field_tree, offset, 2, "%s",
+ proto_tree_add_text(field_tree, offset, 2, "%s",
decode_boolean_bitfield(flags, F_BROADCAST,
2*8,
"Broadcast packet",
"Not a broadcast packet"));
if (flags & F_RESPONSE && !is_wack) {
- proto_tree_add_item(field_tree, offset, 2,
+ proto_tree_add_text(field_tree, offset, 2,
"%s",
decode_enumerated_bitfield(flags, F_RCODE,
2*8,
strcat(buf, "group");
else
strcat(buf, "unique");
- tf = proto_tree_add_item(rr_tree, offset, 2, "Flags: 0x%x (%s)", flags,
+ tf = proto_tree_add_text(rr_tree, offset, 2, "Flags: 0x%x (%s)", flags,
buf);
- field_tree = proto_tree_new();
- proto_item_add_subtree(tf, field_tree, ETT_NBNS_NB_FLAGS);
- proto_tree_add_item(field_tree, offset, 2, "%s",
+ field_tree = proto_item_add_subtree(tf, ett_nbns_nb_flags);
+ proto_tree_add_text(field_tree, offset, 2, "%s",
decode_boolean_bitfield(flags, NB_FLAGS_G,
2*8,
"Group name",
"Unique name"));
- proto_tree_add_item(field_tree, offset, 2, "%s",
+ proto_tree_add_text(field_tree, offset, 2, "%s",
decode_enumerated_bitfield(flags, NB_FLAGS_ONT,
2*8, nb_flags_ont_vals, "%s"));
}
strcat(buf, ", active");
if (flags & NAME_FLAGS_PRM)
strcat(buf, ", permanent node name");
- tf = proto_tree_add_item(rr_tree, offset, 2, "Name flags: 0x%x (%s)",
+ tf = proto_tree_add_text(rr_tree, offset, 2, "Name flags: 0x%x (%s)",
flags, buf);
- field_tree = proto_tree_new();
- proto_item_add_subtree(tf, field_tree, ETT_NBNS_NAME_FLAGS);
- proto_tree_add_item(field_tree, offset, 2, "%s",
+ field_tree = proto_item_add_subtree(tf, ett_nbns_name_flags);
+ proto_tree_add_text(field_tree, offset, 2, "%s",
decode_boolean_bitfield(flags, NAME_FLAGS_G,
2*8,
"Group name",
"Unique name"));
- proto_tree_add_item(field_tree, offset, 2, "%s",
+ proto_tree_add_text(field_tree, offset, 2, "%s",
decode_enumerated_bitfield(flags, NAME_FLAGS_ONT,
2*8, name_flags_ont_vals, "%s"));
- proto_tree_add_item(field_tree, offset, 2, "%s",
+ proto_tree_add_text(field_tree, offset, 2, "%s",
decode_boolean_bitfield(flags, NAME_FLAGS_DRG,
2*8,
"Name is being deregistered",
"Name is not being deregistered"));
- proto_tree_add_item(field_tree, offset, 2, "%s",
+ proto_tree_add_text(field_tree, offset, 2, "%s",
decode_boolean_bitfield(flags, NAME_FLAGS_CNF,
2*8,
"Name is in conflict",
"Name is not in conflict"));
- proto_tree_add_item(field_tree, offset, 2, "%s",
+ proto_tree_add_text(field_tree, offset, 2, "%s",
decode_boolean_bitfield(flags, NAME_FLAGS_ACT,
2*8,
"Name is active",
"Name is not active"));
- proto_tree_add_item(field_tree, offset, 2, "%s",
+ proto_tree_add_text(field_tree, offset, 2, "%s",
decode_boolean_bitfield(flags, NAME_FLAGS_PRM,
2*8,
"Permanent node name",
}
static int
-dissect_nbns_answer(const u_char *nbns_data_ptr, const u_char *pd, int offset,
- proto_tree *nbns_tree, int opcode)
+dissect_nbns_answer(const u_char *pd, int offset, int nbns_data_offset,
+ frame_data *fd, proto_tree *nbns_tree, int opcode)
{
int len;
- char name[MAXDNAME];
+ char name[(NETBIOS_NAME_LEN - 1)*4 + MAXDNAME + 64];
int name_len;
+ int name_type;
int type;
int class;
char *class_name;
char *type_name;
const u_char *dptr;
+ int cur_offset;
const u_char *data_start;
u_int ttl;
u_short data_len;
u_short flags;
proto_tree *rr_tree;
proto_item *trr;
+ char name_str[(NETBIOS_NAME_LEN - 1)*4 + 1];
+ u_int num_names;
+ char nbname[16+4+1]; /* 4 for [<last char>] */
+ u_short name_flags;
data_start = dptr = pd + offset;
+ cur_offset = offset;
- len = get_nbns_name_type_class(nbns_data_ptr, pd, offset, name,
- &name_len, &type, &class);
+ len = get_nbns_name_type_class(pd, offset, nbns_data_offset, name,
+ &name_len, &name_type, &type, &class);
+ if (len < 0) {
+ /* We ran past the end of the data in the packet. */
+ return 0;
+ }
dptr += len;
+ cur_offset += len;
type_name = nbns_type_name(type);
class_name = dns_class_name(class);
+ if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
+ /* We ran past the end of the captured data in the packet. */
+ return 0;
+ }
ttl = pntohl(dptr);
dptr += 4;
+ cur_offset += 4;
+ if (!BYTES_ARE_IN_FRAME(cur_offset, 2)) {
+ /* We ran past the end of the captured data in the packet. */
+ return 0;
+ }
data_len = pntohs(dptr);
dptr += 2;
+ cur_offset += 2;
switch (type) {
case T_NB: /* "NB" record */
- trr = proto_tree_add_item(nbns_tree, offset,
+ if (fd != NULL) {
+ if (opcode != OPCODE_WACK) {
+ col_append_fstr(fd, COL_INFO, " %s %s",
+ type_name, ip_to_str((guint8 *)(dptr + 2)));
+ }
+ }
+ if (nbns_tree == NULL)
+ break;
+ trr = proto_tree_add_text(nbns_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_NBNS_RR, offset, name,
+ strcat(name, " (");
+ strcat(name, netbios_name_type_descr(name_type));
+ strcat(name, ")");
+ rr_tree = add_rr_to_tree(trr, ett_nbns_rr, offset, name,
name_len, type_name, class_name, ttl, data_len);
- offset += (dptr - data_start);
while (data_len > 0) {
if (opcode == OPCODE_WACK) {
/* WACK response. This doesn't contain the
* same type of RR data as other T_NB
* responses. */
+ if (!BYTES_ARE_IN_FRAME(cur_offset, 2)) {
+ /* We ran past the end of the captured
+ data in the packet. */
+ return 0;
+ }
if (data_len < 2) {
- proto_tree_add_item(rr_tree, offset,
+ proto_tree_add_text(rr_tree, cur_offset,
data_len, "(incomplete entry)");
break;
}
flags = pntohs(dptr);
dptr += 2;
- nbns_add_nbns_flags(rr_tree, offset, flags, 1);
- offset += 2;
+ nbns_add_nbns_flags(rr_tree, cur_offset,
+ flags, 1);
+ cur_offset += 2;
data_len -= 2;
} else {
+ if (!BYTES_ARE_IN_FRAME(cur_offset, 2)) {
+ /* We ran past the end of the captured
+ data in the packet. */
+ return 0;
+ }
if (data_len < 2) {
- proto_tree_add_item(rr_tree, offset,
+ proto_tree_add_text(rr_tree, cur_offset,
data_len, "(incomplete entry)");
break;
}
flags = pntohs(dptr);
dptr += 2;
- nbns_add_nb_flags(rr_tree, offset, flags);
- offset += 2;
+ nbns_add_nb_flags(rr_tree, cur_offset, flags);
+ cur_offset += 2;
data_len -= 2;
+ if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
+ /* We ran past the end of the captured
+ data in the packet. */
+ return 0;
+ }
if (data_len < 4) {
- proto_tree_add_item(rr_tree, offset,
+ proto_tree_add_text(rr_tree, cur_offset,
data_len, "(incomplete entry)");
break;
}
- proto_tree_add_item(rr_tree, offset, 4,
+ proto_tree_add_text(rr_tree, cur_offset, 4,
"Addr: %s",
ip_to_str((guint8 *)dptr));
dptr += 4;
- offset += 4;
+ cur_offset += 4;
data_len -= 4;
}
}
break;
case T_NBSTAT: /* "NBSTAT" record */
- {
- u_int num_names;
- char nbname[16+4+1]; /* 4 for [<last char>] */
- u_short name_flags;
-
- trr = proto_tree_add_item(nbns_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_NBNS_RR, offset, name,
- name_len, type_name, class_name, ttl, data_len);
- offset += (dptr - data_start);
- if (data_len < 1) {
- proto_tree_add_item(rr_tree, offset,
- data_len, "(incomplete entry)");
- break;
- }
- num_names = *dptr;
- dptr += 1;
- proto_tree_add_item(rr_tree, offset, 2,
- "Number of names: %u", num_names);
- offset += 1;
-
- while (num_names != 0) {
- if (data_len < 16) {
- proto_tree_add_item(rr_tree, offset,
- data_len, "(incomplete entry)");
- goto out;
- }
- memcpy(nbname, dptr, 16);
- dptr += 16;
- canonicalize_netbios_name(nbname);
- proto_tree_add_item(rr_tree, offset, 16,
- "Name: %s", nbname);
- offset += 16;
- data_len -= 16;
-
- if (data_len < 2) {
- proto_tree_add_item(rr_tree, offset,
- data_len, "(incomplete entry)");
- goto out;
- }
- name_flags = pntohs(dptr);
- dptr += 2;
- nbns_add_name_flags(rr_tree, offset, name_flags);
- offset += 2;
- data_len -= 2;
-
- num_names--;
- }
-
- if (data_len < 6) {
- proto_tree_add_item(rr_tree, offset,
- data_len, "(incomplete entry)");
- break;
- }
- proto_tree_add_item(rr_tree, offset, 6,
- "Unit ID: %s",
- ether_to_str((guint8 *)dptr));
- dptr += 6;
- offset += 6;
- data_len -= 6;
-
- if (data_len < 1) {
- proto_tree_add_item(rr_tree, offset,
- data_len, "(incomplete entry)");
- break;
- }
- proto_tree_add_item(rr_tree, offset, 1,
- "Jumpers: 0x%x", *dptr);
- dptr += 1;
- offset += 1;
- data_len -= 1;
-
- if (data_len < 1) {
- proto_tree_add_item(rr_tree, offset,
- data_len, "(incomplete entry)");
- break;
- }
- proto_tree_add_item(rr_tree, offset, 1,
- "Test result: 0x%x", *dptr);
- dptr += 1;
- offset += 1;
- data_len -= 1;
-
- if (data_len < 2) {
- proto_tree_add_item(rr_tree, offset,
- data_len, "(incomplete entry)");
- break;
- }
- proto_tree_add_item(rr_tree, offset, 2,
- "Version number: 0x%x", pntohs(dptr));
- dptr += 2;
- offset += 2;
- data_len -= 2;
-
- if (data_len < 2) {
- proto_tree_add_item(rr_tree, offset,
- data_len, "(incomplete entry)");
- break;
- }
- proto_tree_add_item(rr_tree, offset, 2,
- "Period of statistics: 0x%x", pntohs(dptr));
- dptr += 2;
- offset += 2;
- data_len -= 2;
-
- if (data_len < 2) {
- proto_tree_add_item(rr_tree, offset,
- data_len, "(incomplete entry)");
- break;
- }
- proto_tree_add_item(rr_tree, offset, 2,
- "Number of CRCs: %u", pntohs(dptr));
- dptr += 2;
- offset += 2;
- data_len -= 2;
-
- if (data_len < 2) {
- proto_tree_add_item(rr_tree, offset,
- data_len, "(incomplete entry)");
- break;
- }
- proto_tree_add_item(rr_tree, offset, 2,
- "Number of alignment errors: %u", pntohs(dptr));
- dptr += 2;
- offset += 2;
- data_len -= 2;
-
- if (data_len < 2) {
- proto_tree_add_item(rr_tree, offset,
- data_len, "(incomplete entry)");
- break;
- }
- proto_tree_add_item(rr_tree, offset, 2,
- "Number of collisions: %u", pntohs(dptr));
- dptr += 2;
- offset += 2;
- data_len -= 2;
-
- if (data_len < 2) {
- proto_tree_add_item(rr_tree, offset,
- data_len, "(incomplete entry)");
- break;
- }
- proto_tree_add_item(rr_tree, offset, 2,
- "Number of send aborts: %u", pntohs(dptr));
- dptr += 2;
- offset += 2;
- data_len -= 2;
-
- if (data_len < 4) {
- proto_tree_add_item(rr_tree, offset,
- data_len, "(incomplete entry)");
- break;
- }
- proto_tree_add_item(rr_tree, offset, 4,
- "Number of good sends: %u", pntohl(dptr));
- dptr += 4;
- offset += 4;
- data_len -= 4;
-
- if (data_len < 4) {
- proto_tree_add_item(rr_tree, offset,
- data_len, "(incomplete entry)");
- break;
- }
- proto_tree_add_item(rr_tree, offset, 4,
- "Number of good receives: %u", pntohl(dptr));
- dptr += 4;
- offset += 4;
- data_len -= 4;
-
- if (data_len < 2) {
- proto_tree_add_item(rr_tree, offset,
- data_len, "(incomplete entry)");
- break;
+ if (fd != NULL)
+ col_append_fstr(fd, COL_INFO, " %s", type_name);
+ if (nbns_tree == NULL)
+ break;
+ trr = proto_tree_add_text(nbns_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_nbns_rr, offset, name,
+ name_len, 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. */
+ return 0;
+ }
+ if (data_len < 1) {
+ proto_tree_add_text(rr_tree, cur_offset,
+ data_len, "(incomplete entry)");
+ break;
+ }
+ num_names = *dptr;
+ dptr += 1;
+ proto_tree_add_text(rr_tree, cur_offset, 2,
+ "Number of names: %u", num_names);
+ cur_offset += 1;
+
+ while (num_names != 0) {
+ if (!BYTES_ARE_IN_FRAME(cur_offset, NETBIOS_NAME_LEN)) {
+ /* We ran past the end of the captured
+ data in the packet. */
+ return 0;
}
- proto_tree_add_item(rr_tree, offset, 2,
- "Number of retransmits: %u", pntohs(dptr));
- dptr += 2;
- offset += 2;
- data_len -= 2;
-
- if (data_len < 2) {
- proto_tree_add_item(rr_tree, offset,
+ if (data_len < NETBIOS_NAME_LEN) {
+ proto_tree_add_text(rr_tree, cur_offset,
data_len, "(incomplete entry)");
- break;
+ goto out;
}
- proto_tree_add_item(rr_tree, offset, 2,
- "Number of no resource conditions: %u", pntohs(dptr));
- dptr += 2;
- offset += 2;
- data_len -= 2;
-
- if (data_len < 2) {
- proto_tree_add_item(rr_tree, offset,
- data_len, "(incomplete entry)");
- break;
+ memcpy(nbname, dptr, NETBIOS_NAME_LEN);
+ dptr += NETBIOS_NAME_LEN;
+ name_type = process_netbios_name(nbname,
+ name_str);
+ proto_tree_add_text(rr_tree, cur_offset,
+ NETBIOS_NAME_LEN, "Name: %s<%02x> (%s)",
+ name_str, name_type,
+ netbios_name_type_descr(name_type));
+ cur_offset += NETBIOS_NAME_LEN;
+ data_len -= NETBIOS_NAME_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_item(rr_tree, offset, 2,
- "Number of command blocks: %u", pntohs(dptr));
- dptr += 2;
- offset += 2;
- data_len -= 2;
-
if (data_len < 2) {
- proto_tree_add_item(rr_tree, offset,
+ proto_tree_add_text(rr_tree, cur_offset,
data_len, "(incomplete entry)");
- break;
+ goto out;
}
- proto_tree_add_item(rr_tree, offset, 2,
- "Number of pending sessions: %u", pntohs(dptr));
+ name_flags = pntohs(dptr);
dptr += 2;
- offset += 2;
+ nbns_add_name_flags(rr_tree, cur_offset, name_flags);
+ cur_offset += 2;
data_len -= 2;
- if (data_len < 2) {
- proto_tree_add_item(rr_tree, offset,
- data_len, "(incomplete entry)");
- break;
- }
- proto_tree_add_item(rr_tree, offset, 2,
- "Max number of pending sessions: %u", pntohs(dptr));
- dptr += 2;
- offset += 2;
-
- proto_tree_add_item(rr_tree, offset, 2,
- "Max total sessions possible: %u", pntohs(dptr));
- dptr += 2;
- offset += 2;
- data_len -= 2;
+ num_names--;
+ }
- if (data_len < 2) {
- proto_tree_add_item(rr_tree, offset,
- data_len, "(incomplete entry)");
- break;
- }
- proto_tree_add_item(rr_tree, offset, 2,
- "Session data packet size: %u", pntohs(dptr));
- dptr += 2;
- offset += 2;
- data_len -= 2;
+ if (!BYTES_ARE_IN_FRAME(cur_offset, 6)) {
+ /* We ran past the end of the captured
+ data in the packet. */
+ return 0;
+ }
+ if (data_len < 6) {
+ proto_tree_add_text(rr_tree, cur_offset,
+ data_len, "(incomplete entry)");
+ break;
+ }
+ proto_tree_add_text(rr_tree, cur_offset, 6,
+ "Unit ID: %s",
+ ether_to_str((guint8 *)dptr));
+ dptr += 6;
+ cur_offset += 6;
+ data_len -= 6;
+
+ if (!BYTES_ARE_IN_FRAME(cur_offset, 1)) {
+ /* We ran past the end of the captured
+ data in the packet. */
+ return 0;
+ }
+ if (data_len < 1) {
+ proto_tree_add_text(rr_tree, cur_offset,
+ data_len, "(incomplete entry)");
+ break;
+ }
+ proto_tree_add_text(rr_tree, cur_offset, 1,
+ "Jumpers: 0x%x", *dptr);
+ dptr += 1;
+ cur_offset += 1;
+ data_len -= 1;
+
+ if (!BYTES_ARE_IN_FRAME(cur_offset, 1)) {
+ /* We ran past the end of the captured
+ data in the packet. */
+ return 0;
+ }
+ if (data_len < 1) {
+ proto_tree_add_text(rr_tree, cur_offset,
+ data_len, "(incomplete entry)");
+ break;
+ }
+ proto_tree_add_text(rr_tree, cur_offset, 1,
+ "Test result: 0x%x", *dptr);
+ dptr += 1;
+ cur_offset += 1;
+ data_len -= 1;
+
+ if (!BYTES_ARE_IN_FRAME(cur_offset, 2)) {
+ /* We ran past the end of the captured
+ data in the packet. */
+ return 0;
+ }
+ if (data_len < 2) {
+ proto_tree_add_text(rr_tree, cur_offset,
+ data_len, "(incomplete entry)");
+ break;
+ }
+ proto_tree_add_text(rr_tree, cur_offset, 2,
+ "Version number: 0x%x", pntohs(dptr));
+ dptr += 2;
+ cur_offset += 2;
+ data_len -= 2;
+
+ if (!BYTES_ARE_IN_FRAME(cur_offset, 2)) {
+ /* We ran past the end of the captured
+ data in the packet. */
+ return 0;
+ }
+ if (data_len < 2) {
+ proto_tree_add_text(rr_tree, cur_offset,
+ data_len, "(incomplete entry)");
+ break;
+ }
+ proto_tree_add_text(rr_tree, cur_offset, 2,
+ "Period of statistics: 0x%x", pntohs(dptr));
+ dptr += 2;
+ cur_offset += 2;
+ data_len -= 2;
+
+ if (!BYTES_ARE_IN_FRAME(cur_offset, 2)) {
+ /* We ran past the end of the captured
+ data in the packet. */
+ return 0;
+ }
+ if (data_len < 2) {
+ proto_tree_add_text(rr_tree, cur_offset,
+ data_len, "(incomplete entry)");
+ break;
+ }
+ proto_tree_add_text(rr_tree, cur_offset, 2,
+ "Number of CRCs: %u", pntohs(dptr));
+ dptr += 2;
+ cur_offset += 2;
+ data_len -= 2;
+
+ if (!BYTES_ARE_IN_FRAME(cur_offset, 2)) {
+ /* We ran past the end of the captured
+ data in the packet. */
+ return 0;
+ }
+ if (data_len < 2) {
+ proto_tree_add_text(rr_tree, cur_offset,
+ data_len, "(incomplete entry)");
+ break;
+ }
+ proto_tree_add_text(rr_tree, cur_offset, 2,
+ "Number of alignment errors: %u", pntohs(dptr));
+ dptr += 2;
+ cur_offset += 2;
+ data_len -= 2;
+
+ if (!BYTES_ARE_IN_FRAME(cur_offset, 2)) {
+ /* We ran past the end of the captured
+ data in the packet. */
+ return 0;
+ }
+ if (data_len < 2) {
+ proto_tree_add_text(rr_tree, cur_offset,
+ data_len, "(incomplete entry)");
+ break;
+ }
+ proto_tree_add_text(rr_tree, cur_offset, 2,
+ "Number of collisions: %u", pntohs(dptr));
+ dptr += 2;
+ cur_offset += 2;
+ data_len -= 2;
+
+ if (!BYTES_ARE_IN_FRAME(cur_offset, 2)) {
+ /* We ran past the end of the captured
+ data in the packet. */
+ return 0;
+ }
+ if (data_len < 2) {
+ proto_tree_add_text(rr_tree, cur_offset,
+ data_len, "(incomplete entry)");
+ break;
+ }
+ proto_tree_add_text(rr_tree, cur_offset, 2,
+ "Number of send aborts: %u", pntohs(dptr));
+ dptr += 2;
+ cur_offset += 2;
+ data_len -= 2;
+
+ if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
+ /* We ran past the end of the captured
+ data in the packet. */
+ return 0;
+ }
+ if (data_len < 4) {
+ proto_tree_add_text(rr_tree, cur_offset,
+ data_len, "(incomplete entry)");
+ break;
+ }
+ proto_tree_add_text(rr_tree, cur_offset, 4,
+ "Number of good sends: %u", pntohl(dptr));
+ dptr += 4;
+ cur_offset += 4;
+ data_len -= 4;
+
+ if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
+ /* We ran past the end of the captured
+ data in the packet. */
+ return 0;
+ }
+ if (data_len < 4) {
+ proto_tree_add_text(rr_tree, cur_offset,
+ data_len, "(incomplete entry)");
+ break;
+ }
+ proto_tree_add_text(rr_tree, cur_offset, 4,
+ "Number of good receives: %u", pntohl(dptr));
+ dptr += 4;
+ cur_offset += 4;
+ data_len -= 4;
+
+ if (!BYTES_ARE_IN_FRAME(cur_offset, 2)) {
+ /* We ran past the end of the captured
+ data in the packet. */
+ return 0;
+ }
+ if (data_len < 2) {
+ proto_tree_add_text(rr_tree, cur_offset,
+ data_len, "(incomplete entry)");
+ break;
+ }
+ proto_tree_add_text(rr_tree, cur_offset, 2,
+ "Number of retransmits: %u", pntohs(dptr));
+ dptr += 2;
+ cur_offset += 2;
+ data_len -= 2;
+
+ if (!BYTES_ARE_IN_FRAME(cur_offset, 2)) {
+ /* We ran past the end of the captured
+ data in the packet. */
+ return 0;
+ }
+ if (data_len < 2) {
+ proto_tree_add_text(rr_tree, cur_offset,
+ data_len, "(incomplete entry)");
+ break;
+ }
+ proto_tree_add_text(rr_tree, cur_offset, 2,
+ "Number of no resource conditions: %u", pntohs(dptr));
+ dptr += 2;
+ cur_offset += 2;
+ data_len -= 2;
+
+ if (!BYTES_ARE_IN_FRAME(cur_offset, 2)) {
+ /* We ran past the end of the captured
+ data in the packet. */
+ return 0;
+ }
+ if (data_len < 2) {
+ proto_tree_add_text(rr_tree, cur_offset,
+ data_len, "(incomplete entry)");
+ break;
}
+ proto_tree_add_text(rr_tree, cur_offset, 2,
+ "Number of command blocks: %u", pntohs(dptr));
+ dptr += 2;
+ cur_offset += 2;
+ data_len -= 2;
+
+ if (!BYTES_ARE_IN_FRAME(cur_offset, 2)) {
+ /* We ran past the end of the captured
+ data in the packet. */
+ return 0;
+ }
+ if (data_len < 2) {
+ proto_tree_add_text(rr_tree, cur_offset,
+ data_len, "(incomplete entry)");
+ break;
+ }
+ proto_tree_add_text(rr_tree, cur_offset, 2,
+ "Number of pending sessions: %u", pntohs(dptr));
+ dptr += 2;
+ cur_offset += 2;
+ data_len -= 2;
+
+ if (!BYTES_ARE_IN_FRAME(cur_offset, 2)) {
+ /* We ran past the end of the captured
+ data in the packet. */
+ return 0;
+ }
+ if (data_len < 2) {
+ proto_tree_add_text(rr_tree, cur_offset,
+ data_len, "(incomplete entry)");
+ break;
+ }
+ proto_tree_add_text(rr_tree, cur_offset, 2,
+ "Max number of pending sessions: %u", pntohs(dptr));
+ dptr += 2;
+ cur_offset += 2;
+
+ if (!BYTES_ARE_IN_FRAME(cur_offset, 2)) {
+ /* We ran past the end of the captured
+ data in the packet. */
+ return 0;
+ }
+ if (data_len < 2) {
+ proto_tree_add_text(rr_tree, cur_offset,
+ data_len, "(incomplete entry)");
+ break;
+ }
+ proto_tree_add_text(rr_tree, cur_offset, 2,
+ "Max total sessions possible: %u", pntohs(dptr));
+ dptr += 2;
+ cur_offset += 2;
+ data_len -= 2;
+
+ if (!BYTES_ARE_IN_FRAME(cur_offset, 2)) {
+ /* We ran past the end of the captured
+ data in the packet. */
+ return 0;
+ }
+ if (data_len < 2) {
+ proto_tree_add_text(rr_tree, cur_offset,
+ data_len, "(incomplete entry)");
+ break;
+ }
+ proto_tree_add_text(rr_tree, cur_offset, 2,
+ "Session data packet size: %u", pntohs(dptr));
+ dptr += 2;
+ cur_offset += 2;
+ data_len -= 2;
out:
break;
default:
- trr = proto_tree_add_item(nbns_tree, offset,
+ if (fd != NULL)
+ col_append_fstr(fd, COL_INFO, " %s", type_name);
+ if (nbns_tree == NULL)
+ break;
+ trr = proto_tree_add_text(nbns_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_NBNS_RR, offset, name,
+ rr_tree = add_rr_to_tree(trr, ett_nbns_rr, offset, name,
name_len, type_name, class_name, ttl, data_len);
- offset += (dptr - data_start);
- proto_tree_add_item(rr_tree, offset, data_len, "Data");
+ proto_tree_add_text(rr_tree, cur_offset, data_len, "Data");
break;
}
dptr += data_len;
}
static int
-dissect_query_records(const u_char *nbns_data_ptr, int count, const u_char *pd,
- int cur_off, proto_tree *nbns_tree)
+dissect_query_records(const u_char *pd, int cur_off, int nbns_data_offset,
+ int count, frame_data *fd, proto_tree *nbns_tree)
{
- int start_off;
- proto_tree *qatree;
- proto_item *ti;
+ int start_off, add_off;
+ proto_tree *qatree = NULL;
+ proto_item *ti = NULL;
start_off = cur_off;
- ti = proto_tree_add_item(nbns_tree, start_off, 0, "Queries");
- qatree = proto_tree_new();
- proto_item_add_subtree(ti, qatree, ETT_NBNS_QRY);
- while (count-- > 0)
- cur_off += dissect_nbns_query(nbns_data_ptr, pd, cur_off, qatree);
- proto_item_set_len(ti, cur_off - start_off);
+ if (nbns_tree != NULL) {
+ ti = proto_tree_add_text(nbns_tree, start_off, 0, "Queries");
+ qatree = proto_item_add_subtree(ti, ett_nbns_qry);
+ }
+ while (count-- > 0) {
+ add_off = dissect_nbns_query(pd, cur_off, nbns_data_offset,
+ fd, qatree);
+ if (add_off <= 0) {
+ /* We ran past the end of the captured data in the
+ packet. */
+ break;
+ }
+ cur_off += add_off;
+ }
+ if (ti != NULL)
+ proto_item_set_len(ti, cur_off - start_off);
return cur_off - start_off;
}
static int
-dissect_answer_records(const u_char *nbns_data_ptr, int count,
- const u_char *pd, int cur_off, proto_tree *nbns_tree, int opcode, char *name)
+dissect_answer_records(const u_char *pd, int cur_off, int nbns_data_offset,
+ int count, frame_data *fd, proto_tree *nbns_tree, int opcode, char *name)
{
- int start_off;
- proto_tree *qatree;
- proto_item *ti;
+ int start_off, add_off;
+ proto_tree *qatree = NULL;
+ proto_item *ti = NULL;
start_off = cur_off;
- ti = proto_tree_add_item(nbns_tree, start_off, 0, name);
- qatree = proto_tree_new();
- proto_item_add_subtree(ti, qatree, ETT_NBNS_ANS);
- while (count-- > 0)
- cur_off += dissect_nbns_answer(nbns_data_ptr, pd, cur_off,
- qatree, opcode);
- proto_item_set_len(ti, cur_off - start_off);
+ if (nbns_tree != NULL) {
+ ti = proto_tree_add_text(nbns_tree, start_off, 0, name);
+ qatree = proto_item_add_subtree(ti, ett_nbns_ans);
+ }
+ while (count-- > 0) {
+ add_off = dissect_nbns_answer(pd, cur_off, nbns_data_offset,
+ fd, qatree, opcode);
+ if (add_off <= 0) {
+ /* We ran past the end of the captured data in the
+ packet. */
+ break;
+ }
+ cur_off += add_off;
+ }
+ if (ti != NULL)
+ proto_item_set_len(ti, cur_off - start_off);
return cur_off - start_off;
}
void
dissect_nbns(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
{
- const u_char *nbns_data_ptr;
- proto_tree *nbns_tree;
+ int nbns_data_offset;
+ proto_tree *nbns_tree = NULL;
proto_item *ti;
guint16 id, flags, quest, ans, auth, add;
int cur_off;
- nbns_data_ptr = &pd[offset];
+ nbns_data_offset = offset;
+
+ if (check_col(fd, COL_PROTOCOL))
+ col_add_str(fd, COL_PROTOCOL, "NBNS");
+
+ if (pi.captured_len < NBNS_HDRLEN) {
+ col_add_str(fd, COL_INFO, "Short NBNS packet");
+ dissect_data(pd, offset, fd, tree);
+ return;
+ }
/* To do: check for runts, errs, etc. */
id = pntohs(&pd[offset + NBNS_ID]);
auth = pntohs(&pd[offset + NBNS_AUTH]);
add = pntohs(&pd[offset + NBNS_ADD]);
- if (check_col(fd, COL_PROTOCOL))
- col_add_str(fd, COL_PROTOCOL, "NBNS (UDP)");
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" : "");
+ } 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 to the COL_INFO column (a call to
+ "check_col(fd, COL_INFO)" is more expensive than a check
+ that a pointer isn't NULL). */
+ fd = NULL;
}
if (tree) {
- ti = proto_tree_add_item(tree, offset, END_OF_FRAME,
- "NetBIOS Name Service");
- nbns_tree = proto_tree_new();
- proto_item_add_subtree(ti, nbns_tree, ETT_NBNS);
+ ti = proto_tree_add_item(tree, proto_nbns, offset, END_OF_FRAME, NULL);
+ nbns_tree = proto_item_add_subtree(ti, ett_nbns);
+
+ if (flags & F_RESPONSE) {
+ proto_tree_add_item_hidden(nbns_tree, hf_nbns_response,
+ 0, 0, TRUE);
+ } else {
+ proto_tree_add_item_hidden(nbns_tree, hf_nbns_query,
+ 0, 0, TRUE);
+ }
- proto_tree_add_item(nbns_tree, offset + NBNS_ID, 2,
- "Transaction ID: 0x%04X", id);
+ proto_tree_add_item(nbns_tree, hf_nbns_transaction_id,
+ offset + NBNS_ID, 2, id);
nbns_add_nbns_flags(nbns_tree, offset + NBNS_FLAGS, flags, 0);
- proto_tree_add_item(nbns_tree, offset + NBNS_QUEST, 2,
- "Questions: %d",
- quest);
- proto_tree_add_item(nbns_tree, offset + NBNS_ANS, 2,
- "Answer RRs: %d",
- ans);
- proto_tree_add_item(nbns_tree, offset + NBNS_AUTH, 2,
- "Authority RRs: %d",
- auth);
- proto_tree_add_item(nbns_tree, offset + NBNS_ADD, 2,
- "Additional RRs: %d",
- add);
-
- cur_off = offset + NBNS_HDRLEN;
+ proto_tree_add_item(nbns_tree, hf_nbns_count_questions,
+ offset + NBNS_QUEST, 2, quest);
+ proto_tree_add_item(nbns_tree, hf_nbns_count_answers,
+ offset + NBNS_ANS, 2, ans);
+ proto_tree_add_item(nbns_tree, hf_nbns_count_auth_rr,
+ offset + NBNS_AUTH, 2, auth);
+ proto_tree_add_item(nbns_tree, hf_nbns_count_add_rr,
+ offset + NBNS_ADD, 2, add);
+ }
+
+ cur_off = offset + NBNS_HDRLEN;
- if (quest > 0)
- cur_off += dissect_query_records(nbns_data_ptr,
- quest, pd, cur_off, nbns_tree);
+ if (quest > 0) {
+ /* If this is a response, don't add information about the
+ queries to the summary, just add information about the
+ answers. */
+ cur_off += dissect_query_records(pd, cur_off,
+ nbns_data_offset, quest,
+ (!(flags & F_RESPONSE) ? fd : NULL), nbns_tree);
+ }
- if (ans > 0)
- cur_off += dissect_answer_records(nbns_data_ptr,
- ans, pd, cur_off, nbns_tree,
- flags & F_OPCODE,
- "Answers");
+ if (ans > 0) {
+ /* If this is a request, don't add information about the
+ answers to the summary, just add information about the
+ queries. */
+ cur_off += dissect_answer_records(pd, cur_off,
+ nbns_data_offset, ans,
+ ((flags & F_RESPONSE) ? fd : NULL), nbns_tree,
+ flags & F_OPCODE, "Answers");
+ }
+ if (tree) {
+ /* Don't add information about the authoritative name
+ servers, or the additional records, to the summary. */
if (auth > 0)
- cur_off += dissect_answer_records(nbns_data_ptr,
- auth, pd, cur_off, nbns_tree,
+ cur_off += dissect_answer_records(pd, cur_off,
+ nbns_data_offset,
+ auth, NULL, nbns_tree,
flags & F_OPCODE,
"Authoritative nameservers");
if (add > 0)
- cur_off += dissect_answer_records(nbns_data_ptr,
- add, pd, cur_off, nbns_tree,
+ cur_off += dissect_answer_records(pd, cur_off,
+ nbns_data_offset,
+ add, NULL, nbns_tree,
flags & F_OPCODE,
"Additional records");
}
void
dissect_nbdgm(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
{
- proto_tree *nbdgm_tree;
+ proto_tree *nbdgm_tree = NULL;
proto_item *ti;
struct nbdgm_header header;
int flags;
int message_index;
+ int max_data = pi.captured_len - offset;
char *message[] = {
"Unknown",
char *yesno[] = { "No", "Yes" };
- char name[32];
+ char name[(NETBIOS_NAME_LEN - 1)*4 + MAXDNAME];
+ int name_type;
int len;
header.msg_type = pd[offset];
}
if (check_col(fd, COL_PROTOCOL))
- col_add_str(fd, COL_PROTOCOL, "NBDS (UDP)");
+ col_add_str(fd, COL_PROTOCOL, "NBDS");
if (check_col(fd, COL_INFO)) {
col_add_fstr(fd, COL_INFO, "%s", message[message_index]);
}
if (tree) {
- ti = proto_tree_add_item(tree, offset, header.dgm_length,
- "NetBIOS Datagram Service");
- nbdgm_tree = proto_tree_new();
- proto_item_add_subtree(ti, nbdgm_tree, ETT_NBDGM);
-
- proto_tree_add_item(nbdgm_tree, offset, 1, "Message Type: %s",
- message[message_index]);
- proto_tree_add_item(nbdgm_tree, offset+1, 1, "More fragments follow: %s",
- yesno[header.flags.more]);
- proto_tree_add_item(nbdgm_tree, offset+1, 1, "This is first fragment: %s",
- yesno[header.flags.first]);
- proto_tree_add_item(nbdgm_tree, offset+1, 1, "Node Type: %s",
- node[header.flags.node_type]);
-
- proto_tree_add_item(nbdgm_tree, offset+2, 2, "Datagram ID: 0x%04X",
- header.dgm_id);
- proto_tree_add_item(nbdgm_tree, offset+4, 4, "Source IP: %s",
- ip_to_str((guint8 *)&header.src_ip));
- proto_tree_add_item(nbdgm_tree, offset+8, 2, "Source Port: %d",
- header.src_port);
-
- offset += 10;
-
- if (header.msg_type == 0x10 ||
- header.msg_type == 0x11 || header.msg_type == 0x12) {
-
- proto_tree_add_item(nbdgm_tree, offset, 2,
+ ti = proto_tree_add_item(tree, proto_nbdgm, offset, header.dgm_length, NULL);
+ nbdgm_tree = proto_item_add_subtree(ti, ett_nbdgm);
+
+ proto_tree_add_uint_format(nbdgm_tree, hf_nbdgm_type,
+ offset, 1,
+ header.msg_type,
+ "Message Type: %s",
+ message[message_index]);
+ proto_tree_add_boolean_format(nbdgm_tree, hf_nbdgm_fragment,
+ offset+1, 1,
+ header.flags.more,
+ "More fragments follow: %s",
+ yesno[header.flags.more]);
+ proto_tree_add_boolean_format(nbdgm_tree, hf_nbdgm_first,
+ offset+1, 1,
+ header.flags.first,
+ "This is first fragment: %s",
+ yesno[header.flags.first]);
+ proto_tree_add_uint_format(nbdgm_tree, hf_nbdgm_node_type,
+ offset+1, 1,
+ header.flags.node_type,
+ "Node Type: %s",
+ node[header.flags.node_type]);
+
+ proto_tree_add_item(nbdgm_tree, hf_nbdgm_datagram_id,
+ offset+2, 2, header.dgm_id);
+ proto_tree_add_item(nbdgm_tree, hf_nbdgm_src_ip,
+ offset+4, 4, header.src_ip);
+ proto_tree_add_item(nbdgm_tree, hf_nbdgm_src_port,
+ offset+8, 2, header.src_port);
+
+ }
+
+ offset += 10;
+ max_data -= 10;
+
+ if (header.msg_type == 0x10 ||
+ header.msg_type == 0x11 || header.msg_type == 0x12) {
+
+ if (tree) {
+ proto_tree_add_text(nbdgm_tree, offset, 2,
"Datagram length: %d bytes", header.dgm_length);
- proto_tree_add_item(nbdgm_tree, offset+2, 2,
+ proto_tree_add_text(nbdgm_tree, offset+2, 2,
"Packet offset: %d bytes", header.pkt_offset);
+ }
- offset += 4;
-
- /* Source name */
- len = get_nbns_name(&pd[offset], pd, offset, name);
+ offset += 4;
+ max_data -= 4;
- proto_tree_add_item(nbdgm_tree, offset, len, "Source name: %s",
- name);
- offset += len;
+ /* Source name */
+ len = get_nbns_name(pd, offset, offset, name, &name_type);
- /* Destination name */
- len = get_nbns_name(&pd[offset], pd, offset, name);
+ if (tree) {
+ add_name_and_type(nbdgm_tree, offset, len,
+ "Source name", name, name_type);
+ }
+ offset += len;
+ max_data -= len;
- proto_tree_add_item(nbdgm_tree, offset, len, "Destination name: %s",
- name);
- offset += len;
+ /* Destination name */
+ len = get_nbns_name(pd, offset, offset, name, &name_type);
- /* here we can pass the packet off to the next protocol */
- dissect_data(pd, offset, fd, nbdgm_tree);
+ if (tree) {
+ add_name_and_type(nbdgm_tree, offset, len,
+ "Destination name", name, name_type);
}
- else if (header.msg_type == 0x13) {
- proto_tree_add_item(nbdgm_tree, offset, 1, "Error code: %s",
+ offset += len;
+ max_data -= len;
+
+ /* here we can pass the packet off to the next protocol */
+ dissect_smb(pd, offset, fd, tree, max_data);
+ }
+ else if (header.msg_type == 0x13) {
+ if (tree) {
+ proto_tree_add_text(nbdgm_tree, offset, 1, "Error code: %s",
val_to_str(header.error_code, error_codes, "Unknown (0x%x)"));
}
- else if (header.msg_type == 0x14 ||
- header.msg_type == 0x15 || header.msg_type == 0x16) {
- /* Destination name */
- len = get_nbns_name(&pd[offset], pd, offset, name);
-
- proto_tree_add_item(nbdgm_tree, offset, len, "Destination name: %s",
- name);
+ }
+ else if (header.msg_type == 0x14 ||
+ header.msg_type == 0x15 || header.msg_type == 0x16) {
+ /* Destination name */
+ len = get_nbns_name(pd, offset, offset, name, &name_type);
+
+ if (tree) {
+ add_name_and_type(nbdgm_tree, offset, len,
+ "Destination name", name, name_type);
}
}
}
guint8 flags;
guint16 length;
int len;
- char name[32];
+ char name[(NETBIOS_NAME_LEN - 1)*4 + MAXDNAME];
+ int name_type;
msg_type = pd[offset];
flags = pd[offset + 1];
length += 65536;
if (tree) {
- ti = proto_tree_add_item(tree, offset, length + 4,
- "NetBIOS Session Service");
- nbss_tree = proto_tree_new();
- proto_item_add_subtree(ti, nbss_tree, ETT_NBSS);
+ ti = proto_tree_add_item(tree, proto_nbss, offset, length + 4, NULL);
+ nbss_tree = proto_item_add_subtree(ti, ett_nbss);
- proto_tree_add_item(nbss_tree, offset, 1, "Message Type: %s",
- val_to_str(msg_type, message_types, "Unknown (%x)"));
+ proto_tree_add_uint_format(nbss_tree, hf_nbss_type,
+ offset, 1,
+ msg_type,
+ "Message Type: %s",
+ val_to_str(msg_type, message_types,
+ "Unknown (%x)"));
}
offset += 1;
if (tree) {
- tf = proto_tree_add_item(nbss_tree, offset, 1, "Flags: 0x%04x", flags);
- field_tree = proto_tree_new();
- proto_item_add_subtree(tf, field_tree, ETT_NBSS_FLAGS);
- proto_tree_add_item(field_tree, offset, 1, "%s",
+ tf = proto_tree_add_item(nbss_tree, hf_nbss_flags, offset, 1, flags);
+ field_tree = proto_item_add_subtree(tf, ett_nbss_flags);
+ proto_tree_add_text(field_tree, offset, 1, "%s",
decode_boolean_bitfield(flags, NBSS_FLAGS_E,
8, "Add 65536 to length", "Add 0 to length"));
}
offset += 1;
if (tree) {
- proto_tree_add_item(nbss_tree, offset, 2, "Length: %u", length);
+ proto_tree_add_text(nbss_tree, offset, 2, "Length: %u", length);
}
offset += 2;
switch (msg_type) {
case SESSION_REQUEST:
- len = get_nbns_name(&pd[offset], pd, offset, name);
+ len = get_nbns_name(pd, offset, offset, name, &name_type);
if (tree)
- proto_tree_add_item(nbss_tree, offset, len,
- "Called name: %s", name);
+ add_name_and_type(nbss_tree, offset, len,
+ "Called name", name, name_type);
offset += len;
- len = get_nbns_name(&pd[offset], pd, offset, name);
+ len = get_nbns_name(pd, offset, offset, name, &name_type);
if (tree)
- proto_tree_add_item(nbss_tree, offset, len,
- "Calling name: %s", name);
+ add_name_and_type(nbss_tree, offset, len,
+ "Calling name", name, name_type);
break;
case NEGATIVE_SESSION_RESPONSE:
if (tree)
- proto_tree_add_item(nbss_tree, offset, 1,
+ proto_tree_add_text(nbss_tree, offset, 1,
"Error code: %s",
val_to_str(pd[offset], error_codes, "Unknown (%x)"));
break;
case RETARGET_SESSION_RESPONSE:
if (tree)
- proto_tree_add_item(nbss_tree, offset, 4,
+ proto_tree_add_text(nbss_tree, offset, 4,
"Retarget IP address: %s",
ip_to_str((guint8 *)&pd[offset]));
offset += 4;
if (tree)
- proto_tree_add_item(nbss_tree, offset, 2,
+ proto_tree_add_text(nbss_tree, offset, 2,
"Retarget port: %u", pntohs(&pd[offset]));
break;
}
void
-dissect_nbss(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, int max_data)
+dissect_nbss(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
{
guint8 msg_type;
guint8 flags;
guint16 length;
int len;
+ int max_data;
msg_type = pd[offset];
flags = pd[offset + 1];
if (flags & NBSS_FLAGS_E)
length += 65536;
+ /*
+ * XXX - we should set this based on both "pi.captured_len"
+ * and "length"....
+ */
+ max_data = pi.captured_len - offset;
+
+ /* Hmmm, it may be a continuation message ... */
+
+#define RJSHACK 1
+#ifdef RJSHACK
+ if (((msg_type != SESSION_REQUEST) &&
+ (msg_type != POSITIVE_SESSION_RESPONSE) &&
+ (msg_type != NEGATIVE_SESSION_RESPONSE) &&
+ (msg_type != RETARGET_SESSION_RESPONSE) &&
+ (msg_type != SESSION_MESSAGE)) ||
+ ((msg_type == SESSION_MESSAGE) &&
+ (memcmp(pd + offset + 4, "\377SMB", 4) != 0))) {
+
+ if (check_col(fd, COL_PROTOCOL))
+ col_add_str(fd, COL_PROTOCOL, "NBSS");
+ if (check_col(fd, COL_INFO)) {
+ col_add_fstr(fd, COL_INFO, "NBSS Continuation Message");
+ }
+
+ if (tree)
+ proto_tree_add_text(tree, offset, max_data, "Continuation data");
+
+ return;
+ }
+#endif
+
if (check_col(fd, COL_PROTOCOL))
- col_add_str(fd, COL_PROTOCOL, "NBSS (TCP)");
+ col_add_str(fd, COL_PROTOCOL, "NBSS");
if (check_col(fd, COL_INFO)) {
col_add_fstr(fd, COL_INFO,
val_to_str(msg_type, message_types, "Unknown (%x)"));
}
- while (max_data > 0) {
- len = dissect_nbss_packet(pd, offset, fd, tree, max_data);
- offset += len;
- max_data -= len;
+ while (max_data > 0) {
+ len = dissect_nbss_packet(pd, offset, fd, tree, max_data);
+ offset += len;
+ max_data -= len;
}
}
+
+void
+proto_register_nbt(void)
+{
+
+ static hf_register_info hf_nbns[] = {
+ { &hf_nbns_response,
+ { "Response", "nbns.response",
+ FT_BOOLEAN, BASE_NONE, NULL, 0x0,
+ "TRUE if NBNS response" }},
+ { &hf_nbns_query,
+ { "Query", "nbns.query",
+ FT_BOOLEAN, BASE_NONE, NULL, 0x0,
+ "TRUE if NBNS query" }},
+ { &hf_nbns_transaction_id,
+ { "Transaction ID", "nbns.id",
+ FT_UINT16, BASE_HEX, NULL, 0x0,
+ "Identification of transaction" }},
+ { &hf_nbns_count_questions,
+ { "Questions", "nbns.count.queries",
+ FT_UINT16, BASE_DEC, NULL, 0x0,
+ "Number of queries in packet" }},
+ { &hf_nbns_count_answers,
+ { "Answer RRs", "nbns.count.answers",
+ FT_UINT16, BASE_DEC, NULL, 0x0,
+ "Number of answers in packet" }},
+ { &hf_nbns_count_auth_rr,
+ { "Authority RRs", "nbns.count.auth_rr",
+ FT_UINT16, BASE_DEC, NULL, 0x0,
+ "Number of authoritative records in packet" }},
+ { &hf_nbns_count_add_rr,
+ { "Additional RRs", "nbns.count.add_rr",
+ FT_UINT16, BASE_DEC, NULL, 0x0,
+ "Number of additional records in packet" }}
+ };
+
+ static hf_register_info hf_nbdgm[] = {
+ { &hf_nbdgm_type,
+ { "Message Type", "nbdgm.type",
+ FT_UINT8, BASE_DEC, NULL, 0x0,
+ "NBDGM message type" }},
+ { &hf_nbdgm_fragment,
+ { "Fragmented", "nbdgm.next",
+ FT_BOOLEAN, BASE_NONE, NULL, 0x0,
+ "TRUE if more fragments follow" }},
+ { &hf_nbdgm_first,
+ { "First fragment", "nbdgm.first",
+ FT_BOOLEAN, BASE_NONE, NULL, 0x0,
+ "TRUE if first fragment" }},
+ { &hf_nbdgm_node_type,
+ { "Node Type", "nbdgm.node_type",
+ FT_UINT8, BASE_DEC, NULL, 0x0,
+ "Node type" }},
+ { &hf_nbdgm_datagram_id,
+ { "Datagram ID", "nbdgm.dgram_id",
+ FT_UINT16, BASE_HEX, NULL, 0x0,
+ "Datagram identifier" }},
+ { &hf_nbdgm_src_ip,
+ { "Source IP", "nbdgm.src.ip",
+ FT_IPv4, BASE_NONE, NULL, 0x0,
+ "Source IPv4 address" }},
+ { &hf_nbdgm_src_port,
+ { "Source Port", "nbdgm.src.port",
+ FT_UINT16, BASE_DEC, NULL, 0x0,
+ "Source port" }}
+ };
+
+ static hf_register_info hf_nbss[] = {
+ { &hf_nbss_type,
+ { "Message Type", "nbss.type",
+ FT_UINT8, BASE_DEC, NULL, 0x0,
+ "NBSS message type" }},
+ { &hf_nbss_flags,
+ { "Flags", "nbss.flags",
+ FT_UINT8, BASE_HEX, NULL, 0x0,
+ "NBSS message flags" }}
+ };
+ static gint *ett[] = {
+ &ett_nbns,
+ &ett_nbns_qd,
+ &ett_nbns_flags,
+ &ett_nbns_nb_flags,
+ &ett_nbns_name_flags,
+ &ett_nbns_rr,
+ &ett_nbns_qry,
+ &ett_nbns_ans,
+ &ett_nbdgm,
+ &ett_nbss,
+ &ett_nbss_flags,
+ };
+
+ proto_nbns = proto_register_protocol("NetBIOS Name Service", "nbns");
+ proto_register_field_array(proto_nbns, hf_nbns, array_length(hf_nbns));
+
+ proto_nbdgm = proto_register_protocol("NetBIOS Datagram Service", "nbdgm");
+ proto_register_field_array(proto_nbdgm, hf_nbdgm, array_length(hf_nbdgm));
+
+ proto_nbss = proto_register_protocol("NetBIOS Session Service", "nbss");
+ proto_register_field_array(proto_nbss, hf_nbss, array_length(hf_nbss));
+
+ proto_register_subtree_array(ett, array_length(ett));
+}