UDP: Heuristic dissector for conversation taking precedence

When a single UDP port is supporting multiple protocols, for example RTP and
RTCP can share a port, and one of these protocols is detected through a
heuristic before a superior protocol (e.g. SIP/SDP) has established that the
port has multiple protocols, then only the heuristic is used. This is due to
only looking for an exact match with find_conversation() and not going any
further. The superior protocol only adds the dissector by source address/port.
So, to fix, if we do not find the exact match, we continue serching for a
dissector on the partial matches.

Bug: 14370
Change-Id: Icdded9ca1637cd594b920f979f6f0a003bef9aae
Reviewed-on: https://code.wireshark.org/review/25432
Petri-Dish: Michael Mann <mmann78@netscape.net>
Tested-by: Petri Dish Buildbot
Reviewed-by: Michael Mann <mmann78@netscape.net>
This commit is contained in:
Robert Jongbloed 2018-01-23 10:48:57 +00:00 committed by Michael Mann
parent 9ff64c8d7c
commit d16308c89a
7 changed files with 54 additions and 22 deletions

View File

@ -1233,6 +1233,23 @@ conversation_get_dissector(conversation_t *conversation, const guint32 frame_num
return (dissector_handle_t)wmem_tree_lookup32_le(conversation->dissector_tree, frame_num);
}
static gboolean try_conversation_call_dissector_helper(conversation_t *conversation, gboolean* dissector_success,
tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data)
{
int ret;
dissector_handle_t handle = (dissector_handle_t)wmem_tree_lookup32_le(
conversation->dissector_tree, pinfo->num);
if (handle == NULL)
return FALSE;
ret = call_dissector_only(handle, tvb, pinfo, tree, data);
/* Let the caller decide what to do with success or rejection */
(*dissector_success) = (ret != 0);
return TRUE;
}
/*
* Given two address/port pairs for a packet, search for a matching
* conversation and, if found and it has a conversation dissector,
@ -1246,28 +1263,43 @@ conversation_get_dissector(conversation_t *conversation, const guint32 frame_num
gboolean
try_conversation_dissector(const address *addr_a, const address *addr_b, const endpoint_type etype,
const guint32 port_a, const guint32 port_b, tvbuff_t *tvb, packet_info *pinfo,
proto_tree *tree, void* data)
proto_tree *tree, void* data, const guint options)
{
conversation_t *conversation;
gboolean dissector_success;
conversation = find_conversation(pinfo->num, addr_a, addr_b, etype, port_a,
port_b, 0);
/* Try each mode based on option flags */
conversation = find_conversation(pinfo->num, addr_a, addr_b, etype, port_a, port_b, 0);
if (conversation != NULL) {
int ret;
dissector_handle_t handle = (dissector_handle_t)wmem_tree_lookup32_le(conversation->dissector_tree, pinfo->num);
if (handle == NULL)
return FALSE;
ret=call_dissector_only(handle, tvb, pinfo, tree, data);
if(!ret) {
/* this packet was rejected by the dissector
* so return FALSE in case our caller wants
* to do some cleaning up.
*/
return FALSE;
}
return TRUE;
if (try_conversation_call_dissector_helper(conversation, &dissector_success, tvb, pinfo, tree, data))
return dissector_success;
}
if (options & NO_ADDR_B) {
conversation = find_conversation(pinfo->num, addr_a, addr_b, etype, port_a, port_b, NO_ADDR_B);
if (conversation != NULL) {
if (try_conversation_call_dissector_helper(conversation, &dissector_success, tvb, pinfo, tree, data))
return dissector_success;
}
}
if (options & NO_PORT_B) {
conversation = find_conversation(pinfo->num, addr_a, addr_b, etype, port_a, port_b, NO_PORT_B);
if (conversation != NULL) {
if (try_conversation_call_dissector_helper(conversation, &dissector_success, tvb, pinfo, tree, data))
return dissector_success;
}
}
if (options & (NO_ADDR_B|NO_PORT_B)) {
conversation = find_conversation(pinfo->num, addr_a, addr_b, etype, port_a, port_b, NO_ADDR_B|NO_PORT_B);
if (conversation != NULL) {
if (try_conversation_call_dissector_helper(conversation, &dissector_success, tvb, pinfo, tree, data))
return dissector_success;
}
}
return FALSE;
}

