aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGuy Harris <guy@alum.mit.edu>2001-12-05 08:20:30 +0000
committerGuy Harris <guy@alum.mit.edu>2001-12-05 08:20:30 +0000
commit6b253331f087fbecb5de5e4548fbbe644d19b7af (patch)
tree43a7a7e7ed39be14d47f53c6f515e1acd3d37a15
parentfaacd2b71c6e1141c7fa88ca2164e56fb4a0daa7 (diff)
Support for reassembly of DCERPC over SMB, from Ronnie Sahlberg.
svn path=/trunk/; revision=4335
-rw-r--r--packet-dcerpc.c4
-rw-r--r--packet-smb-pipe.c73
-rw-r--r--packet-smb.c195
-rw-r--r--packet-tcp.c5
-rw-r--r--smb.h15
5 files changed, 203 insertions, 89 deletions
diff --git a/packet-dcerpc.c b/packet-dcerpc.c
index d64772ca29..5ede69e934 100644
--- a/packet-dcerpc.c
+++ b/packet-dcerpc.c
@@ -2,7 +2,7 @@
* Routines for DCERPC packet disassembly
* Copyright 2001, Todd Sabin <tas@webspan.net>
*
- * $Id: packet-dcerpc.c,v 1.19 2001/11/27 22:37:19 guy Exp $
+ * $Id: packet-dcerpc.c,v 1.20 2001/12/05 08:20:28 guy Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@ethereal.com>
@@ -1582,5 +1582,5 @@ proto_reg_handoff_dcerpc (void)
heur_dissector_add ("tcp", dissect_dcerpc_cn_bs, proto_dcerpc);
heur_dissector_add ("netbios", dissect_dcerpc_cn_pk, proto_dcerpc);
heur_dissector_add ("udp", dissect_dcerpc_dg, proto_dcerpc);
- heur_dissector_add ("smb_transact", dissect_dcerpc_cn_pk, proto_dcerpc);
+ heur_dissector_add ("smb_transact", dissect_dcerpc_cn_bs, proto_dcerpc);
}
diff --git a/packet-smb-pipe.c b/packet-smb-pipe.c
index cd7c6d1596..9c815ceba3 100644
--- a/packet-smb-pipe.c
+++ b/packet-smb-pipe.c
@@ -8,7 +8,7 @@ XXX Fixme : shouldnt show [malformed frame] for long packets
* significant rewrite to tvbuffify the dissector, Ronnie Sahlberg and
* Guy Harris 2001
*
- * $Id: packet-smb-pipe.c,v 1.58 2001/11/28 11:33:54 guy Exp $
+ * $Id: packet-smb-pipe.c,v 1.59 2001/12/05 08:20:28 guy Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@ethereal.com>
@@ -55,6 +55,7 @@ XXX Fixme : shouldnt show [malformed frame] for long packets
#include "packet-smb-pipe.h"
#include "packet-smb-browse.h"
#include "packet-dcerpc.h"
+#include "reassemble.h"
static int proto_smb_pipe = -1;
static int hf_pipe_function = -1;
@@ -72,6 +73,7 @@ static int hf_pipe_getinfo_pipe_name = -1;
static int hf_pipe_write_raw_bytes_written = -1;
static gint ett_smb_pipe = -1;
+static gint ett_smb_pipe_fragments = -1;
static int proto_smb_lanman = -1;
static int hf_function_code = -1;
@@ -2533,7 +2535,7 @@ static heur_dissector_list_t smb_transact_heur_subdissector_list;
static gboolean
dissect_pipe_msrpc(tvbuff_t *d_tvb, packet_info *pinfo, proto_tree *parent_tree,
- guint16 fid)
+ proto_tree *tree, guint32 fid)
{
dcerpc_private_info dcerpc_priv;
smb_info_t *smb_priv = (smb_info_t *)pinfo->private_data;
@@ -2544,11 +2546,73 @@ dissect_pipe_msrpc(tvbuff_t *d_tvb, packet_info *pinfo, proto_tree *parent_tree,
pinfo->private_data = &dcerpc_priv;
+ /* offer desegmentation service to DCERPC */
+ pinfo->can_desegment=0;
+ pinfo->desegment_offset = 0;
+ pinfo->desegment_len = 0;
+ if(smb_dcerpc_reassembly){
+ pinfo->can_desegment=2;
+ }
+
+ /* see if this packet is already desegmented */
+ if(smb_dcerpc_reassembly && pinfo->fd->flags.visited){
+ fragment_data *fd_head;
+ tvbuff_t *new_tvb;
+
+ fd_head=fragment_get(pinfo, pinfo->fd->num ,
+ dcerpc_fragment_table);
+ if(fd_head && fd_head->flags&FD_DEFRAGMENTED){
+ proto_tree *tr;
+ proto_item *it;
+ fragment_data *fd;
+
+ new_tvb = tvb_new_real_data(fd_head->data,
+ fd_head->datalen, fd_head->datalen,
+ "DCERPC over SMB");
+ tvb_set_child_real_data_tvbuff(d_tvb, new_tvb);
+ pinfo->fd->data_src=g_slist_append(pinfo->fd->data_src,
+ new_tvb);
+ pinfo->fragmented=FALSE;
+
+ d_tvb=new_tvb;
+
+ /* list what segments we have */
+ it = proto_tree_add_text(tree, d_tvb, 0, 0, "Fragments");
+ tr = proto_item_add_subtree(it, ett_smb_pipe_fragments);
+ for(fd=fd_head->next;fd;fd=fd->next){
+ proto_tree_add_text(tr, d_tvb, 0, 0, "Frame:%d Data:%d-%d",
+ fd->frame, fd->offset, fd->offset+fd->len-1);
+ }
+ }
+ }
+
result = dissector_try_heuristic(smb_transact_heur_subdissector_list, d_tvb,
pinfo, parent_tree);
-
pinfo->private_data = smb_priv;
+ /* check if dissector wanted us to desegment the data */
+ if(smb_dcerpc_reassembly && !pinfo->fd->flags.visited && pinfo->desegment_len){
+ fragment_add(d_tvb, 0, pinfo, pinfo->fd->num,
+ dcerpc_fragment_table,
+ 0, tvb_length(d_tvb), TRUE);
+ fragment_set_tot_len(pinfo, pinfo->fd->num,
+ dcerpc_fragment_table,
+ pinfo->desegment_len+tvb_length(d_tvb));
+ /* since the other fragments are in normal ReadAndX and WriteAndX calls
+ we must make sure we can map FID values to this defragmentation
+ session */
+ /* first remove any old mappings */
+ if(g_hash_table_lookup(smb_priv->ct->dcerpc_fid_to_frame, (void *)fid)){
+ g_hash_table_remove(smb_priv->ct->dcerpc_fid_to_frame, (void *)fid);
+ }
+ g_hash_table_insert(smb_priv->ct->dcerpc_fid_to_frame, (void *)fid,
+ (void *)pinfo->fd->num);
+ }
+ /* clear out the variables */
+ pinfo->can_desegment=0;
+ pinfo->desegment_offset = 0;
+ pinfo->desegment_len = 0;
+
if (!result)
call_dissector(data_handle, d_tvb, pinfo, parent_tree);
@@ -2786,7 +2850,7 @@ dissect_pipe_smb(tvbuff_t *sp_tvb, tvbuff_t *s_tvb, tvbuff_t *pd_tvb,
if (d_tvb == NULL)
return FALSE;
return dissect_pipe_msrpc(d_tvb, pinfo, tree,
- fid);
+ pipe_tree, fid);
}
break;
}
@@ -2988,6 +3052,7 @@ proto_register_smb_pipe(void)
};
static gint *ett[] = {
&ett_smb_pipe,
+ &ett_smb_pipe_fragments,
};
proto_smb_pipe = proto_register_protocol(
diff --git a/packet-smb.c b/packet-smb.c
index e9b3eb529e..adda0b19a9 100644
--- a/packet-smb.c
+++ b/packet-smb.c
@@ -2,7 +2,7 @@
* Routines for smb packet dissection
* Copyright 1999, Richard Sharpe <rsharpe@ns.aus.com>
*
- * $Id: packet-smb.c,v 1.178 2001/12/05 00:49:31 guy Exp $
+ * $Id: packet-smb.c,v 1.179 2001/12/05 08:20:28 guy Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@ethereal.com>
@@ -666,18 +666,24 @@ static const gchar *get_unicode_or_ascii_string(tvbuff_t *tvb,
/* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
- These are needed by the reassembly of SMB Transaction payload
+ These are needed by the reassembly of SMB Transaction payload and DCERPC over SMB
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */
-/* Reassembly of SMB Transaction calls */
static gboolean smb_trans_reassembly = FALSE;
+gboolean smb_dcerpc_reassembly = FALSE;
static GHashTable *smb_trans_fragment_table = NULL;
+GHashTable *dcerpc_fragment_table = NULL;
static void
smb_trans_reassembly_init(void)
{
fragment_table_init(&smb_trans_fragment_table);
}
+static void
+smb_dcerpc_reassembly_init(void)
+{
+ fragment_table_init(&dcerpc_fragment_table);
+}
static fragment_data *
@@ -802,10 +808,6 @@ static int smb_transact2_info_init_count = 200;
static GMemChunk *smb_transact_info_chunk = NULL;
static int smb_transact_info_init_count = 200;
-typedef struct conv_tables {
- GHashTable *unmatched;
- GHashTable *matched;
-} conv_tables_t;
static GMemChunk *conv_tables_chunk = NULL;
static int conv_tables_count = 10;
@@ -4597,8 +4599,8 @@ static int
dissect_read_andx_response(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, proto_tree *smb_tree)
{
guint8 wc, cmd=0xff;
- guint16 andxoffset=0, bc, datalen=0;
- smb_info_t *si;
+ guint16 andxoffset=0, bc, datalen=0, dataoffset=0;
+ smb_info_t *si = (smb_info_t *)pinfo->private_data;
WORD_COUNT;
@@ -4621,7 +4623,6 @@ dissect_read_andx_response(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
offset += 2;
/* If we have seen the request, then print which FID this refers to */
- si = (smb_info_t *)pinfo->private_data;
/* first check if we have seen the request */
if(si->sip != NULL && si->sip->frame_req>0){
add_fid(tvb, pinfo, tree, 0, 0, (int)si->sip->extra_info);
@@ -4645,7 +4646,8 @@ dissect_read_andx_response(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
offset += 2;
/* data offset */
- proto_tree_add_item(tree, hf_smb_data_offset, tvb, offset, 2, TRUE);
+ dataoffset=tvb_get_letohs(tvb, offset);
+ proto_tree_add_uint(tree, hf_smb_data_offset, tvb, offset, 2, dataoffset);
offset += 2;
/* 10 reserved bytes */
@@ -4655,6 +4657,43 @@ dissect_read_andx_response(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
BYTE_COUNT;
+ /* is this part of DCERPC over SMB reassembly?*/
+ if(smb_dcerpc_reassembly && !pinfo->fd->flags.visited && (bc<=tvb_length_remaining(tvb, offset)) ){
+ guint32 frame;
+ frame=(guint32)g_hash_table_lookup(si->ct->dcerpc_fid_to_frame,
+ si->sip->extra_info);
+ if(frame){
+ fragment_data *fd_head;
+ /* first fragment is always from a SMB Trans command and
+ offset 0 of the following read/write SMB commands start
+ BEYOND the first Trans SMB payload. Look for offset
+ in first read fragment */
+ fd_head=fragment_get(pinfo, frame, dcerpc_fragment_table);
+ if(fd_head){
+ /* skip to last fragment and add this data there*/
+ while(fd_head->next){
+ fd_head=fd_head->next;
+ }
+ /* if dataoffset was not specified in the SMB command
+ then we try to guess it as good as we can
+ */
+ if(dataoffset==0){
+ dataoffset=offset+bc-datalen;
+ }
+ fd_head=fragment_add(tvb, dataoffset, pinfo,
+ frame, dcerpc_fragment_table,
+ fd_head->offset+fd_head->len,
+ datalen, TRUE);
+ /* we completed reassembly, abort searching for more
+ fragments*/
+ if(fd_head){
+ g_hash_table_remove(si->ct->dcerpc_fid_to_frame,
+ si->sip->extra_info);
+ }
+ }
+ }
+ }
+
/* file data */
offset = dissect_file_data(tvb, pinfo, tree, offset, bc, datalen);
bc = 0;
@@ -12745,6 +12784,7 @@ dissect_smb(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree)
guint8 errclass = 0;
guint16 errcode = 0;
guint16 uid, pid, tid;
+ conversation_t *conversation;
top_tree=parent_tree;
@@ -12798,6 +12838,29 @@ dissect_smb(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree)
proto_tree_add_text(htree, tvb, offset, 4, "Server Component: SMB");
offset += 4; /* Skip the marker */
+ /* find which conversation we are part of and get the tables for that
+ conversation*/
+ conversation = find_conversation(&pinfo->src, &pinfo->dst,
+ pinfo->ptype, pinfo->srcport, pinfo->destport, 0);
+ if(conversation){
+ si.ct=conversation_get_proto_data(conversation, proto_smb);
+ } else {
+ /* OK this is a new conversation, we must create it
+ and attach appropriate data (matched and unmatched
+ table for this conversation)
+ */
+ conversation = conversation_new(&pinfo->src, &pinfo->dst,
+ pinfo->ptype, pinfo->srcport, pinfo->destport, 0);
+ si.ct = g_mem_chunk_alloc(conv_tables_chunk);
+ si.ct->matched= g_hash_table_new(smb_saved_info_hash_matched,
+ smb_saved_info_equal_matched);
+ si.ct->unmatched= g_hash_table_new(smb_saved_info_hash_matched,
+ smb_saved_info_equal_matched);
+ si.ct->dcerpc_fid_to_frame=g_hash_table_new(
+ smb_saved_info_hash_matched,
+ smb_saved_info_equal_matched);
+ conversation_add_proto_data(conversation, proto_smb, si.ct);
+ }
if( (si.request)
&& (si.mid==0)
@@ -12829,47 +12892,37 @@ dissect_smb(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree)
requests smb_saved_info_t but we dont touch it or change anything
in it.
*/
- conversation_t *conversation;
- conv_tables_t *ct;
si.unidir = TRUE; /*we dont expect an answer to this one*/
-
- /* find which conversation we are part of and get the tables for that
- conversation*/
- conversation = find_conversation(&pinfo->src, &pinfo->dst,
- pinfo->ptype, pinfo->srcport, pinfo->destport, 0);
- if(conversation){
- ct=conversation_get_proto_data(conversation, proto_smb);
- if(!pinfo->fd->flags.visited){
- /* try to find which original call we match and if we
- find it add us to the matched table. Dont touch
- anything else since we dont want this one to mess
- up the request/response matching. We still consider
- the initial call the real request and this is only
- some sort of continuation.
- */
- /* we only check the unmatched table and assume that the
- last seen MID matching ours is the right one.
- This can fail but is better than nothing
- */
- sip=g_hash_table_lookup(ct->unmatched, (void *)si.mid);
- if(sip!=NULL){
- g_hash_table_insert(ct->matched, (void *)pinfo->fd->num, sip);
- }
- } else {
- /* we have seen this packet before; check the
- matching table
- */
- sip=g_hash_table_lookup(ct->matched, (void *)pinfo->fd->num);
- if(sip==NULL){
- /*
- We didn't find it.
- Too bad, unfortunately there is not really much we can
- do now since this means that we never saw the initial
- request.
- */
- }
+ if(!pinfo->fd->flags.visited){
+ /* try to find which original call we match and if we
+ find it add us to the matched table. Dont touch
+ anything else since we dont want this one to mess
+ up the request/response matching. We still consider
+ the initial call the real request and this is only
+ some sort of continuation.
+ */
+ /* we only check the unmatched table and assume that the
+ last seen MID matching ours is the right one.
+ This can fail but is better than nothing
+ */
+ sip=g_hash_table_lookup(si.ct->unmatched, (void *)si.mid);
+ if(sip!=NULL){
+ g_hash_table_insert(si.ct->matched, (void *)pinfo->fd->num, sip);
+ }
+ } else {
+ /* we have seen this packet before; check the
+ matching table
+ */
+ sip=g_hash_table_lookup(si.ct->matched, (void *)pinfo->fd->num);
+ if(sip==NULL){
+ /*
+ We didn't find it.
+ Too bad, unfortunately there is not really much we can
+ do now since this means that we never saw the initial
+ request.
+ */
}
}
@@ -12902,38 +12955,13 @@ dissect_smb(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree)
}
}
} else { /* normal bidirectional request or response */
- conversation_t *conversation;
- conv_tables_t *ct;
-
si.unidir = FALSE;
- /* first we try to find which conversation this packet is
- part of
- */
- conversation = find_conversation(&pinfo->src, &pinfo->dst,
- pinfo->ptype, pinfo->srcport, pinfo->destport, 0);
- if(conversation==NULL){
- /* OK this is a new conversation, we must create it
- and attach appropriate data (matched and unmatched
- table for this conversation)
- */
- conversation = conversation_new(&pinfo->src, &pinfo->dst,
- pinfo->ptype, pinfo->srcport, pinfo->destport, 0);
- ct = g_mem_chunk_alloc(conv_tables_chunk);
- ct->matched= g_hash_table_new(smb_saved_info_hash_matched,
- smb_saved_info_equal_matched);
- ct->unmatched= g_hash_table_new(smb_saved_info_hash_matched,
- smb_saved_info_equal_matched);
- conversation_add_proto_data(conversation, proto_smb, ct);
- } else {
- /* this is an old conversation, just get the tables */
- ct=conversation_get_proto_data(conversation, proto_smb);
- }
if(!pinfo->fd->flags.visited){
/* first see if we find an unmatched smb "equal" to
the current one
*/
- sip=g_hash_table_lookup(ct->unmatched, (void *)si.mid);
+ sip=g_hash_table_lookup(si.ct->unmatched, (void *)si.mid);
if(sip!=NULL){
if(si.request){
/* ok, we are processing an SMB
@@ -12950,7 +12978,7 @@ dissect_smb(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree)
request and concentrate on the
present one instead.
*/
- g_hash_table_remove(ct->unmatched, (void *)si.mid);
+ g_hash_table_remove(si.ct->unmatched, (void *)si.mid);
} else {
/* we have found a response to some request we have seen earlier.
What we do now depends on whether this is the first response
@@ -12959,13 +12987,13 @@ dissect_smb(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree)
if(sip->frame_res==0){
/* ok it is the first response we have seen to this packet */
sip->frame_res = pinfo->fd->num;
- g_hash_table_insert(ct->matched, (void *)sip->frame_req, sip);
- g_hash_table_insert(ct->matched, (void *)sip->frame_res, sip);
+ g_hash_table_insert(si.ct->matched, (void *)sip->frame_req, sip);
+ g_hash_table_insert(si.ct->matched, (void *)sip->frame_res, sip);
} else {
/* we have already seen another response to this one, but
register it anyway so we see which request it matches
*/
- g_hash_table_insert(ct->matched, (void *)pinfo->fd->num, sip);
+ g_hash_table_insert(si.ct->matched, (void *)pinfo->fd->num, sip);
}
}
}
@@ -12974,7 +13002,7 @@ dissect_smb(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree)
sip->frame_req = pinfo->fd->num;
sip->frame_res = 0;
sip->extra_info = NULL;
- g_hash_table_insert(ct->unmatched, (void *)si.mid, sip);
+ g_hash_table_insert(si.ct->unmatched, (void *)si.mid, sip);
}
} else {
/* we have seen this packet before; check the
@@ -12985,7 +13013,7 @@ dissect_smb(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree)
we've seen this packet before, we've already
saved the information.
*/
- sip=g_hash_table_lookup(ct->matched, (void *)pinfo->fd->num);
+ sip=g_hash_table_lookup(si.ct->matched, (void *)pinfo->fd->num);
}
}
@@ -14911,7 +14939,12 @@ proto_register_smb(void)
"Reassemble SMB Transaction payload",
"Whether the dissector should do reassembly the payload of SMB Transaction commands spanning multiple SMB PDUs",
&smb_trans_reassembly);
+ prefs_register_bool_preference(smb_module, "smb.dcerpc.reassembly",
+ "Reassemble DCERPC over SMB",
+ "Whether the dissector should do reassembly of DCERPC over SMB commands",
+ &smb_dcerpc_reassembly);
register_init_routine(smb_trans_reassembly_init);
+ register_init_routine(smb_dcerpc_reassembly_init);
}
void
diff --git a/packet-tcp.c b/packet-tcp.c
index 269ecf2b8b..566e69fcb7 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.120 2001/12/03 08:47:27 guy Exp $
+ * $Id: packet-tcp.c,v 1.121 2001/12/05 08:20:30 guy Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@ethereal.com>
@@ -539,6 +539,9 @@ desegment_tcp(tvbuff_t *tvb, packet_info *pinfo, int offset,
*/
call_dissector(data_handle,tvb_new_subset(tvb, deseg_offset,-1,tvb_reported_length_remaining(tvb,deseg_offset)), pinfo, tree);
}
+ pinfo->can_desegment=0;
+ pinfo->desegment_offset = 0;
+ pinfo->desegment_len = 0;
}
diff --git a/smb.h b/smb.h
index 1c6d8aeb87..56c90f12e7 100644
--- a/smb.h
+++ b/smb.h
@@ -2,7 +2,7 @@
* Defines for smb packet dissection
* Copyright 1999, Richard Sharpe <rsharpe@ns.aus.com>
*
- * $Id: smb.h,v 1.28 2001/12/05 00:49:32 guy Exp $
+ * $Id: smb.h,v 1.29 2001/12/05 08:20:30 guy Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@ethereal.com>
@@ -242,6 +242,15 @@ typedef struct {
#define TRANSACTION_PIPE 0
#define TRANSACTION_MAILSLOT 1
+/* this is the structure which is associated with each conversation */
+typedef struct conv_tables {
+ /* these two tables are used to match requests with responses */
+ GHashTable *unmatched;
+ GHashTable *matched;
+ /* this tables is used by DCERPC over SMB reassembly*/
+ GHashTable *dcerpc_fid_to_frame;
+} conv_tables_t;
+
typedef struct smb_info {
int cmd, mid;
gboolean unicode; /* Are strings in this SMB Unicode? */
@@ -250,6 +259,7 @@ typedef struct smb_info {
int info_level;
int info_count;
smb_saved_info_t *sip; /* smb_saved_info_t, if any, for this */
+ conv_tables_t *ct;
} smb_info_t;
/*
@@ -270,4 +280,7 @@ extern void add_fid(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
extern int dissect_ipc_state(tvbuff_t *tvb, packet_info *pinfo,
proto_tree *parent_tree, int offset, gboolean setstate);
+extern gboolean smb_dcerpc_reassembly;
+extern GHashTable *dcerpc_fragment_table;
+
#endif