aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGuy Harris <guy@alum.mit.edu>2001-09-12 08:13:33 +0000
committerGuy Harris <guy@alum.mit.edu>2001-09-12 08:13:33 +0000
commit94e029fef6806a1013c4612328bc391bb9be6a14 (patch)
tree66580ef1d1f581c9de825853ce3c9804542cf45d
parente35a8ac8fe7204e12cee3d174a1b6f3aee5b1c7f (diff)
When establishing or searching for a conversation for ONC RPC, use both
source and destination addresses if the transport is TCP (we use that, for now, as a proxy for "if the transport is connection-oriented"), as the endpoint addresses should be the same for all packets. Have both a heuristic RPC dissector and a non-heuristic version, and make the non-heuristic version the dissector for the conversations we create; that version will, if the frame doesn't look like a call or reply, mark it as continuation data. svn path=/trunk/; revision=3921
-rw-r--r--packet-rpc.c223
1 files changed, 190 insertions, 33 deletions
diff --git a/packet-rpc.c b/packet-rpc.c
index 044c195409..a3d8a7dcb0 100644
--- a/packet-rpc.c
+++ b/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.68 2001/09/03 10:33:06 guy Exp $
+ * $Id: packet-rpc.c,v 1.69 2001/09/12 08:13:33 guy Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@ethereal.com>
@@ -217,6 +217,7 @@ typedef struct _rpc_prog_info_value {
char* progname;
} rpc_prog_info_value;
+static void dissect_rpc(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
/***********************************/
/* Hash array with procedure names */
@@ -1125,13 +1126,35 @@ dissect_rpc_indir_call(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
/* 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
+ we can match up calls with replies.
+
+ If the transport is connection-oriented (we check, for
+ now, only for "pinfo->ptype" of PT_TCP), we take
+ into account the address from which the call was sent
+ and the address to which the call was sent, because
+ the addresses of the two endpoints should be the same
+ for all calls and replies.
+
+ If the transport is connectionless, 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);
+ to which the call was sent. */
+ if (pinfo->ptype == PT_TCP) {
+ conversation = find_conversation(&pinfo->src,
+ &pinfo->dst, pinfo->ptype, pinfo->srcport,
+ pinfo->destport, 0);
+ } else {
+ /*
+ * XXX - can we just use NO_ADDR_B? Unfortunately,
+ * you currently still have to pass a non-null
+ * pointer for the second address argument even
+ * if you do that.
+ */
+ 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.
@@ -1139,11 +1162,21 @@ dissect_rpc_indir_call(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
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, 0);
+ if (pinfo->ptype == PT_TCP) {
+ conversation = conversation_new(&pinfo->src,
+ &pinfo->dst, pinfo->ptype, pinfo->srcport,
+ pinfo->destport, 0);
+ } else {
+ conversation = conversation_new(&pinfo->src,
+ &null_address, pinfo->ptype, pinfo->srcport,
+ pinfo->destport, 0);
+ }
}
+ /* Make the dissector for this conversation the non-heuristic
+ RPC dissector. */
+ conversation_set_dissector(conversation, dissect_rpc);
+
/* Prepare the key data.
Dissectors for RPC procedure calls and replies shouldn't
@@ -1226,12 +1259,33 @@ dissect_rpc_indir_reply(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
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);
+ call was sent.
+
+ If the transport is connection-oriented (we check, for
+ now, only for "pinfo->ptype" of PT_TCP), we take
+ into account the address from which the call was sent
+ and the address to which the call was sent, because
+ the addresses of the two endpoints should be the same
+ for all calls and replies.
+
+ If the transport is connectionless, 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. */
+ if (pinfo->ptype == PT_TCP) {
+ conversation = find_conversation(&pinfo->src, &pinfo->dst,
+ pinfo->ptype, pinfo->srcport, pinfo->destport, 0);
+ } else {
+ /*
+ * XXX - can we just use NO_ADDR_B? Unfortunately,
+ * you currently still have to pass a non-null
+ * pointer for the second address argument even
+ * if you do that.
+ */
+ 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.
@@ -1306,8 +1360,32 @@ dissect_rpc_indir_reply(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
return offset;
}
+/*
+ * Just mark this as a continuation of an earlier packet.
+ */
+static void
+dissect_rpc_continuation(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+ proto_item *rpc_item;
+ proto_tree *rpc_tree;
+
+ if (check_col(pinfo->fd, COL_PROTOCOL))
+ col_set_str(pinfo->fd, COL_PROTOCOL, "RPC");
+ if (check_col(pinfo->fd, COL_INFO))
+ col_set_str(pinfo->fd, COL_INFO, "Continuation");
+
+ if (tree) {
+ rpc_item = proto_tree_add_item(tree, proto_rpc, tvb, 0,
+ tvb_length(tvb), FALSE);
+ rpc_tree = proto_item_add_subtree(rpc_item, ett_rpc);
+ proto_tree_add_text(rpc_tree, tvb, 0, tvb_length(tvb),
+ "Continuation data");
+ }
+}
+
static gboolean
-dissect_rpc(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+dissect_rpc_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
+ gboolean is_heur)
{
int offset = 0;
guint32 msg_type;
@@ -1364,8 +1442,11 @@ dissect_rpc(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
/* the first 4 bytes are special in "record marking mode" */
if (use_rm) {
- if (!tvb_bytes_exist(tvb, offset, 4))
+ if (!tvb_bytes_exist(tvb, offset, 4)) {
+ if (!is_heur)
+ dissect_rpc_continuation(tvb, pinfo, tree);
return FALSE;
+ }
rpc_rm = tvb_get_ntohl(tvb, offset);
offset += 4;
}
@@ -1375,6 +1456,8 @@ dissect_rpc(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
*/
if (!tvb_bytes_exist(tvb, offset, 8)) {
/* Captured data in packet isn't enough to let us tell. */
+ if (!is_heur)
+ dissect_rpc_continuation(tvb, pinfo, tree);
return FALSE;
}
@@ -1388,6 +1471,8 @@ dissect_rpc(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
if (!tvb_bytes_exist(tvb, offset, 16)) {
/* Captured data in packet isn't enough to let us
tell. */
+ if (!is_heur)
+ dissect_rpc_continuation(tvb, pinfo, tree);
return FALSE;
}
@@ -1401,6 +1486,8 @@ dissect_rpc(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
((rpc_prog = g_hash_table_lookup(rpc_progs, &rpc_prog_key))
== NULL)) {
/* They're not, so it's probably not an RPC call. */
+ if (!is_heur)
+ dissect_rpc_continuation(tvb, pinfo, tree);
return FALSE;
}
break;
@@ -1409,16 +1496,40 @@ dissect_rpc(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
/* Check for RPC reply. 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);
+ come from the port to which the call was sent.
+
+ If the transport is connection-oriented (we check, for
+ now, only for "pinfo->ptype" of PT_TCP), we take
+ into account the address from which the call was sent
+ and the address to which the call was sent, because
+ the addresses of the two endpoints should be the same
+ for all calls and replies.
+
+ If the transport is connectionless, 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. */
+ if (pinfo->ptype == PT_TCP) {
+ conversation = find_conversation(&pinfo->src,
+ &pinfo->dst, pinfo->ptype, pinfo->srcport,
+ pinfo->destport, 0);
+ } else {
+ /*
+ * XXX - can we just use NO_ADDR_B? Unfortunately,
+ * you currently still have to pass a non-null
+ * pointer for the second address argument even
+ * if you do that.
+ */
+ 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. */
+ if (!is_heur)
+ dissect_rpc_continuation(tvb, pinfo, tree);
return FALSE;
}
@@ -1429,6 +1540,8 @@ dissect_rpc(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
if (rpc_call == NULL) {
/* The XID doesn't match a call from that
conversation, so it's probably not an RPC reply. */
+ if (!is_heur)
+ dissect_rpc_continuation(tvb, pinfo, tree);
return FALSE;
}
break;
@@ -1437,6 +1550,8 @@ dissect_rpc(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
/* The putative message type field contains neither
RPC_CALL nor RPC_REPLY, so it's not an RPC call or
reply. */
+ if (!is_heur)
+ dissect_rpc_continuation(tvb, pinfo, tree);
return FALSE;
}
@@ -1579,21 +1694,53 @@ dissect_rpc(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
/* 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
+ we can match up calls with replies.
+
+ If the transport is connection-oriented (we check, for
+ now, only for "pinfo->ptype" of PT_TCP), we take
+ into account the address from which the call was sent
+ and the address to which the call was sent, because
+ the addresses of the two endpoints should be the same
+ for all calls and replies.
+
+ If the transport is connectionless, 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);
+ to which the call was sent. */
+ if (pinfo->ptype == PT_TCP) {
+ conversation = find_conversation(&pinfo->src,
+ &pinfo->dst, pinfo->ptype, pinfo->srcport,
+ pinfo->destport, 0);
+ } else {
+ /*
+ * XXX - can we just use NO_ADDR_B? Unfortunately,
+ * you currently still have to pass a non-null
+ * pointer for the second address argument even
+ * if you do that.
+ */
+ 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. */
- conversation = conversation_new(&pinfo->src,
- &null_address, pinfo->ptype, pinfo->srcport,
- pinfo->destport, 0);
+ if (pinfo->ptype == PT_TCP) {
+ conversation = conversation_new(&pinfo->src,
+ &pinfo->dst, pinfo->ptype, pinfo->srcport,
+ pinfo->destport, 0);
+ } else {
+ conversation = conversation_new(&pinfo->src,
+ &null_address, pinfo->ptype, pinfo->srcport,
+ pinfo->destport, 0);
+ }
}
+ /* Make the dissector for this conversation the non-heuristic
+ RPC dissector. */
+ conversation_set_dissector(conversation, dissect_rpc);
+
/* prepare the key data */
rpc_call_key.xid = xid;
rpc_call_key.conversation = conversation;
@@ -1934,6 +2081,17 @@ dissect_rpc(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
return TRUE;
}
+static gboolean
+dissect_rpc_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+ return dissect_rpc_common(tvb, pinfo, tree, TRUE);
+}
+
+static void
+dissect_rpc(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+ dissect_rpc_common(tvb, pinfo, tree, FALSE);
+}
/* Discard any state we've saved. */
static void
@@ -2139,10 +2297,9 @@ proto_register_rpc(void)
rpc_procs = g_hash_table_new(rpc_proc_hash, rpc_proc_equal);
}
-
void
proto_reg_handoff_rpc(void)
{
- heur_dissector_add("tcp", dissect_rpc, proto_rpc);
- heur_dissector_add("udp", dissect_rpc, proto_rpc);
+ heur_dissector_add("tcp", dissect_rpc_heur, proto_rpc);
+ heur_dissector_add("udp", dissect_rpc_heur, proto_rpc);
}