aboutsummaryrefslogtreecommitdiffstats
path: root/epan/conversation.c
diff options
context:
space:
mode:
authorAndersBroman <anders.broman@ericsson.com>2016-02-01 13:00:29 +0100
committerAnders Broman <a.broman58@gmail.com>2016-02-02 05:15:55 +0000
commitf80e9df7939be9d88062718d6c15fa2983e5e605 (patch)
tree5c77f37e767b568e7881c06d55ecb062e205e17e /epan/conversation.c
parent872f8b45826d2bd0fe5b87a23516f82d926f2944 (diff)
Create an extended converstaion hastable taking more address information
into consideration. This makes it possible to differentiate between packets on different vlans and can be expanded to handle tunnels. Change-Id: Id36e71028702d1ba4b6b3047e822e5a62056a1e2 Reviewed-on: https://code.wireshark.org/review/13637 Reviewed-by: Anders Broman <a.broman58@gmail.com>
Diffstat (limited to 'epan/conversation.c')
-rw-r--r--epan/conversation.c286
1 files changed, 268 insertions, 18 deletions
diff --git a/epan/conversation.c b/epan/conversation.c
index 9357f0e9ed..70c3ab0a27 100644
--- a/epan/conversation.c
+++ b/epan/conversation.c
@@ -29,7 +29,6 @@
#include "conversation.h"
/* define DEBUG_CONVERSATION for pretty debug printing */
-/* #define DEBUG_CONVERSATION */
#include "conversation_debug.h"
#ifdef DEBUG_CONVERSATION
@@ -37,6 +36,12 @@ int _debug_conversation_indent = 0;
#endif
/*
+* Hash table for conversations with no wildcards and extended keys for transport to
+* differentiate between packets with different vlan_ids etc
+*/
+static GHashTable *conversation_hashtable_exact_ext = NULL;
+
+/*
* Hash table for conversations with no wildcards.
*/
static GHashTable *conversation_hashtable_exact = NULL;
@@ -65,6 +70,7 @@ typedef struct conversation_key {
port_type ptype;
guint32 port1;
guint32 port2;
+ guint32 vlan_id; /** Outer VLAN Id from pinfo->vlan_id, currently only used in conversation_hashtable_exact_ext*/
} conversation_key;
#endif
/*
@@ -215,6 +221,43 @@ conversation_hash_exact(gconstpointer v)
}
/*
+* Compute the hash value for two given address/port pairs if the match
+* is to be exact extended with more transport parameters like vlan id
+*/
+/* http://eternallyconfuzzled.com/tuts/algorithms/jsw_tut_hashing.aspx#existing
+* One-at-a-Time hash
+*/
+static guint
+conversation_hash_exact_ext(gconstpointer v)
+{
+ const conversation_key *key = (const conversation_key *)v;
+ guint hash_val;
+ address tmp_addr;
+
+ hash_val = 0;
+ tmp_addr.len = 4;
+
+ hash_val = add_address_to_hash(hash_val, &key->addr1);
+
+ tmp_addr.data = &key->port1;
+ hash_val = add_address_to_hash(hash_val, &tmp_addr);
+
+ hash_val = add_address_to_hash(hash_val, &key->addr2);
+
+ tmp_addr.data = &key->port2;
+ hash_val = add_address_to_hash(hash_val, &tmp_addr);
+
+ tmp_addr.data = &key->vlan_id;
+ hash_val = add_address_to_hash(hash_val, &tmp_addr);
+
+ hash_val += (hash_val << 3);
+ hash_val ^= (hash_val >> 11);
+ hash_val += (hash_val << 15);
+
+ return hash_val;
+}
+
+/*
* Compare two conversation keys for an exact match.
*/
static gint
@@ -267,6 +310,65 @@ conversation_match_exact(gconstpointer v, gconstpointer w)
}
/*
+* Compare two conversation keys for an exact match.
+* extended with more address keys
+*/
+static gint
+conversation_match_exact_ext(gconstpointer v, gconstpointer w)
+{
+ const conversation_key *v1 = (const conversation_key *)v;
+ const conversation_key *v2 = (const conversation_key *)w;
+
+ if (v1->ptype != v2->ptype)
+ return 0; /* different types of port */
+
+ /*
+ * Are the first and second port 1 values the same, the first and
+ * second port 2 values the same, the first and second address
+ * 1 values the same, and the first and second address 2 values
+ * the same?
+ */
+ DPRINT(("match exact ext: %s:%d -> %s:%d (ptype=%d, vlan_id1 %u, vlan_id2 %u)",
+ address_to_str(wmem_packet_scope(), &v1->addr1), v1->port1,
+ address_to_str(wmem_packet_scope(), &v2->addr1), v2->port2, v1->ptype, v1->vlan_id, v2->vlan_id));
+
+ if (v1->port1 == v2->port1 &&
+ v1->port2 == v2->port2 &&
+ addresses_equal(&v1->addr1, &v2->addr1) &&
+ addresses_equal(&v1->addr2, &v2->addr2) &&
+ v1->vlan_id == v2->vlan_id) {
+ /*
+ * Yes. It's the same conversation, and the two
+ * address/port pairs are going in the same direction.
+ */
+ return 1;
+ }
+
+ /*
+ * Is the first port 2 the same as the second port 1, the first
+ * port 1 the same as the second port 2, the first address 2
+ * the same as the second address 1, and the first address 1
+ * the same as the second address 2?
+ */
+ if (v1->port2 == v2->port1 &&
+ v1->port1 == v2->port2 &&
+ addresses_equal(&v1->addr2, &v2->addr1) &&
+ addresses_equal(&v1->addr1, &v2->addr2) &&
+ v1->vlan_id == v2->vlan_id) {
+ /*
+ * Yes. It's the same conversation, and the two
+ * address/port pairs are going in opposite directions.
+ */
+ return 1;
+ }
+
+ /*
+ * The addresses or the ports don't match.
+ */
+ return 0;
+}
+
+/*
* Compute the hash value for two given address/port pairs if the match
* has a wildcard address 2.
*/
@@ -484,6 +586,9 @@ conversation_cleanup(void)
* don't have to clean them up.
*/
conversation_keys = NULL;
+ if (conversation_hashtable_exact_ext != NULL) {
+ g_hash_table_destroy(conversation_hashtable_exact_ext);
+ }
if (conversation_hashtable_exact != NULL) {
g_hash_table_destroy(conversation_hashtable_exact);
}
@@ -497,6 +602,7 @@ conversation_cleanup(void)
g_hash_table_destroy(conversation_hashtable_no_addr2_or_port2);
}
+ conversation_hashtable_exact_ext = NULL;
conversation_hashtable_exact = NULL;
conversation_hashtable_no_addr2 = NULL;
conversation_hashtable_no_port2 = NULL;
@@ -518,6 +624,9 @@ conversation_init(void)
* pointed to by conversation data structures that were freed
* above.
*/
+ conversation_hashtable_exact_ext =
+ g_hash_table_new_full(conversation_hash_exact_ext,
+ conversation_match_exact_ext, NULL, free_data_list);
conversation_hashtable_exact =
g_hash_table_new_full(conversation_hash_exact,
conversation_match_exact, NULL, free_data_list);
@@ -663,10 +772,13 @@ conversation_remove_from_hashtable(GHashTable *hashtable, conversation_t *conv)
* The options field is used to specify whether the address 2 value
* and/or port 2 value are not given and any value is acceptable
* when searching for this conversation.
+ *
+ * If option USE_EXT_ADDRESS_INF is used pinfo MUST be included and only exact match of the address
+ * parameters will work.
*/
conversation_t *
-conversation_new(const guint32 setup_frame, const address *addr1, const address *addr2, const port_type ptype,
- const guint32 port1, const guint32 port2, const guint options)
+conversation_new_ext(const guint32 setup_frame, const address *addr1, const address *addr2, const port_type ptype,
+ const guint32 port1, const guint32 port2, packet_info *pinfo, const guint options)
{
/*
DISSECTOR_ASSERT(!(options | CONVERSATION_TEMPLATE) || ((options | (NO_ADDR2 | NO_PORT2 | NO_PORT2_FORCE))) &&
@@ -676,9 +788,9 @@ conversation_new(const guint32 setup_frame, const address *addr1, const address
conversation_t *conversation=NULL;
conversation_key *new_key;
- DPRINT(("creating conversation for frame #%d: %s:%d -> %s:%d (ptype=%d)",
+ DPRINT(("creating conversation for frame #%d: %s:%d -> %s:%d (ptype=%d, options %u)",
setup_frame, address_to_str(wmem_packet_scope(), addr1), port1,
- address_to_str(wmem_packet_scope(), addr2), port2, ptype));
+ address_to_str(wmem_packet_scope(), addr2), port2, ptype, options));
if (options & NO_ADDR2) {
if (options & (NO_PORT2|NO_PORT2_FORCE)) {
@@ -702,6 +814,15 @@ conversation_new(const guint32 setup_frame, const address *addr1, const address
new_key->ptype = ptype;
new_key->port1 = port1;
new_key->port2 = port2;
+ if (options == USE_EXT_ADDRESS_INF) {
+ DPRINT(("Extended addr inf, vlan_id %u", pinfo->vlan_id));
+ hashtable = conversation_hashtable_exact_ext;
+ new_key->vlan_id = pinfo->vlan_id;
+ }
+ else {
+ new_key->vlan_id = 0;
+ }
+
conversation = wmem_new(wmem_file_scope(), conversation_t);
memset(conversation, 0, sizeof(conversation_t));
@@ -726,6 +847,20 @@ conversation_new(const guint32 setup_frame, const address *addr1, const address
}
/*
+* Given two address/port pairs for a packet, create a new conversation
+* to contain packets between those address/port pairs.
+*
+* The options field is used to specify whether the address 2 value
+* and/or port 2 value are not given and any value is acceptable
+* when searching for this conversation.
+*/
+conversation_t *
+conversation_new(const guint32 setup_frame, const address *addr1, const address *addr2, const port_type ptype,
+ const guint32 port1, const guint32 port2, const guint options)
+{
+ return conversation_new_ext(setup_frame, addr1, addr2, ptype, port1, port2, NULL, options);
+}
+/*
* Set the port 2 value in a key. Remove the original from table,
* update the options and port values, insert the updated key.
*/
@@ -802,7 +937,7 @@ conversation_set_addr2(conversation_t *conv, const address *addr)
*/
static conversation_t *
conversation_lookup_hashtable(GHashTable *hashtable, const guint32 frame_num, const address *addr1, const address *addr2,
- const port_type ptype, const guint32 port1, const guint32 port2)
+ const port_type ptype, const guint32 port1, const guint32 port2, packet_info *pinfo)
{
conversation_t* convo=NULL;
conversation_t* match=NULL;
@@ -818,6 +953,9 @@ conversation_lookup_hashtable(GHashTable *hashtable, const guint32 frame_num, co
key.ptype = ptype;
key.port1 = port1;
key.port2 = port2;
+ if (pinfo) {
+ key.vlan_id = pinfo->vlan_id;
+ }
chain_head = (conversation_t *)g_hash_table_lookup(hashtable, &key);
@@ -898,14 +1036,14 @@ find_conversation(const guint32 frame_num, const address *addr_a, const address
conversation =
conversation_lookup_hashtable(conversation_hashtable_exact,
frame_num, addr_a, addr_b, ptype,
- port_a, port_b);
+ port_a, port_b, NULL);
/* Didn't work, try the other direction */
if (conversation == NULL) {
DPRINT(("trying opposite direction"));
conversation =
conversation_lookup_hashtable(conversation_hashtable_exact,
frame_num, addr_b, addr_a, ptype,
- port_b, port_a);
+ port_b, port_a, NULL);
}
if ((conversation == NULL) && (addr_a->type == AT_FC)) {
/* In Fibre channel, OXID & RXID are never swapped as
@@ -914,7 +1052,7 @@ find_conversation(const guint32 frame_num, const address *addr_a, const address
conversation =
conversation_lookup_hashtable(conversation_hashtable_exact,
frame_num, addr_b, addr_a, ptype,
- port_a, port_b);
+ port_a, port_b, NULL);
}
DPRINT(("exact match %sfound",conversation?"":"not "));
if (conversation != NULL)
@@ -938,7 +1076,7 @@ find_conversation(const guint32 frame_num, const address *addr_a, const address
DPRINT(("trying wildcarded dest address"));
conversation =
conversation_lookup_hashtable(conversation_hashtable_no_addr2,
- frame_num, addr_a, addr_b, ptype, port_a, port_b);
+ frame_num, addr_a, addr_b, ptype, port_a, port_b, NULL);
if ((conversation == NULL) && (addr_a->type == AT_FC)) {
/* In Fibre channel, OXID & RXID are never swapped as
* TCP/UDP ports are in TCP/IP.
@@ -946,7 +1084,7 @@ find_conversation(const guint32 frame_num, const address *addr_a, const address
conversation =
conversation_lookup_hashtable(conversation_hashtable_no_addr2,
frame_num, addr_b, addr_a, ptype,
- port_a, port_b);
+ port_a, port_b, NULL);
}
if (conversation != NULL) {
/*
@@ -990,7 +1128,7 @@ find_conversation(const guint32 frame_num, const address *addr_a, const address
DPRINT(("trying dest addr:port as source addr:port with wildcarded dest addr"));
conversation =
conversation_lookup_hashtable(conversation_hashtable_no_addr2,
- frame_num, addr_b, addr_a, ptype, port_b, port_a);
+ frame_num, addr_b, addr_a, ptype, port_b, port_a, NULL);
if (conversation != NULL) {
/*
* If this is for a connection-oriented
@@ -1034,14 +1172,14 @@ find_conversation(const guint32 frame_num, const address *addr_a, const address
DPRINT(("trying wildcarded dest port"));
conversation =
conversation_lookup_hashtable(conversation_hashtable_no_port2,
- frame_num, addr_a, addr_b, ptype, port_a, port_b);
+ frame_num, addr_a, addr_b, ptype, port_a, port_b, NULL);
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,
- frame_num, addr_b, addr_a, ptype, port_a, port_b);
+ frame_num, addr_b, addr_a, ptype, port_a, port_b, NULL);
}
if (conversation != NULL) {
/*
@@ -1085,7 +1223,7 @@ find_conversation(const guint32 frame_num, const address *addr_a, const address
DPRINT(("trying dest addr:port as source addr:port and wildcarded dest port"));
conversation =
conversation_lookup_hashtable(conversation_hashtable_no_port2,
- frame_num, addr_b, addr_a, ptype, port_b, port_a);
+ frame_num, addr_b, addr_a, ptype, port_b, port_a, NULL);
if (conversation != NULL) {
/*
* If this is for a connection-oriented
@@ -1124,7 +1262,7 @@ find_conversation(const guint32 frame_num, const address *addr_a, const address
DPRINT(("trying wildcarding dest addr:port"));
conversation =
conversation_lookup_hashtable(conversation_hashtable_no_addr2_or_port2,
- frame_num, addr_a, addr_b, ptype, port_a, port_b);
+ frame_num, addr_a, addr_b, ptype, port_a, port_b, NULL);
if (conversation != NULL) {
/*
* If this is for a connection-oriented protocol:
@@ -1171,11 +1309,11 @@ find_conversation(const guint32 frame_num, const address *addr_a, const address
if (addr_a->type == AT_FC)
conversation =
conversation_lookup_hashtable(conversation_hashtable_no_addr2_or_port2,
- frame_num, addr_b, addr_a, ptype, port_a, port_b);
+ frame_num, addr_b, addr_a, ptype, port_a, port_b, NULL);
else
conversation =
conversation_lookup_hashtable(conversation_hashtable_no_addr2_or_port2,
- frame_num, addr_b, addr_a, ptype, port_b, port_a);
+ frame_num, addr_b, addr_a, ptype, port_b, port_a, NULL);
if (conversation != NULL) {
/*
* If this is for a connection-oriented protocol, set the
@@ -1210,6 +1348,55 @@ find_conversation(const guint32 frame_num, const address *addr_a, const address
return NULL;
}
+/*
+* Try to find a conversation matching the extended address information key
+* returns NULL if not found.
+*
+*/
+conversation_t *
+find_conversation_ext_from_pinfo(packet_info *pinfo)
+{
+ conversation_t *conversation;
+
+ DPRINT(("trying exact match ext"));
+ DPRINT(("for frame #%d: %s:%d -> %s:%d vlan_id %u (ptype=%d)",
+ pinfo->num, address_to_str(wmem_packet_scope(), &pinfo->src), pinfo->srcport,
+ address_to_str(wmem_packet_scope(), &pinfo->dst), pinfo->destport, pinfo->vlan_id, pinfo->ptype));
+ conversation =
+ conversation_lookup_hashtable(conversation_hashtable_exact_ext,
+ pinfo->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
+ pinfo->srcport, pinfo->destport, pinfo);
+ /* Didn't work, try the other direction */
+ if (conversation == NULL) {
+ DPRINT(("trying opposite direction"));
+ conversation =
+ conversation_lookup_hashtable(conversation_hashtable_exact_ext,
+ pinfo->num, &pinfo->dst, &pinfo->src, pinfo->ptype,
+ pinfo->destport, pinfo->srcport, pinfo);
+ }
+ if ((conversation == NULL) && (pinfo->src.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_ext,
+ pinfo->num, &pinfo->dst, &pinfo->src, pinfo->ptype,
+ pinfo->srcport, pinfo->destport, pinfo);
+ }
+ DPRINT(("exact match ext %sfound", conversation ? "" : "not "));
+ if (conversation != NULL) {
+ return conversation;
+ }
+
+ DPRINT(("no matches found"));
+
+ /*
+ * We found no conversation.
+ */
+ return NULL;
+
+}
+
static gint
p_compare(gconstpointer a, gconstpointer b)
{
@@ -1374,6 +1561,69 @@ find_or_create_conversation(packet_info *pinfo)
return conv;
}
+conversation_t *
+find_or_create_conversation_ext(packet_info *pinfo, const guint options)
+{
+ conversation_t *conv = NULL;
+
+ DPRINT(("called for frame #%d: %s:%d -> %s:%d (ptype=%d)",
+ pinfo->num, address_to_str(wmem_packet_scope(), &pinfo->src), pinfo->srcport,
+ address_to_str(wmem_packet_scope(), &pinfo->dst), pinfo->destport, pinfo->ptype));
+ DINDENT();
+
+ if (!(options & USE_EXT_ADDRESS_INF)) {
+ /* Have we seen this conversation before? */
+ if ((conv = find_conversation(pinfo->num, &pinfo->src, &pinfo->dst,
+ pinfo->ptype, pinfo->srcport,
+ pinfo->destport, 0)) != NULL) {
+ DPRINT(("found previous conversation for frame #%d (last_frame=%d)",
+ pinfo->num, conv->last_frame));
+ if (pinfo->num > conv->last_frame) {
+ conv->last_frame = pinfo->num;
+ }
+ }
+ else {
+ /* No, this is a new conversation. */
+ DPRINT(("did not find previous conversation for frame #%d",
+ pinfo->num));
+ DINDENT();
+ conv = conversation_new(pinfo->num, &pinfo->src,
+ &pinfo->dst, pinfo->ptype,
+ pinfo->srcport, pinfo->destport, 0);
+ DENDENT();
+ }
+
+ DENDENT();
+
+ return conv;
+ }
+ /* Check in the extended key hastable */
+
+ /* Have we seen this conversation before? */
+ if ((conv = find_conversation_ext_from_pinfo(pinfo)) != NULL) {
+ DPRINT(("found previous conversation for frame #%d (last_frame=%d)",
+ pinfo->num, conv->last_frame));
+ if (pinfo->num > conv->last_frame) {
+ conv->last_frame = pinfo->num;
+ }
+ }
+ else {
+ /* No, this is a new conversation. */
+ DPRINT(("did not find previous conversation for frame #%d",
+ pinfo->num));
+ DINDENT();
+ conv = conversation_new_ext(pinfo->num, &pinfo->src,
+ &pinfo->dst, pinfo->ptype,
+ pinfo->srcport, pinfo->destport, pinfo, USE_EXT_ADDRESS_INF);
+ DENDENT();
+ }
+
+ DENDENT();
+
+ return conv;
+}
+
+
GHashTable *
get_conversation_hashtable_exact(void)
{