/* packet-nbns.c
* 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>
+ * Guy Harris <guy@alum.mit.edu>
*
- * $Id: packet-nbns.c,v 1.56 2001/09/17 02:07:00 guy Exp $
+ * $Id: packet-nbns.c,v 1.66 2001/12/03 03:59:37 guy Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@ethereal.com>
#include "packet.h"
#include "packet-dns.h"
#include "packet-netbios.h"
-#include "packet-smb.h"
+#include "packet-tcp.h"
#include "prefs.h"
static int proto_nbns = -1;
proto_tree *nbdgm_tree = NULL;
proto_item *ti = NULL;
struct nbdgm_header header;
- int msglen;
int flags;
int message_index;
- int max_data = tvb_length_remaining(tvb, offset);
tvbuff_t *next_tvb;
static const value_string error_codes[] = {
}
offset += 10;
- max_data -= 10;
switch (header.msg_type) {
}
offset += 4;
- max_data -= 4;
/* Source name */
len = get_nbns_name(tvb, offset, offset, name, &name_type);
"Source name", name, name_type);
}
offset += len;
- max_data -= len;
/* Destination name */
len = get_nbns_name(tvb, offset, offset, name, &name_type);
"Destination name", name, name_type);
}
offset += len;
- max_data -= 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);
- {
- const guint8 *next_pd;
- int next_offset;
-
- next_tvb = tvb_new_subset(tvb, offset, -1, -1);
- tvb_compat(next_tvb, &next_pd, &next_offset);
-
- dissect_smb(next_pd, next_offset, pinfo->fd, tree,
- max_data);
- }
+ next_tvb = tvb_new_subset(tvb, offset, -1, -1);
+ dissect_netbios_payload(next_tvb, pinfo, tree);
break;
case NBDS_ERROR:
proto_item *tf;
guint8 msg_type;
guint8 flags;
- guint16 length;
+ int length;
int len;
char name[(NETBIOS_NAME_LEN - 1)*4 + MAXDNAME];
int name_type;
+ gint reported_len;
tvbuff_t *next_tvb;
msg_type = tvb_get_guint8(tvb, offset);
case SESSION_MESSAGE:
/*
- * Here we can pass the packet off to the next protocol.
+ * 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);
- {
- const guint8 *next_pd;
- int next_offset;
-
- next_tvb = tvb_new_subset(tvb, offset, -1, -1);
- tvb_compat(next_tvb, &next_pd, &next_offset);
-
- dissect_smb(next_pd, next_offset, pinfo->fd, tree,
- max_data - 4);
- }
+ 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);
+ dissect_netbios_payload(next_tvb, pinfo, tree);
break;
}
static void
dissect_nbss(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
{
+ struct tcpinfo *tcpinfo = pinfo->private_data;
int offset = 0;
- guint8 msg_type;
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->fd, COL_PROTOCOL))
col_set_str(pinfo->fd, COL_PROTOCOL, "NBSS");
if (check_col(pinfo->fd, COL_INFO))
col_clear(pinfo->fd, COL_INFO);
- msg_type = tvb_get_guint8(tvb, offset);
+ max_data = tvb_length(tvb);
- /*
- * XXX - we should set this based on both the length remaining
- * and "length"....
- */
- max_data = tvb_length_remaining(tvb, offset);
+ msg_type = tvb_get_guint8(tvb, offset);
if (pinfo->match_port == TCP_PORT_CIFS) {
/*
is_cifs = FALSE;
}
- /* 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_KEEP_ALIVE) &&
- (msg_type != SESSION_MESSAGE)) ||
- ((msg_type == SESSION_MESSAGE) &&
- (max_data < 8 || tvb_memeql(tvb, offset + 4, "\377SMB", 4) != 0))) {
-
- /*
- * Either the first byte isn't one of the known message types,
- * or it's a session message but we either don't have enough
- * data in the frame for the NBSS/CIFS header plus an SMB header,
- * or we do but the message data doesn't begin with 0xFF S M B.
- * Assume it's a continuation message.
- */
- if (check_col(pinfo->fd, COL_INFO)) {
- col_add_fstr(pinfo->fd, COL_INFO, "NBSS Continuation Message");
- }
+ /*
+ * 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 (tree)
- proto_tree_add_text(tree, tvb, offset, max_data, "Continuation data");
+ /*
+ * 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;
+ }
- return;
- }
-#endif
+ /*
+ * 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->fd, COL_INFO)) {
col_add_fstr(pinfo->fd, COL_INFO,
- val_to_str(msg_type, message_types, "Unknown (%x)"));
+ val_to_str(msg_type, message_types, "Unknown (%02x)"));
}
while (max_data > 0) {
offset += len;
max_data -= len;
}
+
+ return;
+
+continuation:
+ /*
+ * It looks like a continuation.
+ */
+ if (check_col(pinfo->fd, COL_INFO))
+ col_add_fstr(pinfo->fd, COL_INFO, "NBSS Continuation Message");
+
+ if (tree) {
+ ti = proto_tree_add_item(tree, proto_nbss, tvb, 0,
+ max_data, FALSE);
+ nbss_tree = proto_item_add_subtree(ti, ett_nbss);
+ proto_tree_add_text(nbss_tree, tvb, 0, max_data,
+ "Continuation data");
+ }
}
void
void
proto_reg_handoff_nbt(void)
{
- dissector_add("udp.port", UDP_PORT_NBNS, dissect_nbns, proto_nbns);
- dissector_add("udp.port", UDP_PORT_NBDGM, dissect_nbdgm, proto_nbdgm);
- dissector_add("tcp.port", TCP_PORT_NBSS, dissect_nbss, proto_nbss);
- dissector_add("tcp.port", TCP_PORT_CIFS, dissect_nbss, proto_nbss);
+ 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);
}