For indirect RPC calls, remember the call information, and add a

dissector for indirect replies that looks up the call.  Use them in the
portmapper/RPCBIND dissector.

svn path=/trunk/; revision=3008
This commit is contained in:
Guy Harris 2001-02-09 07:59:00 +00:00
parent f190eff056
commit ea037e9084
3 changed files with 248 additions and 27 deletions

View File

@ -1,7 +1,7 @@
/* packet-portmap.c
* Routines for portmap dissection
*
* $Id: packet-portmap.c,v 1.27 2001/02/09 06:49:29 guy Exp $
* $Id: packet-portmap.c,v 1.28 2001/02/09 07:59:00 guy Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@zing.org>
@ -50,6 +50,8 @@ static int hf_portmap_proc = -1;
static int hf_portmap_version = -1;
static int hf_portmap_port = -1;
static int hf_portmap_answer = -1;
static int hf_portmap_args = -1;
static int hf_portmap_result = -1;
static int hf_portmap_rpcb = -1;
static int hf_portmap_rpcb_prog = -1;
static int hf_portmap_rpcb_version = -1;
@ -231,31 +233,39 @@ int dissect_callit_call(tvbuff_t *tvb, int offset, packet_info *pinfo,
rpc_proc_name(prog, vers, proc), proc);
}
if ( tree )
{
proto_tree_add_text(tree, tvb, offset+12, 4,
"Argument length: %u",
tvb_get_ntohl(tvb, offset+12));
}
offset += 16;
offset += 12;
/* Dissect the arguments for this procedure.
Make the columns non-writable, so the dissector won't change
them out from under us. */
col_set_writable(pinfo->fd, FALSE);
offset = dissect_rpc_indir_call(tvb, pinfo, tree, offset, prog,
vers, proc);
offset = dissect_rpc_indir_call(tvb, pinfo, tree, offset,
hf_portmap_args, prog, vers, proc);
return offset;
}
/*
* XXX - to dissect a CALLIT reply, we'd need to somehow associate
* the program/version/procedure information we get on a call with
* the RPC dissector's information about the call, and get that
* information from the reply dissector.
*/
/* Dissect a callit reply */
int dissect_callit_reply(tvbuff_t *tvb, int offset, packet_info *pinfo,
proto_tree *tree)
{
if ( tree )
{
proto_tree_add_item(tree, hf_portmap_port, tvb,
offset, 4, FALSE);
}
offset += 4;
/* Dissect the result of this procedure.
Make the columns non-writable, so the dissector won't change
them out from under us. */
col_set_writable(pinfo->fd, FALSE);
offset = dissect_rpc_indir_reply(tvb, pinfo, tree, offset,
hf_portmap_result, hf_portmap_prog, hf_portmap_version,
hf_portmap_proc);
return offset;
}
/* proc number, "proc name", dissect_request, dissect_reply */
/* NULL as function pointer means: type of arguments is "void". */
@ -282,7 +292,7 @@ static const vsff portmap2_proc[] = {
{ PORTMAPPROC_DUMP, "DUMP",
NULL, dissect_dump_reply },
{ PORTMAPPROC_CALLIT, "CALLIT",
dissect_callit_call, NULL },
dissect_callit_call, dissect_callit_reply },
{ 0, NULL, NULL, NULL }
};
/* end of Portmap version 2 */
@ -359,6 +369,25 @@ int dissect_rpcb3_dump_reply(tvbuff_t *tvb, int offset, packet_info *pinfo,
return offset;
}
/* RFC 1833, page 4 */
int dissect_rpcb_rmtcallres(tvbuff_t *tvb, int offset, packet_info *pinfo,
proto_tree *tree)
{
/* Dissect the remote universal address. */
offset = dissect_rpc_string_tvb(tvb, pinfo, tree,
hf_portmap_rpcb_addr, offset, NULL);
/* Dissect the result of this procedure.
Make the columns non-writable, so the dissector won't change
them out from under us. */
col_set_writable(pinfo->fd, FALSE);
offset = dissect_rpc_indir_reply(tvb, pinfo, tree, offset,
hf_portmap_result, hf_portmap_prog, hf_portmap_version,
hf_portmap_proc);
return offset;
}
/* Portmapper version 3, RFC 1833, Page 7 */
static const vsff portmap3_proc[] = {
@ -373,7 +402,7 @@ static const vsff portmap3_proc[] = {
{ RPCBPROC_DUMP, "DUMP",
NULL, dissect_rpcb3_dump_reply },
{ RPCBPROC_CALLIT, "CALLIT",
dissect_callit_call, NULL },
dissect_callit_call, dissect_rpcb_rmtcallres },
{ RPCBPROC_GETTIME, "GETTIME",
NULL, NULL },
{ RPCBPROC_UADDR2TADDR, "UADDR2TADDR",
@ -398,7 +427,7 @@ static const vsff portmap4_proc[] = {
{ RPCBPROC_DUMP, "DUMP",
NULL, dissect_rpcb3_dump_reply },
{ RPCBPROC_BCAST, "BCAST",
dissect_callit_call, NULL },
dissect_callit_call, dissect_rpcb_rmtcallres },
{ RPCBPROC_GETTIME, "GETTIME",
NULL, NULL },
{ RPCBPROC_UADDR2TADDR, "UADDR2TADDR",
@ -408,7 +437,7 @@ static const vsff portmap4_proc[] = {
{ RPCBPROC_GETVERSADDR, "GETVERSADDR",
NULL, NULL },
{ RPCBPROC_INDIRECT, "INDIRECT",
dissect_callit_call, NULL },
dissect_callit_call, dissect_rpcb_rmtcallres },
{ RPCBPROC_GETADDRLIST, "GETADDRLIST",
NULL, NULL },
{ RPCBPROC_GETSTAT, "GETSTAT",
@ -439,6 +468,12 @@ proto_register_portmap(void)
{ &hf_portmap_answer, {
"Answer", "portmap.answer", FT_BOOLEAN, BASE_DEC,
NULL, 0, "Answer" }},
{ &hf_portmap_args, {
"Arguments", "portmap.args", FT_BYTES, BASE_HEX,
NULL, 0, "Arguments" }},
{ &hf_portmap_result, {
"Result", "portmap.result", FT_BYTES, BASE_HEX,
NULL, 0, "Result" }},
{ &hf_portmap_rpcb, {
"RPCB", "portmap.rpcb", FT_NONE, 0,
NULL, 0, "RPCB" }},

View File

@ -2,7 +2,7 @@
* Routines for rpc dissection
* Copyright 1999, Uwe Girlich <Uwe.Girlich@philosys.de>
*
* $Id: packet-rpc.c,v 1.53 2001/02/09 06:49:29 guy Exp $
* $Id: packet-rpc.c,v 1.54 2001/02/09 07:59:00 guy Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@zing.org>
@ -404,6 +404,8 @@ static GMemChunk *rpc_call_info_value_chunk;
static GHashTable *rpc_calls;
static GHashTable *rpc_indir_calls;
/* compare 2 keys */
gint
rpc_call_equal(gconstpointer k1, gconstpointer k2)
@ -1118,13 +1120,21 @@ dissect_rpc_authgss_priv_data(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tre
/*
* Dissect the arguments to an indirect call; used by the portmapper/RPCBIND
* dissector.
*
* Record this call in a hash table, similar to the hash table for
* direct calls, so we can find it when dissecting an indirect call reply.
*/
int
dissect_rpc_indir_call(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
int offset, guint32 prog, guint32 vers, guint32 proc)
int offset, int args_id, guint32 prog, guint32 vers, guint32 proc)
{
conversation_t* conversation;
static address null_address = { AT_NONE, 0, NULL };
rpc_proc_info_key key;
rpc_proc_info_value *value;
rpc_call_info_value *rpc_call;
rpc_call_info_key rpc_call_key;
rpc_call_info_key *new_rpc_call_key;
old_dissect_function_t *old_dissect_function = NULL;
dissect_function_t *dissect_function = NULL;
@ -1136,15 +1146,184 @@ dissect_rpc_indir_call(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
old_dissect_function = value->dissect_call.old;
else
dissect_function = value->dissect_call.new;
/* Keep track of the address and port whence the call came,
and the port to which the call is being sent, so that
we can match up calls wityh replies. (We don't worry
about the address to which the call was sent and from
which the reply was sent, because there's no
guarantee that the reply will come from the address
to which the call was sent.) */
conversation = find_conversation(&pinfo->src, &null_address,
pinfo->ptype, pinfo->srcport, pinfo->destport, 0);
if (conversation == NULL) {
/* It's not part of any conversation - create a new
one.
XXX - this should never happen, as we should've
created a conversation for it in the RPC
dissector. */
conversation = conversation_new(&pinfo->src,
&null_address, pinfo->ptype, pinfo->srcport,
pinfo->destport, NULL, 0);
}
/* Prepare the key data.
Dissectors for RPC procedure calls and replies shouldn't
create new tvbuffs, and we don't create one ourselves,
so we should have been handed the tvbuff for this RPC call;
as such, the XID is at offset 0 in this tvbuff. */
rpc_call_key.xid = tvb_get_ntohl(tvb, 0);
rpc_call_key.conversation = conversation;
/* look up the request */
rpc_call = g_hash_table_lookup(rpc_indir_calls, &rpc_call_key);
if (rpc_call == NULL) {
/* We didn't find it; create a new entry.
Prepare the value data.
Not all of it is needed for handling indirect
calls, so we set a bunch of items to 0. */
new_rpc_call_key = g_mem_chunk_alloc(rpc_call_info_key_chunk);
*new_rpc_call_key = rpc_call_key;
rpc_call = g_mem_chunk_alloc(rpc_call_info_value_chunk);
rpc_call->req_num = 0;
rpc_call->rep_num = 0;
rpc_call->prog = prog;
rpc_call->vers = vers;
rpc_call->proc = proc;
rpc_call->flavor = 0;
rpc_call->gss_proc = 0;
rpc_call->gss_svc = 0;
rpc_call->proc_info = value;
/* store it */
g_hash_table_insert(rpc_indir_calls, new_rpc_call_key,
rpc_call);
}
}
else {
/* We don't know the procedure.
Happens only with strange program versions or
non-existing dissectors.
Just show the arguments as opaque data. */
offset = dissect_rpc_data_tvb(tvb, pinfo, tree, args_id,
offset);
return offset;
}
if ( tree )
{
proto_tree_add_text(tree, tvb, offset, 4,
"Argument length: %u",
tvb_get_ntohl(tvb, offset));
}
offset += 4;
/* Dissect the arguments */
offset = call_dissect_function(tvb, pinfo, tree, offset,
old_dissect_function, dissect_function, NULL);
return offset;
}
/*
* Dissect the results in an indirect reply; used by the portmapper/RPCBIND
* dissector.
*/
int
dissect_rpc_indir_reply(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
int offset, int result_id, int prog_id, int vers_id, int proc_id)
{
conversation_t* conversation;
static address null_address = { AT_NONE, 0, NULL };
rpc_call_info_key rpc_call_key;
rpc_call_info_value *rpc_call;
char *procname = NULL;
char procname_static[20];
old_dissect_function_t *old_dissect_function = NULL;
dissect_function_t *dissect_function = NULL;
/* Look for the matching call in the hash table of indirect
calls. A reply must match a call that we've seen, and the
reply must be sent to the same port and address that the
call came from, and must come from the port to which the
call was sent. (We don't worry about the address to which
the call was sent and from which the reply was sent, because
there's no guarantee that the reply will come from the address
to which the call was sent.) */
conversation = find_conversation(&null_address, &pinfo->dst,
pinfo->ptype, pinfo->srcport, pinfo->destport, 0);
if (conversation == NULL) {
/* We haven't seen an RPC call for that conversation,
so we can't check for a reply to that call.
Just show the reply stuff as opaque data. */
offset = dissect_rpc_data_tvb(tvb, pinfo, tree, result_id,
offset);
return offset;
}
/* The XIDs of the call and reply must match. */
rpc_call_key.xid = tvb_get_ntohl(tvb, 0);
rpc_call_key.conversation = conversation;
rpc_call = g_hash_table_lookup(rpc_indir_calls, &rpc_call_key);
if (rpc_call == NULL) {
/* The XID doesn't match a call from that
conversation, so it's probably not an RPC reply.
Just show the reply stuff as opaque data. */
offset = dissect_rpc_data_tvb(tvb, pinfo, tree, result_id,
offset);
return offset;
}
if (rpc_call->proc_info != NULL) {
if (rpc_call->proc_info->is_old_dissector)
old_dissect_function = rpc_call->proc_info->dissect_reply.old;
else
dissect_function = rpc_call->proc_info->dissect_reply.new;
if (rpc_call->proc_info->name != NULL) {
procname = rpc_call->proc_info->name;
}
else {
sprintf(procname_static, "proc-%u", rpc_call->proc);
procname = procname_static;
}
}
else {
/* happens only with strange program versions or
non-existing dissectors */
#if 0
dissect_function = NULL;
#endif
sprintf(procname_static, "proc-%u", rpc_call->proc);
procname = procname_static;
}
if ( tree )
{
/* Put the program, version, and procedure into the tree. */
proto_tree_add_uint_format(tree, prog_id, tvb,
0, 0, rpc_call->prog, "Program: %s (%u)",
rpc_prog_name(rpc_call->prog), rpc_call->prog);
proto_tree_add_uint(tree, vers_id, tvb, 0, 0, rpc_call->vers);
proto_tree_add_uint_format(tree, proc_id, tvb,
0, 0, rpc_call->proc, "Procedure: %s (%u)",
procname, rpc_call->proc);
}
if (dissect_function == NULL) {
/* We don't know how to dissect the reply procedure.
Just show the reply stuff as opaque data. */
offset = dissect_rpc_data_tvb(tvb, pinfo, tree, result_id,
offset);
return offset;
}
if (tree) {
/* Put the length of the reply value into the tree. */
proto_tree_add_text(tree, tvb, offset, 4,
"Argument length: %u",
tvb_get_ntohl(tvb, offset));
}
offset += 4;
/* Dissect the return value */
offset = call_dissect_function(tvb, pinfo, tree, offset,
old_dissect_function, dissect_function, NULL);
return offset;
@ -1747,12 +1926,15 @@ rpc_init_protocol(void)
{
if (rpc_calls != NULL)
g_hash_table_destroy(rpc_calls);
if (rpc_indir_calls != NULL)
g_hash_table_destroy(rpc_indir_calls);
if (rpc_call_info_key_chunk != NULL)
g_mem_chunk_destroy(rpc_call_info_key_chunk);
if (rpc_call_info_value_chunk != NULL)
g_mem_chunk_destroy(rpc_call_info_value_chunk);
rpc_calls = g_hash_table_new(rpc_call_hash, rpc_call_equal);
rpc_indir_calls = g_hash_table_new(rpc_call_hash, rpc_call_equal);
rpc_call_info_key_chunk = g_mem_chunk_new("call_info_key_chunk",
sizeof(rpc_call_info_key),
200 * sizeof(rpc_call_info_key),

View File

@ -1,6 +1,6 @@
/* packet-rpc.h
*
* $Id: packet-rpc.h,v 1.25 2001/02/09 06:49:29 guy Exp $
* $Id: packet-rpc.h,v 1.26 2001/02/09 07:59:00 guy Exp $
*
* (c) 1999 Uwe Girlich
*
@ -123,7 +123,11 @@ extern int dissect_rpc_uint64_tvb(tvbuff_t *tvb, packet_info *pinfo,
proto_tree *tree, int hfindex, int offset);
extern int dissect_rpc_indir_call(tvbuff_t *tvb, packet_info *pinfo,
proto_tree *tree, int offset, guint32 prog, guint32 vers, guint32 proc);
proto_tree *tree, int offset, int args_id, guint32 prog, guint32 vers,
guint32 proc);
extern int dissect_rpc_indir_reply(tvbuff_t *tvb, packet_info *pinfo,
proto_tree *tree, int offset, int result_id, int prog_id, int vers_id,
int proc_id);
#endif /* packet-rpc.h */