wireshark/epan/dissectors/packet-nbipx.c

877 lines
26 KiB
C

/* packet-nbipx.c
* Routines for NetBIOS over IPX packet disassembly
* Gilbert Ramirez <gram@alumni.rice.edu>
*
* Wireshark - Network traffic analyzer
* By Gerald Combs <gerald@wireshark.org>
* Copyright 1998 Gerald Combs
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "config.h"
#include <epan/packet.h>
#include "packet-ipx.h"
#include "packet-netbios.h"
void proto_register_nbipx(void);
void proto_reg_handoff_nbipx(void);
void proto_register_nmpi(void);
void proto_reg_handoff_nmpi(void);
static int proto_nbipx = -1;
static int hf_nbipx_packettype = -1;
static int hf_nbipx_name_flags = -1;
static int hf_nbipx_name_flags_group = -1;
static int hf_nbipx_name_flags_in_use = -1;
static int hf_nbipx_name_flags_registered = -1;
static int hf_nbipx_name_flags_duplicated = -1;
static int hf_nbipx_name_flags_deregistered = -1;
static int hf_nbipx_conn_control = -1;
static int hf_nbipx_conn_control_sys_packet = -1;
static int hf_nbipx_conn_control_ack = -1;
static int hf_nbipx_conn_control_attention = -1;
static int hf_nbipx_conn_control_end_msg = -1;
static int hf_nbipx_conn_control_resend = -1;
static int hf_nbipx_session_src_conn_id = -1;
static int hf_nbipx_session_dest_conn_id = -1;
static int hf_nbipx_session_send_seq_number = -1;
static int hf_nbipx_session_total_data_length = -1;
static int hf_nbipx_session_offset = -1;
static int hf_nbipx_session_data_length = -1;
static int hf_nbipx_session_recv_seq_number = -1;
static int hf_nbipx_session_bytes_received = -1;
static int hf_nbipx_ipx_network = -1;
static int hf_nbipx_opcode = -1;
static int hf_nbipx_name_type = -1;
static int hf_nbipx_messageid = -1;
static gint ett_nbipx = -1;
static gint ett_nbipx_conn_ctrl = -1;
static gint ett_nbipx_name_type_flags = -1;
static void dissect_conn_control(tvbuff_t *tvb, int offset, proto_tree *tree);
static heur_dissector_list_t netbios_heur_subdissector_list;
/* There is no RFC or public specification of Netware or Microsoft
* NetBIOS over IPX packets. I have had to decode the protocol myself,
* so there are holes and perhaps errors in this code. (gram)
*
* A list of "NovelNetBIOS" packet types can be found at
*
* http://web.archive.org/web/20150319134837/http://www.protocols.com/pbook/novel.htm#NetBIOS
*
* and at least some of those packet types appear to match what's in
* some NBIPX packets.
*
* Note, however, that it appears that sometimes NBIPX packets have
* 8 IPX addresses at the beginning, and sometimes they don't.
*
* In the section on "NetBIOS Broadcasts", the document at
*
* http://www.microsoft.com/technet/network/ipxrout.asp
*
* says that "the NetBIOS over IPX Broadcast header" contains 8 IPX
* network numbers in the "IPX WAN broadcast header", and that it's
* followed by a "Name Type Flags" byte (giving information about the
* name being registered, deregistered, or checked), a "Data Stream
* Type 2" byte giving the type of operation (NBIPX_FIND_NAME,
* NBIPX_NAME_RECOGNIZED, or NBIPX_CHECK_NAME - the latter is called
* "Add Name"), and a 16-byte NetBIOS name.
*
* It also says that "NetBIOS over IPX Broadcast packets" have a
* packet type of 0x14 (20, or IPX_PACKET_TYPE_WANBCAST) and a
* socket number of 0x455 (IPX_SOCKET_NETBIOS).
*
* However, there are also non-broadcast packets that *also* contain
* the 8 IPX network numbers; they appear to be replies to broadcast
* packets, and have a packet type of 0x4 (IPX_PACKET_TYPE_PEP).
*
* Other IPX_PACKET_TYPE_PEP packets to and from the IPX_SOCKET_NETBIOS
* socket, however, *don't* have the 8 IPX network numbers; there does
* not seem to be any obvious algorithm to determine whether the packet
* has the addresses or not. Microsoft Knowledge Base article Q128335
* appears to show some code from the NBIPX implementation in NT that
* tries to determine the packet type - and it appears to use heuristics
* based on the packet length and on looking at what might be the NBIPX
* "Data Stream Type" byte depending on whether the packet has the 8
* IPX network numbers or not.
*
* So, for now, we treat *all* NBIPX packets as having a "Data Stream
* Type" byte, preceded by another byte of NBIPX information and
* followed by more NBIPX stuff, and assume that it's preceded by
* 8 IPX network numbers iff:
*
* the packet is a WAN Broadcast packet
*
* or
*
* the packet is the right size for one of those PEP name replies
* (50 bytes) *and* has a name packet type as the Data Stream
* Type byte at the offset where that byte would be if the packet
* does have the 8 IPX network numbers at the beginning.
*
* The page at
*
* http://ourworld.compuserve.com/homepages/TimothyDEvans/encap.htm
*
* indicates, under "NBIPX session packets", that "NBIPX session packets"
* have
*
* 1 byte of NBIPX connection control flag
* 1 byte of data stream type
* 2 bytes of source connection ID
* 2 bytes of destination connection ID
* 2 bytes of send sequence number
* 2 bytes of total data length
* 2 bytes of offset
* 2 bytes of data length
* 2 bytes of receive sequence number
* 2 bytes of "bytes received"
*
* followed by data.
*
* Packets with a data stream type of NBIPX_DIRECTED_DATAGRAM appear to
* have, following the data stream type, two NetBIOS names, the first
* of which is the receiver's NetBIOS name and the second of which is
* the sender's NetBIOS name. The page at
*
* http://support.microsoft.com/support/kb/articles/q203/0/51.asp
*
* speaks of type 4 (PEP) packets as being used for "SAP, NetBIOS sessions
* and directed datagrams" and type 20 (WAN Broadcast) as being used for
* "NetBIOS name resolution broadcasts" (but nothing about the non-broadcast
* type 4 name resolution stuff).
*
* We assume that this means that, once you get past the 8 IPX network
* numbers if present:
*
* the first byte is a name type byte for the name packets
* and a connection control flag for the other packets;
*
* the second byte is a data stream type;
*
* the rest of the bytes are:
*
* the NetBIOS name being registered/deregistered/etc.,
* for name packets;
*
* the two NetBIOS names, followed by the NetBIOS
* datagram, for NBIPX_DIRECTED_DATAGRAM packets;
*
* the session packet header, possibly followed by
* session data, for session packets.
*
* We don't know yet how to interpret NBIPX_STATUS_QUERY or
* NBIPX_STATUS_RESPONSE.
*
* For now, we treat the datagrams and session data as SMB stuff.
*/
#define NBIPX_FIND_NAME 1
#define NBIPX_NAME_RECOGNIZED 2
#define NBIPX_CHECK_NAME 3
#define NBIPX_NAME_IN_USE 4
#define NBIPX_DEREGISTER_NAME 5
#define NBIPX_SESSION_DATA 6
#define NBIPX_SESSION_END 7
#define NBIPX_SESSION_END_ACK 8
#define NBIPX_STATUS_QUERY 9
#define NBIPX_STATUS_RESPONSE 10
#define NBIPX_DIRECTED_DATAGRAM 11
static const value_string nbipx_data_stream_type_vals[] = {
{NBIPX_FIND_NAME, "Find name"},
{NBIPX_NAME_RECOGNIZED, "Name recognized"},
{NBIPX_CHECK_NAME, "Check name"},
{NBIPX_NAME_IN_USE, "Name in use"},
{NBIPX_DEREGISTER_NAME, "Deregister name"},
{NBIPX_SESSION_DATA, "Session data"},
{NBIPX_SESSION_END, "Session end"},
{NBIPX_SESSION_END_ACK, "Session end ACK"},
{NBIPX_STATUS_QUERY, "Status query"},
{NBIPX_STATUS_RESPONSE, "Status response"},
{NBIPX_DIRECTED_DATAGRAM, "Directed datagram"},
{0, NULL}
};
/*
* Opcodes.
*/
#define INAME_CLAIM 0xf1
#define INAME_DELETE 0xf2
#define INAME_QUERY 0xf3
#define INAME_FOUND 0xf4
#define IMSG_HANGUP 0xf5
#define IMSLOT_SEND 0xfc
#define IMSLOT_FIND 0xfd
#define IMSLOT_NAME 0xfe
static const value_string nmpi_opcode_vals[] = {
{INAME_CLAIM, "Claim name"},
{INAME_DELETE, "Delete name"},
{INAME_QUERY, "Query name"},
{INAME_FOUND, "Name found"},
{IMSG_HANGUP, "Messenger hangup"},
{IMSLOT_SEND, "Mailslot write"},
{IMSLOT_FIND, "Find mailslot name"},
{IMSLOT_NAME, "Mailslot name found"},
{0, NULL}
};
/*
* Name types.
*/
#define INTYPE_MACHINE 1
#define INTYPE_WORKGROUP 2
#define INTYPE_BROWSER 3
static const value_string nmpi_name_type_vals[] = {
{INTYPE_MACHINE, "Machine"},
{INTYPE_WORKGROUP, "Workgroup"},
{INTYPE_BROWSER, "Browser"},
{0, NULL}
};
static const true_false_string tfs_system_non_system = { "System packet", "Non-system packet" };
static void
add_routers(proto_tree *tree, tvbuff_t *tvb, int offset)
{
int i;
/* Eight routers are listed */
for (i = 0; i < 8; i++) {
if (tvb_get_ntohl(tvb, offset) != 0) {
proto_tree_add_item(tree, hf_nbipx_ipx_network, tvb, offset, 4, ENC_NA);
}
offset += 4;
}
}
static void
dissect_netbios_payload(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
{
heur_dtbl_entry_t *hdtbl_entry;
/*
* Try the heuristic dissectors for NetBIOS; if none of them
* accept the packet, dissect it as data.
*/
if (!dissector_try_heuristic(netbios_heur_subdissector_list,
tvb, pinfo, tree, &hdtbl_entry, NULL))
call_data_dissector(tvb, pinfo, tree);
}
static int
dissect_nbipx(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data)
{
gboolean has_routes;
proto_tree *nbipx_tree = NULL;
proto_item *ti = NULL;
int offset = 0;
guint8 packet_type;
proto_tree *name_type_flag_tree;
proto_item *tf;
char name[(NETBIOS_NAME_LEN - 1)*4 + 1];
int name_type;
gboolean has_payload;
tvbuff_t *next_tvb;
ipxhdr_t *ipxh;
/* Reject the packet if data is NULL */
if (data == NULL)
return 0;
ipxh = (ipxhdr_t*)data;
col_set_str(pinfo->cinfo, COL_PROTOCOL, "NBIPX");
col_clear(pinfo->cinfo, COL_INFO);
if (ipxh->ipx_type == IPX_PACKET_TYPE_WANBCAST) {
/*
* This is a WAN Broadcast packet; we assume it will have
* 8 IPX addresses at the beginning.
*/
has_routes = TRUE;
} else {
/*
* This isn't a WAN Broadcast packet, but it still might
* have the 8 addresses.
*
* If it's the right length for a name operation,
* and, if we assume it has routes, the packet type
* is a name operation, assume it has routes.
*
* NOTE: this will throw an exception if the byte that
* would be the packet type byte if this has the 8
* addresses isn't present; if that's the case, we don't
* know how to interpret this packet, so we can't dissect
* it anyway.
*/
has_routes = FALSE; /* start out assuming it doesn't */
if (tvb_reported_length(tvb) == 50) {
packet_type = tvb_get_guint8(tvb, offset + 32 + 1);
switch (packet_type) {
case NBIPX_FIND_NAME:
case NBIPX_NAME_RECOGNIZED:
case NBIPX_CHECK_NAME:
case NBIPX_NAME_IN_USE:
case NBIPX_DEREGISTER_NAME:
has_routes = TRUE;
break;
}
}
}
if (tree) {
ti = proto_tree_add_item(tree, proto_nbipx, tvb, 0,
-1, ENC_NA);
nbipx_tree = proto_item_add_subtree(ti, ett_nbipx);
}
if (has_routes) {
if (tree)
add_routers(nbipx_tree, tvb, 0);
offset += 32;
}
packet_type = tvb_get_guint8(tvb, offset + 1);
switch (packet_type) {
case NBIPX_FIND_NAME:
case NBIPX_NAME_RECOGNIZED:
case NBIPX_CHECK_NAME:
case NBIPX_NAME_IN_USE:
case NBIPX_DEREGISTER_NAME:
name_type = get_netbios_name(tvb, offset+2, name, (NETBIOS_NAME_LEN - 1)*4 + 1);
col_add_fstr(pinfo->cinfo, COL_INFO, "%s %s<%02x>",
val_to_str_const(packet_type, nbipx_data_stream_type_vals, "Unknown"),
name, name_type);
if (nbipx_tree) {
tf = proto_tree_add_item(nbipx_tree, hf_nbipx_name_flags, tvb, offset, 1, ENC_LITTLE_ENDIAN);
name_type_flag_tree = proto_item_add_subtree(tf, ett_nbipx_name_type_flags);
proto_tree_add_item(name_type_flag_tree, hf_nbipx_name_flags_group, tvb, offset, 1, ENC_LITTLE_ENDIAN);
proto_tree_add_item(name_type_flag_tree, hf_nbipx_name_flags_in_use, tvb, offset, 1, ENC_LITTLE_ENDIAN);
proto_tree_add_item(name_type_flag_tree, hf_nbipx_name_flags_registered, tvb, offset, 1, ENC_LITTLE_ENDIAN);
proto_tree_add_item(name_type_flag_tree, hf_nbipx_name_flags_duplicated, tvb, offset, 1, ENC_LITTLE_ENDIAN);
proto_tree_add_item(name_type_flag_tree, hf_nbipx_name_flags_deregistered, tvb, offset, 1, ENC_LITTLE_ENDIAN);
}
offset += 1;
proto_tree_add_uint(nbipx_tree, hf_nbipx_packettype, tvb, offset, 1, packet_type);
offset += 1;
if (nbipx_tree)
netbios_add_name("Name", tvb, offset, nbipx_tree);
offset += NETBIOS_NAME_LEN;
/*
* No payload to be interpreted by another protocol.
*/
has_payload = FALSE;
break;
case NBIPX_SESSION_DATA:
case NBIPX_SESSION_END:
case NBIPX_SESSION_END_ACK:
col_set_str(pinfo->cinfo, COL_INFO,
val_to_str_const(packet_type, nbipx_data_stream_type_vals, "Unknown"));
dissect_conn_control(tvb, offset, nbipx_tree);
offset += 1;
proto_tree_add_uint(nbipx_tree, hf_nbipx_packettype, tvb, offset, 1, packet_type);
offset += 1;
proto_tree_add_item(nbipx_tree, hf_nbipx_session_src_conn_id, tvb, offset, 2, ENC_LITTLE_ENDIAN);
offset += 2;
proto_tree_add_item(nbipx_tree, hf_nbipx_session_dest_conn_id, tvb, offset, 2, ENC_LITTLE_ENDIAN);
offset += 2;
proto_tree_add_item(nbipx_tree, hf_nbipx_session_send_seq_number, tvb, offset, 2, ENC_LITTLE_ENDIAN);
offset += 2;
proto_tree_add_item(nbipx_tree, hf_nbipx_session_total_data_length, tvb, offset, 2, ENC_LITTLE_ENDIAN);
offset += 2;
proto_tree_add_item(nbipx_tree, hf_nbipx_session_offset, tvb, offset, 2, ENC_LITTLE_ENDIAN);
offset += 2;
proto_tree_add_item(nbipx_tree, hf_nbipx_session_data_length, tvb, offset, 2, ENC_LITTLE_ENDIAN);
offset += 2;
proto_tree_add_item(nbipx_tree, hf_nbipx_session_recv_seq_number, tvb, offset, 2, ENC_LITTLE_ENDIAN);
offset += 2;
proto_tree_add_item(nbipx_tree, hf_nbipx_session_bytes_received, tvb, offset, 2, ENC_LITTLE_ENDIAN);
offset += 2;
/*
* We may have payload to dissect.
*/
has_payload = TRUE;
break;
case NBIPX_DIRECTED_DATAGRAM:
col_set_str(pinfo->cinfo, COL_INFO,
val_to_str_const(packet_type, nbipx_data_stream_type_vals, "Unknown"));
dissect_conn_control(tvb, offset, nbipx_tree);
offset += 1;
proto_tree_add_uint(nbipx_tree, hf_nbipx_packettype, tvb, offset, 1, packet_type);
offset += 1;
if (nbipx_tree)
netbios_add_name("Receiver's Name", tvb, offset,
nbipx_tree);
offset += NETBIOS_NAME_LEN;
if (nbipx_tree)
netbios_add_name("Sender's Name", tvb, offset,
nbipx_tree);
offset += NETBIOS_NAME_LEN;
/*
* We may have payload to dissect.
*/
has_payload = TRUE;
break;
default:
col_set_str(pinfo->cinfo, COL_INFO,
val_to_str_const(packet_type, nbipx_data_stream_type_vals, "Unknown"));
/*
* We don't know what the first byte is.
*/
offset += 1;
/*
* The second byte is a data stream type byte.
*/
proto_tree_add_uint(nbipx_tree, hf_nbipx_packettype, tvb, offset, 1, packet_type);
offset += 1;
/*
* We don't know what the rest of the packet is.
*/
has_payload = FALSE;
}
/*
* Set the length of the NBIPX tree item.
*/
if (ti != NULL)
proto_item_set_len(ti, offset);
if (has_payload && tvb_offset_exists(tvb, offset)) {
next_tvb = tvb_new_subset_remaining(tvb, offset);
dissect_netbios_payload(next_tvb, pinfo, tree);
}
return tvb_captured_length(tvb);
}
static void
dissect_conn_control(tvbuff_t *tvb, int offset, proto_tree *tree)
{
proto_item *ti;
proto_tree *cc_tree;
if (tree) {
ti = proto_tree_add_item(tree, hf_nbipx_conn_control, tvb, offset, 1, ENC_LITTLE_ENDIAN);
cc_tree = proto_item_add_subtree(ti, ett_nbipx_conn_ctrl);
proto_tree_add_item(cc_tree, hf_nbipx_conn_control_sys_packet, tvb, offset, 1, ENC_LITTLE_ENDIAN);
proto_tree_add_item(cc_tree, hf_nbipx_conn_control_ack, tvb, offset, 1, ENC_LITTLE_ENDIAN);
proto_tree_add_item(cc_tree, hf_nbipx_conn_control_attention, tvb, offset, 1, ENC_LITTLE_ENDIAN);
proto_tree_add_item(cc_tree, hf_nbipx_conn_control_end_msg, tvb, offset, 1, ENC_LITTLE_ENDIAN);
proto_tree_add_item(cc_tree, hf_nbipx_conn_control_resend, tvb, offset, 1, ENC_LITTLE_ENDIAN);
}
}
void
proto_register_nbipx(void)
{
static hf_register_info hf[] = {
{ &hf_nbipx_packettype,
{ "Packet Type", "nmpi.packettype",
FT_UINT8, BASE_HEX, VALS(nbipx_data_stream_type_vals), 0,
NULL, HFILL }
},
{ &hf_nbipx_name_flags,
{ "Name type flag", "nmpi.name_flags",
FT_UINT8, BASE_HEX, NULL, 0,
NULL, HFILL }
},
{ &hf_nbipx_name_flags_group,
{ "Name", "nmpi.name_flags.group",
FT_BOOLEAN, 8, TFS(&tfs_group_unique_name), 0x80,
NULL, HFILL }
},
{ &hf_nbipx_name_flags_in_use,
{ "In use", "nmpi.name_flags.in_use",
FT_BOOLEAN, 8, TFS(&tfs_used_notused), 0x40,
NULL, HFILL }
},
{ &hf_nbipx_name_flags_registered,
{ "Registered", "nmpi.name_flags.registered",
FT_BOOLEAN, 8, TFS(&tfs_yes_no), 0x04,
NULL, HFILL }
},
{ &hf_nbipx_name_flags_duplicated,
{ "Duplicated", "nmpi.name_flags.duplicated",
FT_BOOLEAN, 8, TFS(&tfs_yes_no), 0x02,
NULL, HFILL }
},
{ &hf_nbipx_name_flags_deregistered,
{ "Deregistered", "nmpi.name_flags.deregistered",
FT_BOOLEAN, 8, TFS(&tfs_yes_no), 0x01,
NULL, HFILL }
},
{ &hf_nbipx_conn_control,
{ "Connection control", "nmpi.conn_control",
FT_UINT8, BASE_HEX, NULL, 0,
NULL, HFILL }
},
{ &hf_nbipx_conn_control_sys_packet,
{ "Packet", "nmpi.conn_control.sys_packet",
FT_BOOLEAN, 8, TFS(&tfs_system_non_system), 0x80,
NULL, HFILL }
},
{ &hf_nbipx_conn_control_ack,
{ "Acknowledgement", "nmpi.conn_control.ack",
FT_BOOLEAN, 8, TFS(&tfs_required_not_required), 0x40,
NULL, HFILL }
},
{ &hf_nbipx_conn_control_attention,
{ "Attention", "nmpi.conn_control.attention",
FT_BOOLEAN, 8, TFS(&tfs_yes_no), 0x20,
NULL, HFILL }
},
{ &hf_nbipx_conn_control_end_msg,
{ "End of message", "nmpi.conn_control.end_msg",
FT_BOOLEAN, 8, TFS(&tfs_yes_no), 0x10,
NULL, HFILL }
},
{ &hf_nbipx_conn_control_resend,
{ "Resend", "nmpi.conn_control.resend",
FT_BOOLEAN, 8, TFS(&tfs_yes_no), 0x08,
NULL, HFILL }
},
{ &hf_nbipx_session_src_conn_id,
{ "Source connection ID", "nmpi.session.src_conn_id",
FT_UINT16, BASE_HEX, NULL, 0,
NULL, HFILL }
},
{ &hf_nbipx_session_dest_conn_id,
{ "Destination connection ID", "nmpi.session.dest_conn_id",
FT_UINT16, BASE_HEX, NULL, 0,
NULL, HFILL }
},
{ &hf_nbipx_session_send_seq_number,
{ "Send sequence number", "nmpi.session.send_seq_number",
FT_UINT16, BASE_DEC, NULL, 0,
NULL, HFILL }
},
{ &hf_nbipx_session_total_data_length,
{ "Total data length", "nmpi.session.total_data_length",
FT_UINT16, BASE_DEC, NULL, 0,
NULL, HFILL }
},
{ &hf_nbipx_session_offset,
{ "Offset", "nmpi.session.offset",
FT_UINT16, BASE_DEC, NULL, 0,
NULL, HFILL }
},
{ &hf_nbipx_session_data_length,
{ "Data length", "nmpi.session.data_length",
FT_UINT16, BASE_DEC, NULL, 0,
NULL, HFILL }
},
{ &hf_nbipx_session_recv_seq_number,
{ "Receive sequence number", "nmpi.session.recv_seq_number",
FT_UINT16, BASE_DEC, NULL, 0,
NULL, HFILL }
},
{ &hf_nbipx_session_bytes_received,
{ "Bytes received", "nmpi.session.bytes_received",
FT_UINT16, BASE_DEC, NULL, 0,
NULL, HFILL }
},
{ &hf_nbipx_ipx_network,
{ "IPX Network", "nmpi.ipx_network",
FT_IPXNET, BASE_NONE, NULL, 0,
NULL, HFILL }
},
{ &hf_nbipx_opcode,
{ "Opcode", "nmpi.opcode",
FT_UINT8, BASE_HEX, VALS(nmpi_opcode_vals), 0,
NULL, HFILL }
},
{ &hf_nbipx_name_type,
{ "Name Type", "nmpi.name_type",
FT_UINT8, BASE_HEX, VALS(nmpi_name_type_vals), 0,
NULL, HFILL }
},
{ &hf_nbipx_messageid,
{ "Message ID", "nmpi.messageid",
FT_UINT16, BASE_HEX, NULL, 0,
NULL, HFILL }
},
};
static gint *ett[] = {
&ett_nbipx,
&ett_nbipx_conn_ctrl,
&ett_nbipx_name_type_flags,
};
proto_nbipx = proto_register_protocol("NetBIOS over IPX", "NBIPX", "nbipx");
proto_register_field_array(proto_nbipx, hf, array_length(hf));
proto_register_subtree_array(ett, array_length(ett));
}
void
proto_reg_handoff_nbipx(void)
{
dissector_handle_t nbipx_handle;
nbipx_handle = create_dissector_handle(dissect_nbipx, proto_nbipx);
dissector_add_uint("ipx.socket", IPX_SOCKET_NETBIOS, nbipx_handle);
netbios_heur_subdissector_list = find_heur_dissector_list("netbios");
}
/*
* Microsoft appear to have something they call "direct hosting", where
* SMB - and, I infer, related stuff, such as name resolution - runs
* directly over IPX. (In Windows 2000, they also run SMB directly over
* TCP, on port 445, and that also appears to be called "direct hosting".
* Wireshark handles SMB-over-TCP.)
*
* The document at
*
* http://support.microsoft.com/support/kb/articles/q203/0/51.asp
*
* speaks of NMPI - the "Name Management Protocol on IPX" - as being
* "Microsoft's protocol for name management support when you use IPX
* without the NetBIOS interface," and says that "This process of routing
* the SMB protocol directly through IPX is known as Direct Hosting."
*
* It speaks of IPX socket 0x551 as being for NMPI; we define it as
* IPX_SOCKET_NWLINK_SMB_NAMEQUERY.
*
* We also define IPX_SOCKET_NWLINK_SMB_DGRAM as 0x0553 and define
* IPX_SOCKET_NWLINK_SMB_BROWSE as 0x0555 (with a "? not sure on this"
* comment after the latter one).
*
* We have seen at least some browser announcements on IPX socket 0x553;
* those are WAN broadcast packets, complete with 8 IPX network
* numbers, and with the header containing the usual two NetBIOS names
* that show up in NetBIOS datagrams.
*
* Network Monitor calls those packets NMPI packets, even though they're
* on socket 0x553, not socket 0x551, and contain SMB datagrams, not name
* resolution packets.
*
* At least some of this is discussed in the "SMBPUB.DOC" Word document
* stored in
*
* ftp://ftp.microsoft.com/developr/drg/CIFS/smbpub.zip
*
* which can also be found in text form at
*
* http://www.samba.org/samba/ftp/specs/smbpub.txt
*
* which says that for "connectionless IPX transport" the sockets that
* are used are:
*
* SMB_SERVER_SOCKET (0x550) - SMB requests from clients
* SMB_NAME_SOCKET (0x551) - name claims and name query messages
* REDIR_SOCKET (0x552) - used by the redirector (client) for
* sending SMB requests and receiving SMB replies
* MAILSLOT_SOCKET (0x553) - used by the redirector and browser
* for mailslot datagrams
* MESSENGER_SOCKET (0x554) - used by the redirector to send
* messages from client to client
*
* Name claim/query packets, and mailslot datagrams, are:
*
* 8 IPX network addresses
* 1 byte of opcode
* 1 byte of name type
* 2 bytes of message ID
* 16 bytes of name being sought or claimed
* 16 bytes of requesting machine
*
* The opcode is one of:
*
* INAME_CLAIM (0xf1) - server name claim message
* INAME_DELETE (0xf2) - relinquish server name
* INAME_QUERY (0xf3) - locate server name
* INAME_FOUND (0xf4) - response to INAME_QUERY
* IMSG_HANGUP (0xf5) - messenger hangup
* IMSLOT_SEND (0xfc) - mailslot write
* IMSLOT_FIND (0xfd) - find name for mailslot write
* IMSLOT_NAME (0xfe) - response to IMSLOT_FIND
*
* The name type is one of:
*
* INTYPE_MACHINE 1
* INTYPE_WKGROUP 2
* INTYPE_BROWSER 3
*/
static int proto_nmpi = -1;
static gint ett_nmpi = -1;
static gint ett_nmpi_name_type_flags = -1;
static int
dissect_nmpi(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
{
proto_tree *nmpi_tree = NULL;
proto_item *ti;
int offset = 0;
guint8 opcode;
char name[(NETBIOS_NAME_LEN - 1)*4 + 1];
int name_type;
char node_name[(NETBIOS_NAME_LEN - 1)*4 + 1];
/*int node_name_type = 0;*/
tvbuff_t *next_tvb;
col_set_str(pinfo->cinfo, COL_PROTOCOL, "NMPI");
col_clear(pinfo->cinfo, COL_INFO);
if (tree) {
ti = proto_tree_add_item(tree, proto_nmpi, tvb, offset, 68,
ENC_NA);
nmpi_tree = proto_item_add_subtree(ti, ett_nmpi);
add_routers(nmpi_tree, tvb, offset);
}
offset += 32;
/*
* XXX - we don't use "node_name" or "node_name_type".
*/
opcode = tvb_get_guint8(tvb, offset);
name_type = get_netbios_name(tvb, offset+4, name, (NETBIOS_NAME_LEN - 1)*4 + 1);
/*node_name_type = */get_netbios_name(tvb, offset+20, node_name, (NETBIOS_NAME_LEN - 1)*4 + 1);
switch (opcode) {
case INAME_CLAIM:
col_add_fstr(pinfo->cinfo, COL_INFO, "Claim name %s<%02x>",
name, name_type);
break;
case INAME_DELETE:
col_add_fstr(pinfo->cinfo, COL_INFO, "Delete name %s<%02x>",
name, name_type);
break;
case INAME_QUERY:
col_add_fstr(pinfo->cinfo, COL_INFO, "Query name %s<%02x>",
name, name_type);
break;
case INAME_FOUND:
col_add_fstr(pinfo->cinfo, COL_INFO, "Name %s<%02x> found",
name, name_type);
break;
case IMSG_HANGUP:
col_add_fstr(pinfo->cinfo, COL_INFO,
"Messenger hangup on %s<%02x>", name, name_type);
break;
case IMSLOT_SEND:
col_add_fstr(pinfo->cinfo, COL_INFO,
"Mailslot write to %s<%02x>", name, name_type);
break;
case IMSLOT_FIND:
col_add_fstr(pinfo->cinfo, COL_INFO,
"Find mailslot name %s<%02x>", name, name_type);
break;
case IMSLOT_NAME:
col_add_fstr(pinfo->cinfo, COL_INFO,
"Mailslot name %s<%02x> found", name, name_type);
break;
default:
col_add_fstr(pinfo->cinfo, COL_INFO,
"Unknown NMPI op 0x%02x: name %s<%02x>",
opcode, name, name_type);
break;
}
if (tree) {
proto_tree_add_item(nmpi_tree, hf_nbipx_opcode, tvb, offset, 1, ENC_LITTLE_ENDIAN);
proto_tree_add_item(nmpi_tree, hf_nbipx_name_type, tvb, offset+1, 1, ENC_LITTLE_ENDIAN);
proto_tree_add_item(nmpi_tree, hf_nbipx_messageid, tvb, offset+2, 2, ENC_LITTLE_ENDIAN);
netbios_add_name("Requested name", tvb, offset+4, nmpi_tree);
netbios_add_name("Source name", tvb, offset+20, nmpi_tree);
}
offset += 1 + 1 + 2 + NETBIOS_NAME_LEN + NETBIOS_NAME_LEN;
if (opcode == IMSLOT_SEND && tvb_offset_exists(tvb, offset)) {
next_tvb = tvb_new_subset_remaining(tvb, offset);
dissect_netbios_payload(next_tvb, pinfo, tree);
}
return tvb_captured_length(tvb);
}
void
proto_register_nmpi(void)
{
/*
static hf_register_info hf[] = {
{ &variable,
{ "Name", "nmpi.abbreviation", TYPE, VALS_POINTER }},
}; */
static gint *ett[] = {
&ett_nmpi,
&ett_nmpi_name_type_flags,
};
proto_nmpi = proto_register_protocol("Name Management Protocol over IPX",
"NMPI", "nmpi");
/* proto_register_field_array(proto_nmpi, hf, array_length(hf));*/
proto_register_subtree_array(ett, array_length(ett));
}
void
proto_reg_handoff_nmpi(void)
{
dissector_handle_t nmpi_handle;
nmpi_handle = create_dissector_handle(dissect_nmpi, proto_nmpi);
dissector_add_uint("ipx.socket", IPX_SOCKET_NWLINK_SMB_NAMEQUERY,
nmpi_handle);
dissector_add_uint("ipx.socket", IPX_SOCKET_NWLINK_SMB_MAILSLOT,
nmpi_handle);
}
/*
* Editor modelines - https://www.wireshark.org/tools/modelines.html
*
* Local variables:
* c-basic-offset: 8
* tab-width: 8
* indent-tabs-mode: t
* End:
*
* vi: set shiftwidth=8 tabstop=8 noexpandtab:
* :indentSize=8:tabSize=8:noTabs=false:
*/