![Guy Harris](/assets/img/avatar_default.png)
dynamically-assigned "ett_" integer values, assigned by "proto_register_subtree_array()"; this: obviates the need to update "packet.h" whenever you add a new subtree type - you only have to add a call to "proto_register_subtree_array()" to a "register" routine and an array of pointers to "ett_", if they're not already there, and add a pointer to the new "ett_" variable to the array, if they are there; would allow run-time-loaded dissectors to allocate subtree types when they're loaded. svn path=/trunk/; revision=1043
416 lines
13 KiB
C
416 lines
13 KiB
C
/* packet-nbipx.c
|
|
* Routines for NetBIOS over IPX packet disassembly
|
|
* Gilbert Ramirez <gram@verdict.uthscsa.edu>
|
|
*
|
|
* $Id: packet-nbipx.c,v 1.15 1999/11/16 11:42:38 guy Exp $
|
|
*
|
|
* Ethereal - Network traffic analyzer
|
|
* By Gerald Combs <gerald@zing.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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
# include "config.h"
|
|
#endif
|
|
|
|
#ifdef HAVE_SYS_TYPES_H
|
|
# include <sys/types.h>
|
|
#endif
|
|
|
|
#include <glib.h>
|
|
#include "packet.h"
|
|
#include "packet-ipx.h" /* for ipxnet_to_string() */
|
|
#include "packet-netbios.h"
|
|
|
|
static int proto_nbipx = -1;
|
|
|
|
static gint ett_nbipx = -1;
|
|
static gint ett_nbipx_name_type_flags = -1;
|
|
|
|
enum nbipx_protocol {
|
|
NETBIOS_NETWARE,
|
|
NETBIOS_NWLINK
|
|
};
|
|
|
|
static void
|
|
dissect_nbipx_ns(const u_char *pd, int offset, frame_data *fd, proto_tree *tree,
|
|
int max_data);
|
|
static void
|
|
dissect_nbipx_dg(const u_char *pd, int offset, frame_data *fd, proto_tree *tree,
|
|
int max_data);
|
|
|
|
/* 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 the offset of the packet type in an NBIPX packet
|
|
* *DEPENDS ON THE PACKET TYPE*; "Find name" and "Name recognized" have
|
|
* it at one offset, "Directed datagram" has it at another. Does the
|
|
* NBIPX code base it on the length, or what? Non-broadcast directed
|
|
* datagram packets have an IPX type of "IPX", just as "Find name" and
|
|
* "Name recognized" do.... For now, we base it on the length.
|
|
*/
|
|
#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}
|
|
};
|
|
|
|
#define NWLINK_NAME_QUERY 1
|
|
#define NWLINK_SMB 2
|
|
#define NWLINK_NETBIOS_DATAGRAM 3
|
|
|
|
static const value_string nwlink_data_stream_type_vals[] = {
|
|
{NWLINK_NAME_QUERY, "Name query"},
|
|
{NWLINK_SMB, "SMB"},
|
|
{NWLINK_NETBIOS_DATAGRAM, "NetBIOS datagram"},
|
|
{0, NULL}
|
|
};
|
|
|
|
/* NetWare */
|
|
void
|
|
dissect_nbipx(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
|
|
{
|
|
int max_data = pi.captured_len - offset;
|
|
|
|
if (check_col(fd, COL_PROTOCOL))
|
|
col_add_str(fd, COL_PROTOCOL, "NBIPX");
|
|
|
|
/*
|
|
* As said above, we look at the length of the packet to decide
|
|
* whether to treat it as a name-service packet or a datagram
|
|
* (the packet type would tell us, but it's at a *DIFFERENT
|
|
* LOCATION* in different types of packet...).
|
|
*/
|
|
if (END_OF_FRAME == 50)
|
|
dissect_nbipx_ns(pd, offset, fd, tree, max_data);
|
|
else
|
|
dissect_nbipx_dg(pd, offset, fd, tree, max_data);
|
|
}
|
|
|
|
static void
|
|
add_routers(proto_tree *tree, const u_char *pd, int offset)
|
|
{
|
|
int i;
|
|
int rtr_offset;
|
|
guint32 router;
|
|
|
|
/* Eight routers are listed */
|
|
for (i = 0; i < 8; i++) {
|
|
rtr_offset = offset + (i << 2);
|
|
memcpy(&router, &pd[rtr_offset], 4);
|
|
if (router != 0) {
|
|
proto_tree_add_text(tree, rtr_offset, 4, "IPX Network: %s",
|
|
ipxnet_to_string((guint8*)&router));
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
dissect_nbipx_ns(const u_char *pd, int offset, frame_data *fd, proto_tree *tree,
|
|
int max_data)
|
|
{
|
|
proto_tree *nbipx_tree;
|
|
proto_item *ti;
|
|
guint8 packet_type;
|
|
guint8 name_type_flag;
|
|
proto_tree *name_type_flag_tree;
|
|
proto_item *tf;
|
|
char name[(NETBIOS_NAME_LEN - 1)*4 + 1];
|
|
int name_type;
|
|
|
|
name_type_flag = pd[offset+32];
|
|
packet_type = pd[offset+33];
|
|
name_type = get_netbios_name(pd, offset+34, name);
|
|
|
|
if (check_col(fd, COL_INFO)) {
|
|
switch (packet_type) {
|
|
case NBIPX_FIND_NAME:
|
|
case NBIPX_NAME_RECOGNIZED:
|
|
case NBIPX_CHECK_NAME:
|
|
case NBIPX_NAME_IN_USE:
|
|
case NBIPX_DEREGISTER_NAME:
|
|
col_add_fstr(fd, COL_INFO, "%s %s<%02x>",
|
|
val_to_str(packet_type, nbipx_data_stream_type_vals, "Unknown"),
|
|
name, name_type);
|
|
break;
|
|
|
|
default:
|
|
col_add_fstr(fd, COL_INFO, "%s",
|
|
val_to_str(packet_type, nbipx_data_stream_type_vals, "Unknown"));
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (tree) {
|
|
ti = proto_tree_add_item(tree, proto_nbipx, offset, 50, NULL);
|
|
nbipx_tree = proto_item_add_subtree(ti, ett_nbipx);
|
|
|
|
add_routers(nbipx_tree, pd, offset);
|
|
|
|
tf = proto_tree_add_text(nbipx_tree, offset+32, 1,
|
|
"Name type flag: 0x%02x", name_type_flag);
|
|
name_type_flag_tree = proto_item_add_subtree(tf,
|
|
ett_nbipx_name_type_flags);
|
|
proto_tree_add_text(name_type_flag_tree, offset+32,
|
|
1, "%s",
|
|
decode_boolean_bitfield(name_type_flag, 0x80, 8,
|
|
"Group name", "Unique name"));
|
|
proto_tree_add_text(name_type_flag_tree, offset+32,
|
|
1, "%s",
|
|
decode_boolean_bitfield(name_type_flag, 0x40, 8,
|
|
"Name in use", "Name not used"));
|
|
proto_tree_add_text(name_type_flag_tree, offset+32,
|
|
1, "%s",
|
|
decode_boolean_bitfield(name_type_flag, 0x04, 8,
|
|
"Name registered", "Name not registered"));
|
|
proto_tree_add_text(name_type_flag_tree, offset+32,
|
|
1, "%s",
|
|
decode_boolean_bitfield(name_type_flag, 0x02, 8,
|
|
"Name duplicated", "Name not duplicated"));
|
|
proto_tree_add_text(name_type_flag_tree, offset+32,
|
|
1, "%s",
|
|
decode_boolean_bitfield(name_type_flag, 0x01, 8,
|
|
"Name deregistered", "Name not deregistered"));
|
|
|
|
proto_tree_add_text(nbipx_tree, offset+33, 1,
|
|
"Packet Type: %s (%02X)",
|
|
val_to_str(packet_type, nbipx_data_stream_type_vals, "Unknown"),
|
|
packet_type);
|
|
|
|
netbios_add_name("Name", &pd[offset], offset,
|
|
34, nbipx_tree);
|
|
}
|
|
}
|
|
|
|
static void
|
|
dissect_nbipx_dg(const u_char *pd, int offset, frame_data *fd, proto_tree *tree,
|
|
int max_data)
|
|
{
|
|
proto_tree *nbipx_tree;
|
|
proto_item *ti;
|
|
|
|
if (check_col(fd, COL_INFO))
|
|
col_add_fstr(fd, COL_INFO, "NetBIOS datagram over NBIPX");
|
|
|
|
if (tree) {
|
|
ti = proto_tree_add_item(tree, proto_nbipx, offset,
|
|
2+16+16, NULL);
|
|
nbipx_tree = proto_item_add_subtree(ti, ett_nbipx);
|
|
|
|
proto_tree_add_text(nbipx_tree, offset, 1,
|
|
"Connection control: 0x%02x", pd[offset]);
|
|
proto_tree_add_text(nbipx_tree, offset+1, 1,
|
|
"Packet Type: %s (%02X)",
|
|
val_to_str(pd[offset+1], nbipx_data_stream_type_vals, "Unknown"),
|
|
pd[offset+1]);
|
|
netbios_add_name("Receiver's Name", &pd[offset],
|
|
offset, 2, nbipx_tree);
|
|
netbios_add_name("Sender's Name", &pd[offset],
|
|
offset, 2+16, nbipx_tree);
|
|
|
|
dissect_smb(pd, offset+2+16+16, fd, tree, max_data - 2+16+16);
|
|
}
|
|
}
|
|
|
|
void
|
|
dissect_nwlink_dg(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
|
|
{
|
|
int max_data = pi.captured_len - offset;
|
|
proto_tree *nbipx_tree;
|
|
proto_item *ti;
|
|
guint8 packet_type;
|
|
guint8 name_type_flag;
|
|
proto_tree *name_type_flag_tree;
|
|
proto_item *tf;
|
|
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;
|
|
|
|
name_type_flag = pd[offset+32];
|
|
packet_type = pd[offset+33];
|
|
name_type = get_netbios_name(pd, offset+36, name);
|
|
node_name_type = get_netbios_name(pd, offset+52, node_name);
|
|
|
|
if (check_col(fd, COL_PROTOCOL))
|
|
col_add_str(fd, COL_PROTOCOL, "NWLink");
|
|
|
|
if (check_col(fd, COL_INFO)) {
|
|
/*
|
|
* XXX - Microsoft Network Monitor thinks that the octet
|
|
* at 32 is a packet type, e.g. "mailslot write" for
|
|
* browser announcements, and that the octet at 33 is a
|
|
* name type, in the sense of the 16th byte of a
|
|
* NetBIOS name.
|
|
*
|
|
* A name type of 2 shows up in a "host announcement",
|
|
* and a name type of 3 shows up in a "local master
|
|
* annoumcement", so maybe that field really *is* a
|
|
* name type - the fact that it's not associated with
|
|
* any of the NetBIOS names in the packet nonwithstanding.
|
|
*
|
|
* I haven't seen any packets with the name type octet
|
|
* being anything other than 2 or 3, so I don't know
|
|
* whether those are name service operations; however,
|
|
* given that NWLink, unlike socket-0x0455 NBIPX,
|
|
* has separate sockets for name queries and datagrams,
|
|
* it may be that this really is a name type, and that
|
|
* these are all datagrams, not name queries.
|
|
*/
|
|
switch (packet_type) {
|
|
case NWLINK_NAME_QUERY:
|
|
col_add_fstr(fd, COL_INFO, "Name Query for %s<%02x>",
|
|
name, name_type);
|
|
break;
|
|
|
|
case NWLINK_SMB:
|
|
/* Session? */
|
|
col_add_fstr(fd, COL_INFO, "SMB over NBIPX");
|
|
break;
|
|
|
|
case NWLINK_NETBIOS_DATAGRAM:
|
|
/* Datagram? (Where did we see this?) */
|
|
col_add_fstr(fd, COL_INFO, "NetBIOS datagram over NBIPX");
|
|
break;
|
|
|
|
default:
|
|
col_add_str(fd, COL_INFO, "NetBIOS over IPX (NWLink)");
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (tree) {
|
|
ti = proto_tree_add_item(tree, proto_nbipx, offset, 68, NULL);
|
|
nbipx_tree = proto_item_add_subtree(ti, ett_nbipx);
|
|
|
|
add_routers(nbipx_tree, pd, offset);
|
|
|
|
/*
|
|
* XXX - is "packet_type" really a packet type? See
|
|
* above.
|
|
*/
|
|
if (packet_type != NWLINK_SMB &&
|
|
packet_type != NWLINK_NETBIOS_DATAGRAM) {
|
|
tf = proto_tree_add_text(nbipx_tree, offset+32, 1,
|
|
"Name type flag: 0x%02x",
|
|
name_type_flag);
|
|
name_type_flag_tree = proto_item_add_subtree(tf,
|
|
ett_nbipx_name_type_flags);
|
|
proto_tree_add_text(name_type_flag_tree, offset+32,
|
|
1, "%s",
|
|
decode_boolean_bitfield(name_type_flag, 0x80, 8,
|
|
"Group name", "Unique name"));
|
|
proto_tree_add_text(name_type_flag_tree, offset+32,
|
|
1, "%s",
|
|
decode_boolean_bitfield(name_type_flag, 0x40, 8,
|
|
"Name in use", "Name not used"));
|
|
proto_tree_add_text(name_type_flag_tree, offset+32,
|
|
1, "%s",
|
|
decode_boolean_bitfield(name_type_flag, 0x04, 8,
|
|
"Name registered", "Name not registered"));
|
|
proto_tree_add_text(name_type_flag_tree, offset+32,
|
|
1, "%s",
|
|
decode_boolean_bitfield(name_type_flag, 0x02, 8,
|
|
"Name duplicated", "Name not duplicated"));
|
|
proto_tree_add_text(name_type_flag_tree, offset+32,
|
|
1, "%s",
|
|
decode_boolean_bitfield(name_type_flag, 0x01, 8,
|
|
"Name deregistered", "Name not deregistered"));
|
|
|
|
netbios_add_name("Group name", &pd[offset], offset,
|
|
36, nbipx_tree);
|
|
netbios_add_name("Node name", &pd[offset], offset,
|
|
52, nbipx_tree);
|
|
proto_tree_add_text(nbipx_tree, offset+33, 1,
|
|
"Packet Type: %s (%02X)",
|
|
val_to_str(packet_type, nwlink_data_stream_type_vals, "Unknown"),
|
|
packet_type);
|
|
} else {
|
|
proto_tree_add_text(nbipx_tree, offset+32, 1,
|
|
"Packet type: 0x%02x", name_type_flag);
|
|
proto_tree_add_text(nbipx_tree, offset+33, 1,
|
|
"Name Type: %s (0x%02x)",
|
|
netbios_name_type_descr(packet_type),
|
|
packet_type);
|
|
proto_tree_add_text(nbipx_tree, offset+34, 2,
|
|
"Message ID: 0x%04x", pletohs(&pd[offset+34]));
|
|
netbios_add_name("Requested name", &pd[offset], offset,
|
|
36, nbipx_tree);
|
|
netbios_add_name("Source name", &pd[offset], offset,
|
|
52, nbipx_tree);
|
|
}
|
|
}
|
|
|
|
switch (packet_type) {
|
|
case NWLINK_SMB:
|
|
case NWLINK_NETBIOS_DATAGRAM:
|
|
dissect_smb(pd, offset + 68, fd, tree, max_data - 68);
|
|
break;
|
|
|
|
default:
|
|
dissect_data(pd, offset + 68, fd, tree);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void
|
|
proto_register_nbipx(void)
|
|
{
|
|
/* static hf_register_info hf[] = {
|
|
{ &variable,
|
|
{ "Name", "nbipx.abbreviation", TYPE, VALS_POINTER }},
|
|
};*/
|
|
static gint *ett[] = {
|
|
&ett_nbipx,
|
|
&ett_nbipx_name_type_flags,
|
|
};
|
|
|
|
proto_nbipx = proto_register_protocol("NetBIOS over IPX", "nbipx");
|
|
/* proto_register_field_array(proto_nbipx, hf, array_length(hf));*/
|
|
proto_register_subtree_array(ett, array_length(ett));
|
|
}
|