forked from osmocom/wireshark
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:
parent
f190eff056
commit
ea037e9084
|
@ -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" }},
|
||||
|
|
190
packet-rpc.c
190
packet-rpc.c
|
@ -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),
|
||||
|
|
|
@ -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 */
|
||||
|
||||
|
|
Loading…
Reference in New Issue