aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--epan/conversation.c910
-rw-r--r--epan/conversation.h110
-rw-r--r--epan/packet.c1
-rw-r--r--epan/packet_info.h4
-rw-r--r--ui/qt/conversation_hash_tables_dialog.cpp59
5 files changed, 480 insertions, 604 deletions
diff --git a/epan/conversation.c b/epan/conversation.c
index aef2d5f53a..8fc9bba215 100644
--- a/epan/conversation.c
+++ b/epan/conversation.c
@@ -18,9 +18,18 @@
#include "to_str.h"
#include "conversation.h"
-// To do:
-// - Switch the "id" routines (conversation_new_by_id, etc) to elements.
-// - Switch the rest of the routines to elements.
+// The conversation database is a map of maps that contain conversation_t's.
+// Top-level map keys are strings that describe each conversation type.
+// Second-level map keys are conversation_element_t arrays.
+// {
+// "uint,endpoint": {
+// [ { type: CE_ADDR, addr_val: 10.20.30.40}, { type: CE_PORT, uint_val: 80 } ... ]: <conversation_t>
+// [ { type: CE_ADDR, addr_val: 1.1.1.1}, { type: CE_PORT, uint_val: 53 } ... ]: <conversation_t>
+// }
+// }
+// Instead of using strings as keys we could bit-shift conversation endpoint types
+// into a guint64, e.g. 0x0000000102010200 for CE_ADDRESS,CE_PORT,CE_ADDRESS,CE_PORT,CE_ENDPOINT.
+// We could also use this to prepend a type+length indicator for element arrays.
/* define DEBUG_CONVERSATION for pretty debug printing */
/* #define DEBUG_CONVERSATION */
@@ -30,21 +39,33 @@
int _debug_conversation_indent = 0;
#endif
+/*
+ * We could use an element list here, but this is effectively a parameter list
+ * for find_conversation and is more compact.
+ */
struct endpoint {
address addr1;
address addr2;
- endpoint_type etype;
guint32 port1;
guint32 port2;
+ endpoint_type etype;
};
-struct conversation_key {
- // XXX Replace these with conversation_element_t's.
- address addr1;
- address addr2;
- endpoint_type etype;
- guint32 port1;
- guint32 port2;
+/* Element offsets for address+port conversations */
+enum {
+ ADDR1_IDX,
+ PORT1_IDX,
+ ADDR2_IDX,
+ PORT2_IDX,
+ ENDP_EXACT_IDX,
+ EXACT_IDX_COUNT,
+ PORT2_NO_ADDR2_IDX = ADDR2_IDX,
+ ENDP_NO_ADDR2_IDX = PORT2_IDX,
+ ENDP_NO_PORT2_IDX = PORT2_IDX,
+ ENDP_NO_ADDR2_PORT2_IDX = ADDR2_IDX,
+ NO_ADDR2_IDX_COUNT = ENDP_EXACT_IDX,
+ NO_PORT2_IDX_COUNT = ENDP_EXACT_IDX,
+ NO_ADDR2_PORT2_IDX_COUNT = PORT2_IDX,
};
/*
@@ -84,11 +105,12 @@ static guint32 new_index;
*/
static address null_address_ = ADDRESS_INIT_NONE;
-static conversation_t *conversation_lookup_hashtable(wmem_map_t *conversation_hashtable, const guint32 frame_num, conversation_key_t conv_key);
/* Element count including the terminating CE_ENDPOINT */
-#define MAX_CONVERSATION_ELEMENTS 10 // Arbitrary.
-static size_t conversation_element_count(conversation_element_t *elements) {
+#define MAX_CONVERSATION_ELEMENTS 8 // Arbitrary.
+static size_t
+conversation_element_count(conversation_element_t *elements)
+{
size_t count = 0;
while (elements[count].type != CE_ENDPOINT) {
count++;
@@ -100,11 +122,24 @@ static size_t conversation_element_count(conversation_element_t *elements) {
return count;
}
+static endpoint_type
+conversation_endpoint_type(conversation_element_t *elements)
+{
+ size_t count = 0;
+ while (elements[count].type != CE_ENDPOINT) {
+ count++;
+ DISSECTOR_ASSERT(count < MAX_CONVERSATION_ELEMENTS);
+ }
+ return elements[count].endpoint_type_val;
+}
+
/* Create a string based on element types. */
-static char* conversation_element_list_name(wmem_allocator_t *allocator, conversation_element_t *elements) {
+static char*
+conversation_element_list_name(wmem_allocator_t *allocator, conversation_element_t *elements) {
const char *type_names[] = {
"endpoint",
"address",
+ "port",
"string",
"uint",
"uint64",
@@ -120,6 +155,82 @@ static char* conversation_element_list_name(wmem_allocator_t *allocator, convers
return wmem_strbuf_finalize(conv_hash_group);
}
+#if 0 // debugging
+static char* conversation_element_list_values(conversation_element_t *elements) {
+ const char *type_names[] = {
+ "endpoint",
+ "address",
+ "port",
+ "string",
+ "uint",
+ "uint64",
+ };
+ char *sep = "";
+ GString *value_str = g_string_new("");
+ size_t element_count = conversation_element_count(elements);
+ for (size_t i = 0; i < element_count; i++) {
+ conversation_element_t *cur_el = &elements[i];
+ g_string_append_printf(value_str, "%s%s=", sep, type_names[cur_el->type]);
+ sep = ",";
+ switch (cur_el->type) {
+ case CE_ENDPOINT:
+ g_string_append_printf(value_str, "%d", cur_el->endpoint_type_val);
+ break;
+ case CE_ADDRESS:
+ {
+ char *as = address_to_str(NULL, &cur_el->addr_val);
+ g_string_append(value_str, as);
+ g_free(as);
+ }
+ break;
+ case CE_PORT:
+ g_string_append_printf(value_str, "%u", cur_el->port_val);
+ break;
+ case CE_STRING:
+ g_string_append(value_str, cur_el->str_val);
+ break;
+ case CE_UINT:
+ g_string_append_printf(value_str, "%u", cur_el->uint_val);
+ break;
+ case CE_UINT64:
+ g_string_append_printf(value_str, "%" G_GUINT64_FORMAT, cur_el->uint64_val);
+ break;
+ }
+ }
+ return g_string_free(value_str, FALSE);
+}
+#endif
+
+static bool
+is_no_addr2_key(conversation_element_t *key)
+{
+ if (key[ADDR1_IDX].type == CE_ADDRESS && key[PORT1_IDX].type == CE_PORT
+ && key[PORT2_NO_ADDR2_IDX].type == CE_PORT && key[ENDP_NO_ADDR2_IDX].type == CE_ENDPOINT) {
+ return true;
+ }
+ return false;
+}
+
+static bool
+is_no_port2_key(conversation_element_t *key)
+{
+ if (key[ADDR1_IDX].type == CE_ADDRESS && key[PORT1_IDX].type == CE_PORT
+ && key[ADDR2_IDX].type == CE_ADDRESS && key[ENDP_NO_PORT2_IDX].type == CE_ENDPOINT) {
+ return true;
+ }
+ return false;
+}
+
+static bool
+is_no_addr2_port2_key(conversation_element_t *key)
+{
+ if (key[ADDR1_IDX].type == CE_ADDRESS && key[PORT1_IDX].type == CE_PORT
+ && key[ENDP_NO_ADDR2_PORT2_IDX].type == CE_ENDPOINT) {
+ return true;
+ }
+ return false;
+}
+
/*
* Creates a new conversation with known endpoints based on a conversation
* created with the CONVERSATION_TEMPLATE option while keeping the
@@ -137,12 +248,12 @@ static char* conversation_element_list_name(wmem_allocator_t *allocator, convers
static conversation_t *
conversation_create_from_template(conversation_t *conversation, const address *addr2, const guint32 port2)
{
+ endpoint_type etype = conversation_endpoint_type(conversation->key_ptr);
/*
* 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->etype != ENDPOINT_UDP)
+ if (conversation->options & CONVERSATION_TEMPLATE && etype != ENDPOINT_UDP)
{
/*
* Set up a new options mask where the conversation template bit and the
@@ -154,8 +265,8 @@ conversation_create_from_template(conversation_t *conversation, const address *a
/*
* Are both the NO_ADDR2 and NO_PORT2 wildcards set in the options mask?
*/
- if (conversation->options & NO_ADDR2 &&
- conversation->options & NO_PORT2)
+ if (conversation->options & NO_ADDR2 && conversation->options & NO_PORT2
+ && is_no_addr2_port2_key(conversation->key_ptr))
{
/*
* The conversation template was created without knowledge of both
@@ -164,11 +275,11 @@ conversation_create_from_template(conversation_t *conversation, const address *a
*/
new_conversation_from_template =
conversation_new(conversation->setup_frame,
- &conversation->key_ptr->addr1, addr2,
- conversation->key_ptr->etype, conversation->key_ptr->port1,
+ &conversation->key_ptr[ADDR1_IDX].addr_val, addr2,
+ etype, conversation->key_ptr[PORT1_IDX].port_val,
port2, options);
}
- else if (conversation->options & NO_PORT2)
+ else if (conversation->options & NO_PORT2 && is_no_port2_key(conversation->key_ptr))
{
/*
* The conversation template was created without knowledge of port 2
@@ -176,11 +287,11 @@ conversation_create_from_template(conversation_t *conversation, const address *a
*/
new_conversation_from_template =
conversation_new(conversation->setup_frame,
- &conversation->key_ptr->addr1, &conversation->key_ptr->addr2,
- conversation->key_ptr->etype, conversation->key_ptr->port1,
+ &conversation->key_ptr[ADDR1_IDX].addr_val, &conversation->key_ptr[ADDR2_IDX].addr_val,
+ etype, conversation->key_ptr[PORT1_IDX].port_val,
port2, options);
}
- else if (conversation->options & NO_ADDR2)
+ else if (conversation->options & NO_ADDR2 && is_no_addr2_key(conversation->key_ptr))
{
/*
* The conversation template was created without knowledge of address
@@ -188,9 +299,9 @@ conversation_create_from_template(conversation_t *conversation, const address *a
*/
new_conversation_from_template =
conversation_new(conversation->setup_frame,
- &conversation->key_ptr->addr1, addr2,
- conversation->key_ptr->etype, conversation->key_ptr->port1,
- conversation->key_ptr->port2, options);
+ &conversation->key_ptr[ADDR1_IDX].addr_val, addr2,
+ etype, conversation->key_ptr[PORT1_IDX].port_val,
+ conversation->key_ptr[PORT2_NO_ADDR2_IDX].port_val, options);
}
else
{
@@ -217,282 +328,6 @@ conversation_create_from_template(conversation_t *conversation, const address *a
}
/*
- * Compute the hash value for two given address/port pairs if the match
- * is to be exact.
- */
-/* https://web.archive.org/web/20070615045827/http://eternallyconfuzzled.com/tuts/algorithms/jsw_tut_hashing.aspx#existing
- * (formerly at http://eternallyconfuzzled.com/tuts/algorithms/jsw_tut_hashing.aspx#existing)
- * One-at-a-Time hash
- */
-guint
-conversation_hash_exact(gconstpointer v)
-{
- const conversation_key_t key = (const conversation_key_t)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);
-
- 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
-conversation_match_exact(gconstpointer v, gconstpointer w)
-{
- const conversation_key_t v1 = (const conversation_key_t)v;
- const conversation_key_t v2 = (const conversation_key_t)w;
-
- if (v1->etype != v2->etype)
- 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?
- */
- if (v1->port1 == v2->port1 &&
- v1->port2 == v2->port2 &&
- addresses_equal(&v1->addr1, &v2->addr1) &&
- addresses_equal(&v1->addr2, &v2->addr2)) {
- /*
- * 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)) {
- /*
- * 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.
- */
-static guint
-conversation_hash_no_addr2(gconstpointer v)
-{
- const conversation_key_t key = (const conversation_key_t)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);
-
- tmp_addr.data = &key->port2;
- 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, except for the address 2 value.
- * We don't check both directions of the conversation - the routine
- * doing the hash lookup has to do two searches, as the hash key
- * will be different for the two directions.
- */
-static gint
-conversation_match_no_addr2(gconstpointer v, gconstpointer w)
-{
- const conversation_key_t v1 = (const conversation_key_t)v;
- const conversation_key_t v2 = (const conversation_key_t)w;
-
- if (v1->etype != v2->etype)
- return 0; /* different types of port */
-
- /*
- * Are the first and second port 1 values the same, the first and
- * second port 2 valuess the same, and the first and second
- * address 1 values the same?
- */
- if (v1->port1 == v2->port1 &&
- v1->port2 == v2->port2 &&
- addresses_equal(&v1->addr1, &v2->addr1)) {
- /*
- * Yes. It's the same conversation, and the two
- * address/port pairs are going in the same direction.
- */
- 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 port 2.
- */
-static guint
-conversation_hash_no_port2(gconstpointer v)
-{
- const conversation_key_t key = (const conversation_key_t)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);
-
- hash_val += ( hash_val << 3 );
- hash_val ^= ( hash_val >> 11 );
- hash_val += ( hash_val << 15 );
-
- return hash_val;
-}
-
-/*
- * Compare two conversation keys, except for the port 2 value.
- * We don't check both directions of the conversation - the routine
- * doing the hash lookup has to do two searches, as the hash key
- * will be different for the two directions.
- */
-static gint
-conversation_match_no_port2(gconstpointer v, gconstpointer w)
-{
- const conversation_key_t v1 = (const conversation_key_t)v;
- const conversation_key_t v2 = (const conversation_key_t)w;
-
- if (v1->etype != v2->etype)
- return 0; /* different types of port */
-
- /*
- * Are the first and second port 1 values the same, the first and
- * second address 1 values the same, and the first and second
- * address 2 values the same?
- */
- if (v1->port1 == v2->port1 &&
- addresses_equal(&v1->addr1, &v2->addr1) &&
- addresses_equal(&v1->addr2, &v2->addr2)) {
- /*
- * Yes. It's the same conversation, and the two
- * address/port pairs are going in the same direction.
- */
- 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 and port 2.
- */
-static guint
-conversation_hash_no_addr2_or_port2(gconstpointer v)
-{
- const conversation_key_t key = (const conversation_key_t)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 += ( hash_val << 3 );
- hash_val ^= ( hash_val >> 11 );
- hash_val += ( hash_val << 15 );
-
- return hash_val;
-}
-
-/*
- * Compare the address 1 and port 1 in the two conversation keys.
- * We don't check both directions of the conversation - the routine
- * doing the hash lookup has to do two searches, as the hash key
- * will be different for the two directions.
- */
-static gint
-conversation_match_no_addr2_or_port2(gconstpointer v, gconstpointer w)
-{
- const conversation_key_t v1 = (const conversation_key_t)v;
- const conversation_key_t v2 = (const conversation_key_t)w;
-
- if (v1->etype != v2->etype)
- return 0; /* different types of port */
-
- /*
- * Are the first and second port 1 values the same and the first
- * and second address 1 values the same?
- */
- if (v1->port1 == v2->port1 &&
- addresses_equal(&v1->addr1, &v2->addr1)) {
- /*
- * Yes. It's the same conversation, and the two
- * address/port pairs are going in the same direction.
- */
- return 1;
- }
-
- /*
- * The addresses or the ports don't match.
- */
- return 0;
-}
-
-/*
* Compute the hash value for two given element lists if the match
* is to be exact.
*/
@@ -513,6 +348,11 @@ conversation_hash_element_list(gconstpointer v)
case CE_ADDRESS:
hash_val = add_address_to_hash(hash_val, &element->addr_val);
break;
+ case CE_PORT:
+ tmp_addr.len = (int) sizeof(element->port_val);
+ tmp_addr.data = &element->port_val;
+ hash_val = add_address_to_hash(hash_val, &tmp_addr);
+ break;
case CE_STRING:
tmp_addr.len = (int) strlen(element->str_val);
tmp_addr.data = element->str_val;
@@ -566,6 +406,11 @@ conversation_match_element_list(gconstpointer v1, gconstpointer v2)
return FALSE;
}
break;
+ case CE_PORT:
+ if (element1->port_val != element2->port_val) {
+ return FALSE;
+ }
+ break;
case CE_STRING:
if (strcmp(element1->str_val, element2->str_val)) {
return FALSE;
@@ -611,21 +456,59 @@ conversation_init(void)
* pointed to by conversation data structures that were freed
* above.
*/
- conversation_hashtable_exact_addr_port =
- wmem_map_new_autoreset(wmem_epan_scope(), wmem_file_scope(), conversation_hash_exact,
- conversation_match_exact);
- conversation_hashtable_no_addr2 =
- wmem_map_new_autoreset(wmem_epan_scope(), wmem_file_scope(), conversation_hash_no_addr2,
- conversation_match_no_addr2);
- conversation_hashtable_no_port2 =
- wmem_map_new_autoreset(wmem_epan_scope(), wmem_file_scope(), conversation_hash_no_port2,
- conversation_match_no_port2);
- conversation_hashtable_no_addr2_or_port2 =
- wmem_map_new_autoreset(wmem_epan_scope(), wmem_file_scope(), conversation_hash_no_addr2_or_port2,
- conversation_match_no_addr2_or_port2);
-
- conversation_hashtable_element_list =
- wmem_map_new(wmem_epan_scope(), wmem_str_hash, g_str_equal);
+ conversation_hashtable_element_list = wmem_map_new(wmem_epan_scope(), wmem_str_hash, g_str_equal);
+
+ conversation_element_t exact_elements[EXACT_IDX_COUNT] = {
+ { CE_ADDRESS, .addr_val = ADDRESS_INIT_NONE },
+ { CE_PORT, .port_val = 0 },
+ { CE_ADDRESS, .addr_val = ADDRESS_INIT_NONE },
+ { CE_PORT, .port_val = 0 },
+ { CE_ENDPOINT, .endpoint_type_val = ENDPOINT_NONE }
+ };
+ char *exact_map_key = conversation_element_list_name(wmem_epan_scope(), exact_elements);
+ conversation_hashtable_exact_addr_port = wmem_map_new_autoreset(wmem_epan_scope(), wmem_file_scope(),
+ conversation_hash_element_list,
+ conversation_match_element_list);
+ wmem_map_insert(conversation_hashtable_element_list, wmem_strdup(wmem_epan_scope(), exact_map_key),
+ conversation_hashtable_exact_addr_port);
+
+ conversation_element_t no_addr2_elements[NO_ADDR2_IDX_COUNT] = {
+ { CE_ADDRESS, .addr_val = ADDRESS_INIT_NONE },
+ { CE_PORT, .port_val = 0 },
+ { CE_PORT, .port_val = 0 },
+ { CE_ENDPOINT, .endpoint_type_val = ENDPOINT_NONE }
+ };
+ char *no_addr2_map_key = conversation_element_list_name(wmem_epan_scope(), no_addr2_elements);
+ conversation_hashtable_no_addr2 = wmem_map_new_autoreset(wmem_epan_scope(), wmem_file_scope(),
+ conversation_hash_element_list,
+ conversation_match_element_list);
+ wmem_map_insert(conversation_hashtable_element_list, wmem_strdup(wmem_epan_scope(), no_addr2_map_key),
+ conversation_hashtable_no_addr2);
+
+ conversation_element_t no_port2_elements[NO_PORT2_IDX_COUNT] = {
+ { CE_ADDRESS, .addr_val = ADDRESS_INIT_NONE },
+ { CE_PORT, .port_val = 0 },
+ { CE_ADDRESS, .addr_val = ADDRESS_INIT_NONE },
+ { CE_ENDPOINT, .endpoint_type_val = ENDPOINT_NONE }
+ };
+ char *no_port2_map_key = conversation_element_list_name(wmem_epan_scope(), no_port2_elements);
+ conversation_hashtable_no_port2 = wmem_map_new_autoreset(wmem_epan_scope(), wmem_file_scope(),
+ conversation_hash_element_list,
+ conversation_match_element_list);
+ wmem_map_insert(conversation_hashtable_element_list, wmem_strdup(wmem_epan_scope(), no_port2_map_key),
+ conversation_hashtable_no_port2);
+
+ conversation_element_t no_addr2_or_port2_elements[NO_ADDR2_PORT2_IDX_COUNT] = {
+ { CE_ADDRESS, .addr_val = ADDRESS_INIT_NONE },
+ { CE_PORT, .port_val = 0 },
+ { CE_ENDPOINT, .endpoint_type_val = ENDPOINT_NONE }
+ };
+ char *no_addr2_or_port2_map_key = conversation_element_list_name(wmem_epan_scope(), no_addr2_or_port2_elements);
+ conversation_hashtable_no_addr2_or_port2 = wmem_map_new_autoreset(wmem_epan_scope(), wmem_file_scope(),
+ conversation_hash_element_list,
+ conversation_match_element_list);
+ wmem_map_insert(conversation_hashtable_element_list, wmem_strdup(wmem_epan_scope(), no_addr2_or_port2_map_key),
+ conversation_hashtable_no_addr2_or_port2);
conversation_element_t id_elements[2] = {
{ CE_UINT, .uint_val = 0 },
@@ -770,48 +653,6 @@ conversation_remove_from_hashtable(wmem_map_t *hashtable, conversation_t *conv)
}
}
-#if 0 // debugging
-static char* conversation_element_list_values(conversation_element_t *elements) {
- const char *type_names[] = {
- "endpoint",
- "address",
- "string",
- "uint",
- "uint64",
- };
- char *sep = "";
- GString *value_str = g_string_new("");
- size_t element_count = conversation_element_count(elements);
- for (size_t i = 0; i < element_count; i++) {
- conversation_element_t *cur_el = &elements[i];
- g_string_append_printf(value_str, "%s%s=", sep, type_names[cur_el->type]);
- sep = ",";
- switch (cur_el->type) {
- case CE_ADDRESS:
- {
- char *as = address_to_str(NULL, &cur_el->addr_val);
- g_string_append(value_str, as);
- g_free(as);
- }
- break;
- case CE_ENDPOINT:
- g_string_append_printf(value_str, "%d", cur_el->endpoint_type_val);
- break;
- case CE_STRING:
- g_string_append(value_str, cur_el->str_val);
- break;
- case CE_UINT:
- g_string_append_printf(value_str, "%u", cur_el->uint_val);
- break;
- case CE_UINT64:
- g_string_append_printf(value_str, "%" G_GUINT64_FORMAT, cur_el->uint64_val);
- break;
- }
- }
- return g_string_free(value_str, FALSE);
-}
-#endif
-
conversation_t *conversation_new_full(const guint32 setup_frame, conversation_element_t *elements)
{
DISSECTOR_ASSERT(elements);
@@ -840,8 +681,7 @@ conversation_t *conversation_new_full(const guint32 setup_frame, conversation_el
new_index++;
- // XXX Overloading conversation_key_t this way is terrible and we shouldn't do it.
- conversation->key_ptr = (conversation_key_t) conv_key;
+ conversation->key_ptr = conv_key;
conversation_insert_into_hashtable(el_list_map, conversation);
return conversation;
}
@@ -863,8 +703,7 @@ conversation_new(const guint32 setup_frame, const address *addr1, const address
"A conversation template may not be constructed without wildcard options");
*/
wmem_map_t* hashtable;
- conversation_t *conversation=NULL;
- conversation_key_t new_key;
+ conversation_t *conversation = NULL;
/*
* Verify that the correct options are used, if any.
*/
@@ -959,34 +798,59 @@ conversation_new(const guint32 setup_frame, const address *addr1, const address
}
#endif
+ // Always allocate an "exact"-sized key in case we call conversation_set_port2
+ // or conversation_set_addr2 later.
+ conversation_element_t *new_key = wmem_alloc(wmem_file_scope(), sizeof(conversation_element_t) * EXACT_IDX_COUNT);
+ size_t addr2_idx = 0;
+ size_t port2_idx = 0;
+ size_t endp_idx;
+
+ new_key[ADDR1_IDX].type = CE_ADDRESS;
+ if (addr1 != NULL) {
+ copy_address_wmem(wmem_file_scope(), &new_key[ADDR1_IDX].addr_val, addr1);
+ } else {
+ clear_address(&new_key[ADDR1_IDX].addr_val);
+ }
+ new_key[PORT1_IDX].type = CE_PORT;
+ new_key[PORT1_IDX].port_val = port1;
+
if (options & NO_ADDR2) {
if (options & (NO_PORT2|NO_PORT2_FORCE)) {
hashtable = conversation_hashtable_no_addr2_or_port2;
+ endp_idx = ENDP_NO_ADDR2_PORT2_IDX;
} else {
hashtable = conversation_hashtable_no_addr2;
+ port2_idx = PORT2_NO_ADDR2_IDX;
+ endp_idx = ENDP_NO_ADDR2_IDX;
}
} else {
+ addr2_idx = ADDR2_IDX;
if (options & (NO_PORT2|NO_PORT2_FORCE)) {
hashtable = conversation_hashtable_no_port2;
+ endp_idx = ENDP_NO_PORT2_IDX;
} else {
hashtable = conversation_hashtable_exact_addr_port;
+ port2_idx = PORT2_IDX;
+ endp_idx = ENDP_EXACT_IDX;
}
}
- new_key = wmem_new0(wmem_file_scope(), struct conversation_key);
- if (addr1 != NULL) {
- copy_address_wmem(wmem_file_scope(), &new_key->addr1, addr1);
- } else {
- clear_address(&new_key->addr1);
+ if (addr2_idx) {
+ new_key[addr2_idx].type = CE_ADDRESS;
+ if (addr2 != NULL) {
+ copy_address_wmem(wmem_file_scope(), &new_key[addr2_idx].addr_val, addr2);
+ } else {
+ clear_address(&new_key[addr2_idx].addr_val);
+ }
}
- if (addr2 != NULL) {
- copy_address_wmem(wmem_file_scope(), &new_key->addr2, addr2);
- } else {
- clear_address(&new_key->addr2);
+
+ if (port2_idx) {
+ new_key[port2_idx].type = CE_PORT;
+ new_key[port2_idx].port_val = port2;
}
- new_key->etype = etype;
- new_key->port1 = port1;
- new_key->port2 = port2;
+
+ new_key[endp_idx].type = CE_ENDPOINT;
+ new_key[endp_idx].endpoint_type_val = etype;
conversation = wmem_new0(wmem_file_scope(), conversation_t);
@@ -1020,15 +884,14 @@ conversation_new_by_id(const guint32 setup_frame, const endpoint_type etype, con
elements[0].uint_val = id;
elements[1].type = CE_ENDPOINT;
elements[1].endpoint_type_val = etype;
- // XXX Overloading conversation_key_t this way is terrible and we shouldn't do it.
- conversation->key_ptr = (conversation_key_t) elements;
+ conversation->key_ptr = elements;
conversation_insert_into_hashtable(conversation_hashtable_id, conversation);
return conversation;
}
/*
- * Set the port 2 value in a key. Remove the original from table,
+ * Set the port 2 value in a key. Remove the original from table,
* update the options and port values, insert the updated key.
*/
void
@@ -1051,11 +914,21 @@ conversation_set_port2(conversation_t *conv, const guint32 port)
} else {
conversation_remove_from_hashtable(conversation_hashtable_no_port2, conv);
}
+
+ // Shift our endpoint element over and set our port. We assume that conv->key_ptr
+ // was created with conversation_new and that we have enough element slots.
conv->options &= ~NO_PORT2;
- conv->key_ptr->port2 = port;
if (conv->options & NO_ADDR2) {
+ // addr1,port1,endp -> addr1,port1,port2,endp
+ conv->key_ptr[ENDP_NO_ADDR2_IDX] = conv->key_ptr[ENDP_NO_ADDR2_PORT2_IDX];
+ conv->key_ptr[PORT2_NO_ADDR2_IDX].type = CE_PORT;
+ conv->key_ptr[PORT2_NO_ADDR2_IDX].port_val = port;
conversation_insert_into_hashtable(conversation_hashtable_no_addr2, conv);
} else {
+ // addr1,port1,addr2,endp -> addr1,port1,addr2,port2,endp
+ conv->key_ptr[ENDP_EXACT_IDX] = conv->key_ptr[ENDP_NO_PORT2_IDX];
+ conv->key_ptr[PORT2_IDX].type = CE_PORT;
+ conv->key_ptr[PORT2_IDX].port_val = port;
conversation_insert_into_hashtable(conversation_hashtable_exact_addr_port, conv);
}
DENDENT();
@@ -1088,17 +961,29 @@ conversation_set_addr2(conversation_t *conv, const address *addr)
} else {
conversation_remove_from_hashtable(conversation_hashtable_no_port2, conv);
}
+
+ // Shift our endpoint and, if needed, our port element over and set our address.
+ // We assume that conv->key_ptr was created with conversation_new and that we have
+ // enough element slots.
conv->options &= ~NO_ADDR2;
- copy_address_wmem(wmem_file_scope(), &conv->key_ptr->addr2, addr);
+ wmem_map_t *hashtable;
if (conv->options & NO_PORT2) {
- conversation_insert_into_hashtable(conversation_hashtable_no_port2, conv);
+ // addr1,port1,endp -> addr1,port1,addr2,endp
+ conv->key_ptr[ENDP_NO_PORT2_IDX] = conv->key_ptr[ENDP_NO_ADDR2_PORT2_IDX];
+ hashtable = conversation_hashtable_no_port2;
} else {
- conversation_insert_into_hashtable(conversation_hashtable_exact_addr_port, conv);
+ // addr1,port1,port2,endp -> addr1,port1,addr2,port2,endp
+ conv->key_ptr[ENDP_EXACT_IDX] = conv->key_ptr[ENDP_NO_ADDR2_IDX];
+ conv->key_ptr[PORT2_IDX] = conv->key_ptr[PORT2_NO_ADDR2_IDX];
+ hashtable = conversation_hashtable_exact_addr_port;
}
+ conv->key_ptr[ADDR2_IDX].type = CE_ADDRESS;
+ copy_address_wmem(wmem_file_scope(), &conv->key_ptr[ADDR2_IDX].addr_val, addr);
+ conversation_insert_into_hashtable(hashtable, conv);
DENDENT();
}
-static conversation_t *conversation_lookup_hashtable(wmem_map_t *conversation_hashtable, const guint32 frame_num, conversation_key_t conv_key)
+static conversation_t *conversation_lookup_hashtable(wmem_map_t *conversation_hashtable, const guint32 frame_num, conversation_element_t *conv_key)
{
conversation_t* convo = NULL;
conversation_t* match = NULL;
@@ -1137,7 +1022,7 @@ conversation_t *find_conversation_full(const guint32 frame_num, conversation_ele
return NULL;
}
- return conversation_lookup_hashtable(el_list_map, frame_num, (conversation_key_t)elements);
+ return conversation_lookup_hashtable(el_list_map, frame_num, elements);
}
/*
@@ -1145,30 +1030,67 @@ conversation_t *find_conversation_full(const guint32 frame_num, conversation_ele
* {addr1, port1, addr2, port2} and set up before frame_num.
*/
static conversation_t *
-conversation_lookup_addr_port(wmem_map_t *hashtable, const guint32 frame_num, const address *addr1, const address *addr2,
- const endpoint_type etype, const guint32 port1, const guint32 port2)
+conversation_lookup_exact(const guint32 frame_num, const address *addr1, const guint32 port1,
+ const address *addr2, const guint32 port2, const endpoint_type etype)
{
- struct conversation_key key;
+ conversation_element_t key[EXACT_IDX_COUNT] = {
+ { CE_ADDRESS, .addr_val = *addr1 },
+ { CE_PORT, .port_val = port1 },
+ { CE_ADDRESS, .addr_val = *addr2 },
+ { CE_PORT, .port_val = port2 },
+ { CE_ENDPOINT, .endpoint_type_val = etype },
+ };
+ return conversation_lookup_hashtable(conversation_hashtable_exact_addr_port, frame_num, key);
+}
- /*
- * We don't make a copy of the address data, we just copy the
- * pointer to it, as "key" disappears when we return.
- */
- if (addr1 != NULL) {
- key.addr1 = *addr1;
- } else {
- clear_address(&key.addr1);
- }
- if (addr2 != NULL) {
- key.addr2 = *addr2;
- } else {
- clear_address(&key.addr2);
- }
- key.etype = etype;
- key.port1 = port1;
- key.port2 = port2;
+/*
+ * Search a particular hash table for a conversation with the specified
+ * {addr1, port1, port2} and set up before frame_num.
+ */
+static conversation_t *
+conversation_lookup_no_addr2(const guint32 frame_num, const address *addr1, const guint32 port1,
+ const guint32 port2, const endpoint_type etype)
+{
+ conversation_element_t key[NO_ADDR2_IDX_COUNT] = {
+ { CE_ADDRESS, .addr_val = *addr1 },
+ { CE_PORT, .port_val = port1 },
+ { CE_PORT, .port_val = port2 },
+ { CE_ENDPOINT, .endpoint_type_val = etype },
+ };
+ return conversation_lookup_hashtable(conversation_hashtable_no_addr2, frame_num, key);
+}
+
+/*
+ * Search a particular hash table for a conversation with the specified
+ * {addr1, port1, addr2} and set up before frame_num.
+ */
+static conversation_t *
+conversation_lookup_no_port2(const guint32 frame_num, const address *addr1, const guint32 port1,
+ const address *addr2, const endpoint_type etype)
+{
+ conversation_element_t key[NO_PORT2_IDX_COUNT] = {
+ { CE_ADDRESS, .addr_val = *addr1 },
+ { CE_PORT, .port_val = port1 },
+ { CE_ADDRESS, .addr_val = *addr2 },
+ { CE_ENDPOINT, .endpoint_type_val = etype },
+ };
+ return conversation_lookup_hashtable(conversation_hashtable_no_port2, frame_num, key);
+}
- return conversation_lookup_hashtable(hashtable, frame_num, &key);
+/*
+ * Search a particular hash table for a conversation with the specified
+ * {addr1, port1, addr2} and set up before frame_num.
+ */
+static conversation_t *
+conversation_lookup_no_addr2_or_port2(const guint32 frame_num, const address *addr1, const guint32 port1,
+ const endpoint_type etype)
+{
+ conversation_element_t key[NO_ADDR2_PORT2_IDX_COUNT] = {
+ { CE_ADDRESS, .addr_val = *addr1 },
+ { CE_PORT, .port_val = port1 },
+ { CE_ENDPOINT, .endpoint_type_val = etype },
+ };
+ return conversation_lookup_hashtable(conversation_hashtable_no_addr2_or_port2, frame_num, key);
}
/*
@@ -1229,18 +1151,12 @@ find_conversation(const guint32 frame_num, const address *addr_a, const address
*/
DPRINT(("trying exact match: %s:%d -> %s:%d",
addr_a_str, port_a, addr_b_str, port_b));
- conversation =
- conversation_lookup_addr_port(conversation_hashtable_exact_addr_port,
- frame_num, addr_a, addr_b, etype,
- port_a, port_b);
+ conversation = conversation_lookup_exact(frame_num, addr_a, port_a, addr_b, port_b, etype);
/* Didn't work, try the other direction */
if (conversation == NULL) {
DPRINT(("trying exact match: %s:%d -> %s:%d",
addr_b_str, port_b, addr_a_str, port_a));
- conversation =
- conversation_lookup_addr_port(conversation_hashtable_exact_addr_port,
- frame_num, addr_b, addr_a, etype,
- port_b, port_a);
+ conversation = conversation_lookup_exact(frame_num, addr_b, port_b, addr_a, port_a, etype);
}
if ((conversation == NULL) && (addr_a->type == AT_FC)) {
/* In Fibre channel, OXID & RXID are never swapped as
@@ -1248,10 +1164,7 @@ find_conversation(const guint32 frame_num, const address *addr_a, const address
*/
DPRINT(("trying exact match: %s:%d -> %s:%d",
addr_b_str, port_a, addr_a_str, port_b));
- conversation =
- conversation_lookup_addr_port(conversation_hashtable_exact_addr_port,
- frame_num, addr_b, addr_a, etype,
- port_a, port_b);
+ conversation = conversation_lookup_exact(frame_num, addr_b, port_a, addr_a, port_b, etype);
}
DPRINT(("exact match %sfound",conversation?"":"not "));
if (conversation != NULL)
@@ -1274,19 +1187,14 @@ find_conversation(const guint32 frame_num, const address *addr_a, const address
*/
DPRINT(("trying wildcarded match: %s:%d -> *:%d",
addr_a_str, port_a, port_b));
- conversation =
- conversation_lookup_addr_port(conversation_hashtable_no_addr2,
- frame_num, addr_a, addr_b, etype, port_a, port_b);
+ conversation = conversation_lookup_no_addr2(frame_num, addr_a, port_a, port_b, etype);
if ((conversation == NULL) && (addr_a->type == AT_FC)) {
/* In Fibre channel, OXID & RXID are never swapped as
* TCP/UDP ports are in TCP/IP.
*/
DPRINT(("trying wildcarded match: %s:%d -> *:%d",
addr_b_str, port_a, port_b));
- conversation =
- conversation_lookup_addr_port(conversation_hashtable_no_addr2,
- frame_num, addr_b, addr_a, etype,
- port_a, port_b);
+ conversation = conversation_lookup_no_addr2(frame_num, addr_b, port_a, port_b, etype);
}
if (conversation != NULL) {
/*
@@ -1329,9 +1237,7 @@ find_conversation(const guint32 frame_num, const address *addr_a, const address
if (!(options & NO_ADDR_B)) {
DPRINT(("trying wildcarded match: %s:%d -> *:%d",
addr_b_str, port_b, port_a));
- conversation =
- conversation_lookup_addr_port(conversation_hashtable_no_addr2,
- frame_num, addr_b, addr_a, etype, port_b, port_a);
+ conversation = conversation_lookup_no_addr2(frame_num, addr_b, port_b, port_a, etype);
if (conversation != NULL) {
/*
* If this is for a connection-oriented
@@ -1374,17 +1280,13 @@ find_conversation(const guint32 frame_num, const address *addr_a, const address
*/
DPRINT(("trying wildcarded match: %s:%d -> %s:*",
addr_a_str, port_a, addr_b_str));
- conversation =
- conversation_lookup_addr_port(conversation_hashtable_no_port2,
- frame_num, addr_a, addr_b, etype, port_a, port_b);
+ conversation = conversation_lookup_no_port2(frame_num, addr_a, port_a, addr_b, etype);
if ((conversation == NULL) && (addr_a->type == AT_FC)) {
/* In Fibre channel, OXID & RXID are never swapped as
* TCP/UDP ports are in TCP/IP
*/
DPRINT(("trying wildcarded match: %s:%d -> %s:*", addr_b_str, port_a, addr_a_str));
- conversation =
- conversation_lookup_addr_port(conversation_hashtable_no_port2,
- frame_num, addr_b, addr_a, etype, port_a, port_b);
+ conversation = conversation_lookup_no_port2(frame_num, addr_b, port_a, addr_a, etype);
}
if (conversation != NULL) {
/*
@@ -1427,9 +1329,7 @@ find_conversation(const guint32 frame_num, const address *addr_a, const address
if (!(options & NO_PORT_B)) {
DPRINT(("trying wildcarded match: %s:%d -> %s:*",
addr_b_str, port_b, addr_a_str));
- conversation =
- conversation_lookup_addr_port(conversation_hashtable_no_port2,
- frame_num, addr_b, addr_a, etype, port_b, port_a);
+ conversation = conversation_lookup_no_port2(frame_num, addr_b, port_b, addr_a, etype);
if (conversation != NULL) {
/*
* If this is for a connection-oriented
@@ -1466,9 +1366,7 @@ find_conversation(const guint32 frame_num, const address *addr_a, const address
* (Neither "addr_b" nor "port_b" take part in this lookup.)
*/
DPRINT(("trying wildcarded match: %s:%d -> *:*", addr_a_str, port_a));
- conversation =
- conversation_lookup_addr_port(conversation_hashtable_no_addr2_or_port2,
- frame_num, addr_a, addr_b, etype, port_a, port_b);
+ conversation = conversation_lookup_no_addr2_or_port2(frame_num, addr_a, port_a, etype);
if (conversation != NULL) {
/*
* If this is for a connection-oriented protocol:
@@ -1521,15 +1419,11 @@ find_conversation(const guint32 frame_num, const address *addr_a, const address
if ((addr_a != NULL) && (addr_a->type == AT_FC)) {
DPRINT(("trying wildcarded match: %s:%d -> *:*",
addr_b_str, port_a));
- conversation =
- conversation_lookup_addr_port(conversation_hashtable_no_addr2_or_port2,
- frame_num, addr_b, addr_a, etype, port_a, port_b);
+ conversation = conversation_lookup_no_addr2_or_port2(frame_num, addr_b, port_a, etype);
} else {
DPRINT(("trying wildcarded match: %s:%d -> *:*",
addr_b_str, port_b));
- conversation =
- conversation_lookup_addr_port(conversation_hashtable_no_addr2_or_port2,
- frame_num, addr_b, addr_a, etype, port_b, port_a);
+ conversation = conversation_lookup_no_addr2_or_port2(frame_num, addr_b, port_b, etype);
}
if (conversation != NULL) {
/*
@@ -1578,7 +1472,7 @@ find_conversation_by_id(const guint32 frame, const endpoint_type etype, const gu
{ CE_ENDPOINT, .endpoint_type_val = etype }
};
- return conversation_lookup_hashtable(conversation_hashtable_id, frame, (conversation_key_t)elements);
+ return conversation_lookup_hashtable(conversation_hashtable_id, frame, elements);
}
void
@@ -1762,7 +1656,7 @@ try_conversation_dissector_by_id(const endpoint_type etype, const guint32 id, tv
conversation_t *
find_conversation_pinfo(packet_info *pinfo, const guint options)
{
- conversation_t *conv=NULL;
+ conversation_t *conv = NULL;
DINSTR(gchar *src_str = address_to_str(NULL, &pinfo->src));
DINSTR(gchar *dst_str = address_to_str(NULL, &pinfo->dst));
@@ -1780,7 +1674,7 @@ find_conversation_pinfo(packet_info *pinfo, const guint options)
pinfo->conv_endpoint->etype, pinfo->conv_endpoint->port1,
pinfo->conv_endpoint->port2, 0)) != NULL) {
DPRINT(("found previous conversation for frame #%u (last_frame=%d)",
- pinfo->num, conv->last_frame));
+ pinfo->num, conv->last_frame));
if (pinfo->num > conv->last_frame) {
conv->last_frame = pinfo->num;
}
@@ -1859,62 +1753,49 @@ conversation_create_endpoint(struct _packet_info *pinfo, address* addr1, address
endpoint_type etype, guint32 port1, guint32 port2)
{
pinfo->conv_endpoint = wmem_new0(pinfo->pool, struct endpoint);
- pinfo->use_endpoint = TRUE;
- if (addr1 != NULL)
+ if (addr1 != NULL) {
copy_address_wmem(pinfo->pool, &pinfo->conv_endpoint->addr1, addr1);
-
- if (addr2 != NULL)
+ }
+ if (addr2 != NULL) {
copy_address_wmem(pinfo->pool, &pinfo->conv_endpoint->addr2, addr2);
+ }
pinfo->conv_endpoint->etype = etype;
pinfo->conv_endpoint->port1 = port1;
pinfo->conv_endpoint->port2 = port2;
+
+ pinfo->use_endpoint = TRUE;
}
void
-conversation_create_endpoint_by_id(struct _packet_info *pinfo,
- endpoint_type etype, guint32 id)
+conversation_create_endpoint_by_id(struct _packet_info *pinfo, endpoint_type etype, guint32 id)
{
- /* Force the lack of a address or port B */
- conversation_create_endpoint(pinfo, &null_address_, &null_address_, etype, id, 0);
+ pinfo->conv_elements = wmem_alloc0(pinfo->pool, sizeof(conversation_element_t) * 2);
+ pinfo->conv_elements[0].type = CE_UINT;
+ pinfo->conv_elements[1].uint_val = id;
+ pinfo->conv_elements[1].type = CE_ENDPOINT;
+ pinfo->conv_elements[1].endpoint_type_val = etype;
+
+ pinfo->use_endpoint = TRUE;
}
guint32
conversation_get_endpoint_by_id(struct _packet_info *pinfo, endpoint_type etype, const guint options)
{
- if (pinfo->conv_endpoint == NULL)
+ if (pinfo->conv_endpoint == NULL) {
return 0;
+ }
- if ((pinfo->conv_endpoint->etype != etype) &&
- ((options & USE_LAST_ENDPOINT) != USE_LAST_ENDPOINT))
+ if (pinfo->conv_elements[0].type != CE_UINT || pinfo->conv_elements[1].type != CE_ENDPOINT) {
return 0;
+ }
- return pinfo->conv_endpoint->port1;
-}
-
-wmem_map_t *
-get_conversation_hashtable_exact(void)
-{
- return conversation_hashtable_exact_addr_port;
-}
-
-wmem_map_t *
-get_conversation_hashtable_no_addr2(void)
-{
- return conversation_hashtable_no_addr2;
-}
-
-wmem_map_t *
-get_conversation_hashtable_no_port2(void)
-{
- return conversation_hashtable_no_port2;
-}
+ if ((pinfo->conv_elements[1].endpoint_type_val != etype) && ((options & USE_LAST_ENDPOINT) != USE_LAST_ENDPOINT)) {
+ return 0;
+ }
-wmem_map_t *
-get_conversation_hashtable_no_addr2_or_port2(void)
-{
- return conversation_hashtable_no_addr2_or_port2;
+ return pinfo->conv_elements[0].uint_val;
}
wmem_map_t *
@@ -1923,28 +1804,50 @@ get_conversation_hashtables(void)
return conversation_hashtable_element_list;
}
-address*
-conversation_key_addr1(const conversation_key_t key)
+const address*
+conversation_key_addr1(const conversation_element_t *key)
{
- return &key->addr1;
+ const address *addr = &null_address_;
+ if (key[ADDR1_IDX].type == CE_ADDRESS) {
+ addr = &key[ADDR1_IDX].addr_val;
+ }
+ return addr;
}
-address*
-conversation_key_addr2(const conversation_key_t key)
+guint32
+conversation_key_port1(const conversation_element_t * key)
{
- return &key->addr2;
+ guint32 port = 0;
+ if (key[ADDR1_IDX].type == CE_ADDRESS && key[PORT1_IDX].type == CE_PORT) {
+ port = key[PORT1_IDX].port_val;
+ }
+ return port;
}
-guint32
-conversation_key_port1(const conversation_key_t key)
+const address*
+conversation_key_addr2(const conversation_element_t * key)
{
- return key->port1;
+ const address *addr = &null_address_;
+ if (key[ADDR1_IDX].type == CE_ADDRESS && key[PORT1_IDX].type == CE_PORT && key[ADDR2_IDX].type == CE_ADDRESS) {
+ addr = &key[ADDR2_IDX].addr_val;
+ }
+ return addr;
}
guint32
-conversation_key_port2(const conversation_key_t key)
+conversation_key_port2(const conversation_element_t * key)
{
- return key->port2;
+ guint32 port = 0;
+ if (key[ADDR1_IDX].type == CE_ADDRESS && key[PORT1_IDX].type == CE_PORT) {
+ if (key[ADDR2_IDX].type == CE_ADDRESS && key[PORT2_IDX].type == CE_PORT) {
+ // Exact
+ port = key[PORT2_IDX].port_val;
+ } else if (key[PORT2_NO_ADDR2_IDX].type == CE_PORT) {
+ // No addr 2
+ port = key[PORT2_NO_ADDR2_IDX].port_val;
+ }
+ }
+ return port;
}
WS_DLL_PUBLIC
@@ -1984,21 +1887,6 @@ endpoint_type conversation_pt_to_endpoint_type(port_type pt)
return ENDPOINT_NONE;
}
-gchar*
-conversation_get_html_hash(const conversation_key_t key)
-{
- gchar *hash, *addr1, *addr2;
-
- addr1 = address_to_str(NULL, &key->addr1);
- addr2 = address_to_str(NULL, &key->addr2);
- hash = wmem_strdup_printf(NULL, "<tr><td>%s</td><td>%d</td><td>%s</td><td>%d</td></tr>\n",
- addr1, key->port1, addr2, key->port2);
- wmem_free(NULL, addr1);
- wmem_free(NULL, addr2);
-
- return hash;
-}
-
/*
* Editor modelines - https://www.wireshark.org/tools/modelines.html
*
diff --git a/epan/conversation.h b/epan/conversation.h
index c34dd9614f..3533116d42 100644
--- a/epan/conversation.h
+++ b/epan/conversation.h
@@ -91,10 +91,32 @@ typedef enum {
} endpoint_type;
/**
- * Key used for identifying a conversation.
+ * Conversation element type.
*/
-struct conversation_key;
-typedef struct conversation_key* conversation_key_t;
+typedef enum {
+ CE_ENDPOINT,
+ CE_ADDRESS,
+ CE_PORT,
+ CE_STRING,
+ CE_UINT,
+ CE_UINT64,
+} conversation_element_type;
+
+/**
+ * Elements used to identify conversations for *_full routines and pinfo->conv_elements.
+ * Arrays must be terminated with an element .type set to CE_ENDPOINT.
+ */
+typedef struct conversation_element {
+ conversation_element_type type;
+ union {
+ endpoint_type endpoint_type_val;
+ address addr_val;
+ unsigned int port_val;
+ const char *str_val;
+ unsigned int uint_val;
+ uint64_t uint64_val;
+ };
+} conversation_element_t;
/**
* Data structure representing a conversation.
@@ -110,17 +132,16 @@ typedef struct conversation {
wmem_tree_t *data_list; /** list of data associated with conversation */
wmem_tree_t *dissector_tree; /** tree containing protocol dissector client associated with conversation */
guint options; /** wildcard flags */
- conversation_key_t key_ptr; /** pointer to the key for this conversation */
+ conversation_element_t *key_ptr; /** Keys are conversation element arrays terminated with a CE_ENDPOINT */
} conversation_t;
-
struct endpoint;
typedef struct endpoint* endpoint_t;
-WS_DLL_PUBLIC address* conversation_key_addr1(const conversation_key_t key);
-WS_DLL_PUBLIC address* conversation_key_addr2(const conversation_key_t key);
-WS_DLL_PUBLIC guint32 conversation_key_port1(const conversation_key_t key);
-WS_DLL_PUBLIC guint32 conversation_key_port2(const conversation_key_t key);
+WS_DLL_PUBLIC const address* conversation_key_addr1(const conversation_element_t *key);
+WS_DLL_PUBLIC guint32 conversation_key_port1(const conversation_element_t *key);
+WS_DLL_PUBLIC const address* conversation_key_addr2(const conversation_element_t *key);
+WS_DLL_PUBLIC guint32 conversation_key_port2(const conversation_element_t *key);
/**
* Create a new hash tables for conversations.
@@ -133,32 +154,6 @@ extern void conversation_init(void);
extern void conversation_epan_reset(void);
/**
- * Conversation element type.
- */
-typedef enum {
- CE_ENDPOINT,
- CE_ADDRESS,
- CE_STRING,
- CE_UINT,
- CE_UINT64,
-} conversation_element_type;
-
-/**
- * Elements used to identify conversations for *_full routines and pinfo->conv_elements.
- * Arrays must be terminated with an element .type set to CE_ENDPOINT.
- */
-typedef struct conversation_element {
- conversation_element_type type;
- union {
- endpoint_type endpoint_type_val;
- address addr_val;
- const char *str_val;
- unsigned int uint_val;
- uint64_t uint64_val;
- };
-} conversation_element_t;
-
-/**
* Create a new conversation identified by a list of elements.
* @param setup_frame The first frame in the conversation.
* @param elements An array of element types and values. Must not be NULL. Must be terminated with a CE_ENDPOINT element.
@@ -297,12 +292,36 @@ WS_DLL_PUBLIC void conversation_set_dissector_from_frame_number(conversation_t *
WS_DLL_PUBLIC dissector_handle_t conversation_get_dissector(conversation_t *conversation, const guint32 frame_num);
+/**
+ * Save address+port information in the current packet info which can be matched by
+ * find_conversation_pinfo. Supports wildcarding.
+ * @param pinfo Packet info.
+ * @param addr1 The first address in the identifying tuple.
+ * @param addr2 The second address in the identifying tuple.
+ * @param etype The endpoint type.
+ * @param port1 The first port in the identifying tuple.
+ * @param port2 The second port in the identifying tuple.
+ */
WS_DLL_PUBLIC void conversation_create_endpoint(struct _packet_info *pinfo, address* addr1, address* addr2,
endpoint_type etype, guint32 port1, guint32 port2);
+/**
+ * Save ID information in the current packet info which can be matched by
+ * conversation_get_endpoint_by_id. Does not support wildcarding.
+ * @param pinfo Packet info.
+ * @param etype The endpoint type.
+ * @param id A unique ID.
+ */
WS_DLL_PUBLIC void conversation_create_endpoint_by_id(struct _packet_info *pinfo,
endpoint_type etype, guint32 id);
+/**
+ * @brief conversation_get_endpoint_by_id
+ * @param pinfo Packet info.
+ * @param etype The endpoint type.
+ * @param options USE_LAST_ENDPOINT or 0.
+ * @return The endpoint ID if successful, or 0 on failure.
+ */
WS_DLL_PUBLIC guint32 conversation_get_endpoint_by_id(struct _packet_info *pinfo,
endpoint_type etype, const guint options);
@@ -325,18 +344,20 @@ WS_DLL_PUBLIC gboolean try_conversation_dissector_by_id(const endpoint_type etyp
/* These routines are used to set undefined values for a conversation */
+/**
+ * Set the second port in a conversation created with conversation_new.
+ * @param conv Conversation. Must be created with conversation_new.
+ * @param port The second port to set.
+ */
WS_DLL_PUBLIC void conversation_set_port2(conversation_t *conv, const guint32 port);
+/**
+ * Set the second address in a conversation created with conversation_new.
+ * @param conv Conversation. Must be created with conversation_new.
+ * @param port The second address to set.
+ */
WS_DLL_PUBLIC void conversation_set_addr2(conversation_t *conv, const address *addr);
-WS_DLL_PUBLIC wmem_map_t *get_conversation_hashtable_exact(void);
-
-WS_DLL_PUBLIC wmem_map_t *get_conversation_hashtable_no_addr2(void);
-
-WS_DLL_PUBLIC wmem_map_t * get_conversation_hashtable_no_port2(void);
-
-WS_DLL_PUBLIC wmem_map_t *get_conversation_hashtable_no_addr2_or_port2(void);
-
/**
* @brief Get a hash table of conversation hash table.
*
@@ -353,9 +374,6 @@ WS_DLL_PUBLIC endpoint_type conversation_pt_to_endpoint_type(port_type pt);
WS_DLL_PUBLIC guint conversation_hash_exact(gconstpointer v);
-/* Provide a wmem_alloced (NULL scope) hash string using HTML tags */
-WS_DLL_PUBLIC gchar *conversation_get_html_hash(const conversation_key_t key);
-
#ifdef __cplusplus
}
#endif /* __cplusplus */
diff --git a/epan/packet.c b/epan/packet.c
index 341a38672c..a3f0f865f1 100644
--- a/epan/packet.c
+++ b/epan/packet.c
@@ -591,6 +591,7 @@ dissect_record(epan_dissect_t *edt, int file_type_subtype,
edt->pi.ptype = PT_NONE;
edt->pi.use_endpoint = FALSE;
edt->pi.conv_endpoint = NULL;
+ edt->pi.conv_elements = NULL;
edt->pi.p2p_dir = P2P_DIR_UNKNOWN;
edt->pi.link_dir = LINK_DIR_UNKNOWN;
edt->pi.src_win_scale = -1; /* unknown Rcv.Wind.Shift */
diff --git a/epan/packet_info.h b/epan/packet_info.h
index 41ba15856f..50f5cda733 100644
--- a/epan/packet_info.h
+++ b/epan/packet_info.h
@@ -72,8 +72,8 @@ typedef struct _packet_info {
guint32 match_uint; /**< matched uint for calling subdissector from table */
const char *match_string; /**< matched string for calling subdissector from table */
gboolean use_endpoint; /**< TRUE if endpoint member should be used for conversations */
- struct endpoint* conv_endpoint; /**< Data that can be used for conversations */
- struct conversation_element *conv_elements; /**< Conversation identifier; alternative to conv_endpoint */
+ struct endpoint* conv_endpoint; /**< Data that can be used for address+port conversations, including wildcarding */
+ struct conversation_element *conv_elements; /**< Arbritrary conversation identifier; can't be wildcarded */
guint16 can_desegment; /**< >0 if this segment could be desegmented.
A dissector that can offer this API (e.g.
TCP) sets can_desegment=2, then
diff --git a/ui/qt/conversation_hash_tables_dialog.cpp b/ui/qt/conversation_hash_tables_dialog.cpp
index 9a26838ca9..80dec2e482 100644
--- a/ui/qt/conversation_hash_tables_dialog.cpp
+++ b/ui/qt/conversation_hash_tables_dialog.cpp
@@ -33,6 +33,7 @@ fill_named_table(gpointer key, gpointer value _U_, gpointer user_data)
if (html_table->isEmpty()) {
html_table->append("<tr>");
int addr_count = 1;
+ int port_count = 1;
int string_count = 1;
int uint_count = 1;
int uint64_count = 1;
@@ -42,6 +43,9 @@ fill_named_table(gpointer key, gpointer value _U_, gpointer user_data)
case CE_ADDRESS:
title = QString("Address %1").arg(addr_count++);
break;
+ case CE_PORT:
+ title = QString("Port %1").arg(port_count++);
+ break;
case CE_STRING:
title = QString("String %1").arg(string_count++);
break;
@@ -70,6 +74,9 @@ title_done:
case CE_ADDRESS:
val = address_to_qstring(&cur_el->addr_val);
break;
+ case CE_PORT:
+ val = QString::number(cur_el->port_val);
+ break;
case CE_STRING:
val = cur_el->str_val;
break;
@@ -102,12 +109,7 @@ ConversationHashTablesDialog::ConversationHashTablesDialog(QWidget *parent) :
QString html;
- html += "<h3>Conversation Hash Tables</h3>\n";
-
- html += hashTableToHtmlTable("conversation_hashtable_exact", get_conversation_hashtable_exact());
- html += hashTableToHtmlTable("conversation_hashtable_no_addr2", get_conversation_hashtable_no_addr2());
- html += hashTableToHtmlTable("conversation_hashtable_no_port2", get_conversation_hashtable_no_port2());
- html += hashTableToHtmlTable("conversation_hashtable_no_addr2_or_port2", get_conversation_hashtable_no_addr2_or_port2());
+ html += "<h2>Conversation Hash Tables</h2>\n";
wmem_map_t *conversation_tables = get_conversation_hashtables();
wmem_list_t *table_names = wmem_map_get_keys(NULL, conversation_tables);
@@ -116,7 +118,12 @@ ConversationHashTablesDialog::ConversationHashTablesDialog(QWidget *parent) :
const char *table_name = static_cast<const char *>(wmem_list_frame_data(cur_frame));
wmem_map_t *table = static_cast<wmem_map_t *>(wmem_map_lookup(conversation_tables, table_name));
- html += QString("<p>%1, %2 entries</p>\n").arg(table_name).arg(wmem_map_size(table));
+ if (!table) {
+ html += QString("<h3>%1, Error: table not found</h3>\n").arg(table_name);
+ continue;
+ }
+
+ html += QString("<h3>%1, %2 entries</h3>\n").arg(table_name).arg(wmem_map_size(table));
QString html_table;
html += "<table>\n";
wmem_map_foreach(table, fill_named_table, &html_table);
@@ -131,41 +138,3 @@ ConversationHashTablesDialog::~ConversationHashTablesDialog()
{
delete ui;
}
-
-static void
-populate_html_table(gpointer data, gpointer user_data)
-{
- const conversation_key_t conv_key = (conversation_key_t)data;
- QString* html_table = (QString*)user_data;
- gchar* tmp = conversation_get_html_hash(conv_key);
-
- // XXX Add a column for the hash value.
- (*html_table) += QString(tmp);
- wmem_free(NULL, tmp);
-}
-
-const QString ConversationHashTablesDialog::hashTableToHtmlTable(const QString table_name, wmem_map_t *hash_table)
-{
- wmem_list_t *conversation_keys = NULL;
- guint num_keys = 0;
- if (hash_table)
- {
- conversation_keys = wmem_map_get_keys(NULL, hash_table);
- num_keys = wmem_list_count(conversation_keys);
- }
-
- QString html_table = QString("<p>%1, %2 entries</p>").arg(table_name).arg(num_keys);
- if (num_keys > 0)
- {
- int one_em = fontMetrics().height();
- html_table += QString("<table cellpadding=\"%1\">\n").arg(one_em / 4);
-
- html_table += "<tr><th align=\"left\">Address 1</th><th align=\"left\">Port 1</th><th align=\"left\">Address 2</th><th align=\"left\">Port 2</th></tr>\n";
-
- wmem_list_foreach(conversation_keys, populate_html_table, (void*)&html_table);
- html_table += "</table>\n";
- }
- if (conversation_keys)
- wmem_destroy_list(conversation_keys);
- return html_table;
-}