diff options
Diffstat (limited to 'packet-nbns.c')
-rw-r--r-- | packet-nbns.c | 1926 |
1 files changed, 0 insertions, 1926 deletions
diff --git a/packet-nbns.c b/packet-nbns.c deleted file mode 100644 index e2d51d206c..0000000000 --- a/packet-nbns.c +++ /dev/null @@ -1,1926 +0,0 @@ -/* packet-nbns.c - * Routines for NetBIOS-over-TCP packet disassembly (the name dates back - * to when it had only NBNS) - * Guy Harris <guy@alum.mit.edu> - * - * $Id$ - * - * Ethereal - Network traffic analyzer - * By Gerald Combs <gerald@ethereal.com> - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include <stdio.h> -#include <string.h> -#include <glib.h> - -#include <epan/packet.h> -#include "packet-dns.h" -#include "packet-netbios.h" -#include "packet-tcp.h" -#include "packet-frame.h" -#include "prefs.h" - -static int proto_nbns = -1; -static int hf_nbns_flags = -1; -static int hf_nbns_flags_response = -1; -static int hf_nbns_flags_opcode = -1; -static int hf_nbns_flags_authoritative = -1; -static int hf_nbns_flags_truncated = -1; -static int hf_nbns_flags_recdesired = -1; -static int hf_nbns_flags_recavail = -1; -static int hf_nbns_flags_broadcast = -1; -static int hf_nbns_flags_rcode = -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; - -/* desegmentation of NBSS over TCP */ -static gboolean nbss_desegment = TRUE; - -/* See RFC 1001 and 1002 for information on the first three, and see - - http://www.cifs.com/specs/draft-leach-cifs-v1-spec-01.txt - - Appendix B, and various messages on the CIFS mailing list such as - - http://discuss.microsoft.com/SCRIPTS/WA-MSD.EXE?A2=ind9811A&L=cifs&P=R386 - - for information on the fourth. */ -#define UDP_PORT_NBNS 137 -#define UDP_PORT_NBDGM 138 -#define TCP_PORT_NBSS 139 -#define TCP_PORT_CIFS 445 - -/* Packet structure taken from RFC 1002. See also RFC 1001. - * Opcode, flags, and rcode treated as "flags", similarly to DNS, - * to make it easier to lift the dissection code from "packet-dns.c". */ - -/* Offsets of fields in the NBNS header. */ -#define NBNS_ID 0 -#define NBNS_FLAGS 2 -#define NBNS_QUEST 4 -#define NBNS_ANS 6 -#define NBNS_AUTH 8 -#define NBNS_ADD 10 - -/* Length of NBNS header. */ -#define NBNS_HDRLEN 12 - -/* type values */ -#define T_NB 32 /* NetBIOS name service RR */ -#define T_NBSTAT 33 /* NetBIOS node status RR */ - -/* Bit fields in the flags */ -#define F_RESPONSE (1<<15) /* packet is response */ -#define F_OPCODE (0xF<<11) /* query opcode */ -#define OPCODE_SHIFT 11 -#define F_AUTHORITATIVE (1<<10) /* response is authoritative */ -#define F_TRUNCATED (1<<9) /* response is truncated */ -#define F_RECDESIRED (1<<8) /* recursion desired */ -#define F_RECAVAIL (1<<7) /* recursion available */ -#define F_BROADCAST (1<<4) /* broadcast/multicast packet */ -#define F_RCODE (0xF<<0) /* reply code */ - -static const true_false_string tfs_flags_response = { - "Message is a response", - "Message is a query" -}; - -static const true_false_string tfs_flags_authoritative = { - "Server is an authority for domain", - "Server is not an authority for domain" -}; - -static const true_false_string tfs_flags_truncated = { - "Message is truncated", - "Message is not truncated" -}; - -static const true_false_string tfs_flags_recdesired = { - "Do query recursively", - "Don't do query recursively" -}; - -static const true_false_string tfs_flags_recavail = { - "Server can do recursive queries", - "Server can't do recursive queries" -}; - -static const true_false_string tfs_flags_broadcast = { - "Broadcast packet", - "Not a broadcast packet" -}; - -/* Opcodes */ -#define OPCODE_QUERY 0 /* standard query */ -#define OPCODE_REGISTRATION 5 /* registration */ -#define OPCODE_RELEASE 6 /* release name */ -#define OPCODE_WACK 7 /* wait for acknowledgement */ -#define OPCODE_REFRESH 8 /* refresh registration */ -#define OPCODE_REFRESHALT 9 /* refresh registration (alternate opcode) */ -#define OPCODE_MHREGISTRATION 15 /* multi-homed registration */ - -static const value_string opcode_vals[] = { - { OPCODE_QUERY, "Name query" }, - { OPCODE_REGISTRATION, "Registration" }, - { OPCODE_RELEASE, "Release" }, - { OPCODE_WACK, "Wait for acknowledgment" }, - { OPCODE_REFRESH, "Refresh" }, - { OPCODE_REFRESHALT, "Refresh (alternate opcode)" }, - { OPCODE_MHREGISTRATION, "Multi-homed registration" }, - { 0, NULL } -}; - -/* Reply codes */ -#define RCODE_NOERROR 0 -#define RCODE_FMTERROR 1 -#define RCODE_SERVFAIL 2 -#define RCODE_NAMEERROR 3 -#define RCODE_NOTIMPL 4 -#define RCODE_REFUSED 5 -#define RCODE_ACTIVE 6 -#define RCODE_CONFLICT 7 - -static const value_string rcode_vals[] = { - { RCODE_NOERROR, "No error" }, - { RCODE_FMTERROR, "Request was invalidly formatted" }, - { RCODE_SERVFAIL, "Server failure" }, - { RCODE_NAMEERROR, "Requested name does not exist" }, - { RCODE_NOTIMPL, "Request is not implemented" }, - { RCODE_REFUSED, "Request was refused" }, - { RCODE_ACTIVE, "Name is owned by another node" }, - { RCODE_CONFLICT, "Name is in conflict" }, - { 0, NULL } -}; - -/* Values for the "NB_FLAGS" field of RR data. From RFC 1001 and 1002, - * except for NB_FLAGS_ONT_H_NODE, which was discovered by looking at - * packet traces. */ -#define NB_FLAGS_ONT (3<<(15-2)) /* bits for node type */ -#define NB_FLAGS_ONT_B_NODE (0<<(15-2)) /* B-mode node */ -#define NB_FLAGS_ONT_P_NODE (1<<(15-2)) /* P-mode node */ -#define NB_FLAGS_ONT_M_NODE (2<<(15-2)) /* M-mode node */ -#define NB_FLAGS_ONT_H_NODE (3<<(15-2)) /* H-mode node */ - -#define NB_FLAGS_G (1<<(15-0)) /* group name */ - -/* Values for the "NAME_FLAGS" field of a NODE_NAME entry in T_NBSTAT - * RR data. From RFC 1001 and 1002, except for NAME_FLAGS_ONT_H_NODE, - * which was discovered by looking at packet traces. */ -#define NAME_FLAGS_PRM (1<<(15-6)) /* name is permanent node name */ - -#define NAME_FLAGS_ACT (1<<(15-5)) /* name is active */ - -#define NAME_FLAGS_CNF (1<<(15-4)) /* name is in conflict */ - -#define NAME_FLAGS_DRG (1<<(15-3)) /* name is being deregistered */ - -#define NAME_FLAGS_ONT (3<<(15-2)) /* bits for node type */ -#define NAME_FLAGS_ONT_B_NODE (0<<(15-2)) /* B-mode node */ -#define NAME_FLAGS_ONT_P_NODE (1<<(15-2)) /* P-mode node */ -#define NAME_FLAGS_ONT_M_NODE (2<<(15-2)) /* M-mode node */ - -#define NAME_FLAGS_G (1<<(15-0)) /* group name */ - -static char * -nbns_type_name (int type) -{ - switch (type) { - case T_NB: - return "NB"; - case T_NBSTAT: - return "NBSTAT"; - } - - return "unknown"; -} - -#define NBNAME_BUF_LEN 128 - -static int -get_nbns_name(tvbuff_t *tvb, int offset, int nbns_data_offset, - char *name_ret, int *name_type_ret) -{ - int name_len; - char name[MAXDNAME]; - char nbname[NBNAME_BUF_LEN]; - char *pname, *pnbname, cname, cnbname; - int name_type; - - name_len = get_dns_name(tvb, offset, nbns_data_offset, name, - sizeof(name)); - - /* OK, now undo the first-level encoding. */ - pname = &name[0]; - pnbname = &nbname[0]; - for (;;) { - /* Every two characters of the first level-encoded name - * turn into one character in the decoded name. */ - cname = *pname; - if (cname == '\0') - break; /* no more characters */ - if (cname == '.') - break; /* scope ID follows */ - if (cname < 'A' || cname > 'Z') { - /* Not legal. */ - strcpy(nbname, - "Illegal NetBIOS name (character not between A and Z in first-level encoding)"); - goto bad; - } - cname -= 'A'; - cnbname = cname << 4; - pname++; - - cname = *pname; - if (cname == '\0' || cname == '.') { - /* No more characters in the name - but we're in - * the middle of a pair. Not legal. */ - strcpy(nbname, - "Illegal NetBIOS name (odd number of bytes)"); - goto bad; - } - if (cname < 'A' || cname > 'Z') { - /* Not legal. */ - strcpy(nbname, - "Illegal NetBIOS name (character not between A and Z in first-level encoding)"); - goto bad; - } - cname -= 'A'; - cnbname |= cname; - pname++; - - /* 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 != 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(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(tvbuff_t *tvb, 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(tvb, offset, nbns_data_offset, name_ret, - name_type_ret); - offset += name_len; - - type = tvb_get_ntohs(tvb, offset); - offset += 2; - - class = tvb_get_ntohs(tvb, offset); - - *type_ret = type; - *class_ret = class; - *name_len_ret = name_len; - - return name_len + 4; -} - -static void -add_name_and_type(proto_tree *tree, tvbuff_t *tvb, int offset, int len, - char *tag, char *name, int name_type) -{ - if (name_type != -1) { - proto_tree_add_text(tree, tvb, offset, len, "%s: %s (%s)", - tag, name, netbios_name_type_descr(name_type)); - } else { - proto_tree_add_text(tree, tvb, offset, len, "%s: %s", - tag, name); - } -} - -static int -dissect_nbns_query(tvbuff_t *tvb, int offset, int nbns_data_offset, - column_info *cinfo, proto_tree *nbns_tree) -{ - int len; - char name[(NETBIOS_NAME_LEN - 1)*4 + MAXDNAME]; - int name_len; - int name_type; - int type; - int class; - char *class_name; - char *type_name; - int data_offset; - int data_start; - proto_tree *q_tree; - proto_item *tq; - - data_start = data_offset = offset; - - len = get_nbns_name_type_class(tvb, offset, nbns_data_offset, name, - &name_len, &name_type, &type, &class); - data_offset += len; - - type_name = nbns_type_name(type); - class_name = dns_class_name(class); - - if (cinfo != NULL) - col_append_fstr(cinfo, COL_INFO, " %s %s", type_name, name); - if (nbns_tree != NULL) { - tq = proto_tree_add_text(nbns_tree, tvb, offset, len, - "%s: type %s, class %s", name, type_name, class_name); - q_tree = proto_item_add_subtree(tq, ett_nbns_qd); - - add_name_and_type(q_tree, tvb, offset, name_len, "Name", name, - name_type); - offset += name_len; - - proto_tree_add_text(q_tree, tvb, offset, 2, "Type: %s", type_name); - offset += 2; - - proto_tree_add_text(q_tree, tvb, offset, 2, "Class: %s", class_name); - offset += 2; - } - - return data_offset - data_start; -} - -static void -nbns_add_nbns_flags(column_info *cinfo, proto_tree *nbns_tree, tvbuff_t *tvb, int offset, - gushort flags, int is_wack) -{ - char buf[128+1]; - guint16 opcode; - proto_tree *field_tree; - proto_item *tf; - - opcode = (guint16) ((flags & F_OPCODE) >> OPCODE_SHIFT); - strcpy(buf, val_to_str(opcode, opcode_vals, "Unknown operation")); - if (flags & F_RESPONSE && !is_wack) { - strcat(buf, " response"); - strcat(buf, ", "); - strcat(buf, val_to_str(flags & F_RCODE, rcode_vals, - "Unknown error")); - - if ((flags & F_RCODE) && check_col(cinfo, COL_INFO)) - col_append_fstr(cinfo, COL_INFO, ", %s", - val_to_str(flags & F_RCODE, rcode_vals, - "Unknown error")); - } - tf = proto_tree_add_uint_format(nbns_tree, hf_nbns_flags, - tvb, offset, 2, flags, "Flags: 0x%04x (%s)", flags, buf); - field_tree = proto_item_add_subtree(tf, ett_nbns_flags); - proto_tree_add_item(field_tree, hf_nbns_flags_response, - tvb, offset, 2, FALSE); - proto_tree_add_item(field_tree, hf_nbns_flags_opcode, - tvb, offset, 2, FALSE); - if (flags & F_RESPONSE) { - proto_tree_add_item(field_tree, hf_nbns_flags_authoritative, - tvb, offset, 2, FALSE); - } - proto_tree_add_item(field_tree, hf_nbns_flags_truncated, - tvb, offset, 2, FALSE); - proto_tree_add_item(field_tree, hf_nbns_flags_recdesired, - tvb, offset, 2, FALSE); - if (flags & F_RESPONSE) { - proto_tree_add_item(field_tree, hf_nbns_flags_recavail, - tvb, offset, 2, FALSE); - } - proto_tree_add_item(field_tree, hf_nbns_flags_broadcast, - tvb, offset, 2, FALSE); - if (flags & F_RESPONSE && !is_wack) { - proto_tree_add_item(field_tree, hf_nbns_flags_rcode, - tvb, offset, 2, FALSE); - } -} - -static void -nbns_add_nb_flags(proto_tree *rr_tree, tvbuff_t *tvb, int offset, gushort flags) -{ - char buf[128+1]; - proto_tree *field_tree; - proto_item *tf; - static const value_string nb_flags_ont_vals[] = { - { NB_FLAGS_ONT_B_NODE, "B-node" }, - { NB_FLAGS_ONT_P_NODE, "P-node" }, - { NB_FLAGS_ONT_M_NODE, "M-node" }, - { NB_FLAGS_ONT_H_NODE, "H-node" }, - { 0, NULL } - }; - - strcpy(buf, val_to_str(flags & NB_FLAGS_ONT, nb_flags_ont_vals, - "Unknown")); - strcat(buf, ", "); - if (flags & NB_FLAGS_G) - strcat(buf, "group"); - else - strcat(buf, "unique"); - tf = proto_tree_add_text(rr_tree, tvb, offset, 2, "Flags: 0x%x (%s)", flags, - buf); - field_tree = proto_item_add_subtree(tf, ett_nbns_nb_flags); - proto_tree_add_text(field_tree, tvb, offset, 2, "%s", - decode_boolean_bitfield(flags, NB_FLAGS_G, - 2*8, - "Group name", - "Unique name")); - proto_tree_add_text(field_tree, tvb, offset, 2, "%s", - decode_enumerated_bitfield(flags, NB_FLAGS_ONT, - 2*8, nb_flags_ont_vals, "%s")); -} - -static void -nbns_add_name_flags(proto_tree *rr_tree, tvbuff_t *tvb, int offset, - gushort flags) -{ - char buf[128+1]; - proto_item *field_tree; - proto_item *tf; - static const value_string name_flags_ont_vals[] = { - { NAME_FLAGS_ONT_B_NODE, "B-node" }, - { NAME_FLAGS_ONT_P_NODE, "P-node" }, - { NAME_FLAGS_ONT_M_NODE, "M-node" }, - { 0, NULL } - }; - - strcpy(buf, val_to_str(flags & NAME_FLAGS_ONT, name_flags_ont_vals, - "Unknown")); - strcat(buf, ", "); - if (flags & NAME_FLAGS_G) - strcat(buf, "group"); - else - strcat(buf, "unique"); - if (flags & NAME_FLAGS_DRG) - strcat(buf, ", being deregistered"); - if (flags & NAME_FLAGS_CNF) - strcat(buf, ", in conflict"); - if (flags & NAME_FLAGS_ACT) - strcat(buf, ", active"); - if (flags & NAME_FLAGS_PRM) - strcat(buf, ", permanent node name"); - tf = proto_tree_add_text(rr_tree, tvb, offset, 2, "Name flags: 0x%x (%s)", - flags, buf); - field_tree = proto_item_add_subtree(tf, ett_nbns_name_flags); - proto_tree_add_text(field_tree, tvb, offset, 2, "%s", - decode_boolean_bitfield(flags, NAME_FLAGS_G, - 2*8, - "Group name", - "Unique name")); - proto_tree_add_text(field_tree, tvb, offset, 2, "%s", - decode_enumerated_bitfield(flags, NAME_FLAGS_ONT, - 2*8, name_flags_ont_vals, "%s")); - proto_tree_add_text(field_tree, tvb, offset, 2, "%s", - decode_boolean_bitfield(flags, NAME_FLAGS_DRG, - 2*8, - "Name is being deregistered", - "Name is not being deregistered")); - proto_tree_add_text(field_tree, tvb, offset, 2, "%s", - decode_boolean_bitfield(flags, NAME_FLAGS_CNF, - 2*8, - "Name is in conflict", - "Name is not in conflict")); - proto_tree_add_text(field_tree, tvb, offset, 2, "%s", - decode_boolean_bitfield(flags, NAME_FLAGS_ACT, - 2*8, - "Name is active", - "Name is not active")); - proto_tree_add_text(field_tree, tvb, offset, 2, "%s", - decode_boolean_bitfield(flags, NAME_FLAGS_PRM, - 2*8, - "Permanent node name", - "Not permanent node name")); -} - -static int -dissect_nbns_answer(tvbuff_t *tvb, int offset, int nbns_data_offset, - column_info *cinfo, proto_tree *nbns_tree, int opcode) -{ - int len; - 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; - int data_offset; - int cur_offset; - int data_start; - guint ttl; - gushort data_len; - gushort flags; - proto_tree *rr_tree; - proto_item *trr; - char name_str[(NETBIOS_NAME_LEN - 1)*4 + 1]; - guint num_names; - char nbname[16+4+1]; /* 4 for [<last char>] */ - gushort name_flags; - - data_start = data_offset = offset; - cur_offset = offset; - - len = get_nbns_name_type_class(tvb, offset, nbns_data_offset, name, - &name_len, &name_type, &type, &class); - data_offset += len; - cur_offset += len; - - type_name = nbns_type_name(type); - class_name = dns_class_name(class); - - ttl = tvb_get_ntohl(tvb, data_offset); - data_offset += 4; - cur_offset += 4; - - data_len = tvb_get_ntohs(tvb, data_offset); - data_offset += 2; - cur_offset += 2; - - switch (type) { - case T_NB: /* "NB" record */ - if (cinfo != NULL) { - if (opcode != OPCODE_WACK) { - col_append_fstr(cinfo, COL_INFO, " %s %s", - type_name, - ip_to_str(tvb_get_ptr(tvb, data_offset+2, 4))); - } - } - if (nbns_tree == NULL) - break; - trr = proto_tree_add_text(nbns_tree, tvb, offset, - (data_offset - data_start) + data_len, - "%s: type %s, class %s", - name, type_name, class_name); - strcat(name, " ("); - strcat(name, netbios_name_type_descr(name_type)); - strcat(name, ")"); - rr_tree = add_rr_to_tree(trr, ett_nbns_rr, tvb, offset, name, - name_len, type_name, class_name, ttl, data_len); - 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 (data_len < 2) { - proto_tree_add_text(rr_tree, tvb, cur_offset, - data_len, "(incomplete entry)"); - break; - } - flags = tvb_get_ntohs(tvb, cur_offset); - nbns_add_nbns_flags(cinfo, rr_tree, tvb, cur_offset, - flags, 1); - cur_offset += 2; - data_len -= 2; - } else { - if (data_len < 2) { - proto_tree_add_text(rr_tree, tvb, cur_offset, - data_len, "(incomplete entry)"); - break; - } - flags = tvb_get_ntohs(tvb, cur_offset); - nbns_add_nb_flags(rr_tree, tvb, cur_offset, - flags); - cur_offset += 2; - data_len -= 2; - - if (data_len < 4) { - proto_tree_add_text(rr_tree, tvb, cur_offset, - data_len, "(incomplete entry)"); - break; - } - proto_tree_add_text(rr_tree, tvb, cur_offset, 4, - "Addr: %s", - ip_to_str(tvb_get_ptr(tvb, cur_offset, 4))); - cur_offset += 4; - data_len -= 4; - } - } - break; - - case T_NBSTAT: /* "NBSTAT" record */ - if (cinfo != NULL) - col_append_fstr(cinfo, COL_INFO, " %s", type_name); - if (nbns_tree == NULL) - break; - trr = proto_tree_add_text(nbns_tree, tvb, offset, - (data_offset - data_start) + data_len, - "%s: type %s, class %s", - name, type_name, class_name); - rr_tree = add_rr_to_tree(trr, ett_nbns_rr, tvb, offset, name, - name_len, type_name, class_name, ttl, data_len); - if (data_len < 1) { - proto_tree_add_text(rr_tree, tvb, cur_offset, - data_len, "(incomplete entry)"); - break; - } - num_names = tvb_get_guint8(tvb, cur_offset); - proto_tree_add_text(rr_tree, tvb, cur_offset, 1, - "Number of names: %u", num_names); - cur_offset += 1; - - while (num_names != 0) { - if (data_len < NETBIOS_NAME_LEN) { - proto_tree_add_text(rr_tree, tvb, cur_offset, - data_len, "(incomplete entry)"); - goto out; - } - tvb_memcpy(tvb, (guint8 *)nbname, cur_offset, - NETBIOS_NAME_LEN); - name_type = process_netbios_name(nbname, - name_str); - proto_tree_add_text(rr_tree, tvb, 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 (data_len < 2) { - proto_tree_add_text(rr_tree, tvb, cur_offset, - data_len, "(incomplete entry)"); - goto out; - } - name_flags = tvb_get_ntohs(tvb, cur_offset); - nbns_add_name_flags(rr_tree, tvb, cur_offset, - name_flags); - cur_offset += 2; - data_len -= 2; - - num_names--; - } - - if (data_len < 6) { - proto_tree_add_text(rr_tree, tvb, cur_offset, - data_len, "(incomplete entry)"); - break; - } - proto_tree_add_text(rr_tree, tvb, cur_offset, 6, - "Unit ID: %s", - ether_to_str(tvb_get_ptr(tvb, cur_offset, 6))); - cur_offset += 6; - data_len -= 6; - - if (data_len < 1) { - proto_tree_add_text(rr_tree, tvb, cur_offset, - data_len, "(incomplete entry)"); - break; - } - proto_tree_add_text(rr_tree, tvb, cur_offset, 1, - "Jumpers: 0x%x", tvb_get_guint8(tvb, cur_offset)); - cur_offset += 1; - data_len -= 1; - - if (data_len < 1) { - proto_tree_add_text(rr_tree, tvb, cur_offset, - data_len, "(incomplete entry)"); - break; - } - proto_tree_add_text(rr_tree, tvb, cur_offset, 1, - "Test result: 0x%x", tvb_get_guint8(tvb, cur_offset)); - cur_offset += 1; - data_len -= 1; - - if (data_len < 2) { - proto_tree_add_text(rr_tree, tvb, cur_offset, - data_len, "(incomplete entry)"); - break; - } - proto_tree_add_text(rr_tree, tvb, cur_offset, 2, - "Version number: 0x%x", tvb_get_ntohs(tvb, cur_offset)); - cur_offset += 2; - data_len -= 2; - - if (data_len < 2) { - proto_tree_add_text(rr_tree, tvb, cur_offset, - data_len, "(incomplete entry)"); - break; - } - proto_tree_add_text(rr_tree, tvb, cur_offset, 2, - "Period of statistics: 0x%x", - tvb_get_ntohs(tvb, cur_offset)); - cur_offset += 2; - data_len -= 2; - - if (data_len < 2) { - proto_tree_add_text(rr_tree, tvb, cur_offset, - data_len, "(incomplete entry)"); - break; - } - proto_tree_add_text(rr_tree, tvb, cur_offset, 2, - "Number of CRCs: %u", tvb_get_ntohs(tvb, cur_offset)); - cur_offset += 2; - data_len -= 2; - - if (data_len < 2) { - proto_tree_add_text(rr_tree, tvb, cur_offset, - data_len, "(incomplete entry)"); - break; - } - proto_tree_add_text(rr_tree, tvb, cur_offset, 2, - "Number of alignment errors: %u", - tvb_get_ntohs(tvb, cur_offset)); - cur_offset += 2; - data_len -= 2; - - if (data_len < 2) { - proto_tree_add_text(rr_tree, tvb, cur_offset, - data_len, "(incomplete entry)"); - break; - } - proto_tree_add_text(rr_tree, tvb, cur_offset, 2, - "Number of collisions: %u", tvb_get_ntohs(tvb, cur_offset)); - cur_offset += 2; - data_len -= 2; - - if (data_len < 2) { - proto_tree_add_text(rr_tree, tvb, cur_offset, - data_len, "(incomplete entry)"); - break; - } - proto_tree_add_text(rr_tree, tvb, cur_offset, 2, - "Number of send aborts: %u", tvb_get_ntohs(tvb, cur_offset)); - cur_offset += 2; - data_len -= 2; - - if (data_len < 4) { - proto_tree_add_text(rr_tree, tvb, cur_offset, - data_len, "(incomplete entry)"); - break; - } - proto_tree_add_text(rr_tree, tvb, cur_offset, 4, - "Number of good sends: %u", tvb_get_ntohl(tvb, cur_offset)); - cur_offset += 4; - data_len -= 4; - - if (data_len < 4) { - proto_tree_add_text(rr_tree, tvb, cur_offset, - data_len, "(incomplete entry)"); - break; - } - proto_tree_add_text(rr_tree, tvb, cur_offset, 4, - "Number of good receives: %u", - tvb_get_ntohl(tvb, cur_offset)); - cur_offset += 4; - data_len -= 4; - - if (data_len < 2) { - proto_tree_add_text(rr_tree, tvb, cur_offset, - data_len, "(incomplete entry)"); - break; - } - proto_tree_add_text(rr_tree, tvb, cur_offset, 2, - "Number of retransmits: %u", tvb_get_ntohs(tvb, cur_offset)); - cur_offset += 2; - data_len -= 2; - - if (data_len < 2) { - proto_tree_add_text(rr_tree, tvb, cur_offset, - data_len, "(incomplete entry)"); - break; - } - proto_tree_add_text(rr_tree, tvb, cur_offset, 2, - "Number of no resource conditions: %u", - tvb_get_ntohs(tvb, cur_offset)); - cur_offset += 2; - data_len -= 2; - - if (data_len < 2) { - proto_tree_add_text(rr_tree, tvb, cur_offset, - data_len, "(incomplete entry)"); - break; - } - proto_tree_add_text(rr_tree, tvb, cur_offset, 2, - "Number of command blocks: %u", - tvb_get_ntohs(tvb, cur_offset)); - cur_offset += 2; - data_len -= 2; - - if (data_len < 2) { - proto_tree_add_text(rr_tree, tvb, cur_offset, - data_len, "(incomplete entry)"); - break; - } - proto_tree_add_text(rr_tree, tvb, cur_offset, 2, - "Number of pending sessions: %u", - tvb_get_ntohs(tvb, cur_offset)); - cur_offset += 2; - data_len -= 2; - - if (data_len < 2) { - proto_tree_add_text(rr_tree, tvb, cur_offset, - data_len, "(incomplete entry)"); - break; - } - proto_tree_add_text(rr_tree, tvb, cur_offset, 2, - "Max number of pending sessions: %u", - tvb_get_ntohs(tvb, cur_offset)); - cur_offset += 2; - data_len -= 2; - - if (data_len < 2) { - proto_tree_add_text(rr_tree, tvb, cur_offset, - data_len, "(incomplete entry)"); - break; - } - proto_tree_add_text(rr_tree, tvb, cur_offset, 2, - "Max total sessions possible: %u", - tvb_get_ntohs(tvb, cur_offset)); - cur_offset += 2; - data_len -= 2; - - if (data_len < 2) { - proto_tree_add_text(rr_tree, tvb, cur_offset, - data_len, "(incomplete entry)"); - break; - } - proto_tree_add_text(rr_tree, tvb, cur_offset, 2, - "Session data packet size: %u", - tvb_get_ntohs(tvb, cur_offset)); - cur_offset += 2; - data_len -= 2; - out: - break; - - default: - if (cinfo != NULL) - col_append_fstr(cinfo, COL_INFO, " %s", type_name); - if (nbns_tree == NULL) - break; - trr = proto_tree_add_text(nbns_tree, tvb, offset, - (data_offset - data_start) + data_len, - "%s: type %s, class %s", - name, type_name, class_name); - rr_tree = add_rr_to_tree(trr, ett_nbns_rr, tvb, offset, name, - name_len, type_name, class_name, ttl, data_len); - proto_tree_add_text(rr_tree, tvb, cur_offset, data_len, "Data"); - cur_offset += data_len; - break; - } - - return cur_offset - data_start; -} - -static int -dissect_query_records(tvbuff_t *tvb, int cur_off, int nbns_data_offset, - int count, column_info *cinfo, proto_tree *nbns_tree) -{ - int start_off, add_off; - proto_tree *qatree = NULL; - proto_item *ti = NULL; - - start_off = cur_off; - if (nbns_tree != NULL) { - ti = proto_tree_add_text(nbns_tree, tvb, start_off, -1, "Queries"); - qatree = proto_item_add_subtree(ti, ett_nbns_qry); - } - while (count-- > 0) { - add_off = dissect_nbns_query(tvb, cur_off, nbns_data_offset, - cinfo, qatree); - 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(tvbuff_t *tvb, int cur_off, int nbns_data_offset, - int count, column_info *cinfo, proto_tree *nbns_tree, int opcode, - char *name) -{ - int start_off, add_off; - proto_tree *qatree = NULL; - proto_item *ti = NULL; - - start_off = cur_off; - if (nbns_tree != NULL) { - ti = proto_tree_add_text(nbns_tree, tvb, start_off, -1, name); - qatree = proto_item_add_subtree(ti, ett_nbns_ans); - } - while (count-- > 0) { - add_off = dissect_nbns_answer(tvb, cur_off, nbns_data_offset, - cinfo, qatree, opcode); - cur_off += add_off; - } - if (ti != NULL) - proto_item_set_len(ti, cur_off - start_off); - return cur_off - start_off; -} - -static void -dissect_nbns(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) -{ - int offset = 0; - int nbns_data_offset; - column_info *cinfo; - proto_tree *nbns_tree = NULL; - proto_item *ti; - guint16 id, flags, opcode, rcode, quest, ans, auth, add; - int cur_off; - - nbns_data_offset = offset; - - if (check_col(pinfo->cinfo, COL_PROTOCOL)) - col_set_str(pinfo->cinfo, COL_PROTOCOL, "NBNS"); - if (check_col(pinfo->cinfo, COL_INFO)) - col_clear(pinfo->cinfo, COL_INFO); - - /* To do: check for runts, errs, etc. */ - id = tvb_get_ntohs(tvb, offset + NBNS_ID); - flags = tvb_get_ntohs(tvb, offset + NBNS_FLAGS); - opcode = (guint16) ((flags & F_OPCODE) >> OPCODE_SHIFT); - rcode = (guint16) (flags & F_RCODE); - - if (check_col(pinfo->cinfo, COL_INFO)) { - col_add_fstr(pinfo->cinfo, COL_INFO, "%s%s", - val_to_str(opcode, opcode_vals, "Unknown operation (%u)"), - (flags & F_RESPONSE) ? " response" : ""); - cinfo = pinfo->cinfo; - } else { - /* Set "cinfo" to NULL; we pass a NULL "cinfo" 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(cinfo, COL_INFO)" is more expensive than - a check that a pointer isn't NULL). */ - cinfo = NULL; - } - - if (tree) { - ti = proto_tree_add_item(tree, proto_nbns, tvb, offset, -1, - FALSE); - nbns_tree = proto_item_add_subtree(ti, ett_nbns); - - proto_tree_add_uint(nbns_tree, hf_nbns_transaction_id, tvb, - offset + NBNS_ID, 2, id); - - nbns_add_nbns_flags(pinfo->cinfo, nbns_tree, tvb, offset + NBNS_FLAGS, - flags, 0); - } - quest = tvb_get_ntohs(tvb, offset + NBNS_QUEST); - if (tree) { - proto_tree_add_uint(nbns_tree, hf_nbns_count_questions, tvb, - offset + NBNS_QUEST, 2, quest); - } - ans = tvb_get_ntohs(tvb, offset + NBNS_ANS); - if (tree) { - proto_tree_add_uint(nbns_tree, hf_nbns_count_answers, tvb, - offset + NBNS_ANS, 2, ans); - } - auth = tvb_get_ntohs(tvb, offset + NBNS_AUTH); - if (tree) { - proto_tree_add_uint(nbns_tree, hf_nbns_count_auth_rr, tvb, - offset + NBNS_AUTH, 2, auth); - } - add = tvb_get_ntohs(tvb, offset + NBNS_ADD); - if (tree) { - proto_tree_add_uint(nbns_tree, hf_nbns_count_add_rr, tvb, - offset + NBNS_ADD, 2, add); - } - - cur_off = offset + NBNS_HDRLEN; - - 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(tvb, cur_off, - nbns_data_offset, quest, - (!(flags & F_RESPONSE) ? cinfo : NULL), nbns_tree); - } - - 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(tvb, cur_off, - nbns_data_offset, ans, - ((flags & F_RESPONSE) ? cinfo : NULL), nbns_tree, - 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(tvb, cur_off, - nbns_data_offset, - auth, NULL, nbns_tree, opcode, - "Authoritative nameservers"); - - if (add > 0) - cur_off += dissect_answer_records(tvb, cur_off, - nbns_data_offset, - add, NULL, nbns_tree, opcode, - "Additional records"); - } -} - -/* NetBIOS datagram packet, from RFC 1002, page 32 */ -struct nbdgm_header { - guint8 msg_type; - struct { - guint8 more; - guint8 first; - guint8 node_type; - } flags; - guint16 dgm_id; - guint32 src_ip; - guint16 src_port; - - /* For packets with data */ - guint16 dgm_length; - guint16 pkt_offset; - - /* For error packets */ - guint8 error_code; -}; - -/* - * NBDS message types. - */ -#define NBDS_DIRECT_UNIQUE 0x10 -#define NBDS_DIRECT_GROUP 0x11 -#define NBDS_BROADCAST 0x12 -#define NBDS_ERROR 0x13 -#define NBDS_QUERY_REQUEST 0x14 -#define NBDS_POS_QUERY_RESPONSE 0x15 -#define NBDS_NEG_QUERY_RESPONSE 0x16 - -static const value_string nbds_msgtype_vals[] = { - { NBDS_DIRECT_UNIQUE, "Direct_unique datagram" }, - { NBDS_DIRECT_GROUP, "Direct_group datagram" }, - { NBDS_BROADCAST, "Broadcast datagram" }, - { NBDS_ERROR, "Datagram error" }, - { NBDS_QUERY_REQUEST, "Datagram query request" }, - { NBDS_POS_QUERY_RESPONSE, "Datagram positive query response" }, - { NBDS_NEG_QUERY_RESPONSE, "Datagram negative query response" }, - { 0, NULL } -}; - -static const true_false_string yesno = { - "Yes", - "No" -}; - -static const value_string node_type_vals[] = { - { 0, "B node" }, - { 1, "P node" }, - { 2, "M node" }, - { 3, "NBDD" }, - { 0, NULL } -}; - -static void -dissect_nbdgm(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) -{ - int offset = 0; - proto_tree *nbdgm_tree = NULL; - proto_item *ti = NULL; - struct nbdgm_header header; - int flags; - int message_index; - tvbuff_t *next_tvb; - - static const value_string error_codes[] = { - { 0x82, "Destination name not present" }, - { 0x83, "Invalid source name format" }, - { 0x84, "Invalid destination name format" }, - { 0x00, NULL } - }; - - char name[(NETBIOS_NAME_LEN - 1)*4 + MAXDNAME]; - int name_type; - int len; - - if (check_col(pinfo->cinfo, COL_PROTOCOL)) - col_set_str(pinfo->cinfo, COL_PROTOCOL, "NBDS"); - if (check_col(pinfo->cinfo, COL_INFO)) - col_clear(pinfo->cinfo, COL_INFO); - - header.msg_type = tvb_get_guint8(tvb, offset); - - flags = tvb_get_guint8(tvb, offset+1); - header.flags.more = flags & 1; - header.flags.first = (flags & 2) >> 1; - header.flags.node_type = (flags & 12) >> 2; - - header.dgm_id = tvb_get_ntohs(tvb, offset+2); - tvb_memcpy(tvb, (guint8 *)&header.src_ip, offset+4, 4); - header.src_port = tvb_get_ntohs(tvb, offset+8); - - switch (header.msg_type) { - - case NBDS_DIRECT_UNIQUE: - case NBDS_DIRECT_GROUP: - case NBDS_BROADCAST: - header.dgm_length = tvb_get_ntohs(tvb, offset+10); - header.pkt_offset = tvb_get_ntohs(tvb, offset+12); - break; - - case NBDS_ERROR: - header.error_code = tvb_get_guint8(tvb, offset+10); - break; - } - - message_index = header.msg_type - 0x0f; - if (message_index < 1 || message_index > 8) { - message_index = 0; - } - - if (check_col(pinfo->cinfo, COL_INFO)) { - col_add_str(pinfo->cinfo, COL_INFO, - val_to_str(header.msg_type, nbds_msgtype_vals, - "Unknown message type (0x%02X)")); - } - - if (tree) { - ti = proto_tree_add_item(tree, proto_nbdgm, tvb, offset, -1, - FALSE); - nbdgm_tree = proto_item_add_subtree(ti, ett_nbdgm); - - proto_tree_add_uint(nbdgm_tree, hf_nbdgm_type, tvb, - offset, 1, - header.msg_type); - proto_tree_add_boolean(nbdgm_tree, hf_nbdgm_fragment, tvb, - offset+1, 1, - header.flags.more); - proto_tree_add_boolean(nbdgm_tree, hf_nbdgm_first, tvb, - offset+1, 1, - header.flags.first); - proto_tree_add_uint(nbdgm_tree, hf_nbdgm_node_type, tvb, - offset+1, 1, - header.flags.node_type); - - proto_tree_add_uint(nbdgm_tree, hf_nbdgm_datagram_id, tvb, - offset+2, 2, header.dgm_id); - proto_tree_add_ipv4(nbdgm_tree, hf_nbdgm_src_ip, tvb, - offset+4, 4, header.src_ip); - proto_tree_add_uint(nbdgm_tree, hf_nbdgm_src_port, tvb, - offset+8, 2, header.src_port); - - } - - offset += 10; - - switch (header.msg_type) { - - case NBDS_DIRECT_UNIQUE: - case NBDS_DIRECT_GROUP: - case NBDS_BROADCAST: - if (tree) { - proto_tree_add_text(nbdgm_tree, tvb, offset, 2, - "Datagram length: %d bytes", header.dgm_length); - proto_tree_add_text(nbdgm_tree, tvb, offset+2, 2, - "Packet offset: %d bytes", header.pkt_offset); - } - - offset += 4; - - /* Source name */ - len = get_nbns_name(tvb, offset, offset, name, &name_type); - - if (tree) { - add_name_and_type(nbdgm_tree, tvb, offset, len, - "Source name", name, name_type); - } - offset += len; - - /* Destination name */ - len = get_nbns_name(tvb, offset, offset, name, &name_type); - - if (tree) { - add_name_and_type(nbdgm_tree, tvb, offset, len, - "Destination name", name, name_type); - } - offset += len; - - /* - * Here we can pass the packet off to the next protocol. - * Set the length of our top-level tree item to include - * only our stuff. - * - * XXX - take the datagram length into account? - */ - proto_item_set_len(ti, offset); - next_tvb = tvb_new_subset(tvb, offset, -1, -1); - dissect_netbios_payload(next_tvb, pinfo, tree); - break; - - case NBDS_ERROR: - if (tree) { - proto_tree_add_text(nbdgm_tree, tvb, offset, 1, "Error code: %s", - val_to_str(header.error_code, error_codes, "Unknown (0x%x)")); - } - offset += 1; - proto_item_set_len(ti, offset); - break; - - case NBDS_QUERY_REQUEST: - case NBDS_POS_QUERY_RESPONSE: - case NBDS_NEG_QUERY_RESPONSE: - /* Destination name */ - len = get_nbns_name(tvb, offset, offset, name, &name_type); - - if (tree) { - add_name_and_type(nbdgm_tree, tvb, offset, len, - "Destination name", name, name_type); - } - offset += len; - proto_item_set_len(ti, offset); - break; - } -} - -/* - * NetBIOS Session Service message types. - */ -#define SESSION_MESSAGE 0x00 -#define SESSION_REQUEST 0x81 -#define POSITIVE_SESSION_RESPONSE 0x82 -#define NEGATIVE_SESSION_RESPONSE 0x83 -#define RETARGET_SESSION_RESPONSE 0x84 -#define SESSION_KEEP_ALIVE 0x85 - -static const value_string message_types[] = { - { SESSION_MESSAGE, "Session message" }, - { SESSION_REQUEST, "Session request" }, - { POSITIVE_SESSION_RESPONSE, "Positive session response" }, - { NEGATIVE_SESSION_RESPONSE, "Negative session response" }, - { RETARGET_SESSION_RESPONSE, "Retarget session response" }, - { SESSION_KEEP_ALIVE, "Session keep-alive" }, - { 0x0, NULL } -}; - -/* - * NetBIOS Session Service flags. - */ -#define NBSS_FLAGS_E 0x1 - -static const value_string error_codes[] = { - { 0x80, "Not listening on called name" }, - { 0x81, "Not listening for called name" }, - { 0x82, "Called name not present" }, - { 0x83, "Called name present, but insufficient resources" }, - { 0x8F, "Unspecified error" }, - { 0x0, NULL } -}; - -/* - * Dissect a single NBSS packet (there may be more than one in a given - * TCP segment). - * - * [ Hmmm, in my experience, I have never seen more than one NBSS in a - * single segment, since they mostly contain SMBs which are essentially - * a request response type protocol (RJS). ] - * - * [ However, under heavy load with many requests multiplexed on one - * session it is not unusual to see multiple requests in one TCP - * segment. Unfortunately, in this case a single session message is - * frequently split over multiple segments, which frustrates decoding - * (MMM). ] - */ -static int -dissect_nbss_packet(tvbuff_t *tvb, int offset, packet_info *pinfo, - proto_tree *tree, int is_cifs) -{ - proto_tree *nbss_tree = NULL; - proto_item *ti = NULL; - proto_tree *field_tree; - proto_item *tf; - guint8 msg_type; - guint8 flags; - volatile int length; - int length_remaining; - int len; - char name[(NETBIOS_NAME_LEN - 1)*4 + MAXDNAME]; - int name_type; - gint reported_len; - tvbuff_t *next_tvb; - const char *saved_proto; - - /* Desegmentation */ - length_remaining = tvb_length_remaining(tvb, offset); - - /* - * Can we do reassembly? - */ - if (nbss_desegment && pinfo->can_desegment) { - /* - * Yes - is the NBSS header split across segment boundaries? - */ - if (length_remaining < 4) { - /* - * Yes. Tell our caller how many more bytes - * we need. - */ - return -(4 - length_remaining); - } - } - - /* - * Get the length of the NBSS message. - */ - if (is_cifs) { - flags = 0; - length = tvb_get_ntoh24(tvb, offset + 1); - } else { - flags = tvb_get_guint8(tvb, offset + 1); - length = tvb_get_ntohs(tvb, offset + 2); - if (flags & NBSS_FLAGS_E) - length += 65536; - } - - /* give a hint to TCP where the next PDU starts - * so that it can attempt to find it in case it starts - * somewhere in the middle of a segment. - */ - if(!pinfo->fd->flags.visited){ - if((length+4)>tvb_reported_length_remaining(tvb, offset)){ - pinfo->want_pdu_tracking=2; - pinfo->bytes_until_next_pdu=(length+4)-tvb_reported_length_remaining(tvb, offset); - } - } - - /* - * Can we do reassembly? - */ - if (nbss_desegment && pinfo->can_desegment) { - /* - * Yes - is the NBSS message split across segment boundaries? - */ - if (length_remaining < length + 4) { - /* - * Yes. Tell our caller how many more bytes - * we need. - */ - return -((length + 4) - length_remaining); - } - } - - msg_type = tvb_get_guint8(tvb, offset); - - if (tree) { - ti = proto_tree_add_item(tree, proto_nbss, tvb, offset, length + 4, FALSE); - nbss_tree = proto_item_add_subtree(ti, ett_nbss); - - proto_tree_add_uint_format(nbss_tree, hf_nbss_type, tvb, - offset, 1, - msg_type, - "Message Type: %s", - val_to_str(msg_type, message_types, - "Unknown (%x)")); - } - - offset += 1; - - if (is_cifs) { - if (tree) { - proto_tree_add_text(nbss_tree, tvb, offset, 3, "Length: %u", length); - } - offset += 3; - } else { - if (tree) { - tf = proto_tree_add_uint(nbss_tree, hf_nbss_flags, tvb, offset, 1, flags); - field_tree = proto_item_add_subtree(tf, ett_nbss_flags); - proto_tree_add_text(field_tree, tvb, 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_text(nbss_tree, tvb, offset, 2, "Length: %u", length); - } - - offset += 2; - } - - switch (msg_type) { - - case SESSION_REQUEST: - len = get_nbns_name(tvb, offset, offset, name, &name_type); - if (tree) - add_name_and_type(nbss_tree, tvb, offset, len, - "Called name", name, name_type); - offset += len; - - if (check_col(pinfo->cinfo, COL_INFO)) - col_append_fstr(pinfo->cinfo, COL_INFO, ", to %s ", name); - - len = get_nbns_name(tvb, offset, offset, name, &name_type); - - if (tree) - add_name_and_type(nbss_tree, tvb, offset, len, - "Calling name", name, name_type); - - if (check_col(pinfo->cinfo, COL_INFO)) - col_append_fstr(pinfo->cinfo, COL_INFO, "from %s", name); - - break; - - case NEGATIVE_SESSION_RESPONSE: - if (tree) - proto_tree_add_text(nbss_tree, tvb, offset, 1, - "Error code: %s", - val_to_str(tvb_get_guint8(tvb, offset), - error_codes, "Unknown (%x)")); - - if (check_col(pinfo->cinfo, COL_INFO)) - col_append_fstr(pinfo->cinfo, COL_INFO, ", %s", - val_to_str(tvb_get_guint8(tvb, offset), - error_codes, "Unknown (%x)")); - - break; - - case RETARGET_SESSION_RESPONSE: - if (tree) - proto_tree_add_text(nbss_tree, tvb, offset, 4, - "Retarget IP address: %s", - ip_to_str(tvb_get_ptr(tvb, offset, 4))); - - offset += 4; - - if (tree) - proto_tree_add_text(nbss_tree, tvb, offset, 2, - "Retarget port: %u", - tvb_get_ntohs(tvb, offset)); - - break; - - case SESSION_MESSAGE: - /* - * Here we can pass the message off to the next protocol. - * Set the length of our top-level tree item to include - * only our stuff. - */ - proto_item_set_len(ti, offset); - len = tvb_length_remaining(tvb, offset); - reported_len = tvb_reported_length_remaining(tvb, offset); - if (len > length) - len = length; - if (reported_len > length) - reported_len = length; - - next_tvb = tvb_new_subset(tvb, offset, len, reported_len); - - /* - * Catch the ReportedBoundsError exception; if this - * particular message happens to get a ReportedBoundsError - * exception, that doesn't mean that we should stop - * dissecting NetBIOS messages within this frame or chunk - * of reassembled data. - * - * If it gets a BoundsError, we can stop, as there's nothing - * more to see, so we just re-throw it. - */ - saved_proto = pinfo->current_proto; - TRY { - dissect_netbios_payload(next_tvb, pinfo, tree); - } - CATCH(BoundsError) { - RETHROW; - } - CATCH(ReportedBoundsError) { - show_reported_bounds_error(tvb, pinfo, tree); - pinfo->current_proto = saved_proto; - } - ENDTRY; - break; - - } - return length + 4; -} - -static void -dissect_nbss(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) -{ - struct tcpinfo *tcpinfo = pinfo->private_data; - int offset = 0; - int max_data; - guint8 msg_type; - guint8 flags; - guint32 length; - int len; - gboolean is_cifs; - proto_tree *nbss_tree; - proto_item *ti; - - if (check_col(pinfo->cinfo, COL_PROTOCOL)) - col_set_str(pinfo->cinfo, COL_PROTOCOL, "NBSS"); - if (check_col(pinfo->cinfo, COL_INFO)) - col_clear(pinfo->cinfo, COL_INFO); - - max_data = tvb_length(tvb); - - msg_type = tvb_get_guint8(tvb, offset); - - if (pinfo->match_port == TCP_PORT_CIFS) { - /* - * Windows 2000 CIFS clients can dispense completely - * with the NETBIOS encapsulation and directly use CIFS - * over TCP. As would be expected, the framing is - * identical, except that the length is 24 bits instead - * of 17. The only message types used are - * SESSION_MESSAGE and SESSION_KEEP_ALIVE. - */ - is_cifs = TRUE; - } else { - is_cifs = FALSE; - } - - /* - * This might be a continuation of an earlier message. - * (Yes, that might be true even if we're doing TCP reassembly, - * as the first TCP segment in the capture might start in the - * middle of an NBNS message.) - */ - - /* - * If this isn't reassembled data, check to see whether it - * looks like a continuation of a message. - * (If it is reassembled data, it shouldn't be a continuation, - * as reassembly should've gathered the continuations together - * into a message.) - */ - if (!tcpinfo->is_reassembled) { - if (max_data < 4) { - /* - * Not enough data for an NBSS header; assume - * it's a continuation of a message. - * - * XXX - if there's not enough data, we should - * attempt to reassemble the data, if the first byte - * is a valid message type. - */ - goto continuation; - } - - /* - * We have enough data for an NBSS header. - * Get the flags and length of the message, - * and see if they're sane. - */ - if (is_cifs) { - flags = 0; - length = tvb_get_ntoh24(tvb, offset + 1); - } else { - flags = tvb_get_guint8(tvb, offset + 1); - length = tvb_get_ntohs(tvb, offset + 2); - if (flags & NBSS_FLAGS_E) - length += 65536; - } - if ((flags & (~NBSS_FLAGS_E)) != 0) { - /* - * A bogus flag was set; assume it's a continuation. - */ - goto continuation; - } - - switch (msg_type) { - - case SESSION_MESSAGE: - /* - * This is variable-length. - * All we know is that it shouldn't be zero. - * (XXX - can we get zero-length messages? - * Not with SMB, but perhaps other NetBIOS-based - * protocols have them.) - */ - if (length == 0) - goto continuation; - break; - - case SESSION_REQUEST: - /* - * This is variable-length. - * The names are DNS-encoded 32-byte values; - * we need at least 2 bytes (one for each name; - * actually, we should have more for the first - * name, as there's no name preceding it so - * there should be no compression), and we - * shouldn't have more than 128 bytes (actually, - * we shouldn't have that many). - * - * XXX - actually, MacOS X 10.1 (yes, that's - * redundant, but that's what Apple calls it, - * not MacOS X.1) puts names longer than 16 - * characters into session request messages, - * so we can have more than 32 bytes of - * name value, so we can have more than 128 - * bytes of data. - */ - if (length < 2 || length > 256) - goto continuation; - break; - - case POSITIVE_SESSION_RESPONSE: - /* - * This has no data, so the length must be zero. - */ - if (length != 0) - goto continuation; - break; - - case NEGATIVE_SESSION_RESPONSE: - /* - * This has 1 byte of data. - */ - if (length != 1) - goto continuation; - break; - - case RETARGET_SESSION_RESPONSE: - /* - * This has 6 bytes of data. - */ - if (length != 6) - goto continuation; - break; - - case SESSION_KEEP_ALIVE: - /* - * This has no data, so the length must be zero. - */ - if (length != 0) - goto continuation; - break; - - default: - /* - * Unknown message type; assume it's a continuation. - */ - goto continuation; - } - } - - if (check_col(pinfo->cinfo, COL_INFO)) { - col_add_fstr(pinfo->cinfo, COL_INFO, - val_to_str(msg_type, message_types, "Unknown (%02x)")); - } - - while (tvb_reported_length_remaining(tvb, offset) > 0) { - len = dissect_nbss_packet(tvb, offset, pinfo, tree, is_cifs); - if (len < 0) { - /* - * We need more data to dissect this, and - * desegmentation is enabled. "-len" is the - * number of additional bytes of data we need. - * - * Tell the TCP dissector where the data for this - * message starts in the data it handed us, and - * how many more bytes we need, and return. - */ - pinfo->desegment_offset = offset; - pinfo->desegment_len = -len; - return; - } - offset += len; - } - - return; - -continuation: - /* - * It looks like a continuation. - */ - if (check_col(pinfo->cinfo, COL_INFO)) - col_add_fstr(pinfo->cinfo, COL_INFO, "NBSS Continuation Message"); - - if (tree) { - ti = proto_tree_add_item(tree, proto_nbss, tvb, 0, -1, FALSE); - nbss_tree = proto_item_add_subtree(ti, ett_nbss); - proto_tree_add_text(nbss_tree, tvb, 0, -1, "Continuation data"); - } -} - -void -proto_register_nbt(void) -{ - - static hf_register_info hf_nbns[] = { - { &hf_nbns_flags, - { "Flags", "nbns.flags", - FT_UINT16, BASE_HEX, NULL, 0x0, - "", HFILL }}, - { &hf_nbns_flags_response, - { "Response", "nbns.flags.response", - FT_BOOLEAN, 16, TFS(&tfs_flags_response), F_RESPONSE, - "Is the message a response?", HFILL }}, - { &hf_nbns_flags_opcode, - { "Opcode", "nbns.flags.opcode", - FT_UINT16, BASE_DEC, VALS(opcode_vals), F_OPCODE, - "Operation code", HFILL }}, - { &hf_nbns_flags_authoritative, - { "Authoritative", "nbns.flags.authoritative", - FT_BOOLEAN, 16, TFS(&tfs_flags_authoritative), F_AUTHORITATIVE, - "Is the server is an authority for the domain?", HFILL }}, - { &hf_nbns_flags_truncated, - { "Truncated", "nbns.flags.truncated", - FT_BOOLEAN, 16, TFS(&tfs_flags_truncated), F_TRUNCATED, - "Is the message truncated?", HFILL }}, - { &hf_nbns_flags_recdesired, - { "Recursion desired", "nbns.flags.recdesired", - FT_BOOLEAN, 16, TFS(&tfs_flags_recdesired), F_RECDESIRED, - "Do query recursively?", HFILL }}, - { &hf_nbns_flags_recavail, - { "Recursion available", "nbns.flags.recavail", - FT_BOOLEAN, 16, TFS(&tfs_flags_recavail), F_RECAVAIL, - "Can the server do recursive queries?", HFILL }}, - { &hf_nbns_flags_broadcast, - { "Broadcast", "nbns.flags.broadcast", - FT_BOOLEAN, 16, TFS(&tfs_flags_broadcast), F_BROADCAST, - "Is this a broadcast packet?", HFILL }}, - { &hf_nbns_flags_rcode, - { "Reply code", "nbns.flags.rcode", - FT_UINT16, BASE_DEC, VALS(rcode_vals), F_RCODE, - "Reply code", HFILL }}, - { &hf_nbns_transaction_id, - { "Transaction ID", "nbns.id", - FT_UINT16, BASE_HEX, NULL, 0x0, - "Identification of transaction", HFILL }}, - { &hf_nbns_count_questions, - { "Questions", "nbns.count.queries", - FT_UINT16, BASE_DEC, NULL, 0x0, - "Number of queries in packet", HFILL }}, - { &hf_nbns_count_answers, - { "Answer RRs", "nbns.count.answers", - FT_UINT16, BASE_DEC, NULL, 0x0, - "Number of answers in packet", HFILL }}, - { &hf_nbns_count_auth_rr, - { "Authority RRs", "nbns.count.auth_rr", - FT_UINT16, BASE_DEC, NULL, 0x0, - "Number of authoritative records in packet", HFILL }}, - { &hf_nbns_count_add_rr, - { "Additional RRs", "nbns.count.add_rr", - FT_UINT16, BASE_DEC, NULL, 0x0, - "Number of additional records in packet", HFILL }} - }; - - static hf_register_info hf_nbdgm[] = { - { &hf_nbdgm_type, - { "Message Type", "nbdgm.type", - FT_UINT8, BASE_DEC, VALS(nbds_msgtype_vals), 0x0, - "NBDGM message type", HFILL }}, - { &hf_nbdgm_fragment, - { "More fragments follow", "nbdgm.next", - FT_BOOLEAN, BASE_NONE, TFS(&yesno), 0x0, - "TRUE if more fragments follow", HFILL }}, - { &hf_nbdgm_first, - { "This is first fragment", "nbdgm.first", - FT_BOOLEAN, BASE_NONE, TFS(&yesno), 0x0, - "TRUE if first fragment", HFILL }}, - { &hf_nbdgm_node_type, - { "Node Type", "nbdgm.node_type", - FT_UINT8, BASE_DEC, VALS(node_type_vals), 0x0, - "Node type", HFILL }}, - { &hf_nbdgm_datagram_id, - { "Datagram ID", "nbdgm.dgram_id", - FT_UINT16, BASE_HEX, NULL, 0x0, - "Datagram identifier", HFILL }}, - { &hf_nbdgm_src_ip, - { "Source IP", "nbdgm.src.ip", - FT_IPv4, BASE_NONE, NULL, 0x0, - "Source IPv4 address", HFILL }}, - { &hf_nbdgm_src_port, - { "Source Port", "nbdgm.src.port", - FT_UINT16, BASE_DEC, NULL, 0x0, - "Source port", HFILL }} - }; - - static hf_register_info hf_nbss[] = { - { &hf_nbss_type, - { "Message Type", "nbss.type", - FT_UINT8, BASE_DEC, NULL, 0x0, - "NBSS message type", HFILL }}, - { &hf_nbss_flags, - { "Flags", "nbss.flags", - FT_UINT8, BASE_HEX, NULL, 0x0, - "NBSS message flags", HFILL }} - }; - 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, - }; - module_t *nbss_module; - - proto_nbns = proto_register_protocol("NetBIOS Name Service", "NBNS", "nbns"); - proto_register_field_array(proto_nbns, hf_nbns, array_length(hf_nbns)); - - proto_nbdgm = proto_register_protocol("NetBIOS Datagram Service", - "NBDS", "nbdgm"); - proto_register_field_array(proto_nbdgm, hf_nbdgm, array_length(hf_nbdgm)); - - proto_nbss = proto_register_protocol("NetBIOS Session Service", - "NBSS", "nbss"); - proto_register_field_array(proto_nbss, hf_nbss, array_length(hf_nbss)); - - proto_register_subtree_array(ett, array_length(ett)); - - nbss_module = prefs_register_protocol(proto_nbss, NULL); - prefs_register_bool_preference(nbss_module, "desegment_nbss_commands", - "Desegment all NBSS packets spanning multiple TCP segments", - "Whether NBSS dissector should desegment all packets spanning multiple TCP segments", - &nbss_desegment); -} - -void -proto_reg_handoff_nbt(void) -{ - dissector_handle_t nbns_handle, nbdgm_handle, nbss_handle; - - nbns_handle = create_dissector_handle(dissect_nbns, proto_nbns); - dissector_add("udp.port", UDP_PORT_NBNS, nbns_handle); - nbdgm_handle = create_dissector_handle(dissect_nbdgm, proto_nbdgm); - dissector_add("udp.port", UDP_PORT_NBDGM, nbdgm_handle); - nbss_handle = create_dissector_handle(dissect_nbss, proto_nbss); - dissector_add("tcp.port", TCP_PORT_NBSS, nbss_handle); - dissector_add("tcp.port", TCP_PORT_CIFS, nbss_handle); -} |