![Michael Mann](/assets/img/avatar_default.png)
This saves many dissectors the need to find the data dissector and store a handle to it. There were also some that were finding it, but not using it. For others this was the only reason for their handoff function, so it could be eliminated. Change-Id: I5d3f951ee1daa3d30c060d21bd12bbc881a8027b Reviewed-on: https://code.wireshark.org/review/14530 Petri-Dish: Michael Mann <mmann78@netscape.net> Reviewed-by: Michael Mann <mmann78@netscape.net>
889 lines
27 KiB
C
889 lines
27 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
|
|
*
|
|
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
*/
|
|
|
|
#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://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 - http://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:
|
|
*/
|