From 94e029fef6806a1013c4612328bc391bb9be6a14 Mon Sep 17 00:00:00 2001 From: Guy Harris Date: Wed, 12 Sep 2001 08:13:33 +0000 Subject: 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 --- packet-rpc.c | 223 ++++++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file 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 * - * $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 @@ -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); } -- cgit v1.2.3