summaryrefslogtreecommitdiff
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)
downloadwireshark-f80e9df7939be9d88062718d6c15fa2983e5e605.tar.gz
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)
{