For indirect RPC calls, remember the call information, and add a
authorguy <guy@f5534014-38df-0310-8fa8-9805f1628bb7>
Fri, 9 Feb 2001 07:59:00 +0000 (07:59 +0000)
committerguy <guy@f5534014-38df-0310-8fa8-9805f1628bb7>
Fri, 9 Feb 2001 07:59:00 +0000 (07:59 +0000)
dissector for indirect replies that looks up the call.  Use them in the
portmapper/RPCBIND dissector.

git-svn-id: http://anonsvn.wireshark.org/wireshark/trunk@3008 f5534014-38df-0310-8fa8-9805f1628bb7

packet-portmap.c
packet-rpc.c
packet-rpc.h

index d10143eb296c49a618b641b0d351b5845a2f1140..7dc5013f950424819b170f2c11a49ccde4249173 100644 (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,32 +233,40 @@ int dissect_callit_call(tvbuff_t *tvb, int offset, packet_info *pinfo,
                        rpc_proc_name(prog, vers, proc), proc);
        }
 
+       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,
+               hf_portmap_args, prog, vers, proc);
+
+       return offset;
+}
+
+/* Dissect a callit reply */
+int dissect_callit_reply(tvbuff_t *tvb, int offset, packet_info *pinfo,
+       proto_tree *tree)
+{
        if ( tree )
        {
-               proto_tree_add_text(tree, tvb, offset+12, 4,
-                       "Argument length: %u",
-                       tvb_get_ntohl(tvb, offset+12));
+               proto_tree_add_item(tree, hf_portmap_port, tvb,
+                       offset, 4, FALSE);
        }
+       offset += 4;
 
-       offset += 16;
-
-       /* Dissect the arguments for this procedure.
+       /* 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_call(tvb, pinfo, tree, offset, prog,
-               vers, proc);
+       offset = dissect_rpc_indir_reply(tvb, pinfo, tree, offset,
+               hf_portmap_result, hf_portmap_prog, hf_portmap_version,
+               hf_portmap_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.
- */
-
 /* proc number, "proc name", dissect_request, dissect_reply */
 /* NULL as function pointer means: type of arguments is "void". */
 static const vsff portmap1_proc[] = {
@@ -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" }},
index fddf3b676f8bb1cf08aba97e7173d987f7ffb3d3..4d6ab2a68fdfe620fa837f8a5c20468f018869df 100644 (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),
index d873b78a84c4a37edaae2753982feecec14e499f..b1a3a4eecb08c628ffa35fab58f9bc8adb95e0d1 100644 (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 */