diff options
author | sahlberg <sahlberg@f5534014-38df-0310-8fa8-9805f1628bb7> | 2004-06-24 07:43:24 +0000 |
---|---|---|
committer | sahlberg <sahlberg@f5534014-38df-0310-8fa8-9805f1628bb7> | 2004-06-24 07:43:24 +0000 |
commit | d9b0accf89576c16e407fecdc54f77d6495b847c (patch) | |
tree | 1ff704569c8b16cfd4efb98028dc4b9d1e17d56c | |
parent | 4c786f2f0ebd8ddaf5f5d2b4292e7ba95ab6734f (diff) |
from todd s
update to reassembly of dg style dcerpc
git-svn-id: http://anonsvn.wireshark.org/wireshark/trunk@11227 f5534014-38df-0310-8fa8-9805f1628bb7
-rw-r--r-- | packet-dcerpc.c | 140 | ||||
-rw-r--r-- | reassemble.c | 143 | ||||
-rw-r--r-- | reassemble.h | 9 |
3 files changed, 239 insertions, 53 deletions
diff --git a/packet-dcerpc.c b/packet-dcerpc.c index 6005a3b158..8c27532a1b 100644 --- a/packet-dcerpc.c +++ b/packet-dcerpc.c @@ -3,7 +3,7 @@ * Copyright 2001, Todd Sabin <tas@webspan.net> * Copyright 2003, Tim Potter <tpot@samba.org> * - * $Id: packet-dcerpc.c,v 1.179 2004/06/09 09:24:06 sahlberg Exp $ + * $Id: packet-dcerpc.c,v 1.180 2004/06/24 07:43:24 sahlberg Exp $ * * Ethereal - Network traffic analyzer * By Gerald Combs <gerald@ethereal.com> @@ -489,7 +489,7 @@ static void dcerpc_reassemble_init(void) { fragment_table_init(&dcerpc_co_reassemble_table); - fragment_table_init(&dcerpc_cl_reassemble_table); + dcerpc_fragment_table_init(&dcerpc_cl_reassemble_table); } /* @@ -782,35 +782,66 @@ dcerpc_bind_hash (gconstpointer k) * To keep track of callid mappings. Should really use some generic * conversation support instead. */ -static GHashTable *dcerpc_calls=NULL; +static GHashTable *dcerpc_cn_calls=NULL; +static GHashTable *dcerpc_dg_calls=NULL; -typedef struct _dcerpc_call_key { +typedef struct _dcerpc_cn_call_key { conversation_t *conv; guint32 call_id; guint16 smb_fid; -} dcerpc_call_key; +} dcerpc_cn_call_key; -static GMemChunk *dcerpc_call_key_chunk=NULL; +typedef struct _dcerpc_dg_call_key { + conversation_t *conv; + guint32 seqnum; + e_uuid_t act_id ; +} dcerpc_dg_call_key; + +static GMemChunk *dcerpc_cn_call_key_chunk=NULL; + +static GMemChunk *dcerpc_dg_call_key_chunk=NULL; static GMemChunk *dcerpc_call_value_chunk=NULL; + static gint -dcerpc_call_equal (gconstpointer k1, gconstpointer k2) +dcerpc_cn_call_equal (gconstpointer k1, gconstpointer k2) { - const dcerpc_call_key *key1 = (const dcerpc_call_key *)k1; - const dcerpc_call_key *key2 = (const dcerpc_call_key *)k2; + const dcerpc_cn_call_key *key1 = (const dcerpc_cn_call_key *)k1; + const dcerpc_cn_call_key *key2 = (const dcerpc_cn_call_key *)k2; return (key1->conv == key2->conv && key1->call_id == key2->call_id && key1->smb_fid == key2->smb_fid); } +static gint +dcerpc_dg_call_equal (gconstpointer k1, gconstpointer k2) +{ + const dcerpc_dg_call_key *key1 = (const dcerpc_dg_call_key *)k1; + const dcerpc_dg_call_key *key2 = (const dcerpc_dg_call_key *)k2; + return (key1->conv == key2->conv + && key1->seqnum == key2->seqnum + && (memcmp (&key1->act_id, &key2->act_id, sizeof (e_uuid_t)) == 0)); +} + static guint -dcerpc_call_hash (gconstpointer k) +dcerpc_cn_call_hash (gconstpointer k) { - const dcerpc_call_key *key = (const dcerpc_call_key *)k; + const dcerpc_cn_call_key *key = (const dcerpc_cn_call_key *)k; return ((guint32)key->conv) + key->call_id + key->smb_fid; } +static guint +dcerpc_dg_call_hash (gconstpointer k) +{ + const dcerpc_dg_call_key *key = (const dcerpc_dg_call_key *)k; + return (((guint32)key->conv) + key->seqnum + key->act_id.Data1 + + (key->act_id.Data2 << 16) + key->act_id.Data3 + + (key->act_id.Data4[0] << 24) + (key->act_id.Data4[1] << 16) + + (key->act_id.Data4[2] << 8) + (key->act_id.Data4[3] << 0) + + (key->act_id.Data4[4] << 24) + (key->act_id.Data4[5] << 16) + + (key->act_id.Data4[6] << 8) + (key->act_id.Data4[7] << 0)); +} /* to keep track of matched calls/responses this one uses the same value struct as calls, but the key is the frame id @@ -2846,20 +2877,20 @@ dissect_dcerpc_cn_rqst (tvbuff_t *tvb, gint offset, packet_info *pinfo, if((bind_value=g_hash_table_lookup(dcerpc_binds, &bind_key)) ){ if(!(hdr->flags&PFC_FIRST_FRAG)){ - dcerpc_call_key call_key; + dcerpc_cn_call_key call_key; dcerpc_call_value *call_value; call_key.conv=conv; call_key.call_id=hdr->call_id; call_key.smb_fid=get_transport_salt(pinfo, transport_type); - if((call_value=g_hash_table_lookup(dcerpc_calls, &call_key))){ + if((call_value=g_hash_table_lookup(dcerpc_cn_calls, &call_key))){ new_matched_key = g_mem_chunk_alloc(dcerpc_matched_key_chunk); *new_matched_key = matched_key; g_hash_table_insert (dcerpc_matched, new_matched_key, call_value); value = call_value; } } else { - dcerpc_call_key *call_key; + dcerpc_cn_call_key *call_key; dcerpc_call_value *call_value; /* We found the binding and it is the first fragment @@ -2867,15 +2898,15 @@ dissect_dcerpc_cn_rqst (tvbuff_t *tvb, gint offset, packet_info *pinfo, the call to both the call table and the matched table */ - call_key=g_mem_chunk_alloc (dcerpc_call_key_chunk); + call_key=g_mem_chunk_alloc (dcerpc_cn_call_key_chunk); call_key->conv=conv; call_key->call_id=hdr->call_id; call_key->smb_fid=get_transport_salt(pinfo, transport_type); /* if there is already a matching call in the table remove it so it is replaced with the new one */ - if(g_hash_table_lookup(dcerpc_calls, call_key)){ - g_hash_table_remove(dcerpc_calls, call_key); + if(g_hash_table_lookup(dcerpc_cn_calls, call_key)){ + g_hash_table_remove(dcerpc_cn_calls, call_key); } call_value=g_mem_chunk_alloc (dcerpc_call_value_chunk); @@ -2888,7 +2919,7 @@ dissect_dcerpc_cn_rqst (tvbuff_t *tvb, gint offset, packet_info *pinfo, call_value->rep_frame=0; call_value->max_ptr=0; call_value->private_data = NULL; - g_hash_table_insert (dcerpc_calls, call_key, call_value); + g_hash_table_insert (dcerpc_cn_calls, call_key, call_value); new_matched_key = g_mem_chunk_alloc(dcerpc_matched_key_chunk); *new_matched_key = matched_key; @@ -2976,14 +3007,14 @@ dissect_dcerpc_cn_resp (tvbuff_t *tvb, gint offset, packet_info *pinfo, matched_key.call_id = hdr->call_id; value=g_hash_table_lookup(dcerpc_matched, &matched_key); if(!value){ - dcerpc_call_key call_key; + dcerpc_cn_call_key call_key; dcerpc_call_value *call_value; call_key.conv=conv; call_key.call_id=hdr->call_id; call_key.smb_fid=get_transport_salt(pinfo, transport_type); - if((call_value=g_hash_table_lookup(dcerpc_calls, &call_key))){ + if((call_value=g_hash_table_lookup(dcerpc_cn_calls, &call_key))){ new_matched_key = g_mem_chunk_alloc(dcerpc_matched_key_chunk); *new_matched_key = matched_key; g_hash_table_insert (dcerpc_matched, new_matched_key, call_value); @@ -3088,14 +3119,14 @@ dissect_dcerpc_cn_fault (tvbuff_t *tvb, gint offset, packet_info *pinfo, matched_key.call_id = hdr->call_id; value=g_hash_table_lookup(dcerpc_matched, &matched_key); if(!value){ - dcerpc_call_key call_key; + dcerpc_cn_call_key call_key; dcerpc_call_value *call_value; call_key.conv=conv; call_key.call_id=hdr->call_id; call_key.smb_fid=get_transport_salt(pinfo, transport_type); - if((call_value=g_hash_table_lookup(dcerpc_calls, &call_key))){ + if((call_value=g_hash_table_lookup(dcerpc_cn_calls, &call_key))){ new_matched_key = g_mem_chunk_alloc(dcerpc_matched_key_chunk); *new_matched_key = matched_key; g_hash_table_insert (dcerpc_matched, new_matched_key, call_value); @@ -3836,10 +3867,8 @@ dissect_dcerpc_dg_stub (tvbuff_t *tvb, int offset, packet_info *pinfo, } } - fd_head = fragment_add_seq(tvb, offset, pinfo, - /* XXX - simply adding the activity id to the sequence number might be unique enough - * to build a meaningful hash value here?! */ - hdr->seqnum + dcerpc_uuid_hash(&hdr->act_id), dcerpc_cl_reassemble_table, + fd_head = fragment_add_dcerpc(tvb, offset, pinfo, + hdr->seqnum, &hdr->act_id, dcerpc_cl_reassemble_table, hdr->frag_num, stub_length, !(hdr->flags1 & PFCL1_LASTFRAG)); if (fd_head != NULL) { @@ -3881,8 +3910,7 @@ dissect_dcerpc_dg_stub (tvbuff_t *tvb, int offset, packet_info *pinfo, static void dissect_dcerpc_dg_rqst (tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *dcerpc_tree, proto_tree *tree, - e_dce_dg_common_hdr_t *hdr, conversation_t *conv, - int transport_type) + e_dce_dg_common_hdr_t *hdr, conversation_t *conv) { dcerpc_info *di; dcerpc_call_value *value, v; @@ -3892,12 +3920,12 @@ dissect_dcerpc_dg_rqst (tvbuff_t *tvb, int offset, packet_info *pinfo, di=get_next_di(); if(!(pinfo->fd->flags.visited)){ dcerpc_call_value *call_value; - dcerpc_call_key *call_key; + dcerpc_dg_call_key *call_key; - call_key=g_mem_chunk_alloc (dcerpc_call_key_chunk); + call_key=g_mem_chunk_alloc (dcerpc_dg_call_key_chunk); call_key->conv=conv; - call_key->call_id=hdr->seqnum; - call_key->smb_fid=get_transport_salt(pinfo, transport_type); + call_key->seqnum=hdr->seqnum; + call_key->act_id=hdr->act_id; call_value=g_mem_chunk_alloc (dcerpc_call_value_chunk); call_value->uuid = hdr->if_id; @@ -3909,7 +3937,7 @@ dissect_dcerpc_dg_rqst (tvbuff_t *tvb, int offset, packet_info *pinfo, call_value->rep_frame=0; call_value->max_ptr=0; call_value->private_data = NULL; - g_hash_table_insert (dcerpc_calls, call_key, call_value); + g_hash_table_insert (dcerpc_dg_calls, call_key, call_value); new_matched_key = g_mem_chunk_alloc(dcerpc_matched_key_chunk); new_matched_key->frame = pinfo->fd->num; @@ -3948,8 +3976,7 @@ dissect_dcerpc_dg_rqst (tvbuff_t *tvb, int offset, packet_info *pinfo, static void dissect_dcerpc_dg_resp (tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *dcerpc_tree, proto_tree *tree, - e_dce_dg_common_hdr_t *hdr, conversation_t *conv, - int transport_type) + e_dce_dg_common_hdr_t *hdr, conversation_t *conv) { dcerpc_info *di; dcerpc_call_value *value, v; @@ -3959,13 +3986,13 @@ dissect_dcerpc_dg_resp (tvbuff_t *tvb, int offset, packet_info *pinfo, di=get_next_di(); if(!(pinfo->fd->flags.visited)){ dcerpc_call_value *call_value; - dcerpc_call_key call_key; + dcerpc_dg_call_key call_key; call_key.conv=conv; - call_key.call_id=hdr->seqnum; - call_key.smb_fid=get_transport_salt(pinfo, transport_type); + call_key.seqnum=hdr->seqnum; + call_key.act_id=hdr->act_id; - if((call_value=g_hash_table_lookup(dcerpc_calls, &call_key))){ + if((call_value=g_hash_table_lookup(dcerpc_dg_calls, &call_key))){ new_matched_key = g_mem_chunk_alloc(dcerpc_matched_key_chunk); new_matched_key->frame = pinfo->fd->num; new_matched_key->call_id = hdr->seqnum; @@ -4030,7 +4057,6 @@ dissect_dcerpc_dg (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) int auth_level; char uuid_str[DCERPC_UUID_STR_LEN]; int uuid_str_len; - int transport_type=DCE_TRANSPORT_UNKNOWN; /* * Check if this looks like a CL DCERPC call. All dg packets @@ -4343,11 +4369,11 @@ dissect_dcerpc_dg (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) break; case PDU_REQ: - dissect_dcerpc_dg_rqst (tvb, offset, pinfo, dcerpc_tree, tree, &hdr, conv, transport_type); + dissect_dcerpc_dg_rqst (tvb, offset, pinfo, dcerpc_tree, tree, &hdr, conv); break; case PDU_RESP: - dissect_dcerpc_dg_resp (tvb, offset, pinfo, dcerpc_tree, tree, &hdr, conv, transport_type); + dissect_dcerpc_dg_resp (tvb, offset, pinfo, dcerpc_tree, tree, &hdr, conv); break; /* these requests have no body */ @@ -4385,17 +4411,29 @@ dcerpc_init_protocol (void) 200 * sizeof (dcerpc_bind_value), G_ALLOC_ONLY); /* structures and data for CALL */ - if (dcerpc_calls){ - g_hash_table_destroy (dcerpc_calls); + if (dcerpc_cn_calls){ + g_hash_table_destroy (dcerpc_cn_calls); } - dcerpc_calls = g_hash_table_new (dcerpc_call_hash, dcerpc_call_equal); - if (dcerpc_call_key_chunk){ - g_mem_chunk_destroy (dcerpc_call_key_chunk); + dcerpc_cn_calls = g_hash_table_new (dcerpc_cn_call_hash, dcerpc_cn_call_equal); + if (dcerpc_dg_calls){ + g_hash_table_destroy (dcerpc_dg_calls); } - dcerpc_call_key_chunk = g_mem_chunk_new ("dcerpc_call_key_chunk", - sizeof (dcerpc_call_key), - 200 * sizeof (dcerpc_call_key), - G_ALLOC_ONLY); + dcerpc_dg_calls = g_hash_table_new (dcerpc_dg_call_hash, dcerpc_dg_call_equal); + if (dcerpc_cn_call_key_chunk){ + g_mem_chunk_destroy (dcerpc_cn_call_key_chunk); + } + dcerpc_cn_call_key_chunk = g_mem_chunk_new ("dcerpc_cn_call_key_chunk", + sizeof (dcerpc_cn_call_key), + 200 * sizeof (dcerpc_cn_call_key), + G_ALLOC_ONLY); + if (dcerpc_dg_call_key_chunk){ + g_mem_chunk_destroy (dcerpc_dg_call_key_chunk); + } + dcerpc_dg_call_key_chunk = g_mem_chunk_new ("dcerpc_dg_call_key_chunk", + sizeof (dcerpc_dg_call_key), + 200 * sizeof (dcerpc_dg_call_key), + G_ALLOC_ONLY); + if (dcerpc_call_value_chunk){ g_mem_chunk_destroy (dcerpc_call_value_chunk); } diff --git a/reassemble.c b/reassemble.c index 43a2c5c52e..84954f9db7 100644 --- a/reassemble.c +++ b/reassemble.c @@ -1,7 +1,7 @@ /* reassemble.c * Routines for {fragment,segment} reassembly * - * $Id: reassemble.c,v 1.49 2004/06/20 19:20:55 guy Exp $ + * $Id: reassemble.c,v 1.50 2004/06/24 07:43:24 sahlberg Exp $ * * Ethereal - Network traffic analyzer * By Gerald Combs <gerald@ethereal.com> @@ -32,6 +32,7 @@ #include "reassemble.h" +#include "packet-dcerpc.h" typedef struct _fragment_key { address src; @@ -39,7 +40,15 @@ typedef struct _fragment_key { guint32 id; } fragment_key; +typedef struct _dcerpc_fragment_key { + address src; + address dst; + guint32 id; + e_uuid_t act_id; +} dcerpc_fragment_key; + static GMemChunk *fragment_key_chunk = NULL; +static GMemChunk *dcerpc_fragment_key_chunk = NULL; static GMemChunk *fragment_data_chunk = NULL; static int fragment_init_count = 200; @@ -97,6 +106,39 @@ fragment_hash(gconstpointer k) return hash_val; } +static gint +dcerpc_fragment_equal(gconstpointer k1, gconstpointer k2) +{ + const dcerpc_fragment_key* key1 = (const dcerpc_fragment_key*) k1; + const dcerpc_fragment_key* key2 = (const dcerpc_fragment_key*) k2; + + /*key.id is the first item to compare since item is most + likely to differ between sessions, thus shortcircuiting + the comparasion of addresses. + */ + return (((key1->id == key2->id) + && (ADDRESSES_EQUAL(&key1->src, &key2->src)) + && (ADDRESSES_EQUAL(&key1->dst, &key2->dst)) + && (memcmp (&key1->act_id, &key2->act_id, sizeof (e_uuid_t)) == 0)) + ? TRUE : FALSE); +} + +static guint +dcerpc_fragment_hash(gconstpointer k) +{ + const dcerpc_fragment_key* key = (const dcerpc_fragment_key*) k; + guint hash_val; + + hash_val = 0; + + hash_val += key->id; + hash_val += key->act_id.Data1; + hash_val += key->act_id.Data2 << 16; + hash_val += key->act_id.Data3; + + return hash_val; +} + typedef struct _reassembled_key { guint32 id; guint32 frame; @@ -214,6 +256,26 @@ fragment_table_init(GHashTable **fragment_table) } } +void +dcerpc_fragment_table_init(GHashTable **fragment_table) +{ + if (*fragment_table != NULL) { + /* + * The fragment hash table exists. + * + * Remove all entries and free fragment data for + * each entry. (The key and value data is freed + * by "reassemble_init()".) + */ + g_hash_table_foreach_remove(*fragment_table, + free_all_fragments, NULL); + } else { + /* The fragment table does not exist. Create it */ + *fragment_table = g_hash_table_new(dcerpc_fragment_hash, + dcerpc_fragment_equal); + } +} + /* * Initialize a reassembled-packet table. */ @@ -246,6 +308,8 @@ reassemble_init(void) { if (fragment_key_chunk != NULL) g_mem_chunk_destroy(fragment_key_chunk); + if (dcerpc_fragment_key_chunk != NULL) + g_mem_chunk_destroy(fragment_key_chunk); if (fragment_data_chunk != NULL) g_mem_chunk_destroy(fragment_data_chunk); if (reassembled_key_chunk != NULL) @@ -254,6 +318,10 @@ reassemble_init(void) sizeof(fragment_key), fragment_init_count * sizeof(fragment_key), G_ALLOC_AND_FREE); + dcerpc_fragment_key_chunk = g_mem_chunk_new("dcerpc_fragment_key_chunk", + sizeof(dcerpc_fragment_key), + fragment_init_count * sizeof(dcerpc_fragment_key), + G_ALLOC_AND_FREE); fragment_data_chunk = g_mem_chunk_new("fragment_data_chunk", sizeof(fragment_data), fragment_init_count * sizeof(fragment_data), @@ -1221,6 +1289,79 @@ fragment_add_seq(tvbuff_t *tvb, int offset, packet_info *pinfo, guint32 id, } } +fragment_data * +fragment_add_dcerpc(tvbuff_t *tvb, int offset, packet_info *pinfo, guint32 id, + void *v_act_id, + GHashTable *fragment_table, guint32 frag_number, + guint32 frag_data_len, gboolean more_frags) +{ + dcerpc_fragment_key key, *new_key; + fragment_data *fd_head; + e_uuid_t *act_id = (e_uuid_t *)v_act_id; + + /* create key to search hash with */ + key.src = pinfo->src; + key.dst = pinfo->dst; + key.id = id; + key.act_id = *act_id; + + fd_head = g_hash_table_lookup(fragment_table, &key); + + /* have we already seen this frame ?*/ + if (pinfo->fd->flags.visited) { + if (fd_head != NULL && fd_head->flags & FD_DEFRAGMENTED) { + return fd_head; + } else { + return NULL; + } + } + + if (fd_head==NULL){ + /* not found, this must be the first snooped fragment for this + * packet. Create list-head. + */ + fd_head=g_mem_chunk_alloc(fragment_data_chunk); + + /* head/first structure in list only holds no other data than + * 'datalen' then we don't have to change the head of the list + * even if we want to keep it sorted + */ + fd_head->next=NULL; + fd_head->datalen=0; + fd_head->offset=0; + fd_head->len=0; + fd_head->flags=FD_BLOCKSEQUENCE; + fd_head->data=NULL; + fd_head->reassembled_in=0; + + /* + * We're going to use the key to insert the fragment, + * so allocate a structure for it, and copy the + * addresses, allocating new buffers for the address + * data. + */ + new_key = g_mem_chunk_alloc(dcerpc_fragment_key_chunk); + COPY_ADDRESS(&new_key->src, &key.src); + COPY_ADDRESS(&new_key->dst, &key.dst); + new_key->id = key.id; + new_key->act_id = key.act_id; + g_hash_table_insert(fragment_table, new_key, fd_head); + } + + if (fragment_add_seq_work(fd_head, tvb, offset, pinfo, + frag_number, frag_data_len, more_frags)) { + /* + * Reassembly is complete. + */ + return fd_head; + } else { + /* + * Reassembly isn't complete. + */ + return NULL; + } +} + /* * This does the work for "fragment_add_seq_check()" and * "fragment_add_seq_next()". diff --git a/reassemble.h b/reassemble.h index 7e836f4df1..58ffcf5ce8 100644 --- a/reassemble.h +++ b/reassemble.h @@ -1,7 +1,7 @@ /* reassemble.h * Declarations of outines for {fragment,segment} reassembly * - * $Id: reassemble.h,v 1.21 2003/12/20 03:21:20 guy Exp $ + * $Id: reassemble.h,v 1.22 2004/06/24 07:43:24 sahlberg Exp $ * * Ethereal - Network traffic analyzer * By Gerald Combs <gerald@ethereal.com> @@ -68,6 +68,7 @@ typedef struct _fragment_data { * Initialize a fragment table. */ extern void fragment_table_init(GHashTable **fragment_table); +extern void dcerpc_fragment_table_init(GHashTable **fragment_table); /* * Initialize a reassembled-packet table. @@ -108,6 +109,12 @@ extern fragment_data *fragment_add_seq(tvbuff_t *tvb, int offset, packet_info *p guint32 id, GHashTable *fragment_table, guint32 frag_number, guint32 frag_data_len, gboolean more_frags); +extern fragment_data * +fragment_add_dcerpc(tvbuff_t *tvb, int offset, packet_info *pinfo, guint32 id, + void *act_id, + GHashTable *fragment_table, guint32 frag_number, + guint32 frag_data_len, gboolean more_frags); + /* * These functions add a new fragment to the fragment hash table. * If this is the first fragment seen for this datagram, a new |