aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile.am3
-rw-r--r--packet-frame.c55
-rw-r--r--packet-frame.h14
-rw-r--r--packet-nbns.c7
-rw-r--r--packet-ndmp.c220
-rw-r--r--packet-rpc.c739
-rw-r--r--packet-tcp.c25
-rw-r--r--packet-tcp.h5
-rw-r--r--rpc_defrag.h43
9 files changed, 822 insertions, 289 deletions
diff --git a/Makefile.am b/Makefile.am
index f0b5629273..11477282d3 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,7 +1,7 @@
# Makefile.am
# Automake file for Ethereal
#
-# $Id: Makefile.am,v 1.412 2002/02/17 00:16:19 guy Exp $
+# $Id: Makefile.am,v 1.413 2002/02/18 23:51:55 guy Exp $
#
# Ethereal - Network traffic analyzer
# By Gerald Combs <gerald@ethereal.com>
@@ -491,6 +491,7 @@ ETHEREAL_COMMON_SRC = \
register.h \
ringbuffer.c \
ringbuffer.h \
+ rpc_defrag.h \
smb.h \
util.c \
util.h \
diff --git a/packet-frame.c b/packet-frame.c
index f11586b59d..308797fe28 100644
--- a/packet-frame.c
+++ b/packet-frame.c
@@ -2,7 +2,7 @@
*
* Top-most dissector. Decides dissector based on Wiretap Encapsulation Type.
*
- * $Id: packet-frame.c,v 1.21 2002/01/24 09:20:47 guy Exp $
+ * $Id: packet-frame.c,v 1.22 2002/02/18 23:51:55 guy Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@ethereal.com>
@@ -155,37 +155,42 @@ dissect_frame(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
if (check_col(pinfo->cinfo, COL_INFO))
col_append_str(pinfo->cinfo, COL_INFO, "[Short Frame]");
proto_tree_add_protocol_format(tree, proto_short, tvb, 0, 0,
- "[Short Frame: %s]", pinfo->current_proto );
+ "[Short Frame: %s]", pinfo->current_proto);
}
CATCH(ReportedBoundsError) {
- if (pinfo->fragmented) {
- /*
- * We were dissecting an unreassembled fragmented
- * packet when the exception was thrown, so the
- * problem isn't that the dissector expected
- * something but it wasn't in the packet, the
- * problem is that the dissector expected something
- * but it wasn't in the fragment we dissected.
- */
- if (check_col(pinfo->cinfo, COL_INFO))
- col_append_str(pinfo->cinfo, COL_INFO,
- "[Unreassembled Packet]");
- proto_tree_add_protocol_format(tree, proto_unreassembled,
- tvb, 0, 0, "[Unreassembled Packet: %s]",
- pinfo->current_proto );
- } else {
- if (check_col(pinfo->cinfo, COL_INFO))
- col_append_str(pinfo->cinfo, COL_INFO,
- "[Malformed Packet]");
- proto_tree_add_protocol_format(tree, proto_malformed,
- tvb, 0, 0, "[Malformed Packet: %s]",
- pinfo->current_proto );
- }
+ show_reported_bounds_error(tvb, pinfo, tree);
}
ENDTRY;
}
void
+show_reported_bounds_error(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+ if (pinfo->fragmented) {
+ /*
+ * We were dissecting an unreassembled fragmented
+ * packet when the exception was thrown, so the
+ * problem isn't that the dissector expected
+ * something but it wasn't in the packet, the
+ * problem is that the dissector expected something
+ * but it wasn't in the fragment we dissected.
+ */
+ if (check_col(pinfo->cinfo, COL_INFO))
+ col_append_str(pinfo->cinfo, COL_INFO,
+ "[Unreassembled Packet]");
+ proto_tree_add_protocol_format(tree, proto_unreassembled,
+ tvb, 0, 0, "[Unreassembled Packet: %s]",
+ pinfo->current_proto);
+ } else {
+ if (check_col(pinfo->cinfo, COL_INFO))
+ col_append_str(pinfo->cinfo, COL_INFO,
+ "[Malformed Packet]");
+ proto_tree_add_protocol_format(tree, proto_malformed,
+ tvb, 0, 0, "[Malformed Packet: %s]", pinfo->current_proto);
+ }
+}
+
+void
proto_register_frame(void)
{
static hf_register_info hf[] = {
diff --git a/packet-frame.h b/packet-frame.h
index b1f7517adb..4c20cdc383 100644
--- a/packet-frame.h
+++ b/packet-frame.h
@@ -2,7 +2,7 @@
*
* Top-most dissector. Decides dissector based on Wiretap Encapsulation Type.
*
- * $Id: packet-frame.h,v 1.2 2000/12/03 22:32:09 guy Exp $
+ * $Id: packet-frame.h,v 1.3 2002/02/18 23:51:55 guy Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@zing.org>
@@ -27,5 +27,15 @@
void
dissect_frame(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
-/* "Protocol" used for "malformed frame" errors */
+/*
+ * Routine used to add an indication of a ReportedBoundsError exception
+ * to the tree.
+ */
+void
+show_reported_bounds_error(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
+
+/*
+ * "Protocol" used for "malformed frame" errors (other than
+ * ReportedBoundsError exceptions).
+ */
extern int proto_malformed;
diff --git a/packet-nbns.c b/packet-nbns.c
index 7127d5c3ca..0c3447f53e 100644
--- a/packet-nbns.c
+++ b/packet-nbns.c
@@ -3,7 +3,7 @@
* to when it had only NBNS)
* Guy Harris <guy@alum.mit.edu>
*
- * $Id: packet-nbns.c,v 1.72 2002/01/21 07:36:37 guy Exp $
+ * $Id: packet-nbns.c,v 1.73 2002/02/18 23:51:55 guy Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@ethereal.com>
@@ -1507,10 +1507,7 @@ dissect_nbss_packet(tvbuff_t *tvb, int offset, packet_info *pinfo,
RETHROW;
}
CATCH(ReportedBoundsError) {
- if (check_col(pinfo->cinfo, COL_INFO))
- col_append_str(pinfo->cinfo, COL_INFO, "[Malformed Packet]");
- proto_tree_add_protocol_format(tree, proto_malformed, tvb, 0, 0,
- "[Malformed Packet: %s]", pinfo->current_proto );
+ show_reported_bounds_error(tvb, pinfo, tree);
pinfo->current_proto = saved_proto;
}
ENDTRY;
diff --git a/packet-ndmp.c b/packet-ndmp.c
index 48de9e8298..098cf3aa46 100644
--- a/packet-ndmp.c
+++ b/packet-ndmp.c
@@ -2,7 +2,7 @@
* Routines for NDMP dissection
* 2001 Ronnie Sahlberg (see AUTHORS for email)
*
- * $Id: packet-ndmp.c,v 1.15 2002/02/13 01:17:58 guy Exp $
+ * $Id: packet-ndmp.c,v 1.16 2002/02/18 23:51:55 guy Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@ethereal.com>
@@ -45,14 +45,13 @@
#include "packet-scsi.h"
#include "packet-frame.h"
#include "prefs.h"
+#include "reassemble.h"
+#include "rpc_defrag.h"
#define TCP_PORT_NDMP 10000
-#define NDMP_FRAGLEN 0x7fffffffL
-
static int proto_ndmp = -1;
static int hf_ndmp_version = -1;
-static int hf_ndmp_size = -1;
static int hf_ndmp_header = -1;
static int hf_ndmp_sequence = -1;
static int hf_ndmp_reply_sequence = -1;
@@ -244,7 +243,8 @@ struct ndmp_header {
/* desegmentation of NDMP packets */
static gboolean ndmp_desegment = TRUE;
-
+/* defragmentation of fragmented NDMP records */
+static gboolean ndmp_defragment = FALSE;
#define NDMP_MESSAGE_REQUEST 0x00
#define NDMP_MESSAGE_REPLY 0x01
@@ -2568,12 +2568,6 @@ dissect_ndmp_cmd(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree
int i;
proto_item *cmd_item=NULL;
proto_tree *cmd_tree=NULL;
- guint32 size;
-
- /* the size of the current PDU */
- size = tvb_get_ntohl(tvb, offset);
- proto_tree_add_uint(tree, hf_ndmp_size, tvb, offset, 4, size&NDMP_FRAGLEN);
- offset += 4;
offset=dissect_ndmp_header(tvb, offset, pinfo, tree, nh);
@@ -2612,121 +2606,119 @@ dissect_ndmp_cmd(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree
return offset;
}
-static void
-dissect_ndmp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree)
+static gboolean
+dissect_ndmp_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
+ tvbuff_t *frag_tvb, fragment_data *ipfd_head, gboolean is_tcp,
+ guint32 rpc_rm)
{
- volatile gboolean first = TRUE;
- volatile int offset = 0;
- guint32 size, available_bytes;
+ int offset = (is_tcp && tvb == frag_tvb) ? 4 : 0;
+ guint32 size;
struct ndmp_header nh;
- proto_item *item=NULL;
- proto_tree *volatile tree=NULL;
- const char *saved_proto;
-
- /* loop through the packet, dissecting multiple NDMP pdus*/
- do {
- available_bytes = tvb_length_remaining(tvb, offset);
-
- /* size of this NDMP PDU */
- size = (tvb_get_ntohl(tvb, offset)&NDMP_FRAGLEN) + 4;
- if(size<28){
- /* too short to be NDMP */
- return;
- }
+ proto_item *ndmp_item = NULL;
+ proto_tree *ndmp_tree = NULL;
+
+ /* size of this NDMP PDU */
+ size = tvb_length_remaining(tvb, offset);
+ if (size < 24) {
+ /* too short to be NDMP */
+ return FALSE;
+ }
- /* desegmentation */
- if(ndmp_desegment){
- if(pinfo->can_desegment
- && size>available_bytes) {
- pinfo->desegment_offset = offset;
- pinfo->desegment_len = size-available_bytes;
- return;
- }
- }
+ /*
+ * Check the NDMP header, if we have it.
+ */
+ nh.seq = tvb_get_ntohl(tvb, offset);
+ nh.time = tvb_get_ntohl(tvb, offset+4);
+ nh.type = tvb_get_ntohl(tvb, offset+8);
+ nh.msg = tvb_get_ntohl(tvb, offset+12);
+ nh.rep_seq = tvb_get_ntohl(tvb, offset+16);
+ nh.err = tvb_get_ntohl(tvb, offset+20);
+
+ if (nh.type > 1)
+ return FALSE;
+ if (nh.msg > 0xa09 || nh.msg == 0)
+ return FALSE;
+ if (nh.err > 0x17)
+ return FALSE;
- /* check the ndmp header, if we have it */
- if(available_bytes<28){
- /* We don't have enough data */
- return;
- }
- nh.seq=tvb_get_ntohl(tvb, offset+4);
- nh.time=tvb_get_ntohl(tvb, offset+8);
- nh.type=tvb_get_ntohl(tvb, offset+12);
- nh.msg=tvb_get_ntohl(tvb, offset+16);
- nh.rep_seq=tvb_get_ntohl(tvb, offset+20);
- nh.err=tvb_get_ntohl(tvb, offset+24);
-
- if(nh.type>1){
- return;
- }
- if((nh.msg>0xa09)||(nh.msg==0)){
- return;
- }
- if(nh.err>0x17){
- return;
- }
+ /*
+ * Check if this is the last fragment.
+ */
+ if (!(rpc_rm & RPC_RM_LASTFRAG)) {
+ /*
+ * This isn't the last fragment.
+ * If we're doing reassembly, just return
+ * TRUE to indicate that this looks like
+ * the beginning of an NDMP message,
+ * and let them do reassembly.
+ */
+ if (ndmp_defragment)
+ return TRUE;
+ }
- if (first) {
- if (check_col(pinfo->cinfo, COL_PROTOCOL))
- col_set_str(pinfo->cinfo, COL_PROTOCOL, "NDMP");
- if (check_col(pinfo->cinfo, COL_INFO))
- col_clear(pinfo->cinfo, COL_INFO);
- first = FALSE;
- }
+ if (check_col(pinfo->cinfo, COL_PROTOCOL))
+ col_set_str(pinfo->cinfo, COL_PROTOCOL, "NDMP");
+ if (check_col(pinfo->cinfo, COL_INFO))
+ col_clear(pinfo->cinfo, COL_INFO);
+
+ if (tree) {
+ ndmp_item = proto_tree_add_item(tree, proto_ndmp,
+ tvb, 0, -1, FALSE);
+ ndmp_tree = proto_item_add_subtree(ndmp_item, ett_ndmp);
- if(parent_tree){
- item = proto_tree_add_item(parent_tree, proto_ndmp, tvb, offset, size, FALSE);
- tree = proto_item_add_subtree(item, ett_ndmp);
+ if (is_tcp) {
+ show_rpc_fraginfo(tvb, frag_tvb, ndmp_tree, rpc_rm,
+ ipfd_head);
}
+ }
+
+ /*
+ * We cannot trust what dissect_ndmp_cmd() tells us, as there
+ * are implementations which pad some additional data after
+ * the PDU. We MUST use size.
+ */
+ dissect_ndmp_cmd(tvb, offset, pinfo, ndmp_tree, &nh);
+ return TRUE;
+}
+
+static void
+dissect_ndmp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+ int offset = 0;
+ int len;
+ proto_item *ndmp_item = NULL;
+ proto_tree *ndmp_tree = NULL;
+ while (tvb_reported_length_remaining(tvb, offset) != 0) {
/*
- * Catch the ReportedBoundsError exception; if this
- * particular message happens to get a ReportedBoundsError
- * exception, that doesn't mean that we should stop
- * dissecting NDMP messages within this frame or chunk
- * of reassembled data.
- *
- * If it gets a BoundsError, we can stop, as there's
- * nothing more to see, so we just re-throw it.
+ * Process this fragment.
*/
- saved_proto = pinfo->current_proto;
- TRY {
- /* We cannot trust what dissect_ndmp_cmd() tells us
- since there are implementations which pads some
- additional data after the PDU. We MUST use size.
- */
- dissect_ndmp_cmd(tvb, offset, pinfo, tree, &nh);
- }
- CATCH(BoundsError) {
- RETHROW;
+ len = dissect_rpc_fragment(tvb, offset, pinfo, tree,
+ dissect_ndmp_message, FALSE, proto_ndmp, ett_ndmp,
+ ndmp_defragment);
+ if (len < 0) {
+ /*
+ * We need more data from the TCP stream for
+ * this fragment.
+ */
+ return;
}
- CATCH(ReportedBoundsError) {
- if (check_col(pinfo->cinfo, COL_INFO)) {
- col_append_str(pinfo->cinfo, COL_INFO,
- "[Malformed Packet]");
- }
- proto_tree_add_protocol_format(parent_tree,
- proto_malformed, tvb, 0, 0,
- "[Malformed Packet: %s]", pinfo->current_proto);
- pinfo->current_proto = saved_proto;
+ if (len == 0) {
+ /*
+ * It's not NDMP. Stop processing.
+ */
+ break;
}
- ENDTRY;
- offset += size;
- } while(offset<(int)tvb_reported_length(tvb));
-}
-
-
+ offset += len;
+ }
+}
void
proto_register_ndmp(void)
{
static hf_register_info hf_ndmp[] = {
- { &hf_ndmp_size, {
- "Size", "ndmp.size", FT_UINT32, BASE_DEC,
- NULL, 0, "Size of this NDMP PDU", HFILL }},
-
{ &hf_ndmp_header, {
"NDMP Header", "ndmp.header", FT_NONE, 0,
NULL, 0, "NDMP Header", HFILL }},
@@ -3370,9 +3362,6 @@ proto_register_ndmp(void)
{ &hf_ndmp_data_est_time_remain, {
"Est Time Remain", "ndmp.data.est_time_remain", FT_RELATIVE_TIME, BASE_DEC,
NULL, 0, "Estimated time remaining", HFILL }},
-
-
-
};
static gint *ett[] = {
@@ -3390,6 +3379,7 @@ proto_register_ndmp(void)
&ett_ndmp_addr,
&ett_ndmp_file,
&ett_ndmp_file_name,
+ &ett_ndmp_file_stats,
&ett_ndmp_file_invalids,
&ett_ndmp_state_invalids,
};
@@ -3403,8 +3393,14 @@ proto_register_ndmp(void)
/* desegmentation */
ndmp_module = prefs_register_protocol(proto_ndmp, NULL);
- prefs_register_bool_preference(ndmp_module, "desegment", "Desegment all NDMP messages spanning multiple TCP segments", "Whether the dissector should desegment NDMP over TCP PDUs or not", &ndmp_desegment);
-
+ prefs_register_bool_preference(ndmp_module, "desegment",
+ "Desegment all NDMP messages spanning multiple TCP segments",
+ "Whether the dissector should desegment NDMP messages",
+ &ndmp_desegment);
+ prefs_register_bool_preference(ndmp_module, "defragment",
+ "Defragment all multi-fragment NDMP messages",
+ "Whether the dissector should defragment multi-fragment NDMP messages",
+ &ndmp_defragment);
}
void
diff --git a/packet-rpc.c b/packet-rpc.c
index 13643f56c9..108f218cfd 100644
--- a/packet-rpc.c
+++ b/packet-rpc.c
@@ -2,7 +2,7 @@
* Routines for rpc dissection
* Copyright 1999, Uwe Girlich <Uwe.Girlich@philosys.de>
*
- * $Id: packet-rpc.c,v 1.86 2002/02/01 07:07:46 guy Exp $
+ * $Id: packet-rpc.c,v 1.87 2002/02/18 23:51:55 guy Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@ethereal.com>
@@ -41,7 +41,10 @@
#include <epan/conversation.h>
#include "packet-rpc.h"
#include "packet-frame.h"
+#include "packet-tcp.h"
#include "prefs.h"
+#include "reassemble.h"
+#include "rpc_defrag.h"
/*
* See:
@@ -60,11 +63,12 @@
* although we don't currently dissect AUTH_DES or AUTH_KERB.
*/
-#define RPC_RM_FRAGLEN 0x7fffffffL
-
/* desegmentation of RPC over TCP */
static gboolean rpc_desegment = TRUE;
+/* defragmentation of fragmented RPC over TCP records */
+static gboolean rpc_defragment = FALSE;
+
static struct true_false_string yesno = { "Yes", "No" };
@@ -188,6 +192,8 @@ static int hf_rpc_array_len = -1;
static int hf_rpc_time = -1;
static gint ett_rpc = -1;
+static gint ett_rpc_fragments = -1;
+static gint ett_rpc_fraghdr = -1;
static gint ett_rpc_string = -1;
static gint ett_rpc_cred = -1;
static gint ett_rpc_verf = -1;
@@ -1374,8 +1380,9 @@ dissect_rpc_continuation(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
}
static gboolean
-dissect_rpc_message(tvbuff_t *tvb, int offset, packet_info *pinfo,
- proto_tree *tree, gboolean use_rm, guint32 rpc_rm)
+dissect_rpc_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
+ tvbuff_t *frag_tvb, fragment_data *ipfd_head, gboolean is_tcp,
+ guint32 rpc_rm)
{
guint32 msg_type;
rpc_call_info_key rpc_call_key;
@@ -1408,11 +1415,12 @@ dissect_rpc_message(tvbuff_t *tvb, int offset, packet_info *pinfo,
unsigned int auth_state;
- proto_item *rpc_item=NULL;
+ proto_item *rpc_item = NULL;
proto_tree *rpc_tree = NULL;
- proto_item *pitem=NULL;
+ proto_item *pitem = NULL;
proto_tree *ptree = NULL;
+ int offset = (is_tcp && tvb == frag_tvb) ? 4 : 0;
int offset_old = offset;
rpc_call_info_key *new_rpc_call_key;
@@ -1519,6 +1527,24 @@ dissect_rpc_message(tvbuff_t *tvb, int offset, packet_info *pinfo,
return FALSE;
}
+ if (is_tcp) {
+ /*
+ * This is RPC-over-TCP; check if this is the last
+ * fragment.
+ */
+ if (!(rpc_rm & RPC_RM_LASTFRAG)) {
+ /*
+ * This isn't the last fragment.
+ * If we're doing reassembly, just return
+ * TRUE to indicate that this looks like
+ * the beginning of an RPC message,
+ * and let them do fragment reassembly.
+ */
+ if (rpc_defragment)
+ return TRUE;
+ }
+ }
+
if (check_col(pinfo->cinfo, COL_PROTOCOL))
col_set_str(pinfo->cinfo, COL_PROTOCOL, "RPC");
if (check_col(pinfo->cinfo, COL_INFO))
@@ -1526,17 +1552,13 @@ dissect_rpc_message(tvbuff_t *tvb, int offset, packet_info *pinfo,
if (tree) {
rpc_item = proto_tree_add_item(tree, proto_rpc, tvb, 0, -1,
- FALSE);
- if (rpc_item) {
- rpc_tree = proto_item_add_subtree(rpc_item, ett_rpc);
- }
- }
+ FALSE);
+ rpc_tree = proto_item_add_subtree(rpc_item, ett_rpc);
- if (use_rm && rpc_tree) {
- proto_tree_add_boolean(rpc_tree,hf_rpc_lastfrag, tvb,
- offset-4, 4, (rpc_rm >> 31) & 0x1);
- proto_tree_add_uint(rpc_tree,hf_rpc_fraglen, tvb,
- offset-4, 4, rpc_rm & RPC_RM_FRAGLEN);
+ if (is_tcp) {
+ show_rpc_fraginfo(tvb, frag_tvb, rpc_tree, rpc_rm,
+ ipfd_head);
+ }
}
xid = tvb_get_ntohl(tvb, offset + 0);
@@ -2067,16 +2089,524 @@ dissect_rpc_message(tvbuff_t *tvb, int offset, packet_info *pinfo,
static gboolean
dissect_rpc_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
{
- return dissect_rpc_message(tvb, 0, pinfo, tree, FALSE, 0);
+ return dissect_rpc_message(tvb, pinfo, tree, NULL, NULL, FALSE, 0);
}
static void
dissect_rpc(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
{
- if (!dissect_rpc_message(tvb, 0, pinfo, tree, FALSE, 0))
+ if (!dissect_rpc_message(tvb, pinfo, tree, NULL, NULL, FALSE, 0))
dissect_rpc_continuation(tvb, pinfo, tree);
}
+/* Defragmentation of RPC-over-TCP records */
+/* table to hold defragmented RPC records */
+static GHashTable *rpc_fragment_table = NULL;
+
+static GHashTable *rpc_reassembly_table = NULL;
+static GMemChunk *rpc_fragment_key_chunk = NULL;
+static int rpc_fragment_init_count = 200;
+
+typedef struct _rpc_fragment_key {
+ guint32 conv_id;
+ guint32 seq;
+ guint32 offset;
+ /* xxx */
+ guint32 start_seq;
+} rpc_fragment_key;
+
+static guint
+rpc_fragment_hash(gconstpointer k)
+{
+ rpc_fragment_key *key = (rpc_fragment_key *)k;
+
+ return key->conv_id + key->seq;
+}
+
+static gint
+rpc_fragment_equal(gconstpointer k1, gconstpointer k2)
+{
+ rpc_fragment_key *key1 = (rpc_fragment_key *)k1;
+ rpc_fragment_key *key2 = (rpc_fragment_key *)k2;
+
+ return key1->conv_id == key2->conv_id &&
+ key1->seq == key2->seq;
+}
+
+static void
+show_rpc_fragheader(tvbuff_t *tvb, proto_tree *tree, guint32 rpc_rm)
+{
+ proto_item *hdr_item;
+ proto_tree *hdr_tree;
+ guint32 fraglen;
+
+ if (tree) {
+ fraglen = rpc_rm & RPC_RM_FRAGLEN;
+
+ hdr_item = proto_tree_add_text(tree, tvb, 0, 4,
+ "Fragment header: %s%u %s",
+ (rpc_rm & RPC_RM_LASTFRAG) ? "Last fragment, " : "",
+ fraglen, plurality(fraglen, "byte", "bytes"));
+ hdr_tree = proto_item_add_subtree(hdr_item, ett_rpc_fraghdr);
+
+ proto_tree_add_boolean(hdr_tree, hf_rpc_lastfrag, tvb, 0, 4,
+ rpc_rm);
+ proto_tree_add_uint(hdr_tree, hf_rpc_fraglen, tvb, 0, 4,
+ rpc_rm);
+ }
+}
+
+static void
+show_rpc_fragment(tvbuff_t *tvb, proto_tree *tree, guint32 rpc_rm)
+{
+ if (tree) {
+ /*
+ * Show the fragment header and the data for the fragment.
+ */
+ show_rpc_fragheader(tvb, tree, rpc_rm);
+ proto_tree_add_text(tree, tvb, 4, -1, "Fragment Data");
+ }
+}
+
+static void
+make_frag_tree(tvbuff_t *tvb, proto_tree *tree, int proto, gint ett,
+ guint32 rpc_rm)
+{
+ proto_item *frag_item;
+ proto_tree *frag_tree;
+
+ if (tree == NULL)
+ return; /* nothing to do */
+
+ frag_item = proto_tree_add_protocol_format(tree, proto, tvb, 0, -1,
+ "%s Fragment", proto_get_protocol_name(proto));
+ frag_tree = proto_item_add_subtree(frag_item, ett);
+ show_rpc_fragment(tvb, frag_tree, rpc_rm);
+}
+
+void
+show_rpc_fraginfo(tvbuff_t *tvb, tvbuff_t *frag_tvb, proto_tree *tree,
+ guint32 rpc_rm, fragment_data *ipfd_head)
+{
+ proto_tree *st = NULL;
+ proto_item *si = NULL;
+ fragment_data *ipfd;
+
+ if (tree == NULL)
+ return; /* don't do any work */
+
+ if (tvb != frag_tvb) {
+ /*
+ * This message was not all in one fragment,
+ * so show the fragment header *and* the data
+ * for the fragment (which is the last fragment),
+ * and a tree with information about all fragments.
+ */
+ show_rpc_fragment(frag_tvb, tree, rpc_rm);
+
+ /*
+ * Show a tree with information about all fragments.
+ */
+ si = proto_tree_add_text(tree, tvb, 0, 0, "Fragments");
+ st = proto_item_add_subtree(si, ett_rpc_fragments);
+ for (ipfd = ipfd_head->next; ipfd != NULL; ipfd = ipfd->next) {
+ proto_tree_add_text(st, tvb, 0, 0,
+ "Frame:%u [%u-%u]",
+ ipfd->frame,
+ ipfd->offset,
+ ipfd->offset + ipfd->len - 1);
+ }
+ } else {
+ /*
+ * This message was all in one fragment, so just show
+ * the fragment header.
+ */
+ show_rpc_fragheader(tvb, tree, rpc_rm);
+ }
+}
+
+static gboolean
+call_message_dissector(tvbuff_t *tvb, tvbuff_t *rec_tvb, packet_info *pinfo,
+ proto_tree *tree, tvbuff_t *frag_tvb, rec_dissector_t dissector,
+ fragment_data *ipfd_head, guint32 rpc_rm)
+{
+ const char *saved_proto;
+ volatile gboolean rpc_succeeded;
+
+ /*
+ * Catch the ReportedBoundsError exception; if
+ * this particular message happens to get a
+ * ReportedBoundsError exception, that doesn't
+ * mean that we should stop dissecting RPC
+ * messages within this frame or chunk of
+ * reassembled data.
+ *
+ * If it gets a BoundsError, we can stop, as there's
+ * nothing more to see, so we just re-throw it.
+ */
+ saved_proto = pinfo->current_proto;
+ rpc_succeeded = FALSE;
+ TRY {
+ rpc_succeeded = (*dissector)(rec_tvb, pinfo, tree,
+ frag_tvb, ipfd_head, TRUE, rpc_rm);
+ }
+ CATCH(BoundsError) {
+ RETHROW;
+ }
+ CATCH(ReportedBoundsError) {
+ show_reported_bounds_error(tvb, pinfo, tree);
+ pinfo->current_proto = saved_proto;
+
+ /*
+ * We treat this as a "successful" dissection of
+ * an RPC packet, as "dissect_rpc_message()"
+ * *did* decide it was an RPC packet, throwing
+ * an exception while dissecting it as such.
+ */
+ rpc_succeeded = TRUE;
+ }
+ ENDTRY;
+ return rpc_succeeded;
+}
+
+int
+dissect_rpc_fragment(tvbuff_t *tvb, int offset, packet_info *pinfo,
+ proto_tree *tree, rec_dissector_t dissector, gboolean is_heur,
+ int proto, int ett, gboolean defragment)
+{
+ struct tcpinfo *tcpinfo = pinfo->private_data;
+ guint32 seq = tcpinfo->seq + offset;
+ guint32 rpc_rm;
+ volatile gint32 len;
+ gint32 seglen;
+ gint tvb_len, tvb_reported_len;
+ tvbuff_t *frag_tvb;
+ gboolean rpc_succeeded;
+ gboolean save_fragmented;
+ rpc_fragment_key old_rfk, *rfk, *new_rfk;
+ conversation_t *conversation;
+ fragment_data *ipfd_head;
+ tvbuff_t *rec_tvb;
+ fragment_data *ipfd;
+
+ /*
+ * Get the record mark.
+ */
+ if (!tvb_bytes_exist(tvb, offset, 4)) {
+ /*
+ * XXX - we should somehow arrange to handle
+ * a record mark split across TCP segments.
+ */
+ return 0; /* not enough to tell if it's valid */
+ }
+ rpc_rm = tvb_get_ntohl(tvb, offset);
+
+ len = rpc_rm & RPC_RM_FRAGLEN;
+
+ /*
+ * Do TCP desegmentation, if enabled.
+ *
+ * XXX - reject fragments bigger than 2 megabytes.
+ * This is arbitrary, but should at least prevent
+ * some crashes from either packets with really
+ * large RPC-over-TCP fragments or from stuff that's
+ * not really valid for this protocol.
+ */
+ if (len > 2*1024*1024)
+ return 0; /* pretend it's not valid */
+ if (rpc_desegment) {
+ seglen = tvb_length_remaining(tvb, offset + 4);
+
+ if (len > seglen && pinfo->can_desegment) {
+ /*
+ * This frame doesn't have all of the
+ * data for this message, but we can do
+ * reassembly on it.
+ *
+ * If this is a heuristic dissector, just
+ * return 0 - we don't want to try to get
+ * more data, as that's too likely to cause
+ * us to misidentify this as valid.
+ *
+ * If this isn't a heuristic dissector,
+ * we've already identified this conversation
+ * as containing data for this protocol, as we
+ * saw valid data in previous frames. Try to
+ * get more data.
+ */
+ if (is_heur)
+ return 0; /* not valid */
+ else {
+ pinfo->desegment_offset = offset;
+ pinfo->desegment_len = len - seglen;
+ return -pinfo->desegment_len;
+ }
+ }
+ }
+ len += 4; /* include record mark */
+ tvb_len = tvb_length_remaining(tvb, offset);
+ tvb_reported_len = tvb_reported_length_remaining(tvb, offset);
+ if (tvb_len > len)
+ tvb_len = len;
+ if (tvb_reported_len > len)
+ tvb_reported_len = len;
+ frag_tvb = tvb_new_subset(tvb, offset, tvb_len,
+ tvb_reported_len);
+
+ /*
+ * If we're not defragmenting, just hand this to the
+ * disssector.
+ */
+ if (!defragment) {
+ /*
+ * This is the first fragment we've seen, and it's also
+ * the last fragment; that means the record wasn't
+ * fragmented. Hand the dissector the tvbuff for the
+ * fragment as the tvbuff for the record.
+ */
+ rec_tvb = frag_tvb;
+ ipfd_head = NULL;
+
+ /*
+ * Mark this as fragmented, so if somebody throws an
+ * exception, we don't report it as a malformed frame.
+ */
+ save_fragmented = pinfo->fragmented;
+ pinfo->fragmented = TRUE;
+ rpc_succeeded = call_message_dissector(tvb, rec_tvb, pinfo,
+ tree, frag_tvb, dissector, ipfd_head, rpc_rm);
+ pinfo->fragmented = save_fragmented;
+ if (!rpc_succeeded)
+ return 0; /* not RPC */
+ return len;
+ }
+
+ /*
+ * First, we check to see if this fragment is part of a record
+ * that we're in the process of defragmenting.
+ *
+ * The key is the conversation ID for the conversation to which
+ * the packet belongs and the current sequence number.
+ * We must first find the conversation and, if we don't find
+ * one, create it. We know this is running over TCP, so the
+ * conversation should not wildcard either address or port.
+ */
+ conversation = find_conversation(&pinfo->src, &pinfo->dst,
+ pinfo->ptype, pinfo->srcport, pinfo->destport, 0);
+ if (conversation == NULL) {
+ /*
+ * It's not part of any conversation - create a new one.
+ */
+ conversation = conversation_new(&pinfo->src, &pinfo->dst,
+ pinfo->ptype, pinfo->srcport, pinfo->destport, 0);
+ }
+ old_rfk.conv_id = conversation->index;
+ old_rfk.seq = seq;
+ rfk = g_hash_table_lookup(rpc_reassembly_table, &old_rfk);
+
+ if (rfk == NULL) {
+ /*
+ * This fragment was not found in our table, so it doesn't
+ * contain a continuation of a higher-level PDU.
+ * Is it the last fragment?
+ */
+ if (!(rpc_rm & RPC_RM_LASTFRAG)) {
+ /*
+ * This isn't the last fragment, so we don't
+ * have the complete record.
+ *
+ * It's the first fragment we've seen, so if
+ * it's truly the first fragment of the record,
+ * and it has enough data, the dissector can at
+ * least check whether it looks like a valid
+ * message, as it contains the start of the
+ * message.
+ *
+ * The dissector should not dissect anything
+ * if the "last fragment" flag isn't set in
+ * the record marker, so it shouldn't throw
+ * an exception.
+ */
+ if (!(*dissector)(frag_tvb, pinfo, tree, frag_tvb,
+ NULL, TRUE, rpc_rm))
+ return 0; /* not valid */
+
+ /*
+ * OK, now start defragmentation with that
+ * fragment. Add this fragment, and set up
+ * next packet/sequence number as well.
+ *
+ * We must remember this fragment.
+ */
+
+ rfk = g_mem_chunk_alloc(rpc_fragment_key_chunk);
+ rfk->conv_id = conversation->index;
+ rfk->seq = seq;
+ rfk->offset = 0;
+ rfk->start_seq = seq;
+ g_hash_table_insert(rpc_reassembly_table, rfk, rfk);
+
+ /*
+ * Start defragmentation.
+ */
+ ipfd_head = fragment_add(tvb, offset + 4, pinfo,
+ rfk->start_seq, rpc_fragment_table,
+ rfk->offset, len - 4, TRUE);
+
+ /*
+ * Make sure that defragmentation isn't complete;
+ * it shouldn't be, as this is the first fragment
+ * we've seen, and the "last fragment" bit wasn't
+ * set on it.
+ */
+ g_assert(ipfd_head == NULL);
+
+ new_rfk = g_mem_chunk_alloc(rpc_fragment_key_chunk);
+ new_rfk->conv_id = rfk->conv_id;
+ new_rfk->seq = seq + len;
+ new_rfk->offset = rfk->offset + len - 4;
+ new_rfk->start_seq = rfk->start_seq;
+ g_hash_table_insert(rpc_reassembly_table, new_rfk,
+ new_rfk);
+
+ /*
+ * This is part of a fragmented record,
+ * but it's not the first part.
+ * Show it as a record marker plus data, under
+ * a top-level tree for this protocol.
+ */
+ make_frag_tree(frag_tvb, tree, proto, ett,rpc_rm);
+
+ /*
+ * No more processing need be done, as we don't
+ * have a complete record.
+ */
+ return len;
+ }
+
+ /*
+ * This is the first fragment we've seen, and it's also
+ * the last fragment; that means the record wasn't
+ * fragmented. Hand the dissector the tvbuff for the
+ * fragment as the tvbuff for the record.
+ */
+ rec_tvb = frag_tvb;
+ ipfd_head = NULL;
+ } else {
+ /*
+ * OK, this fragment was found, which means it continues
+ * a record. This means we must defragment it.
+ * Add it to the defragmentation lists.
+ */
+ ipfd_head = fragment_add(tvb, offset + 4, pinfo,
+ rfk->start_seq, rpc_fragment_table,
+ rfk->offset, len - 4, !(rpc_rm & RPC_RM_LASTFRAG));
+
+ if (ipfd_head == NULL) {
+ /*
+ * fragment_add() returned NULL, This means that
+ * defragmentation is not completed yet.
+ *
+ * We must add an entry to the hash table with
+ * the sequence number following this fragment
+ * as the starting sequence number, so that when
+ * we see that fragment we'll find that entry.
+ *
+ * XXX - as TCP stream data is not currently
+ * guaranteed to be provided in order to dissectors,
+ * RPC fragments aren't guaranteed to be provided
+ * in order, either.
+ */
+ new_rfk = g_mem_chunk_alloc(rpc_fragment_key_chunk);
+ new_rfk->conv_id = rfk->conv_id;
+ new_rfk->seq = seq + len;
+ new_rfk->offset = rfk->offset + len - 4;
+ new_rfk->start_seq = rfk->start_seq;
+ g_hash_table_insert(rpc_reassembly_table, new_rfk,
+ new_rfk);
+
+ /*
+ * This is part of a fragmented record,
+ * but it's not the first part.
+ * Show it as a record marker plus data, under
+ * a top-level tree for this protocol,
+ * but don't hand it to the dissector
+ */
+ make_frag_tree(frag_tvb, tree, proto, ett, rpc_rm);
+
+ /*
+ * No more processing need be done, as we don't
+ * have a complete record.
+ */
+ return len;
+ }
+
+ /*
+ * It's completely defragmented.
+ *
+ * We only call subdissector for the last fragment.
+ * XXX - this assumes in-order delivery of RPC
+ * fragments, which requires in-order delivery of TCP
+ * segments.
+ */
+ if (!(rpc_rm & RPC_RM_LASTFRAG)) {
+ /*
+ * Well, it's defragmented, but this isn't
+ * the last fragment; this probably means
+ * this isn't the first pass, so we don't
+ * need to start defragmentation.
+ *
+ * This is part of a fragmented record,
+ * but it's not the first part.
+ * Show it as a record marker plus data, under
+ * a top-level tree for this protocol,
+ * but don't show it to the dissector.
+ */
+ make_frag_tree(frag_tvb, tree, proto, ett, rpc_rm);
+
+ /*
+ * No more processing need be done, as we
+ * only disssect the data with the last
+ * fragment.
+ */
+ return len;
+ }
+
+ /*
+ * OK, this is the last segment.
+ * Create a tvbuff for the defragmented
+ * record.
+ */
+
+ /*
+ * Create a new TVB structure for
+ * defragmented data.
+ */
+ rec_tvb = tvb_new_real_data(ipfd_head->data,
+ ipfd_head->datalen, ipfd_head->datalen);
+
+ /*
+ * Add this tvb as a child to the original
+ * one.
+ */
+ tvb_set_child_real_data_tvbuff(tvb, rec_tvb);
+
+ /*
+ * Add defragmented data to the data source list.
+ */
+ add_new_data_source(pinfo->fd, rec_tvb, "Defragmented");
+ }
+
+ /*
+ * We have something to hand to the RPC message
+ * dissector.
+ */
+ if (!call_message_dissector(tvb, rec_tvb, pinfo, tree,
+ frag_tvb, dissector, ipfd_head, rpc_rm))
+ return 0; /* not RPC */
+ return len;
+}
+
/*
* Can return:
*
@@ -2097,123 +2627,31 @@ static rpc_tcp_return_t
dissect_rpc_tcp_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
gboolean is_heur)
{
- volatile int offset = 0;
- guint32 rpc_rm;
- volatile gboolean saw_rpc = FALSE;
- volatile gint32 len;
- gint32 seglen;
- gint tvb_len, tvb_reported_len;
- tvbuff_t *msg_tvb;
- const char *saved_proto;
- volatile gboolean rpc_succeeded;
+ int offset = 0;
+ gboolean saw_rpc = FALSE;
+ int len;
while (tvb_reported_length_remaining(tvb, offset) != 0) {
/*
- * XXX - we need to handle records that don't have the "last
- * fragment" bit set, and reassemble fragments.
+ * Process this fragment.
*/
-
- /* the first 4 bytes are special in "record marking mode" */
- if (!tvb_bytes_exist(tvb, offset, 4)) {
+ len = dissect_rpc_fragment(tvb, offset, pinfo, tree,
+ dissect_rpc_message, is_heur, proto_rpc, ett_rpc,
+ rpc_defragment);
+ if (len < 0) {
/*
- * XXX - we should somehow arrange to handle
- * a record mark split across TCP segments.
+ * We need more data from the TCP stream for
+ * this fragment.
*/
- return saw_rpc ? IS_RPC : IS_NOT_RPC;
- }
- rpc_rm = tvb_get_ntohl(tvb, offset);
-
- len = rpc_rm&RPC_RM_FRAGLEN;
-
- /*
- * XXX - reject fragments bigger than 2 megabytes.
- * This is arbitrary, but should at least prevent
- * some crashes from either packets with really
- * large RPC-over-TCP fragments or from stuff that's
- * not really RPC.
- */
- if (len > 2*1024*1024)
- return saw_rpc ? IS_RPC : IS_NOT_RPC;
- if (rpc_desegment) {
- seglen = tvb_length_remaining(tvb, offset + 4);
-
- if (len > seglen && pinfo->can_desegment) {
- /*
- * This frame doesn't have all of the
- * data for this message, but we can do
- * reassembly on it.
- *
- * If this is a heuristic dissector, just
- * return IS_NOT_RPC - we don't want to try
- * to get more data, as that's too likely
- * to cause us to misidentify this as
- * RPC.
- *
- * If this isn't a heuristic dissector,
- * we've already identified this conversation
- * as containing RPC data, as we saw RPC
- * data in previous frames. Try to get
- * more data.
- */
- if (is_heur)
- return IS_NOT_RPC;
- else {
- pinfo->desegment_offset = offset;
- pinfo->desegment_len = len - seglen;
- return NEED_MORE_DATA;
- }
- }
- }
- len += 4; /* include record mark */
- tvb_len = tvb_length_remaining(tvb, offset);
- tvb_reported_len = tvb_reported_length_remaining(tvb, offset);
- if (tvb_len > len)
- tvb_len = len;
- if (tvb_reported_len > len)
- tvb_reported_len = len;
- msg_tvb = tvb_new_subset(tvb, offset, tvb_len,
- tvb_reported_len);
-
- /*
- * Catch the ReportedBoundsError exception; if this
- * particular message happens to get a ReportedBoundsError
- * exception, that doesn't mean that we should stop
- * dissecting RPC messages within this frame or chunk
- * of reassembled data.
- *
- * If it gets a BoundsError, we can stop, as there's
- * nothing more to see, so we just re-throw it.
- */
- saved_proto = pinfo->current_proto;
- rpc_succeeded = FALSE;
- TRY {
- rpc_succeeded = dissect_rpc_message(msg_tvb, 4,
- pinfo, tree, TRUE, rpc_rm);
- }
- CATCH(BoundsError) {
- RETHROW;
+ return NEED_MORE_DATA;
}
- CATCH(ReportedBoundsError) {
- if (check_col(pinfo->cinfo, COL_INFO)) {
- col_append_str(pinfo->cinfo, COL_INFO,
- "[Malformed Packet]");
- }
- proto_tree_add_protocol_format(tree, proto_malformed,
- tvb, 0, 0, "[Malformed Packet: %s]",
- pinfo->current_proto );
- pinfo->current_proto = saved_proto;
-
+ if (len == 0) {
/*
- * We treat this as a "successful" dissection of
- * an RPC packet, as "dissect_rpc_message()"
- * *did* decide it was an RPC packet, throwing
- * an exception while dissecting it as such.
+ * It's not RPC. Stop processing.
*/
- rpc_succeeded = TRUE;
- }
- ENDTRY;
- if (!rpc_succeeded)
break;
+ }
+
offset += len;
saw_rpc = TRUE;
}
@@ -2249,14 +2687,30 @@ dissect_rpc_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
static void
rpc_init_protocol(void)
{
- if (rpc_calls != NULL)
+ if (rpc_calls != NULL) {
g_hash_table_destroy(rpc_calls);
- if (rpc_indir_calls != NULL)
+ rpc_calls = NULL;
+ }
+ if (rpc_indir_calls != NULL) {
g_hash_table_destroy(rpc_indir_calls);
- if (rpc_call_info_key_chunk != NULL)
+ rpc_indir_calls = NULL;
+ }
+ if (rpc_call_info_key_chunk != NULL) {
g_mem_chunk_destroy(rpc_call_info_key_chunk);
- if (rpc_call_info_value_chunk != NULL)
+ rpc_call_info_key_chunk = NULL;
+ }
+ if (rpc_call_info_value_chunk != NULL) {
g_mem_chunk_destroy(rpc_call_info_value_chunk);
+ rpc_call_info_value_chunk = NULL;
+ }
+ if (rpc_fragment_key_chunk != NULL) {
+ g_mem_chunk_destroy(rpc_fragment_key_chunk);
+ rpc_fragment_key_chunk = NULL;
+ }
+ if (rpc_reassembly_table != NULL) {
+ g_hash_table_destroy(rpc_reassembly_table);
+ rpc_reassembly_table = NULL;
+ }
rpc_calls = g_hash_table_new(rpc_call_hash, rpc_call_equal);
rpc_indir_calls = g_hash_table_new(rpc_call_hash, rpc_call_equal);
@@ -2268,6 +2722,14 @@ rpc_init_protocol(void)
sizeof(rpc_call_info_value),
200 * sizeof(rpc_call_info_value),
G_ALLOC_ONLY);
+ rpc_fragment_key_chunk = g_mem_chunk_new("rpc_fragment_key_chunk",
+ sizeof(rpc_fragment_key),
+ rpc_fragment_init_count*sizeof(rpc_fragment_key),
+ G_ALLOC_ONLY);
+ rpc_reassembly_table = g_hash_table_new(rpc_fragment_hash,
+ rpc_fragment_equal);
+
+ fragment_table_init(&rpc_fragment_table);
}
/* will be called once from register.c at startup time */
@@ -2276,11 +2738,11 @@ proto_register_rpc(void)
{
static hf_register_info hf[] = {
{ &hf_rpc_lastfrag, {
- "Last Fragment", "rpc.lastfrag", FT_BOOLEAN, BASE_NONE,
- &yesno, 0, "Last Fragment", HFILL }},
+ "Last Fragment", "rpc.lastfrag", FT_BOOLEAN, 32,
+ &yesno, RPC_RM_LASTFRAG, "Last Fragment", HFILL }},
{ &hf_rpc_fraglen, {
"Fragment Length", "rpc.fraglen", FT_UINT32, BASE_DEC,
- NULL, 0, "Fragment Length", HFILL }},
+ NULL, RPC_RM_FRAGLEN, "Fragment Length", HFILL }},
{ &hf_rpc_xid, {
"XID", "rpc.xid", FT_UINT32, BASE_HEX,
NULL, 0, "XID", HFILL }},
@@ -2424,6 +2886,8 @@ proto_register_rpc(void)
};
static gint *ett[] = {
&ett_rpc,
+ &ett_rpc_fragments,
+ &ett_rpc_fraghdr,
&ett_rpc_string,
&ett_rpc_cred,
&ett_rpc_verf,
@@ -2440,11 +2904,16 @@ proto_register_rpc(void)
register_init_routine(&rpc_init_protocol);
rpc_tcp_handle = create_dissector_handle(dissect_rpc_tcp, proto_rpc);
rpc_handle = create_dissector_handle(dissect_rpc, proto_rpc);
+
rpc_module = prefs_register_protocol(proto_rpc, NULL);
prefs_register_bool_preference(rpc_module, "desegment_rpc_over_tcp",
- "Desegment all RPC over TCP commands",
- "Whether the RPC dissector should desegment all RPC over TCP commands",
+ "Desegment all RPC-over-TCP messages",
+ "Whether the RPC dissector should desegment all RPC-over-TCP messages",
&rpc_desegment);
+ prefs_register_bool_preference(rpc_module, "defragment_rpc_over_tcp",
+ "Defragment all RPC-over-TCP messages",
+ "Whether the RPC dissector should defragment multi-fragment RPC-over-TCP messages",
+ &rpc_defragment);
/*
* Init the hash tables. Dissectors for RPC protocols must
diff --git a/packet-tcp.c b/packet-tcp.c
index cd46b08388..2f7383bf9a 100644
--- a/packet-tcp.c
+++ b/packet-tcp.c
@@ -1,7 +1,7 @@
/* packet-tcp.c
* Routines for TCP packet disassembly
*
- * $Id: packet-tcp.c,v 1.131 2002/02/18 01:08:37 guy Exp $
+ * $Id: packet-tcp.c,v 1.132 2002/02/18 23:51:55 guy Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@ethereal.com>
@@ -222,6 +222,14 @@ tcp_segment_equal(gconstpointer k1, gconstpointer k2)
static void
tcp_desegment_init(void)
{
+ if(tcp_segment_key_chunk){
+ g_mem_chunk_destroy(tcp_segment_key_chunk);
+ tcp_segment_key_chunk = NULL;
+ }
+ if(tcp_segment_address_chunk){
+ g_mem_chunk_destroy(tcp_segment_address_chunk);
+ tcp_segment_address_chunk = NULL;
+ }
/* dont allocate any memory chunks unless the user really
uses this option
@@ -238,17 +246,11 @@ tcp_desegment_init(void)
tcp_segment_equal);
}
- if(tcp_segment_key_chunk){
- g_mem_chunk_destroy(tcp_segment_key_chunk);
- }
tcp_segment_key_chunk = g_mem_chunk_new("tcp_segment_key_chunk",
sizeof(tcp_segment_key),
tcp_segment_init_count*sizeof(tcp_segment_key),
G_ALLOC_ONLY);
- if(tcp_segment_address_chunk){
- g_mem_chunk_destroy(tcp_segment_address_chunk);
- }
tcp_segment_address_chunk = g_mem_chunk_new("tcp_segment_address_chunk",
sizeof(address),
tcp_segment_address_init_count*sizeof(address),
@@ -391,6 +393,12 @@ desegment_tcp(tvbuff_t *tvb, packet_info *pinfo, int offset,
add_new_data_source(pinfo->fd, next_tvb,
"Desegmented");
+ /*
+ * Supply the sequence number of the first of the
+ * reassembled bytes.
+ */
+ tcpinfo->seq = tsk->start_seq;
+
/* indicate that this is reassembled data */
tcpinfo->is_reassembled = TRUE;
@@ -1021,6 +1029,9 @@ dissect_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
proto_tree_add_uint(tcp_tree, hf_tcp_window_size, tvb, offset + 14, 2, th_win);
}
+ /* Supply the sequence number of the first byte. */
+ tcpinfo.seq = th_seq;
+
/* Assume we'll pass un-reassembled data to subdissectors. */
tcpinfo.is_reassembled = FALSE;
diff --git a/packet-tcp.h b/packet-tcp.h
index e8ae0f8f72..5e4c34184b 100644
--- a/packet-tcp.h
+++ b/packet-tcp.h
@@ -1,6 +1,6 @@
/* packet-tcp.h
*
- * $Id: packet-tcp.h,v 1.8 2001/10/01 08:29:35 guy Exp $
+ * $Id: packet-tcp.h,v 1.9 2002/02/18 23:51:55 guy Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@ethereal.com>
@@ -28,8 +28,9 @@
* Private data passed from the TCP dissector to subdissectors.
*/
struct tcpinfo {
+ guint32 seq; /* Sequence number of first byte in the data */
gboolean is_reassembled; /* This is reassembled data. */
- gboolean urgent; /* TRUE if "urgent_pointer is valid */
+ gboolean urgent; /* TRUE if "urgent_pointer" is valid */
guint16 urgent_pointer; /* Urgent pointer value for the current packet. */
};
diff --git a/rpc_defrag.h b/rpc_defrag.h
new file mode 100644
index 0000000000..2f7dc29876
--- /dev/null
+++ b/rpc_defrag.h
@@ -0,0 +1,43 @@
+/* rpc-defrag.h
+ * Declarations for RPC defragmentation
+ *
+ * $Id: rpc_defrag.h,v 1.1 2002/02/18 23:51:55 guy Exp $
+ *
+ * Ethereal - Network traffic analyzer
+ * By Gerald Combs <gerald@ethereal.com>
+ * 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.
+ */
+
+#ifndef __RPC_DEFRAG_H__
+#define __RPC_DEFRAG_H__
+
+/*
+ * RPC-over-TCP fragmentation.
+ */
+#define RPC_RM_LASTFRAG 0x80000000L
+#define RPC_RM_FRAGLEN 0x7fffffffL
+
+typedef (*rec_dissector_t)(tvbuff_t *, packet_info *, proto_tree *,
+ tvbuff_t *, fragment_data *, gboolean, guint32);
+
+extern void show_rpc_fraginfo(tvbuff_t *tvb, tvbuff_t *frag_tvb,
+ proto_tree *tree, guint32 rpc_rm, fragment_data *ipfd_head);
+extern int dissect_rpc_fragment(tvbuff_t *tvb, int offset, packet_info *pinfo,
+ proto_tree *tree, rec_dissector_t dissector, gboolean is_heur,
+ int proto, int ett, gboolean defragment);
+
+#endif /* __RPC_DEFRAG_H__ */