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
This commit is contained in:
Ronnie Sahlberg 2005-11-07 20:32:27 +00:00
parent 262a414f41
commit 8012fd3cd9
1 changed files with 191 additions and 10 deletions

View File

@ -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 }},