Some applications do very naughty things like reusing a port for a different protocol during different stages of an application cycle.

This is very naughty and will cause problems when we have assigned a dissector to a dynamic port using conversation_set_dissector().


To make ethereal handle this case I have changed the try_conversation_dissector() to allow it to fail and return 0,   meaning   yes there is indeed a protocol registered for this conversation but that protocol rejected this packet.
(which only happens for "new" style dissectors, "old" style dissectors will never reject a packet that way)

When this happens  the decode_udp_port() helper will still allow other dissectors to be tried, in the hope that the conversation is now used for some other protocol and thus someone else might be able to decode the packet.


Update SNMP and TFTP dissectors to  check that even if there already is a conversation but that conversation does NOT have snmp/tftp registered as the dissector for it, then create a new conversation anyway and attach the proper dissector.

Since ethereal keeps track of which frame number a conversation started in, this actually works really well.



svn path=/trunk/; revision=14345
This commit is contained in:
Ronnie Sahlberg 2005-05-11 10:40:53 +00:00
parent e3e4f52245
commit fcab322ada
7 changed files with 112 additions and 20 deletions

View File

@ -2462,6 +2462,13 @@ packet-msproxy.c, a conversation can install a dissector to handle
the secondary protocol dissection. After the conversation is created
for the negotiated ports use the conversation_set_dissector to define
the dissection routine.
Before we create these conversations or assign a dissector to them we should
first check that the conversation does not already exist and if it exists
whether it is registered to our protocol or not.
We should do this because is uncommon but it does happen that multiple
different protocols can use the same socketpair during different stages of
an application cycle. By keeping track of the frame number a conversation
was started in ethereal can still tell these different protocols apart.
The second argument to conversation_set_dissector is a dissector handle,
which is created with a call to create_dissector_handle or
@ -2489,16 +2496,30 @@ static void sub_dissector( tvbuff_t *tvb, packet_info *pinfo,
/* if conversation has a data field, create it and load structure */
new_conv_info = g_mem_chunk_alloc( new_conv_vals);
new_conv_info->data1 = value1;
/* First check if a conversation already exists for this
socketpair
*/
conversation = find_conversation(pinfo->fd->num,
&pinfo->src, &pinfo->dst, protocol,
src_port, dst_port, new_conv_info, 0);
/* If there is no such conversation, or if there is one but for
someone elses protocol then we just create a new conversation
and assign our protocol to it.
*/
if( (conversation==NULL)
|| (conversation->dissector_handle!=sub_dissector_handle) ){
new_conv_info = g_mem_chunk_alloc( new_conv_vals);
new_conv_info->data1 = value1;
/* create the conversation for the dynamic port */
conversation = conversation_new( &pinfo->src, &pinfo->dst, protocol,
src_port, dst_port, new_conv_info, 0);
conversation = conversation_new(pinfo->fd->num,
&pinfo->src, &pinfo->dst, protocol,
src_port, dst_port, new_conv_info, 0);
/* set the dissector for the new conversation */
conversation_set_dissector(conversation, sub_dissector_handle);
conversation_set_dissector(conversation, sub_dissector_handle);
}
...
void
@ -2525,6 +2546,19 @@ the server port and address. The key is to create the new
conversation with the second address and port set to the "accept
any" values.
Some server applications can use the same port for different protocols during
different stages of a transaction. For example it might initially use SNMP
to perform some discovery and later switch to use TFTP using the same port.
In order to handle this properly we must first check whether such a
conversation already exists or not and if it exists we also check whether the
registered dissector_handle for that conversation is "our" dissector or not.
If not we create a new conversation ontop of the previous one and set this new
conversation to use our protocol.
Since ethereal keeps track of the frame number where a conversation started
ethereal will still be able to keep the packets apart eventhough they do use
the same socketpair.
(See packet-tftp.c and packet-snmp.c for examples of this)
There are two support routines that will allow the second port and/or
address to be set latter.
@ -2556,12 +2590,25 @@ static dissector_handle_t sub_dissector_handle;
/* NOTE: The second address and port values don't matter because the */
/* NO_ADDR2 and NO_PORT2 options are set. */
conversation = conversation_new( &server_src_addr, 0, protocol,
/* First check if a conversation already exists for this
IP/protocol/port
*/
conversation = find_conversation(pinfo->fd->num,
&server_src_addr, 0, protocol,
server_src_port, 0, NO_ADDR2 | NO_PORT_B);
/* If there is no such conversation, or if there is one but for
someone elses protocol then we just create a new conversation
and assign our protocol to it.
*/
if( (conversation==NULL)
|| (conversation->dissector_handle!=sub_dissector_handle) ){
conversation = conversation_new(pinfo->fd->num,
&server_src_addr, 0, protocol,
server_src_port, 0, new_conv_info, NO_ADDR2 | NO_PORT2);
/* set the dissector for the new conversation */
conversation_set_dissector(conversation, sub_dissector_handle);
conversation_set_dissector(conversation, sub_dissector_handle);
}
2.5 Per packet information

View File

@ -1119,8 +1119,7 @@ conversation_delete_proto_data(conversation_t *conv, int proto)
}
void
conversation_set_dissector(conversation_t *conversation,
dissector_handle_t handle)
conversation_set_dissector(conversation_t *conversation, dissector_handle_t handle)
{
conversation->dissector_handle = handle;
}
@ -1129,6 +1128,11 @@ conversation_set_dissector(conversation_t *conversation,
* Given two address/port pairs for a packet, search for a matching
* conversation and, if found and it has a conversation dissector,
* call that dissector and return TRUE, otherwise return FALSE.
*
* This helper uses call_dissector_only which will NOT call the default
* "data" dissector if the packet was rejected.
* Our caller is responsible to call the data dissector explicitely in case
* this function returns FALSE.
*/
gboolean
try_conversation_dissector(address *addr_a, address *addr_b, port_type ptype,
@ -1141,10 +1145,18 @@ try_conversation_dissector(address *addr_a, address *addr_b, port_type ptype,
port_b, 0);
if (conversation != NULL) {
int ret;
if (conversation->dissector_handle == NULL)
return FALSE;
call_dissector(conversation->dissector_handle, tvb, pinfo,
ret=call_dissector_only(conversation->dissector_handle, tvb, pinfo,
tree);
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;
}
return FALSE;

View File

@ -2361,7 +2361,7 @@ dissect_snmp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
if (pinfo->destport == UDP_PORT_SNMP) {
conversation = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst, PT_UDP,
pinfo->srcport, 0, NO_PORT_B);
if (conversation == NULL) {
if( (conversation == NULL) || (conversation->dissector_handle!=snmp_handle) ){
conversation = conversation_new(pinfo->fd->num, &pinfo->src, &pinfo->dst, PT_UDP,
pinfo->srcport, 0, NO_PORT2);
conversation_set_dissector(conversation, snmp_handle);

View File

@ -117,10 +117,10 @@ dissect_tftp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
if (pinfo->destport == UDP_PORT_TFTP) {
conversation = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst, PT_UDP,
pinfo->srcport, 0, NO_PORT_B);
if (conversation == NULL) {
if( (conversation == NULL) || (conversation->dissector_handle!=tftp_handle) ){
conversation = conversation_new(pinfo->fd->num, &pinfo->src, &pinfo->dst, PT_UDP,
pinfo->srcport, 0, NO_PORT2);
conversation_set_dissector(conversation, tftp_handle);
conversation_set_dissector(conversation, tftp_handle);
}
}

View File

@ -98,8 +98,9 @@ decode_udp_ports(tvbuff_t *tvb, int offset, packet_info *pinfo,
/* for the conversation if available */
if (try_conversation_dissector(&pinfo->src, &pinfo->dst, PT_UDP,
uh_sport, uh_dport, next_tvb, pinfo, tree))
uh_sport, uh_dport, next_tvb, pinfo, tree)){
return;
}
if (try_heuristic_first) {
/* do lookup with the heuristic subdissector table */

View File

@ -365,6 +365,16 @@ struct dissector_handle {
protocol_t *protocol;
};
/* This function will return
* old style dissector :
* length of the payload or 1 of the payload is empty
* new dissector :
* >0 this protocol was successfully dissected and this was this protocol.
* 0 this packet did not match this protocol.
*
* The only time this function will return 0 is if it is a new style dissector
* and if the dissector rejected the packet.
*/
static int
call_dissector_through_handle(dissector_handle_t handle, tvbuff_t *tvb,
packet_info *pinfo, proto_tree *tree)
@ -379,9 +389,9 @@ call_dissector_through_handle(dissector_handle_t handle, tvbuff_t *tvb,
proto_get_protocol_short_name(handle->protocol);
}
if (handle->is_new)
if (handle->is_new) {
ret = (*handle->dissector.new)(tvb, pinfo, tree);
else {
} else {
(*handle->dissector.old)(tvb, pinfo, tree);
ret = tvb_length(tvb);
if (ret == 0) {
@ -1691,7 +1701,9 @@ new_register_dissector(const char *name, new_dissector_t dissector, int proto)
(gpointer) handle);
}
/* Call a dissector through a handle. */
/* Call a dissector through a handle and if this fails call the "data"
* dissector.
*/
int
call_dissector(dissector_handle_t handle, tvbuff_t *tvb,
packet_info *pinfo, proto_tree *tree)
@ -1712,6 +1724,19 @@ call_dissector(dissector_handle_t handle, tvbuff_t *tvb,
return ret;
}
/* Call a dissector through a handle but if the dissector rejected it
* return 0 instead of using the default "data" dissector.
*/
int
call_dissector_only(dissector_handle_t handle, tvbuff_t *tvb,
packet_info *pinfo, proto_tree *tree)
{
int ret;
ret = call_dissector_work(handle, tvb, pinfo, tree);
return ret;
}
/*
* Dumps the "layer type"/"decode as" associations to stdout, similar
* to the proto_registrar_dump_*() routines.

View File

@ -298,9 +298,16 @@ extern dissector_handle_t create_dissector_handle(dissector_t dissector,
extern dissector_handle_t new_create_dissector_handle(new_dissector_t dissector,
int proto);
/* Call a dissector through a handle. */
/* Call a dissector through a handle and if no dissector was found
* pass if over to the "data" dissector instead.
*/
extern int call_dissector(dissector_handle_t handle, tvbuff_t *tvb,
packet_info *pinfo, proto_tree *tree);
/* Call a dissector through a handle but if no dissector was found
* just return 0 and do not call the "data" dissector instead.
*/
extern int call_dissector_only(dissector_handle_t handle, tvbuff_t *tvb,
packet_info *pinfo, proto_tree *tree);
/* Do all one-time initialization. */
extern void dissect_init(void);