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:
parent
262a414f41
commit
8012fd3cd9
|
@ -42,6 +42,9 @@
|
||||||
static int proto_smb2 = -1;
|
static int proto_smb2 = -1;
|
||||||
static int hf_smb2_cmd = -1;
|
static int hf_smb2_cmd = -1;
|
||||||
static int hf_smb2_nt_status = -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_header_len = -1;
|
||||||
static int hf_smb2_seqnum = -1;
|
static int hf_smb2_seqnum = -1;
|
||||||
static int hf_smb2_pid = -1;
|
static int hf_smb2_pid = -1;
|
||||||
|
@ -61,9 +64,70 @@ static gint ett_smb2_secblob = -1;
|
||||||
|
|
||||||
static dissector_handle_t gssapi_handle = NULL;
|
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 {
|
typedef struct _smb2_function {
|
||||||
int (*request)(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);
|
int (*response)(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, smb2_saved_info_t *ssi);
|
||||||
} smb2_function;
|
} smb2_function;
|
||||||
|
|
||||||
#define SMB2_FLAGS_RESPONSE 0x01
|
#define SMB2_FLAGS_RESPONSE 0x01
|
||||||
|
@ -75,7 +139,7 @@ static const true_false_string tfs_flags_response = {
|
||||||
|
|
||||||
|
|
||||||
static int
|
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_item *blob_item;
|
||||||
proto_tree *blob_tree;
|
proto_tree *blob_tree;
|
||||||
|
@ -103,7 +167,7 @@ dissect_smb2_session_setup_request(tvbuff_t *tvb, packet_info *pinfo, proto_tree
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
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_item *blob_item;
|
||||||
proto_tree *blob_tree;
|
proto_tree *blob_tree;
|
||||||
|
@ -130,12 +194,24 @@ dissect_smb2_session_setup_response(tvbuff_t *tvb, packet_info *pinfo, proto_tre
|
||||||
return offset;
|
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 */
|
/* names here are just until we find better names for these functions */
|
||||||
const value_string smb2_cmd_vals[] = {
|
const value_string smb2_cmd_vals[] = {
|
||||||
{ 0x00, "NegotiateProtocol" },
|
{ 0x00, "NegotiateProtocol" },
|
||||||
{ 0x01, "SessionSetupAndX" },
|
{ 0x01, "SessionSetupAndX" },
|
||||||
{ 0x02, "unknown-0x02" },
|
{ 0x02, "unknown-0x02" },
|
||||||
{ 0x03, "TreeConnectAndX" },
|
{ 0x03, "TreeConnect" },
|
||||||
{ 0x04, "TreeDisconnect" },
|
{ 0x04, "TreeDisconnect" },
|
||||||
{ 0x05, "Create" },
|
{ 0x05, "Create" },
|
||||||
{ 0x06, "Close" },
|
{ 0x06, "Close" },
|
||||||
|
@ -401,7 +477,9 @@ static smb2_function smb2_dissector[256] = {
|
||||||
{dissect_smb2_session_setup_request,
|
{dissect_smb2_session_setup_request,
|
||||||
dissect_smb2_session_setup_response},
|
dissect_smb2_session_setup_response},
|
||||||
/* 0x02 */ {NULL, NULL},
|
/* 0x02 */ {NULL, NULL},
|
||||||
/* 0x03 */ {NULL, NULL},
|
/* 0x03 TreeConnect*/
|
||||||
|
{dissect_smb2_tree_connect_request,
|
||||||
|
NULL},
|
||||||
/* 0x04 */ {NULL, NULL},
|
/* 0x04 */ {NULL, NULL},
|
||||||
/* 0x05 */ {NULL, NULL},
|
/* 0x05 */ {NULL, NULL},
|
||||||
/* 0x06 */ {NULL, NULL},
|
/* 0x06 */ {NULL, NULL},
|
||||||
|
@ -658,9 +736,9 @@ static smb2_function smb2_dissector[256] = {
|
||||||
|
|
||||||
|
|
||||||
static int
|
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_item *cmd_item;
|
||||||
proto_tree *cmd_tree;
|
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].response:
|
||||||
smb2_dissector[cmd&0xff].request;
|
smb2_dissector[cmd&0xff].request;
|
||||||
if(cmd_dissector){
|
if(cmd_dissector){
|
||||||
offset=(*cmd_dissector)(tvb, pinfo, cmd_tree, offset);
|
offset=(*cmd_dissector)(tvb, pinfo, cmd_tree, offset, ssi);
|
||||||
} else {
|
} else {
|
||||||
proto_tree_add_item(cmd_tree, hf_smb2_unknown, tvb, offset, -1, FALSE);
|
proto_tree_add_item(cmd_tree, hf_smb2_unknown, tvb, offset, -1, FALSE);
|
||||||
offset=tvb_length(tvb);
|
offset=tvb_length(tvb);
|
||||||
|
@ -698,6 +776,9 @@ dissect_smb2(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree)
|
||||||
guint8 cmd, response;
|
guint8 cmd, response;
|
||||||
guint16 header_len;
|
guint16 header_len;
|
||||||
guint32 nt_status;
|
guint32 nt_status;
|
||||||
|
conversation_t *conversation;
|
||||||
|
smb2_info_t *si;
|
||||||
|
smb2_saved_info_t *ssi, ssi_key;
|
||||||
|
|
||||||
if (check_col(pinfo->cinfo, COL_PROTOCOL)){
|
if (check_col(pinfo->cinfo, COL_PROTOCOL)){
|
||||||
col_set_str(pinfo->cinfo, COL_PROTOCOL, "SMB2");
|
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;
|
offset += 7;
|
||||||
|
|
||||||
/* command sequence number*/
|
/* command sequence number*/
|
||||||
|
ssi_key.seqnum=tvb_get_letoh64(tvb, offset);
|
||||||
proto_tree_add_item(header_tree, hf_smb2_seqnum, tvb, offset, 8, TRUE);
|
proto_tree_add_item(header_tree, hf_smb2_seqnum, tvb, offset, 8, TRUE);
|
||||||
offset += 8;
|
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 */
|
/* Decode the payload */
|
||||||
dissect_smb2_command(pinfo, tree, tvb, offset, cmd, response);
|
dissect_smb2_command(pinfo, tree, tvb, offset, cmd, response, ssi);
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
|
@ -828,6 +1000,15 @@ proto_register_smb2(void)
|
||||||
{ &hf_smb2_cmd,
|
{ &hf_smb2_cmd,
|
||||||
{ "Command", "smb2.cmd", FT_UINT16, BASE_DEC,
|
{ "Command", "smb2.cmd", FT_UINT16, BASE_DEC,
|
||||||
VALS(smb2_cmd_vals), 0, "SMB2 Command Opcode", HFILL }},
|
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,
|
{ &hf_smb2_header_len,
|
||||||
{ "Header Length", "smb2.header_len", FT_UINT16, BASE_DEC,
|
{ "Header Length", "smb2.header_len", FT_UINT16, BASE_DEC,
|
||||||
NULL, 0, "SMB2 Size of Header", HFILL }},
|
NULL, 0, "SMB2 Size of Header", HFILL }},
|
||||||
|
|
Loading…
Reference in New Issue