Keep track of transaction replies that have continuations, and associate
continuations with the message to which they're a continuation. svn path=/trunk/; revision=3834
This commit is contained in:
parent
a588428c1b
commit
a739061860
|
@ -1,5 +1,4 @@
|
|||
/*
|
||||
XXX Fixme : continuation stuff removed, should be solved by smb reassembly
|
||||
XXX Fixme : shouldnt show [malformed frame] for long packets
|
||||
*/
|
||||
|
||||
|
@ -9,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.28 2001/08/07 08:39:56 guy Exp $
|
||||
* $Id: packet-smb-pipe.c,v 1.29 2001/08/11 07:26:24 guy Exp $
|
||||
*
|
||||
* Ethereal - Network traffic analyzer
|
||||
* By Gerald Combs <gerald@ethereal.com>
|
||||
|
@ -64,6 +63,7 @@ static int hf_not_implemented = -1;
|
|||
static int hf_detail_level = -1;
|
||||
static int hf_recv_buf_len = -1;
|
||||
static int hf_response_to = -1;
|
||||
static int hf_continuation_from = -1;
|
||||
static int hf_status = -1;
|
||||
static int hf_convert = -1;
|
||||
static int hf_ecount = -1;
|
||||
|
@ -1396,11 +1396,30 @@ dissect_pipe_lanman(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree)
|
|||
tree = proto_item_add_subtree(item, ett_lanman);
|
||||
}
|
||||
|
||||
/* continuation messages, dont try to decode them */
|
||||
/*
|
||||
* Don't try to decode continuation messages.
|
||||
*
|
||||
* XXX - at some point, we will probably be handed tvbuffs
|
||||
* for the parameters of the first message and for the
|
||||
* reassembled contents of the data of the first message
|
||||
* and all the continuations, and should dissect it.
|
||||
*
|
||||
* Transaction reassembly may, however, be an option, so that if
|
||||
* we don't *have* all the reply messages, you at least can
|
||||
* see what you have, by turning the option off. (We don't know
|
||||
* that we don't have them until we get to the end of the capture,
|
||||
* but, by that time, it may be too late to dissect what we have;
|
||||
* in Tethereal, for example, there's no going back....)
|
||||
*/
|
||||
if (smb_info->ddisp) {
|
||||
if (check_col(pinfo->fd, COL_INFO)) {
|
||||
col_set_str(pinfo->fd, COL_INFO, "Transact Continuation");
|
||||
}
|
||||
if (smb_info->continuation_val != NULL) {
|
||||
/* continuation from the message in frame xx */
|
||||
proto_tree_add_uint(tree, hf_continuation_from, tvb,
|
||||
0, 0, smb_info->continuation_val->frame);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
@ -1571,7 +1590,11 @@ register_proto_smb_pipe(void)
|
|||
|
||||
{ &hf_response_to,
|
||||
{ "Response to request in frame", "lanman.response_to", FT_UINT32, BASE_DEC,
|
||||
NULL, 0, "This is a LANMAN response to the request in frame", HFILL }},
|
||||
NULL, 0, "This is a LANMAN response to the request in the frame in question", HFILL }},
|
||||
|
||||
{ &hf_continuation_from,
|
||||
{ "Continuation from message in frame", "lanman.continuation_from", FT_UINT32, BASE_DEC,
|
||||
NULL, 0, "This is a LANMAN continuation from the message in the frame in question", HFILL }},
|
||||
|
||||
{ &hf_status,
|
||||
{ "Status", "lanman.status", FT_UINT16, BASE_DEC,
|
||||
|
|
229
packet-smb.c
229
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.97 2001/08/07 08:39:56 guy Exp $
|
||||
* $Id: packet-smb.c,v 1.98 2001/08/11 07:26:25 guy Exp $
|
||||
*
|
||||
* Ethereal - Network traffic analyzer
|
||||
* By Gerald Combs <gerald@ethereal.com>
|
||||
|
@ -85,6 +85,8 @@ char *decode_smb_name(unsigned char);
|
|||
int smb_packet_init_count = 200;
|
||||
|
||||
/*
|
||||
* This is a hash table matching transaction requests and replies.
|
||||
*
|
||||
* Unfortunately, the MID is not a transaction ID in, say, the ONC RPC
|
||||
* sense; instead, it's a "multiplex ID" used when there's more than one
|
||||
* request *currently* in flight, to distinguish replies.
|
||||
|
@ -135,6 +137,16 @@ static GHashTable *smb_request_hash = NULL;
|
|||
static GMemChunk *smb_request_keys = NULL;
|
||||
static GMemChunk *smb_request_vals = NULL;
|
||||
|
||||
/*
|
||||
* This is a hash table matching continued transation replies and their
|
||||
* continuations.
|
||||
*
|
||||
* It works similarly to the request/reply hash table.
|
||||
*/
|
||||
static GHashTable *smb_continuation_hash = NULL;
|
||||
|
||||
static GMemChunk *smb_continuation_vals = NULL;
|
||||
|
||||
/* Hash Functions */
|
||||
static gint
|
||||
smb_equal(gconstpointer v, gconstpointer w)
|
||||
|
@ -248,26 +260,26 @@ do_transaction_hashing(conversation_t *conversation, struct smb_info si,
|
|||
|
||||
g_hash_table_insert(smb_request_hash, new_request_key, request_val);
|
||||
} else {
|
||||
/*
|
||||
* This means that we've seen another request in this conversation
|
||||
* with the same request and reply, and without an intervening
|
||||
* reply to that first request, and thus won't be using this
|
||||
* "request_val" structure for that request (as we'd use it only
|
||||
* for the reply).
|
||||
*
|
||||
* Clean out the structure, and set it to refer to this frame.
|
||||
*/
|
||||
request_val -> frame = fd->num;
|
||||
/*
|
||||
* This means that we've seen another request in this conversation
|
||||
* with the same request and reply, and without an intervening
|
||||
* reply to that first request, and thus won't be using this
|
||||
* "request_val" structure for that request (as we'd use it only
|
||||
* for the reply).
|
||||
*
|
||||
* Clean out the structure, and set it to refer to this frame.
|
||||
*/
|
||||
request_val -> frame = fd->num;
|
||||
request_val -> last_transact2_command = -1; /* unknown */
|
||||
if (request_val -> last_transact_command)
|
||||
g_free(request_val -> last_transact_command);
|
||||
request_val -> last_transact_command = NULL;
|
||||
if (request_val -> last_param_descrip)
|
||||
g_free(request_val -> last_param_descrip);
|
||||
request_val -> last_param_descrip = NULL;
|
||||
if (request_val -> last_data_descrip)
|
||||
g_free(request_val -> last_data_descrip);
|
||||
request_val -> last_data_descrip = NULL;
|
||||
if (request_val -> last_transact_command)
|
||||
g_free(request_val -> last_transact_command);
|
||||
request_val -> last_transact_command = NULL;
|
||||
if (request_val -> last_param_descrip)
|
||||
g_free(request_val -> last_param_descrip);
|
||||
request_val -> last_param_descrip = NULL;
|
||||
if (request_val -> last_data_descrip)
|
||||
g_free(request_val -> last_data_descrip);
|
||||
request_val -> last_data_descrip = NULL;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -280,7 +292,8 @@ do_transaction_hashing(conversation_t *conversation, struct smb_info si,
|
|||
* an entry for a matching request, with an unknown reply frame
|
||||
* number, in the hash table.
|
||||
*
|
||||
* If we find it, re-hash it with this frame's reply number.
|
||||
* If we find it, re-hash it with this frame's number as the
|
||||
* reply frame number.
|
||||
*/
|
||||
request_key.conversation = conversation->index;
|
||||
request_key.mid = si.mid;
|
||||
|
@ -328,6 +341,142 @@ do_transaction_hashing(conversation_t *conversation, struct smb_info si,
|
|||
return request_val;
|
||||
}
|
||||
|
||||
static struct smb_continuation_val *
|
||||
do_continuation_hashing(conversation_t *conversation, struct smb_info si,
|
||||
frame_data *fd, guint16 TotalDataCount,
|
||||
guint16 DataCount, const char **TransactName)
|
||||
{
|
||||
struct smb_request_key request_key, *new_request_key;
|
||||
struct smb_continuation_val *continuation_val, *new_continuation_val;
|
||||
gpointer new_request_key_ret, continuation_val_ret;
|
||||
|
||||
continuation_val = NULL;
|
||||
if (si.ddisp != 0) {
|
||||
/*
|
||||
* This reply isn't the first in the series; there should be a
|
||||
* reply of which it is a continuation.
|
||||
*/
|
||||
if (!fd->flags.visited) {
|
||||
/*
|
||||
* This is the first time the frame has been seen; check for
|
||||
* an entry for a matching continued message, with an unknown
|
||||
* continuation frame number, in the hash table.
|
||||
*
|
||||
* If we find it, re-hash it with this frame's number as the
|
||||
* continuation frame number.
|
||||
*/
|
||||
request_key.conversation = conversation->index;
|
||||
request_key.mid = si.mid;
|
||||
request_key.pid = si.pid;
|
||||
request_key.frame_num = 0;
|
||||
|
||||
/*
|
||||
* Look it up - and, if we find it, get pointers to the key and
|
||||
* value structures for it.
|
||||
*/
|
||||
if (g_hash_table_lookup_extended(smb_continuation_hash, &request_key,
|
||||
&new_request_key_ret,
|
||||
&continuation_val_ret)) {
|
||||
new_request_key = new_request_key_ret;
|
||||
continuation_val = continuation_val_ret;
|
||||
|
||||
/*
|
||||
* We found it.
|
||||
* Remove the old entry.
|
||||
*/
|
||||
g_hash_table_remove(smb_continuation_hash, &request_key);
|
||||
|
||||
/*
|
||||
* Now update the key, and put it back into the hash table with
|
||||
* the new key.
|
||||
*/
|
||||
new_request_key->frame_num = fd->num;
|
||||
g_hash_table_insert(smb_continuation_hash, new_request_key,
|
||||
continuation_val);
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* This is not the first time the frame has been seen; check for
|
||||
* an entry for a matching request, with this frame's frame
|
||||
* number as the continuation frame number, in the hash table.
|
||||
*/
|
||||
request_key.conversation = conversation->index;
|
||||
request_key.mid = si.mid;
|
||||
request_key.pid = si.pid;
|
||||
request_key.frame_num = fd->num;
|
||||
|
||||
continuation_val = (struct smb_continuation_val *)
|
||||
g_hash_table_lookup(smb_continuation_hash, &request_key);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If we found the entry for the message of which this is a continuation,
|
||||
* and our caller cares, get the transaction name for that message, as
|
||||
* it's the transaction name for this message as well.
|
||||
*/
|
||||
if (continuation_val != NULL && TransactName != NULL)
|
||||
*TransactName = continuation_val -> transact_name;
|
||||
|
||||
if (TotalDataCount > DataCount + si.ddisp) {
|
||||
/*
|
||||
* This reply isn't the last in the series; there should be a
|
||||
* continuation for it later in the capture.
|
||||
*
|
||||
* If this is the first time the frame has been seen, check for
|
||||
* an entry for the reply in the hash table. If it's not found,
|
||||
* insert an entry for it.
|
||||
*
|
||||
* If it's the first time it's been seen, then we can't have seen
|
||||
* the continuation yet, so the continuation frame number should
|
||||
* be 0, for "unknown".
|
||||
*/
|
||||
if (!fd->flags.visited) {
|
||||
request_key.conversation = conversation->index;
|
||||
request_key.mid = si.mid;
|
||||
request_key.pid = si.pid;
|
||||
request_key.frame_num = 0;
|
||||
|
||||
new_continuation_val = (struct smb_continuation_val *)
|
||||
g_hash_table_lookup(smb_continuation_hash, &request_key);
|
||||
|
||||
if (new_continuation_val == NULL) {
|
||||
/*
|
||||
* Not found.
|
||||
*/
|
||||
new_request_key = g_mem_chunk_alloc(smb_request_keys);
|
||||
new_request_key -> conversation = conversation->index;
|
||||
new_request_key -> mid = si.mid;
|
||||
new_request_key -> pid = si.pid;
|
||||
new_request_key -> frame_num = 0;
|
||||
|
||||
new_continuation_val = g_mem_chunk_alloc(smb_continuation_vals);
|
||||
new_continuation_val -> frame = fd->num;
|
||||
if (TransactName != NULL)
|
||||
new_continuation_val -> transact_name = *TransactName;
|
||||
else
|
||||
new_continuation_val -> transact_name = NULL;
|
||||
|
||||
g_hash_table_insert(smb_continuation_hash, new_request_key,
|
||||
new_continuation_val);
|
||||
} else {
|
||||
/*
|
||||
* This presumably means we never saw the continuation of
|
||||
* the message we found, and this is a reply to a different
|
||||
* request; as we never saw the continuation of that message,
|
||||
* we won't be using this "request_val" structure for that
|
||||
* message (as we'd use it only for the continuation).
|
||||
*
|
||||
* Clean out the structure, and set it to refer to this frame.
|
||||
*/
|
||||
new_continuation_val -> frame = fd->num;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return continuation_val;
|
||||
}
|
||||
|
||||
static void
|
||||
smb_init_protocol(void)
|
||||
{
|
||||
|
@ -345,18 +494,26 @@ smb_init_protocol(void)
|
|||
g_hash_table_foreach_remove(smb_request_hash, free_request_val_data, NULL);
|
||||
g_hash_table_destroy(smb_request_hash);
|
||||
}
|
||||
if (smb_continuation_hash)
|
||||
g_hash_table_destroy(smb_continuation_hash);
|
||||
if (smb_request_keys)
|
||||
g_mem_chunk_destroy(smb_request_keys);
|
||||
if (smb_request_vals)
|
||||
g_mem_chunk_destroy(smb_request_vals);
|
||||
if (smb_continuation_vals)
|
||||
g_mem_chunk_destroy(smb_continuation_vals);
|
||||
|
||||
smb_request_hash = g_hash_table_new(smb_hash, smb_equal);
|
||||
smb_continuation_hash = g_hash_table_new(smb_hash, smb_equal);
|
||||
smb_request_keys = g_mem_chunk_new("smb_request_keys",
|
||||
sizeof(struct smb_request_key),
|
||||
smb_packet_init_count * sizeof(struct smb_request_key), G_ALLOC_AND_FREE);
|
||||
smb_request_vals = g_mem_chunk_new("smb_request_vals",
|
||||
sizeof(struct smb_request_val),
|
||||
smb_packet_init_count * sizeof(struct smb_request_val), G_ALLOC_AND_FREE);
|
||||
smb_continuation_vals = g_mem_chunk_new("smb_continuation_vals",
|
||||
sizeof(struct smb_continuation_val),
|
||||
smb_packet_init_count * sizeof(struct smb_continuation_val), G_ALLOC_AND_FREE);
|
||||
}
|
||||
|
||||
static void (*dissect[256])(const u_char *, int, frame_data *, proto_tree *, proto_tree *, struct smb_info si, int, int, int);
|
||||
|
@ -9100,6 +9257,7 @@ dissect_transact2_smb(const u_char *pd, int offset, frame_data *fd, proto_tree *
|
|||
guint16 ByteCount;
|
||||
conversation_t *conversation;
|
||||
struct smb_request_val *request_val;
|
||||
struct smb_continuation_val *continuation_val;
|
||||
|
||||
/*
|
||||
* Find out what conversation this packet is part of.
|
||||
|
@ -9764,7 +9922,7 @@ dissect_transact_params(const u_char *pd, int offset, frame_data *fd,
|
|||
tvbuff_t *setup_tvb;
|
||||
|
||||
if (!TransactName)
|
||||
return;
|
||||
return;
|
||||
|
||||
/* Should check for error here ... */
|
||||
|
||||
|
@ -10533,13 +10691,26 @@ dissect_transact_smb(const u_char *pd, int offset, frame_data *fd,
|
|||
|
||||
}
|
||||
|
||||
if (request_val != NULL) {
|
||||
dissect_transact_params(pd, offset, fd, parent, tree, si, max_data,
|
||||
SMB_offset, errcode, DataOffset, DataCount,
|
||||
ParameterOffset, ParameterCount,
|
||||
SetupAreaOffset, SetupCount,
|
||||
request_val -> last_transact_command);
|
||||
}
|
||||
if (request_val != NULL)
|
||||
TransactName = request_val -> last_transact_command;
|
||||
else
|
||||
TransactName = NULL;
|
||||
|
||||
/*
|
||||
* Make an entry for this, if it's continued; get the entry for
|
||||
* the message of which it's a continuation, and get the transaction
|
||||
* name for that message, if it's a continuation.
|
||||
*
|
||||
* XXX - eventually, do reassembly of all the continuations, so
|
||||
* we can dissect the entire reply.
|
||||
*/
|
||||
si.continuation_val = do_continuation_hashing(conversation, si, fd,
|
||||
TotalDataCount, DataCount,
|
||||
&TransactName);
|
||||
dissect_transact_params(pd, offset, fd, parent, tree, si, max_data,
|
||||
SMB_offset, errcode, DataOffset, DataCount,
|
||||
ParameterOffset, ParameterCount,
|
||||
SetupAreaOffset, SetupCount, TransactName);
|
||||
|
||||
}
|
||||
|
||||
|
|
21
smb.h
21
smb.h
|
@ -2,7 +2,7 @@
|
|||
* Defines for smb packet dissection
|
||||
* Copyright 1999, Richard Sharpe <rsharpe@ns.aus.com>
|
||||
*
|
||||
* $Id: smb.h,v 1.11 2001/08/07 08:39:57 guy Exp $
|
||||
* $Id: smb.h,v 1.12 2001/08/11 07:26:25 guy Exp $
|
||||
*
|
||||
* Ethereal - Network traffic analyzer
|
||||
* By Gerald Combs <gerald@ethereal.com>
|
||||
|
@ -627,6 +627,13 @@
|
|||
#define SMB_LMapi_SetUserInfo 0x0072
|
||||
#define SMB_LMapi_UserPasswordSet 0x0073
|
||||
|
||||
/*
|
||||
* One of these data structures is allocated for a transaction or
|
||||
* transaction2 request; it keeps track of all information that's
|
||||
* available in the request but not the reply and that's needed in
|
||||
* order to dissect the reply, as well as the frame number of the
|
||||
* request.
|
||||
*/
|
||||
struct smb_request_val {
|
||||
int frame; /* Frame in which this request appeared */
|
||||
int last_transact2_command;
|
||||
|
@ -638,10 +645,22 @@ struct smb_request_val {
|
|||
guint16 last_level; /* Last level in request */
|
||||
};
|
||||
|
||||
/*
|
||||
* One of these data structures is allocated for a transaction reply
|
||||
* that's continued in a later reply; it keeps track of the pathname
|
||||
* from the request that generated the reply, as well as the frame
|
||||
* number of the continued message.
|
||||
*/
|
||||
struct smb_continuation_val {
|
||||
int frame; /* Frame in which this reply appeared */
|
||||
const gchar *transact_name;
|
||||
};
|
||||
|
||||
struct smb_info {
|
||||
int tid, uid, mid, pid; /* Any more? */
|
||||
conversation_t *conversation;
|
||||
struct smb_request_val *request_val;
|
||||
struct smb_continuation_val *continuation_val;
|
||||
gboolean unicode; /* Are strings in this SMB Unicode? */
|
||||
gboolean request; /* Is this a request? */
|
||||
gboolean is_interim_response; /* Is this an interim transaction response? */
|
||||
|
|
Loading…
Reference in New Issue