diff options
-rw-r--r-- | Makefile.am | 3 | ||||
-rw-r--r-- | packet-frame.c | 55 | ||||
-rw-r--r-- | packet-frame.h | 14 | ||||
-rw-r--r-- | packet-nbns.c | 7 | ||||
-rw-r--r-- | packet-ndmp.c | 220 | ||||
-rw-r--r-- | packet-rpc.c | 739 | ||||
-rw-r--r-- | packet-tcp.c | 25 | ||||
-rw-r--r-- | packet-tcp.h | 5 | ||||
-rw-r--r-- | rpc_defrag.h | 43 |
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__ */ |