wireshark/packet-nbipx.c
Guy Harris 7d35e30ca6 Make the NetBIOS dissecting routines all take a pointer to the beginning
of the frame, plus at most one offset from the beginning of the frame,
to make it clearer what the offset is.

Then use that offset in at least some places to do bounds checking.

If a packet has no payload, don't hand it to the SMB dissector.

svn path=/trunk/; revision=1165
1999-11-30 07:45:42 +00:00

441 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.16 1999/11/30 07:45:41 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 + 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+NETBIOS_NAME_LEN+NETBIOS_NAME_LEN, NULL);
nbipx_tree = proto_item_add_subtree(ti, ett_nbipx);
proto_tree_add_text(nbipx_tree, offset, 1,
"Connection control: 0x%02x", pd[offset]);
offset += 1;
max_data -= 1;
if (!BYTES_ARE_IN_FRAME(offset, 1))
return;
proto_tree_add_text(nbipx_tree, offset, 1,
"Packet Type: %s (%02X)",
val_to_str(pd[offset], nbipx_data_stream_type_vals, "Unknown"),
pd[offset]);
offset += 1;
max_data -= 1;
if (!netbios_add_name("Receiver's Name", pd, offset,
nbipx_tree))
return;
offset += NETBIOS_NAME_LEN;
max_data -= NETBIOS_NAME_LEN;
if (!netbios_add_name("Sender's Name", pd, offset,
nbipx_tree))
return;
offset += NETBIOS_NAME_LEN;
max_data -= NETBIOS_NAME_LEN;
if (max_data != 0)
dissect_smb(pd, offset, fd, tree, max_data);
}
}
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"));
if (!netbios_add_name("Group name", pd, offset+36,
nbipx_tree))
return;
if (!netbios_add_name("Node name", pd, offset+52,
nbipx_tree))
return;
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]));
if (!netbios_add_name("Requested name", pd, offset+36,
nbipx_tree))
return;
if (!netbios_add_name("Source name", pd, offset+52,
nbipx_tree))
return;
}
}
offset += 68;
max_data -= 68;
if (max_data != 0) {
switch (packet_type) {
case NWLINK_SMB:
case NWLINK_NETBIOS_DATAGRAM:
dissect_smb(pd, offset, fd, tree, max_data);
break;
default:
dissect_data(pd, offset, 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));
}