From 8012fd3cd92d5a52a4c735c476c2481adca69f9b Mon Sep 17 00:00:00 2001 From: Ronnie Sahlberg Date: Mon, 7 Nov 2005 20:32:27 +0000 Subject: [PATCH] add request response matching so we can start passing info levels around from request to response and start dissecting some of the commands svn path=/trunk/; revision=16424 --- epan/dissectors/packet-smb2.c | 201 ++++++++++++++++++++++++++++++++-- 1 file changed, 191 insertions(+), 10 deletions(-) diff --git a/epan/dissectors/packet-smb2.c b/epan/dissectors/packet-smb2.c index 287c7bf5a2..555b2f19f2 100644 --- a/epan/dissectors/packet-smb2.c +++ b/epan/dissectors/packet-smb2.c @@ -42,6 +42,9 @@ static int proto_smb2 = -1; static int hf_smb2_cmd = -1; static int hf_smb2_nt_status = -1; +static int hf_smb2_response_to = -1; +static int hf_smb2_response_in = -1; +static int hf_smb2_time = -1; static int hf_smb2_header_len = -1; static int hf_smb2_seqnum = -1; static int hf_smb2_pid = -1; @@ -61,9 +64,70 @@ static gint ett_smb2_secblob = -1; static dissector_handle_t gssapi_handle = NULL; +typedef struct _smb2_saved_info_t { + guint64 seqnum; + gboolean response; /* is this a response ? */ + guint32 frame_req, frame_res; + nstime_t req_time; +} smb2_saved_info_t; + +/* structure to keep track of conversations and the hash tables. */ +typedef struct _smb2_info_t { + /* these two tables are used to match requests with responses */ + GHashTable *unmatched; + GHashTable *matched; +} smb2_info_t; + +/* unmatched smb_saved_info structures. + For unmatched smb_saved_info structures we store the smb_saved_info + structure using the SEQNUM field. +*/ +static gint +smb2_saved_info_equal_unmatched(gconstpointer k1, gconstpointer k2) +{ + smb2_saved_info_t *key1 = (smb2_saved_info_t *)k1; + smb2_saved_info_t *key2 = (smb2_saved_info_t *)k2; + return key1->seqnum==key2->seqnum; +} +static guint +smb2_saved_info_hash_unmatched(gconstpointer k) +{ + smb2_saved_info_t *key = (smb2_saved_info_t *)k; + guint32 hash; + + hash=key->seqnum&0xffffffff; + return hash; +} + +/* matched smb_saved_info structures. + For matched smb_saved_info structures we store the smb_saved_info + structure using the SEQNUM field. +*/ +static gint +smb2_saved_info_equal_matched(gconstpointer k1, gconstpointer k2) +{ + smb2_saved_info_t *key1 = (smb2_saved_info_t *)k1; + smb2_saved_info_t *key2 = (smb2_saved_info_t *)k2; + return key1->seqnum==key2->seqnum; +} +static guint +smb2_saved_info_hash_matched(gconstpointer k) +{ + smb2_saved_info_t *key = (smb2_saved_info_t *)k; + guint32 hash; + + hash=key->seqnum&0xffffffff; + return hash; +} + + + + + + typedef struct _smb2_function { - int (*request)(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset); - int (*response)(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset); + int (*request)(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, smb2_saved_info_t *ssi); + int (*response)(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, smb2_saved_info_t *ssi); } smb2_function; #define SMB2_FLAGS_RESPONSE 0x01 @@ -75,7 +139,7 @@ static const true_false_string tfs_flags_response = { static int -dissect_smb2_session_setup_request(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset) +dissect_smb2_session_setup_request(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, smb2_saved_info_t *ssi _U_) { proto_item *blob_item; proto_tree *blob_tree; @@ -103,7 +167,7 @@ dissect_smb2_session_setup_request(tvbuff_t *tvb, packet_info *pinfo, proto_tree } static int -dissect_smb2_session_setup_response(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset) +dissect_smb2_session_setup_response(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, smb2_saved_info_t *ssi _U_) { proto_item *blob_item; proto_tree *blob_tree; @@ -130,12 +194,24 @@ dissect_smb2_session_setup_response(tvbuff_t *tvb, packet_info *pinfo, proto_tre return offset; } +static int +dissect_smb2_tree_connect_request(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset, smb2_saved_info_t *ssi _U_) +{ + /* some unknown bytes */ + proto_tree_add_item(tree, hf_smb2_unknown, tvb, offset, 8, FALSE); + offset += 8; + +/*qqq*/ + return offset; +} + + /* names here are just until we find better names for these functions */ const value_string smb2_cmd_vals[] = { { 0x00, "NegotiateProtocol" }, { 0x01, "SessionSetupAndX" }, { 0x02, "unknown-0x02" }, - { 0x03, "TreeConnectAndX" }, + { 0x03, "TreeConnect" }, { 0x04, "TreeDisconnect" }, { 0x05, "Create" }, { 0x06, "Close" }, @@ -401,7 +477,9 @@ static smb2_function smb2_dissector[256] = { {dissect_smb2_session_setup_request, dissect_smb2_session_setup_response}, /* 0x02 */ {NULL, NULL}, - /* 0x03 */ {NULL, NULL}, + /* 0x03 TreeConnect*/ + {dissect_smb2_tree_connect_request, + NULL}, /* 0x04 */ {NULL, NULL}, /* 0x05 */ {NULL, NULL}, /* 0x06 */ {NULL, NULL}, @@ -658,9 +736,9 @@ static smb2_function smb2_dissector[256] = { static int -dissect_smb2_command(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, int offset, guint8 cmd, guint8 response) +dissect_smb2_command(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, int offset, guint8 cmd, guint8 response, smb2_saved_info_t *ssi) { - int (*cmd_dissector)(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset); + int (*cmd_dissector)(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, smb2_saved_info_t *ssi); proto_item *cmd_item; proto_tree *cmd_tree; @@ -677,7 +755,7 @@ dissect_smb2_command(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, int of smb2_dissector[cmd&0xff].response: smb2_dissector[cmd&0xff].request; if(cmd_dissector){ - offset=(*cmd_dissector)(tvb, pinfo, cmd_tree, offset); + offset=(*cmd_dissector)(tvb, pinfo, cmd_tree, offset, ssi); } else { proto_tree_add_item(cmd_tree, hf_smb2_unknown, tvb, offset, -1, FALSE); offset=tvb_length(tvb); @@ -698,6 +776,9 @@ dissect_smb2(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree) guint8 cmd, response; guint16 header_len; guint32 nt_status; + conversation_t *conversation; + smb2_info_t *si; + smb2_saved_info_t *ssi, ssi_key; if (check_col(pinfo->cinfo, COL_PROTOCOL)){ col_set_str(pinfo->cinfo, COL_PROTOCOL, "SMB2"); @@ -756,6 +837,7 @@ dissect_smb2(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree) offset += 7; /* command sequence number*/ + ssi_key.seqnum=tvb_get_letoh64(tvb, offset); proto_tree_add_item(header_tree, hf_smb2_seqnum, tvb, offset, 8, TRUE); offset += 8; @@ -799,8 +881,98 @@ dissect_smb2(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree) } } + + /* find which conversation we are part of and get the tables for that + * conversation + */ + conversation = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype, pinfo->srcport, pinfo->destport, 0); + if(!conversation){ + /* OK this is a new conversation so lets create it */ + conversation = conversation_new(pinfo->fd->num, &pinfo->src, &pinfo->dst, + pinfo->ptype, pinfo->srcport, pinfo->destport, 0); + } + si=conversation_get_proto_data(conversation, proto_smb2); + if(!si){ + /* no smb2_into_t structure for this conversation yet, + * create it. + */ + si=se_alloc(sizeof(smb2_info_t)); + /* qqq this leaks memory for now since we never free + the hashtables */ + si->matched= g_hash_table_new(smb2_saved_info_hash_matched, + smb2_saved_info_equal_matched); + si->unmatched= g_hash_table_new(smb2_saved_info_hash_unmatched, + smb2_saved_info_equal_unmatched); + + conversation_add_proto_data(conversation, proto_smb2, si); + } + if(!pinfo->fd->flags.visited){ + /* see if we can find this seqnum in the unmatched table */ + ssi=g_hash_table_lookup(si->unmatched, &ssi_key); + + if(!response){ + /* This is a request */ + if(ssi){ + /* this is a request and we already found + * an older ssi so just delete the previous + * one + */ + g_hash_table_remove(si->unmatched, ssi); + ssi=NULL; + } + + if(!ssi){ + /* no we couldnt find it, so just add it then + * if was a request we are decoding + */ + ssi=se_alloc(sizeof(smb2_saved_info_t)); + ssi->seqnum=ssi_key.seqnum; + ssi->frame_req=pinfo->fd->num; + ssi->frame_res=0; + ssi->req_time=pinfo->fd->abs_ts; + g_hash_table_insert(si->unmatched, ssi, ssi); + } + } else { + /* This is a response */ + if(ssi){ + /* just set the response frame and move it to the matched table */ + ssi->frame_res=pinfo->fd->num; + g_hash_table_remove(si->unmatched, ssi); + g_hash_table_insert(si->matched, ssi, ssi); + } + } + } else { + /* see if we can find this seqnum in the matched table */ + ssi=g_hash_table_lookup(si->matched, &ssi_key); + } + + if(ssi){ + if(!response){ + if(ssi->frame_res){ + proto_item *tmp_item; + tmp_item=proto_tree_add_uint(header_tree, hf_smb2_response_in, tvb, 0, 0, ssi->frame_res); + PROTO_ITEM_SET_GENERATED(tmp_item); + } + } else { + if(ssi->frame_req){ + proto_item *tmp_item; + nstime_t t, deltat; + + tmp_item=proto_tree_add_uint(header_tree, hf_smb2_response_to, tvb, 0, 0, ssi->frame_req); + PROTO_ITEM_SET_GENERATED(tmp_item); + t = pinfo->fd->abs_ts; + nstime_delta(&deltat, &t, &ssi->req_time); + tmp_item=proto_tree_add_time(header_tree, hf_smb2_time, tvb, + 0, 0, &deltat); + PROTO_ITEM_SET_GENERATED(tmp_item); + } + } + } + /* if we dont have ssi yet we must fake it */ + /*qqq*/ + /* Decode the payload */ - dissect_smb2_command(pinfo, tree, tvb, offset, cmd, response); + dissect_smb2_command(pinfo, tree, tvb, offset, cmd, response, ssi); } static gboolean @@ -828,6 +1000,15 @@ proto_register_smb2(void) { &hf_smb2_cmd, { "Command", "smb2.cmd", FT_UINT16, BASE_DEC, VALS(smb2_cmd_vals), 0, "SMB2 Command Opcode", HFILL }}, + { &hf_smb2_response_to, + { "Response to", "smb2.response_to", FT_FRAMENUM, BASE_NONE, + NULL, 0, "This packet is a response to the packet in this frame", HFILL }}, + { &hf_smb2_response_in, + { "Response in", "smb2.response_in", FT_FRAMENUM, BASE_NONE, + NULL, 0, "The response to this packet is in this packet", HFILL }}, + { &hf_smb2_time, + { "Time from request", "smb2.time", FT_RELATIVE_TIME, BASE_NONE, + NULL, 0, "Time between Request and Response for SMB2 cmds", HFILL }}, { &hf_smb2_header_len, { "Header Length", "smb2.header_len", FT_UINT16, BASE_DEC, NULL, 0, "SMB2 Size of Header", HFILL }},