View File

@ -224,7 +224,7 @@ WS_DLL_PUBLIC guint32 conversation_get_endpoint_by_id(struct _packet_info *pinfo
extern gboolean
try_conversation_dissector(const address *addr_a, const address *addr_b, const endpoint_type etype,
const guint32 port_a, const guint32 port_b, tvbuff_t *tvb, packet_info *pinfo,
proto_tree *tree, void* data);
proto_tree *tree, void* data, const guint options);
extern gboolean
try_conversation_dissector_by_id(const endpoint_type etype, const guint32 id, tvbuff_t *tvb,

View File

@ -859,7 +859,7 @@ dissect_atp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
conversation_set_dissector(conversation, sub);
}
else if (!try_conversation_dissector(&pinfo->src, &pinfo->dst, conversation_pt_to_endpoint_type(pinfo->ptype),
pinfo->srcport, pinfo->destport, new_tvb,pinfo, tree, &aspinfo)) {
pinfo->srcport, pinfo->destport, new_tvb,pinfo, tree, &aspinfo, 0)) {
call_data_dissector(new_tvb, pinfo, tree);
}

View File

@ -250,7 +250,7 @@ decode_dccp_ports(tvbuff_t *tvb, int offset, packet_info *pinfo,
* for the conversation if available
*/
if (try_conversation_dissector(&pinfo->src, &pinfo->dst, ENDPOINT_DCCP, sport,
dport, next_tvb, pinfo, tree, NULL)) {
dport, next_tvb, pinfo, tree, NULL, 0)) {
return;
}

View File

@ -102,7 +102,7 @@ static void dissect_payload(tvbuff_t *next_tvb, packet_info *pinfo, proto_tree *
/* Trying a dissector assigned to the conversation (Usually from NBAP) */
conv_dissected = try_conversation_dissector(&pinfo->dst, &pinfo->src, ENDPOINT_UDP,
pinfo->destport, pinfo->srcport, next_tvb, pinfo, tree, NULL);
pinfo->destport, pinfo->srcport, next_tvb, pinfo, tree, NULL, 0);
if (!conv_dissected) {
/* No conversation dissector / TVB was rejected, try other options */
if(call_fp_heur) {

View File

@ -5503,7 +5503,7 @@ decode_tcp_ports(tvbuff_t *tvb, int offset, packet_info *pinfo,
/* for the conversation if available */
if (try_conversation_dissector(&pinfo->src, &pinfo->dst, ENDPOINT_TCP,
src_port, dst_port, next_tvb, pinfo, tree, tcpinfo)) {
src_port, dst_port, next_tvb, pinfo, tree, tcpinfo, 0)) {
pinfo->want_pdu_tracking -= !!(pinfo->want_pdu_tracking);
handle_export_pdu_conversation(pinfo, next_tvb, src_port, dst_port, tcpinfo);
return TRUE;

View File

@ -632,7 +632,7 @@ decode_udp_ports(tvbuff_t *tvb, int offset, packet_info *pinfo,
/* determine if this packet is part of a conversation and call dissector */
/* for the conversation if available */
if (try_conversation_dissector(&pinfo->dst, &pinfo->src, ENDPOINT_UDP,
uh_dport, uh_sport, next_tvb, pinfo, tree, NULL)) {
uh_dport, uh_sport, next_tvb, pinfo, tree, NULL, NO_ADDR_B|NO_PORT_B)) {
handle_export_pdu_conversation(pinfo, next_tvb, uh_dport, uh_sport);
return;
}