Add a URL for Gnutella specs.

Don't check, in the dissectors for particular Gnutella packets, whether
the packet goes past the end of the tvbuff - let that throw an exception
so unreassembled packets are shown as such.

Clean up indentation.

Boost GNUTELLA_MAX_SNAP_SIZE to 4096 (one Gnutella spec suggests that
packets should be < 4K), and use it to

	1) clamp the length of packets (so we don't do huge reassembly
	   or have problems when the total packet length, including the
	   header, overflows 32 bits)

and

	2) check the length of packets before using tcp_dissect_pdus(),
	   to distinguish between packets to be reassembled and a
	   transfer stream.

Pass the correct value to tcp_dissect_pdus() as the header length.

svn path=/trunk/; revision=13211
This commit is contained in:
Guy Harris 2005-01-31 00:28:02 +00:00
parent a43da7a4ff
commit e2089f3d82
2 changed files with 81 additions and 75 deletions

View File

@ -38,12 +38,16 @@
#include "packet-gnutella.h"
#include "packet-tcp.h"
/*
* See
*
* http://rfc-gnutella.sourceforge.net/developer/index.html
*/
static int proto_gnutella = -1;
static int hf_gnutella_stream = -1;
static int hf_gnutella_truncated = -1;
static int hf_gnutella_header = -1;
static int hf_gnutella_header_id = -1;
static int hf_gnutella_header_payload = -1;
@ -83,17 +87,7 @@ static int hf_gnutella_push_port = -1;
static gint ett_gnutella = -1;
static void dissect_gnutella_pong(tvbuff_t *tvb, guint offset, proto_tree *tree, guint size) {
if(offset + size > tvb_length(tvb)) {
proto_tree_add_item(tree,
hf_gnutella_truncated,
tvb,
offset,
size,
FALSE);
return;
}
static void dissect_gnutella_pong(tvbuff_t *tvb, guint offset, proto_tree *tree) {
proto_tree_add_item(tree,
hf_gnutella_pong_port,
@ -107,7 +101,7 @@ static void dissect_gnutella_pong(tvbuff_t *tvb, guint offset, proto_tree *tree,
tvb,
offset + GNUTELLA_PONG_IP_OFFSET,
GNUTELLA_IP_LENGTH,
FALSE);
FALSE);
proto_tree_add_item(tree,
hf_gnutella_pong_files,
@ -127,38 +121,28 @@ static void dissect_gnutella_pong(tvbuff_t *tvb, guint offset, proto_tree *tree,
static void dissect_gnutella_query(tvbuff_t *tvb, guint offset, proto_tree *tree, guint size) {
if(offset + size > tvb_length(tvb)) {
proto_tree_add_item(tree,
hf_gnutella_truncated,
tvb,
offset,
size,
FALSE);
return;
}
proto_tree_add_item(tree,
hf_gnutella_query_min_speed,
tvb,
offset + GNUTELLA_QUERY_SPEED_OFFSET,
GNUTELLA_SHORT_LENGTH,
TRUE);
TRUE);
if (size > GNUTELLA_SHORT_LENGTH) {
proto_tree_add_item(tree,
hf_gnutella_query_search,
tvb,
offset + GNUTELLA_QUERY_SEARCH_OFFSET,
size - GNUTELLA_SHORT_LENGTH,
FALSE);
}
else {
proto_tree_add_text(tree,
tvb,
offset + GNUTELLA_QUERY_SEARCH_OFFSET,
0,
"Missing data for Query Search.");
}
if (size > GNUTELLA_SHORT_LENGTH) {
proto_tree_add_item(tree,
hf_gnutella_query_search,
tvb,
offset + GNUTELLA_QUERY_SEARCH_OFFSET,
size - GNUTELLA_SHORT_LENGTH,
FALSE);
}
else {
proto_tree_add_text(tree,
tvb,
offset + GNUTELLA_QUERY_SEARCH_OFFSET,
0,
"Missing data for Query Search.");
}
}
static void dissect_gnutella_queryhit(tvbuff_t *tvb, guint offset, proto_tree *tree, guint size) {
@ -172,16 +156,6 @@ static void dissect_gnutella_queryhit(tvbuff_t *tvb, guint offset, proto_tree *t
int name_at_offset, extra_at_offset;
int cur_char, remaining, used;
if(offset + size > tvb_length(tvb)) {
proto_tree_add_item(tree,
hf_gnutella_truncated,
tvb,
offset,
size,
FALSE);
return;
}
hit_count = tvb_get_guint8(tvb, offset + GNUTELLA_QUERYHIT_COUNT_OFFSET);
proto_tree_add_uint(tree,
@ -317,17 +291,7 @@ static void dissect_gnutella_queryhit(tvbuff_t *tvb, guint offset, proto_tree *t
}
static void dissect_gnutella_push(tvbuff_t *tvb, guint offset, proto_tree *tree, guint size) {
if(offset + size > tvb_length(tvb)) {
proto_tree_add_item(tree,
hf_gnutella_truncated,
tvb,
offset,
size,
FALSE);
return;
}
static void dissect_gnutella_push(tvbuff_t *tvb, guint offset, proto_tree *tree) {
proto_tree_add_item(tree,
hf_gnutella_push_servent_id,
@ -366,12 +330,12 @@ get_gnutella_pdu_len(tvbuff_t *tvb, int offset) {
size = tvb_get_letohl(
tvb,
offset + GNUTELLA_HEADER_SIZE_OFFSET);
if (size > 0x00FFFFFF) {
if (size > GNUTELLA_MAX_SNAP_SIZE) {
/*
* XXX - arbitrary limit, preventing overflows and
* attempts to reassemble 4GB of data.
*/
size = 0x00FFFFFF;
size = GNUTELLA_MAX_SNAP_SIZE;
}
/* The size doesn't include the header */
@ -495,8 +459,7 @@ static void dissect_gnutella_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *
dissect_gnutella_pong(
tvb,
GNUTELLA_HEADER_LENGTH,
gnutella_pong_tree,
size);
gnutella_pong_tree);
break;
case GNUTELLA_PUSH:
pi = proto_tree_add_item(
@ -512,8 +475,7 @@ static void dissect_gnutella_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *
dissect_gnutella_push(
tvb,
GNUTELLA_HEADER_LENGTH,
gnutella_push_tree,
size);
gnutella_push_tree);
break;
case GNUTELLA_QUERY:
pi = proto_tree_add_item(
@ -558,14 +520,55 @@ static void dissect_gnutella_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *
static void dissect_gnutella(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
proto_item *ti;
proto_tree *gnutella_tree = NULL;
guint32 size;
if (check_col(pinfo->cinfo, COL_PROTOCOL))
col_set_str(pinfo->cinfo, COL_PROTOCOL, "Gnutella");
if (check_col(pinfo->cinfo, COL_INFO))
col_clear(pinfo->cinfo, COL_INFO);
tcp_dissect_pdus(tvb, pinfo, tree, TRUE, 2, get_gnutella_pdu_len,
dissect_gnutella_pdu);
/*
* OK, do we have enough data to determine whether this
* is Gnutella messages or just a transfer stream?
*/
if (tvb_bytes_exist(tvb, GNUTELLA_HEADER_SIZE_OFFSET, 4)) {
/*
* Yes - fetch the length and see if it's bigger
* than GNUTELLA_MAX_SNAP_SIZE; if it is, we assume
* it's a transfer stream.
*
* Should we also check the payload descriptor?
*/
size = tvb_get_letohl(
tvb,
GNUTELLA_HEADER_SIZE_OFFSET);
if (size > GNUTELLA_MAX_SNAP_SIZE) {
if (tree) {
ti = proto_tree_add_item(tree,
proto_gnutella,
tvb,
0,
-1,
FALSE);
gnutella_tree = proto_item_add_subtree(ti,
ett_gnutella);
proto_tree_add_item(gnutella_tree,
hf_gnutella_stream,
tvb,
0,
-1,
FALSE);
}
return;
}
}
tcp_dissect_pdus(tvb, pinfo, tree, TRUE, GNUTELLA_HEADER_SIZE_OFFSET+4,
get_gnutella_pdu_len, dissect_gnutella_pdu);
}
void proto_register_gnutella(void) {
@ -596,11 +599,6 @@ void proto_register_gnutella(void) {
FT_NONE, BASE_NONE, NULL, 0,
"Gnutella QueryHit Payload", HFILL }
},
{ &hf_gnutella_truncated,
{ "Truncated Frame", "gnutella.truncated",
FT_NONE, BASE_NONE, NULL, 0,
"The Gnutella Frame Was Truncated", HFILL }
},
{ &hf_gnutella_stream,
{ "Gnutella Upload / Download Stream", "gnutella.stream",
FT_NONE, BASE_NONE, NULL, 0,

View File

@ -27,7 +27,15 @@ void proto_register_gnutella(void);
#define GNUTELLA_TCP_PORT 6346
#define GNUTELLA_MAX_SNAP_SIZE 1500
/*
* Used to determine whether a chunk of data looks like a Gnutella packet
* or not - it might be a transfer stream, or it might be part of a
* Gnutella packet that starts in an earlier missing TCP segment.
*
* One Gnutella spec says packets SHOULD be no bigger than 4K, although
* that's SHOULD, not MUST.
*/
#define GNUTELLA_MAX_SNAP_SIZE 4096
#define GNUTELLA_UNKNOWN_NAME "Unknown"
#define GNUTELLA_PING 0x00