From d061f606b9515d99ab0fec9d38a453e523a387ba Mon Sep 17 00:00:00 2001 From: Guy Harris Date: Wed, 15 Dec 2004 09:25:48 +0000 Subject: From Peter Johansson: "template" conversations - if one is recognized, the template is left around, and a new conversation is created with the wildcards in the template un-wildcarded. svn path=/trunk/; revision=12757 --- epan/conversation.c | 663 ++++++++++++++++++++++++++++++++-------------------- epan/conversation.h | 8 + 2 files changed, 414 insertions(+), 257 deletions(-) (limited to 'epan') diff --git a/epan/conversation.c b/epan/conversation.c index dc1f7a9e97..6718db347b 100644 --- a/epan/conversation.c +++ b/epan/conversation.c @@ -87,6 +87,99 @@ typedef struct _conv_proto_data { static GMemChunk *conv_proto_data_area = NULL; +/* + * Creates a new conversation with known endpoints based on a conversation + * created with the CONVERSATION_TEMPLATE option while keeping the + * conversation created with the CONVERSATION_TEMPLATE option so it can still + * match future connections. + * + * Passing a pointer to a conversation whose options mask does not include + * CONVERSATION_TEMPLATE or where the conversation's protocol type (ptype) + * indicates a non-connnection oriented protocol will return the conversation + * without changes. + * + * addr2 and port2 are used in the function if their respective conversation + * options bits are set (NO_ADDR2 and NO_PORT2). + */ +conversation_t * +conversation_create_from_template(conversation_t *conversation, address *addr2, guint32 port2) +{ + /* + * Add a new conversation and keep the conversation template only if the + * CONVERSATION_TEMPLATE bit is set for a connection oriented protocol. + */ + if(conversation->options & CONVERSATION_TEMPLATE && + conversation->key_ptr->ptype != PT_UDP) + { + /* + * Set up a new options mask where the conversation template bit and the + * bits for absence of a second address and port pair have been removed. + */ + conversation_t *new_conversation_from_template; + guint options = conversation->options & ~(CONVERSATION_TEMPLATE | NO_ADDR2 | NO_PORT2); + + /* + * Are both the NO_ADDR2 and NO_PORT2 wildcards set in the options mask? + */ + if(conversation->options & NO_ADDR2 && + conversation->options & NO_PORT2) + { + /* + * The conversation template was created without knowledge of both + * the second address as well as the second port. Create a new + * conversation with new 2nd address and 2nd port. + */ + new_conversation_from_template = + conversation_new(&conversation->key_ptr->addr1, addr2, + conversation->key_ptr->ptype, conversation->key_ptr->port1, + port2, options); + } + else if(conversation->options & NO_PORT2) + { + /* + * The conversation template was created without knowledge of port 2 + * only. Create a new conversation with new 2nd port. + */ + new_conversation_from_template = + conversation_new(&conversation->key_ptr->addr1, &conversation->key_ptr->addr2, + conversation->key_ptr->ptype, conversation->key_ptr->port1, + port2, options); + } + else if(conversation->options & NO_ADDR2) + { + /* + * The conversation template was created without knowledge of address + * 2. Create a new conversation with new 2nd address. + */ + new_conversation_from_template = + conversation_new(&conversation->key_ptr->addr1, addr2, + conversation->key_ptr->ptype, conversation->key_ptr->port1, + conversation->key_ptr->port2, options); + } + else + { + /* + * The CONVERSATION_TEMPLATE bit was set, but no other bit that the + * CONVERSATION_TEMPLATE bit controls is active. Just return the old + * conversation. + */ + return conversation; + } + + /* + * Set the protocol dissector used for the template conversation as + * the handler of the new conversation as well. + */ + new_conversation_from_template->dissector_handle = conversation->dissector_handle; + + return new_conversation_from_template; + } + else + { + return conversation; + } +} + /* * Compute the hash value for two given address/port pairs if the match * is to be exact. @@ -438,6 +531,10 @@ conversation_t * conversation_new(address *addr1, address *addr2, port_type ptype, guint32 port1, guint32 port2, guint options) { +/* + g_assert(!(options | CONVERSATION_TEMPLATE) || ((options | (NO_ADDR2 | NO_PORT2 | NO_PORT2_FORCE))) && + "A conversation template may not be constructed without wildcard options"); +*/ conversation_t *conversation; conversation_key *new_key; @@ -454,10 +551,10 @@ conversation_new(address *addr1, address *addr2, port_type ptype, conversation->index = new_index; conversation->data_list = NULL; -/* clear dissector handle */ + /* clear dissector handle */ conversation->dissector_handle = NULL; -/* set the options and key pointer */ + /* set the options and key pointer */ conversation->options = options; conversation->key_ptr = new_key; @@ -490,10 +587,13 @@ conversation_new(address *addr1, address *addr2, port_type ptype, void conversation_set_port2(conversation_t *conv, guint32 port) { + g_assert(!(conv->options & CONVERSATION_TEMPLATE) && + "Use the conversation_create_from_template function when the CONVERSATION_TEMPLATE bit is set in the options mask"); + /* * If the port 2 value is not wildcarded, don't set it. */ - if ((!(conv->options & NO_PORT2)) || (conv->options & NO_PORT2_FORCE)) + if ((!(conv->options & NO_PORT2)) || (conv->options & NO_PORT2_FORCE)) return; if (conv->options & NO_ADDR2) { @@ -521,6 +621,9 @@ conversation_set_port2(conversation_t *conv, guint32 port) void conversation_set_addr2(conversation_t *conv, address *addr) { + g_assert(!(conv->options & CONVERSATION_TEMPLATE) && + "Use the conversation_create_from_template function when the CONVERSATION_TEMPLATE bit is set in the options mask"); + /* * If the address 2 value is not wildcarded, don't set it. */ @@ -608,261 +711,307 @@ conversation_t * find_conversation(address *addr_a, address *addr_b, port_type ptype, guint32 port_a, guint32 port_b, guint options) { - conversation_t *conversation; - - /* - * First try an exact match, if we have two addresses and ports. - */ - if (!(options & (NO_ADDR_B|NO_PORT_B))) { - /* - * Neither search address B nor search port B are wildcarded, - * start out with an exact match. - * Exact matches check both directions. - */ - conversation = - conversation_lookup_hashtable(conversation_hashtable_exact, - addr_a, addr_b, ptype, - port_a, port_b); - if ((conversation == NULL) && (addr_a->type == AT_FC)) { - /* In Fibre channel, OXID & RXID are never swapped as - * TCP/UDP ports are in TCP/IP. - */ - conversation = - conversation_lookup_hashtable(conversation_hashtable_exact, - addr_b, addr_a, ptype, - port_a, port_b); - } - if (conversation != NULL) - return conversation; - } - - /* - * Well, that didn't find anything. Try matches that wildcard - * one of the addresses, if we have two ports. - */ - if (!(options & NO_PORT_B)) { - /* - * Search port B isn't wildcarded. - * - * First try looking for a conversation with the specified - * address A and port A as the first address and port, and - * with any address and the specified port B as the second - * address and port. - * ("addr_b" doesn't take part in this lookup.) - */ - conversation = - conversation_lookup_hashtable(conversation_hashtable_no_addr2, - addr_a, addr_b, ptype, port_a, port_b); - if ((conversation == NULL) && (addr_a->type == AT_FC)) { - /* In Fibre channel, OXID & RXID are never swapped as - * TCP/UDP ports are in TCP/IP. - */ - conversation = - conversation_lookup_hashtable(conversation_hashtable_no_addr2, - addr_b, addr_a, ptype, - port_a, port_b); - } - if (conversation != NULL) { - /* - * If search address B isn't wildcarded, and this - * is for a connection-oriented protocol, set the - * second address for this conversation to address - * B, as that's the address that matched the - * wildcarded second address for this conversation. - * - * (XXX - this assumes that, for all connection- - * oriented protocols, the endpoints of a connection - * have only one address each, i.e. you don't get - * packets in a given direction coming from more than - * one address.) - */ - if (!(options & NO_ADDR_B) && ptype != PT_UDP) - conversation_set_addr2(conversation, addr_b); - return conversation; - } - - /* - * Well, that didn't find anything. - * If search address B was specified, try looking for a - * conversation with the specified address B and port B as - * the first address and port, and with any address and the - * specified port A as the second address and port (this - * packet may be going in the opposite direction from the - * first packet in the conversation). - * ("addr_a" doesn't take part in this lookup.) - */ - if (!(options & NO_ADDR_B)) { - conversation = - conversation_lookup_hashtable(conversation_hashtable_no_addr2, - addr_b, addr_a, ptype, port_b, port_a); - if (conversation != NULL) { - /* - * If this is for a connection-oriented - * protocol, set the second address for - * this conversation to address A, as - * that's the address that matched the - * wildcarded second address for this - * conversation. - */ - if (ptype != PT_UDP) { - conversation_set_addr2(conversation, - addr_a); - } - return conversation; - } - } - } - - /* - * Well, that didn't find anything. Try matches that wildcard - * one of the ports, if we have two addresses. - */ - if (!(options & NO_ADDR_B)) { - /* - * Search address B isn't wildcarded. - * - * First try looking for a conversation with the specified - * address A and port A as the first address and port, and - * with the specified address B and any port as the second - * address and port. - * ("port_b" doesn't take part in this lookup.) - */ - conversation = - conversation_lookup_hashtable(conversation_hashtable_no_port2, - addr_a, addr_b, ptype, port_a, port_b); - if ((conversation == NULL) && (addr_a->type == AT_FC)) { - /* In Fibre channel, OXID & RXID are never swapped as - * TCP/UDP ports are in TCP/IP - */ - conversation = - conversation_lookup_hashtable(conversation_hashtable_no_port2, - addr_b, addr_a, ptype, port_a, port_b); - } - if (conversation != NULL) { - /* - * If search port B isn't wildcarded, and this is - * for a connection-oriented protocol, set the - * second port for this conversation to port B, - * as that's the port that matched the wildcarded - * second port for this conversation. - * - * (XXX - this assumes that, for all connection- - * oriented protocols, the endpoints of a connection - * have only one port each, i.e. you don't get - * packets in a given direction coming from more than - * one port.) - */ - if (!(options & NO_PORT_B) && ptype != PT_UDP) - conversation_set_port2(conversation, port_b); - return conversation; - } - - /* - * Well, that didn't find anything. - * If search port B was specified, try looking for a - * conversation with the specified address B and port B - * as the first address and port, and with the specified - * address A and any port as the second address and port - * (this packet may be going in the opposite direction - * from the first packet in the conversation). - * ("port_a" doesn't take part in this lookup.) - */ - if (!(options & NO_PORT_B)) { - conversation = - conversation_lookup_hashtable(conversation_hashtable_no_port2, - addr_b, addr_a, ptype, port_b, port_a); - if (conversation != NULL) { - /* - * If this is for a connection-oriented - * protocol, set the second port for - * this conversation to port A, as - * that's the address that matched the - * wildcarded second address for this - * conversation. - */ - if (ptype != PT_UDP) { - conversation_set_port2(conversation, - port_a); - } - return conversation; - } - } - } - - /* - * Well, that didn't find anything. Try matches that wildcard - * one address/port pair. - * - * First try looking for a conversation with the specified address A - * and port A as the first address and port. - * (Neither "addr_b" nor "port_b" take part in this lookup.) - */ - conversation = - conversation_lookup_hashtable(conversation_hashtable_no_addr2_or_port2, - addr_a, addr_b, ptype, port_a, port_b); - if (conversation != NULL) { - /* - * If this is for a connection-oriented protocol: - * - * if search address B isn't wildcarded, set the - * second address for this conversation to address - * B, as that's the address that matched the - * wildcarded second address for this conversation; - * - * if search port B isn't wildcarded, set the - * second port for this conversation to port B, - * as that's the port that matched the wildcarded - * second port for this conversation. - */ - if (ptype != PT_UDP) { - if (!(options & NO_ADDR_B)) - conversation_set_addr2(conversation, addr_b); - if (!(options & NO_PORT_B)) - conversation_set_port2(conversation, port_b); - } - return conversation; - } - - /* - * Well, that didn't find anything. - * If search address and port B were specified, try looking for a - * conversation with the specified address B and port B as the - * first address and port, and with any second address and port - * (this packet may be going in the opposite direction from the - * first packet in the conversation). - * (Neither "addr_a" nor "port_a" take part in this lookup.) - */ - if (addr_a->type == AT_FC) + conversation_t *conversation; + + /* + * First try an exact match, if we have two addresses and ports. + */ + if (!(options & (NO_ADDR_B|NO_PORT_B))) { + /* + * Neither search address B nor search port B are wildcarded, + * start out with an exact match. + * Exact matches check both directions. + */ + conversation = + conversation_lookup_hashtable(conversation_hashtable_exact, + addr_a, addr_b, ptype, + port_a, port_b); + if ((conversation == NULL) && (addr_a->type == AT_FC)) { + /* In Fibre channel, OXID & RXID are never swapped as + * TCP/UDP ports are in TCP/IP. + */ + conversation = + conversation_lookup_hashtable(conversation_hashtable_exact, + addr_b, addr_a, ptype, + port_a, port_b); + } + if (conversation != NULL) + return conversation; + } + + /* + * Well, that didn't find anything. Try matches that wildcard + * one of the addresses, if we have two ports. + */ + if (!(options & NO_PORT_B)) { + /* + * Search port B isn't wildcarded. + * + * First try looking for a conversation with the specified + * address A and port A as the first address and port, and + * with any address and the specified port B as the second + * address and port. + * ("addr_b" doesn't take part in this lookup.) + */ + conversation = + conversation_lookup_hashtable(conversation_hashtable_no_addr2, + addr_a, addr_b, ptype, port_a, port_b); + if ((conversation == NULL) && (addr_a->type == AT_FC)) { + /* In Fibre channel, OXID & RXID are never swapped as + * TCP/UDP ports are in TCP/IP. + */ + conversation = + conversation_lookup_hashtable(conversation_hashtable_no_addr2, + addr_b, addr_a, ptype, + port_a, port_b); + } + if (conversation != NULL) { + /* + * If search address B isn't wildcarded, and this is for a + * connection-oriented protocol, set the second address for this + * conversation to address B, as that's the address that matched the + * wildcarded second address for this conversation. + * + * (This assumes that, for all connection oriented protocols, the + * endpoints of a connection have only one address each, i.e. you + * don't get packets in a given direction coming from more than one + * address, unless the CONVERSATION_TEMPLATE option is set.) + */ + if (!(options & NO_ADDR_B) && ptype != PT_UDP) + { + if(!(options & CONVERSATION_TEMPLATE)) + { + conversation_set_addr2(conversation, addr_b); + } + else + { + conversation = + conversation_create_from_template(conversation, addr_b, 0); + } + } + return conversation; + } + + /* + * Well, that didn't find anything. + * If search address B was specified, try looking for a + * conversation with the specified address B and port B as + * the first address and port, and with any address and the + * specified port A as the second address and port (this + * packet may be going in the opposite direction from the + * first packet in the conversation). + * ("addr_a" doesn't take part in this lookup.) + */ + if (!(options & NO_ADDR_B)) { + conversation = + conversation_lookup_hashtable(conversation_hashtable_no_addr2, + addr_b, addr_a, ptype, port_b, port_a); + if (conversation != NULL) { + /* + * If this is for a connection-oriented + * protocol, set the second address for + * this conversation to address A, as + * that's the address that matched the + * wildcarded second address for this + * conversation. + */ + if (ptype != PT_UDP) { + if(!(options & CONVERSATION_TEMPLATE)) + { + conversation_set_addr2(conversation, addr_a); + } + else + { + conversation = + conversation_create_from_template(conversation, addr_a, 0); + } + } + return conversation; + } + } + } + + /* + * Well, that didn't find anything. Try matches that wildcard + * one of the ports, if we have two addresses. + */ + if (!(options & NO_ADDR_B)) { + /* + * Search address B isn't wildcarded. + * + * First try looking for a conversation with the specified + * address A and port A as the first address and port, and + * with the specified address B and any port as the second + * address and port. + * ("port_b" doesn't take part in this lookup.) + */ + conversation = + conversation_lookup_hashtable(conversation_hashtable_no_port2, + addr_a, addr_b, ptype, port_a, port_b); + if ((conversation == NULL) && (addr_a->type == AT_FC)) { + /* In Fibre channel, OXID & RXID are never swapped as + * TCP/UDP ports are in TCP/IP + */ + conversation = + conversation_lookup_hashtable(conversation_hashtable_no_port2, + addr_b, addr_a, ptype, port_a, port_b); + } + if (conversation != NULL) { + /* + * If search port B isn't wildcarded, and this is for a connection- + * oriented protocol, set the second port for this conversation to + * port B, as that's the port that matched the wildcarded second port + * for this conversation. + * + * (This assumes that, for all connection oriented protocols, the + * endpoints of a connection have only one port each, i.e. you don't + * get packets in a given direction coming from more than one port, + * unless the CONVERSATION_TEMPLATE option is set.) + */ + if (!(options & NO_PORT_B) && ptype != PT_UDP) + { + if(!(options & CONVERSATION_TEMPLATE)) + { + conversation_set_port2(conversation, port_b); + } + else + { + conversation = + conversation_create_from_template(conversation, 0, port_b); + } + } + return conversation; + } + + /* + * Well, that didn't find anything. + * If search port B was specified, try looking for a + * conversation with the specified address B and port B + * as the first address and port, and with the specified + * address A and any port as the second address and port + * (this packet may be going in the opposite direction + * from the first packet in the conversation). + * ("port_a" doesn't take part in this lookup.) + */ + if (!(options & NO_PORT_B)) { + conversation = + conversation_lookup_hashtable(conversation_hashtable_no_port2, + addr_b, addr_a, ptype, port_b, port_a); + if (conversation != NULL) { + /* + * If this is for a connection-oriented + * protocol, set the second port for + * this conversation to port A, as + * that's the address that matched the + * wildcarded second address for this + * conversation. + */ + if (ptype != PT_UDP) + { + if(!(options & CONVERSATION_TEMPLATE)) + { + conversation_set_port2(conversation, port_a); + } + else + { + conversation = + conversation_create_from_template(conversation, 0, port_a); + } + } + return conversation; + } + } + } + + /* + * Well, that didn't find anything. Try matches that wildcard + * one address/port pair. + * + * First try looking for a conversation with the specified address A + * and port A as the first address and port. + * (Neither "addr_b" nor "port_b" take part in this lookup.) + */ + conversation = + conversation_lookup_hashtable(conversation_hashtable_no_addr2_or_port2, + addr_a, addr_b, ptype, port_a, port_b); + if (conversation != NULL) { + /* + * If this is for a connection-oriented protocol: + * + * if search address B isn't wildcarded, set the + * second address for this conversation to address + * B, as that's the address that matched the + * wildcarded second address for this conversation; + * + * if search port B isn't wildcarded, set the + * second port for this conversation to port B, + * as that's the port that matched the wildcarded + * second port for this conversation. + */ + if (ptype != PT_UDP) + { + if(!(options & CONVERSATION_TEMPLATE)) + { + if (!(options & NO_ADDR_B)) + conversation_set_addr2(conversation, addr_b); + if (!(options & NO_PORT_B)) + conversation_set_port2(conversation, port_b); + } + else + { conversation = - conversation_lookup_hashtable(conversation_hashtable_no_addr2_or_port2, - addr_b, addr_a, ptype, port_a, - port_b); - else - conversation = - conversation_lookup_hashtable(conversation_hashtable_no_addr2_or_port2, - addr_b, addr_a, ptype, port_b, - port_a); - if (conversation != NULL) { - /* - * If this is for a connection-oriented protocol, set the - * second address for this conversation to address A, as - * that's the address that matched the wildcarded second - * address for this conversation, and set the second port - * for this conversation to port A, as that's the port - * that matched the wildcarded second port for this - * conversation. - */ - if (ptype != PT_UDP) { - conversation_set_addr2(conversation, addr_a); - conversation_set_port2(conversation, port_a); - } - return conversation; - } - - /* - * We found no conversation. - */ - return NULL; + conversation_create_from_template(conversation, addr_b, port_b); + } + } + return conversation; + } + + /* + * Well, that didn't find anything. + * If search address and port B were specified, try looking for a + * conversation with the specified address B and port B as the + * first address and port, and with any second address and port + * (this packet may be going in the opposite direction from the + * first packet in the conversation). + * (Neither "addr_a" nor "port_a" take part in this lookup.) + */ + if (addr_a->type == AT_FC) + conversation = + conversation_lookup_hashtable(conversation_hashtable_no_addr2_or_port2, + addr_b, addr_a, ptype, port_a, port_b); + else + conversation = + conversation_lookup_hashtable(conversation_hashtable_no_addr2_or_port2, + addr_b, addr_a, ptype, port_b, port_a); + if (conversation != NULL) { + /* + * If this is for a connection-oriented protocol, set the + * second address for this conversation to address A, as + * that's the address that matched the wildcarded second + * address for this conversation, and set the second port + * for this conversation to port A, as that's the port + * that matched the wildcarded second port for this + * conversation. + */ + if (ptype != PT_UDP) + { + if(!(conversation->options & CONVERSATION_TEMPLATE)) + { + conversation_set_addr2(conversation, addr_a); + conversation_set_port2(conversation, port_a); + } + else + { + conversation = conversation_create_from_template(conversation, addr_a, port_a); + } + } + return conversation; + } + + /* + * We found no conversation. + */ + return NULL; } static gint diff --git a/epan/conversation.h b/epan/conversation.h index b148d9aaa9..04256a9305 100644 --- a/epan/conversation.h +++ b/epan/conversation.h @@ -28,10 +28,18 @@ /* * Flags to pass to "conversation_new()" to indicate that the address 2 * and/or port 2 values for the conversation should be wildcards. + * The CONVERSATION_TEMPLATE option tells that any of the other supplied + * port and / or address wildcards will be used to match an infinite number + * of new connections to the conversation(s) that have the CONVERSATION_- + * TEMPLATE flag set. Any conversation created without the CONVERSATION_- + * TEMPLATE flag will be altered once the first connections (connection + * oriented protocols only) to include the newly found information which + * matched the wildcard options. */ #define NO_ADDR2 0x01 #define NO_PORT2 0x02 #define NO_PORT2_FORCE 0x04 +#define CONVERSATION_TEMPLATE 0x08 /* * Flags to pass to "find_conversation()" to indicate that the address B -- cgit v1.2.3