aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--doc/README.dissector62
-rw-r--r--epan/conversation.c301
-rw-r--r--epan/conversation.h108
-rw-r--r--epan/packet.c1
-rw-r--r--epan/packet_info.h2
-rw-r--r--packaging/debian/libwireshark0.symbols2
-rw-r--r--plugins/epan/falco_bridge/packet-falco-bridge.c44
7 files changed, 469 insertions, 51 deletions
diff --git a/doc/README.dissector b/doc/README.dissector
index 63fa648f75..94b649e737 100644
--- a/doc/README.dissector
+++ b/doc/README.dissector
@@ -2434,12 +2434,12 @@ ServerA:1000 to ClientA:2000 and the packet from ClientA:2000 to ServerA:1000.
2.2.1 Conversation Routines
-There are seven routines that you will use to work with a conversation:
-conversation_new, find_conversation, find_or_create_conversation,
+There are nine routines that you will use to work with a conversation:
+conversation_new, conversation_new_full, find_conversation,
+find_conversation_full, find_or_create_conversation,
conversation_add_proto_data, conversation_get_proto_data,
conversation_delete_proto_data, and conversation_set_dissector.
-
2.2.1.1 The conversation_init function.
This is an internal routine for the conversation code. As such you
@@ -2475,7 +2475,7 @@ Where:
guint32 setup_frame = The lowest numbered frame for this conversation
address* addr1 = first data packet address
address* addr2 = second data packet address
- port_type ptype = port type, this is defined in packet.h
+ endpoint_type etype = endpoint type, defined in conversation.h
guint32 port1 = first data packet port
guint32 port2 = second data packet port
guint options = conversation options, NO_ADDR2 and/or NO_PORT2
@@ -2500,7 +2500,25 @@ packet indicates that, later in the capture, a conversation will be
created using certain addresses and ports, in the case where the packet
doesn't specify the addresses and ports of both sides.
-2.2.1.3 The find_conversation function.
+2.2.1.3 The conversation_new_full function.
+
+This routine will create a new conversation based upon an arbritrary
+lists of elements. Elements can be addresses, strings, unsigned
+integers, or unsigned 64-bit integers. Unlike conversation_new, element
+lists are matched strictly; wildcards aren't (yet) supported.
+
+The conversation_new_full prototype:
+ conversation_t *conversation_new(const guint32 setup_frame,
+ conversation_element_t *elements);
+
+Where:
+ guint32 setup_frame = The lowest numbered frame for
+ this conversation
+ conversation_element_t *elements = An array of data types and
+ values which identify this conversation. The array MUST be
+ terminated with a CE_ENDPOINT element.
+
+2.2.1.4 The find_conversation function.
Call this routine to look up a conversation. If no conversation is found,
the routine will return a NULL value.
@@ -2549,7 +2567,24 @@ NO_ADDR_B|NO_PORT_B, the "addr_b" address will be treated as matching
any "wildcarded" address and the "port_b" port will be treated as
matching any "wildcarded" port.
-2.2.1.4 The find_conversation_pinfo function.
+2.2.1.5 The find_conversation_full function.
+
+Call this routine to look up a conversation based on an element list. If
+no conversation is found, the routine will return a NULL value.
+
+The find_conversation_full prototype:
+
+ conversation_t *find_conversation_full(guint32 frame_num,
+ conversation_element_t *elements);
+
+Where:
+ guint32 setup_frame = The lowest numbered frame for
+ this conversation
+ conversation_element_t *elements = An array of data types and
+ values which identify this conversation. The array MUST be
+ terminated with a CE_ENDPOINT element.
+
+2.2.1.6 The find_conversation_pinfo function.
This convenience function will find an existing conversation (by calling
find_conversation())
@@ -2563,9 +2598,11 @@ Where:
const guint options = conversation options, NO_ADDR_B and/or NO_PORT_B
The frame number and the addresses necessary for find_conversation() are
-taken from the pinfo structure (as is commonly done).
+taken from the addresses and ports in the pinfo structure,
+pinfo->conv_endpoint if pinfo->use_endpoint is set, or
+pinfo->conv_elements if it is set.
-2.2.1.5 The find_or_create_conversation function.
+2.2.1.7 The find_or_create_conversation function.
This convenience function will find an existing conversation (by calling
find_conversation()) and, if a conversation does not already exist, create a
@@ -2582,8 +2619,7 @@ The frame number and the addresses necessary for find_conversation() and
conversation_new() are taken from the pinfo structure (as is commonly done)
and no 'options' are used.
-
-2.2.1.6 The conversation_add_proto_data function.
+2.2.1.8 The conversation_add_proto_data function.
Once you have created a conversation with conversation_new, you can
associate data with it using this function.
@@ -2609,7 +2645,7 @@ Using the protocol number allows several dissectors to
associate data with a given conversation.
-2.2.1.7 The conversation_get_proto_data function.
+2.2.1.9 The conversation_get_proto_data function.
After you have located a conversation with find_conversation, you can use
this function to retrieve any data associated with it.
@@ -2628,7 +2664,7 @@ typically in the proto_register_XXXX portion of a dissector. The function
returns a pointer to the data requested, or NULL if no data was found.
-2.2.1.8 The conversation_delete_proto_data function.
+2.2.1.10 The conversation_delete_proto_data function.
After you are finished with a conversation, you can remove your association
with this function. Please note that ONLY the conversation entry is
@@ -2647,7 +2683,7 @@ Where:
is a unique protocol number created with proto_register_protocol,
typically in the proto_register_XXXX portion of a dissector.
-2.2.1.9 The conversation_set_dissector function
+2.2.1.11 The conversation_set_dissector function
This function sets the protocol dissector to be invoked whenever
conversation parameters (addresses, port_types, ports, etc) are matched
diff --git a/epan/conversation.c b/epan/conversation.c
index e74ae0886a..722978a62c 100644
--- a/epan/conversation.c
+++ b/epan/conversation.c
@@ -11,11 +11,17 @@
#include "config.h"
#include <string.h>
+
#include <glib.h>
+
#include "packet.h"
#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.
+
/* define DEBUG_CONVERSATION for pretty debug printing */
/* #define DEBUG_CONVERSATION */
#include "conversation_debug.h"
@@ -34,7 +40,7 @@ struct endpoint {
};
struct conversation_key {
- struct conversation_key *next;
+ // XXX Replace these with conversation_element_t's.
address addr1;
address addr2;
endpoint_type etype;
@@ -45,7 +51,7 @@ struct conversation_key {
/*
* Hash table for conversations with no wildcards.
*/
-static wmem_map_t *conversation_hashtable_exact = NULL;
+static wmem_map_t *conversation_hashtable_exact_addr_port = NULL;
/*
* Hash table for conversations with one wildcard address.
@@ -62,6 +68,10 @@ static wmem_map_t *conversation_hashtable_no_port2 = NULL;
*/
static wmem_map_t *conversation_hashtable_no_addr2_or_port2 = NULL;
+/*
+ * Hash table of hash tables for conversations identified by element lists.
+ */
+static wmem_map_t *conversation_hashtable_element_list = NULL;
static guint32 new_index;
@@ -443,6 +453,111 @@ conversation_match_no_addr2_or_port2(gconstpointer v, gconstpointer w)
return 0;
}
+/*
+ * Compute the hash value for two given element lists 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_element_list(gconstpointer v)
+{
+ const conversation_element_t *element = (const conversation_element_t*)v;
+ guint hash_val = 0;
+
+ for (;;) {
+ // XXX We could use a hash_arbitrary_bytes routine. Abuse add_address_to_hash in the mean time.
+ address tmp_addr;
+ switch (element->type) {
+ case CE_ADDRESS:
+ hash_val = add_address_to_hash(hash_val, &element->addr_val);
+ break;
+ case CE_STRING:
+ tmp_addr.len = (int) strlen(element->str_val);
+ tmp_addr.data = element->str_val;
+ hash_val = add_address_to_hash(hash_val, &tmp_addr);
+ break;
+ case CE_UINT:
+ tmp_addr.len = (int) sizeof(element->uint_val);
+ tmp_addr.data = &element->uint_val;
+ hash_val = add_address_to_hash(hash_val, &tmp_addr);
+ break;
+ case CE_UINT64:
+ tmp_addr.len = (int) sizeof(element->uint64_val);
+ tmp_addr.data = &element->uint64_val;
+ hash_val = add_address_to_hash(hash_val, &tmp_addr);
+ break;
+ case CE_ENDPOINT:
+ tmp_addr.len = (int) sizeof(element->endpoint_type_val);
+ tmp_addr.data = &element->endpoint_type_val;
+ hash_val = add_address_to_hash(hash_val, &tmp_addr);
+ goto done;
+ break;
+ }
+ element++;
+ }
+
+done:
+ 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 gboolean
+conversation_match_element_list(gconstpointer v1, gconstpointer v2)
+{
+ const conversation_element_t *element1 = (const conversation_element_t*)v1;
+ const conversation_element_t *element2 = (const conversation_element_t*)v2;
+
+ for (;;) {
+ if (element1->type != element2->type) {
+ return FALSE;
+ }
+
+ switch (element1->type) {
+ case CE_ADDRESS:
+ if (!addresses_equal(&element1->addr_val, &element2->addr_val)) {
+ return FALSE;
+ }
+ break;
+ case CE_STRING:
+ if (strcmp(element1->str_val, element2->str_val)) {
+ return FALSE;
+ }
+ break;
+ case CE_UINT:
+ if (element1->uint_val != element2->uint_val) {
+ return FALSE;
+ }
+ break;
+ case CE_UINT64:
+ if (element1->uint64_val != element2->uint64_val) {
+ return FALSE;
+ }
+ break;
+ case CE_ENDPOINT:
+ if (element1->endpoint_type_val != element2->endpoint_type_val) {
+ return FALSE;
+ }
+ goto done;
+ break;
+ }
+ element1++;
+ element2++;
+ }
+
+ done:
+ // Everything matched so far.
+ return TRUE;
+}
+
/**
* Create a new hash tables for conversations.
*/
@@ -457,7 +572,7 @@ conversation_init(void)
* pointed to by conversation data structures that were freed
* above.
*/
- conversation_hashtable_exact =
+ 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 =
@@ -470,6 +585,8 @@ conversation_init(void)
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);
}
/**
@@ -501,6 +618,7 @@ conversation_insert_into_hashtable(wmem_map_t *hashtable, conversation_t *conv)
/* New entry */
conv->next = NULL;
conv->last = conv;
+
wmem_map_insert(hashtable, conv->key_ptr, conv);
DPRINT(("created a new conversation chain"));
}
@@ -602,6 +720,117 @@ conversation_remove_from_hashtable(wmem_map_t *hashtable, conversation_t *conv)
}
}
+/* Element count including the terminating CE_ENDPOINT */
+#define MAX_CONVERSATION_ELEMENTS 10 // Arbitrary.
+static size_t conversation_element_count(conversation_element_t *elements) {
+ size_t count = 0;
+ while (elements[count].type != CE_ENDPOINT) {
+ count++;
+ DISSECTOR_ASSERT(count < MAX_CONVERSATION_ELEMENTS);
+ }
+ count++;
+ // Keying on the endpoint type alone isn't very useful.
+ DISSECTOR_ASSERT(count > 1);
+ return count;
+}
+
+/* Create a string based on element types. Must be g_freed. */
+static char* conversation_element_list_name(conversation_element_t *elements) {
+ const char *type_names[] = {
+ "endpoint",
+ "address",
+ "string",
+ "uint",
+ "uint64",
+ };
+ char *sep = "";
+ GString *conv_hash_group = 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(conv_hash_group, "%s%s", sep, type_names[cur_el->type]);
+ sep = ",";
+ }
+ return g_string_free(conv_hash_group, FALSE);
+}
+
+#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);
+
+ char *el_list_map_key = conversation_element_list_name(elements);
+ wmem_map_t *el_list_map = (wmem_map_t *) wmem_map_lookup(conversation_hashtable_element_list, el_list_map_key);
+ if (!el_list_map) {
+ el_list_map = 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_file_scope(), el_list_map_key), el_list_map);
+ }
+ g_free(el_list_map_key);
+
+ size_t element_count = conversation_element_count(elements);
+ conversation_element_t *conv_key = wmem_memdup(wmem_file_scope(), elements, sizeof(conversation_element_t) * element_count);
+ for (size_t i = 0; i < element_count; i++) {
+ if (conv_key[i].type == CE_ADDRESS) {
+ copy_address_wmem(wmem_file_scope(), &conv_key[i].addr_val, &elements[i].addr_val);
+ } else if (conv_key[i].type == CE_STRING) {
+ conv_key[i].str_val = wmem_strdup(wmem_file_scope(), elements[i].str_val);
+ }
+ }
+
+ conversation_t *conversation = wmem_new0(wmem_file_scope(), conversation_t);
+ conversation->conv_index = new_index;
+ conversation->setup_frame = conversation->last_frame = setup_frame;
+
+ 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_insert_into_hashtable(el_list_map, conversation);
+ return conversation;
+}
+
/*
* Given two address/port pairs for a packet, create a new conversation
* to contain packets between those address/port pairs.
@@ -721,11 +950,11 @@ conversation_new(const guint32 setup_frame, const address *addr1, const address
if (options & (NO_PORT2|NO_PORT2_FORCE)) {
hashtable = conversation_hashtable_no_port2;
} else {
- hashtable = conversation_hashtable_exact;
+ hashtable = conversation_hashtable_exact_addr_port;
}
}
- new_key = wmem_new(wmem_file_scope(), struct conversation_key);
+ new_key = wmem_new0(wmem_file_scope(), struct conversation_key);
if (addr1 != NULL) {
copy_address_wmem(wmem_file_scope(), &new_key->addr1, addr1);
} else {
@@ -797,7 +1026,7 @@ conversation_set_port2(conversation_t *conv, const guint32 port)
if (conv->options & NO_ADDR2) {
conversation_insert_into_hashtable(conversation_hashtable_no_addr2, conv);
} else {
- conversation_insert_into_hashtable(conversation_hashtable_exact, conv);
+ conversation_insert_into_hashtable(conversation_hashtable_exact_addr_port, conv);
}
DENDENT();
}
@@ -834,11 +1063,48 @@ conversation_set_addr2(conversation_t *conv, const address *addr)
if (conv->options & NO_PORT2) {
conversation_insert_into_hashtable(conversation_hashtable_no_port2, conv);
} else {
- conversation_insert_into_hashtable(conversation_hashtable_exact, conv);
+ conversation_insert_into_hashtable(conversation_hashtable_exact_addr_port, conv);
}
DENDENT();
}
+conversation_t *find_conversation_full(const guint32 frame_num, conversation_element_t *elements)
+{
+ char *el_list_map_key = conversation_element_list_name(elements);
+ wmem_map_t *el_list_map = (wmem_map_t *) wmem_map_lookup(conversation_hashtable_element_list, el_list_map_key);
+ g_free(el_list_map_key);
+ if (!el_list_map) {
+ return NULL;
+ }
+
+ conversation_t* convo=NULL;
+ conversation_t* match=NULL;
+ conversation_t* chain_head=NULL;
+ chain_head = (conversation_t *)wmem_map_lookup(el_list_map, elements);
+
+ if (chain_head && (chain_head->setup_frame <= frame_num)) {
+ match = chain_head;
+
+ if (chain_head->last && (chain_head->last->setup_frame <= frame_num))
+ return chain_head->last;
+
+ if (chain_head->latest_found && (chain_head->latest_found->setup_frame <= frame_num))
+ match = chain_head->latest_found;
+
+ for (convo = match; convo && convo->setup_frame <= frame_num; convo = convo->next) {
+ if (convo->setup_frame > match->setup_frame) {
+ match = convo;
+ }
+ }
+ }
+
+ if (match) {
+ chain_head->latest_found = match;
+ }
+
+ return match;
+}
+
/*
* Search a particular hash table for a conversation with the specified
* {addr1, port1, addr2, port2} and set up before frame_num.
@@ -875,10 +1141,10 @@ conversation_lookup_hashtable(wmem_map_t *hashtable, const guint32 frame_num, co
if (chain_head && (chain_head->setup_frame <= frame_num)) {
match = chain_head;
- if ((chain_head->last)&&(chain_head->last->setup_frame<=frame_num))
+ if (chain_head->last && (chain_head->last->setup_frame <= frame_num))
return chain_head->last;
- if ((chain_head->latest_found)&&(chain_head->latest_found->setup_frame<=frame_num))
+ if (chain_head->latest_found && (chain_head->latest_found->setup_frame <= frame_num))
match = chain_head->latest_found;
for (convo = match; convo && convo->setup_frame <= frame_num; convo = convo->next) {
@@ -894,7 +1160,6 @@ conversation_lookup_hashtable(wmem_map_t *hashtable, const guint32 frame_num, co
return match;
}
-
/*
* Given two address/port pairs for a packet, search for a conversation
* containing packets between those address/port pairs. Returns NULL if
@@ -950,7 +1215,7 @@ 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_hashtable(conversation_hashtable_exact,
+ conversation_lookup_hashtable(conversation_hashtable_exact_addr_port,
frame_num, addr_a, addr_b, etype,
port_a, port_b);
/* Didn't work, try the other direction */
@@ -958,7 +1223,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_b, addr_a_str, port_a));
conversation =
- conversation_lookup_hashtable(conversation_hashtable_exact,
+ conversation_lookup_hashtable(conversation_hashtable_exact_addr_port,
frame_num, addr_b, addr_a, etype,
port_b, port_a);
}
@@ -969,7 +1234,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_hashtable(conversation_hashtable_exact,
+ conversation_lookup_hashtable(conversation_hashtable_exact_addr_port,
frame_num, addr_b, addr_a, etype,
port_a, port_b);
}
@@ -1480,6 +1745,14 @@ find_conversation_pinfo(packet_info *pinfo, const guint options)
conv->last_frame = pinfo->num;
}
}
+ } else if (pinfo->conv_elements) {
+ if ((conv = find_conversation_full(pinfo->num, pinfo->conv_elements)) != NULL) {
+ DPRINT(("found previous conversation elements for frame #%u (last_frame=%d)",
+ pinfo->num, conv->last_frame));
+ if (pinfo->num > conv->last_frame) {
+ conv->last_frame = pinfo->num;
+ }
+ }
} else {
if ((conv = find_conversation(pinfo->num, &pinfo->src, &pinfo->dst,
conversation_pt_to_endpoint_type(pinfo->ptype), pinfo->srcport,
@@ -1584,7 +1857,7 @@ conversation_get_endpoint_by_id(struct _packet_info *pinfo, endpoint_type etype,
wmem_map_t *
get_conversation_hashtable_exact(void)
{
- return conversation_hashtable_exact;
+ return conversation_hashtable_exact_addr_port;
}
wmem_map_t *
diff --git a/epan/conversation.h b/epan/conversation.h
index 9d5ec37eeb..83156aa4e5 100644
--- a/epan/conversation.h
+++ b/epan/conversation.h
@@ -21,9 +21,13 @@ extern "C" {
#endif /* __cplusplus */
/**
- *@file
+ * @file
+ * The conversation API lets you correlate packets based on values in a
+ * packet, typically address+port tuples. You can search for conversations
+ * based on their value tuples and attach data to them.
*/
-/*
+
+/**
* 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
@@ -39,15 +43,15 @@ extern "C" {
#define NO_PORT2_FORCE 0x04
#define CONVERSATION_TEMPLATE 0x08
-/*
+/**
* Flags to pass to "find_conversation()" to indicate that the address B
* and/or port B search arguments are wildcards.
*/
#define NO_ADDR_B 0x01
#define NO_PORT_B 0x02
-/* Flags to handle endpoints */
-#define USE_LAST_ENDPOINT 0x08 /* Use last endpoint created, regardless of type */
+/** Flags to handle endpoints */
+#define USE_LAST_ENDPOINT 0x08 /**< Use last endpoint created, regardless of type */
/* Types of port numbers Wireshark knows about. */
typedef enum {
@@ -82,15 +86,18 @@ typedef enum {
ENDPOINT_DVBBBF, /* DVB Base Band Frame ISI/PLP_ID */
ENDPOINT_IWARP_MPA, /* iWarp MPA */
ENDPOINT_BT_UTP, /* BitTorrent uTP Connection ID */
-
+ ENDPOINT_LOG, /* Logging source */
} endpoint_type;
/**
- * Data structure representing a conversation.
+ * Key used for identifying a conversation.
*/
struct conversation_key;
typedef struct conversation_key* conversation_key_t;
+/**
+ * Data structure representing a conversation.
+ */
typedef struct conversation {
struct conversation *next; /** pointer to next conversation on hash chain */
struct conversation *last; /** pointer to the last conversation on hash chain */
@@ -124,18 +131,70 @@ 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.
+ * @return The new conversation.
+ */
+WS_DLL_PUBLIC WS_RETNONNULL conversation_t *conversation_new_full(const guint32 setup_frame, conversation_element_t *elements);
+
+/**
* Given two address/port pairs for a packet, create a new conversation
- * to contain packets between those address/port pairs.
+ * identified by 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.
+ *
+ * @param setup_frame The first frame in the conversation.
+ * @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.
+ * @param options NO_ADDR2, NO_PORT2, NO_PORT2_FORCE, or CONVERSATION_TEMPLATE.
+ * Options except for NO_PORT2 and NO_PORT2_FORCE can be ORed.
+ * @return The new conversation.
*/
-WS_DLL_PUBLIC conversation_t *conversation_new(const guint32 setup_frame, const address *addr1, const address *addr2,
+WS_DLL_PUBLIC WS_RETNONNULL conversation_t *conversation_new(const guint32 setup_frame, const address *addr1, const address *addr2,
const endpoint_type etype, const guint32 port1, const guint32 port2, const guint options);
-WS_DLL_PUBLIC conversation_t *conversation_new_by_id(const guint32 setup_frame, const endpoint_type etype, const guint32 id, const guint options);
+WS_DLL_PUBLIC WS_RETNONNULL conversation_t *conversation_new_by_id(const guint32 setup_frame, const endpoint_type etype, const guint32 id, const guint options);
+
+/**
+ * Search for a conversation based on the structure and values of an element list.
+ * @param frame_num Frame number. Must be greater than or equal to the conversation's initial frame number.
+ * @param elements An array of element types and values. Must not be NULL. Must be terminated with a CE_ENDPOINT element.
+ * @return The matching conversation if found, otherwise NULL.
+ */
+WS_DLL_PUBLIC conversation_t *find_conversation_full(const guint32 frame_num, conversation_element_t *elements);
/**
* Given two address/port pairs for a packet, search for a conversation
@@ -172,6 +231,15 @@ WS_DLL_PUBLIC conversation_t *conversation_new_by_id(const guint32 setup_frame,
* a pointer to the matched conversation;
*
* otherwise, we found no matching conversation, and return NULL.
+ *
+ * @param frame_num Frame number. Must be greater than or equal to the conversation's initial frame number.
+ * @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.
+ * @param options Wildcard options as described above.
+ * @return The matching conversation if found, otherwise NULL.
*/
WS_DLL_PUBLIC conversation_t *find_conversation(const guint32 frame_num, const address *addr_a, const address *addr_b,
const endpoint_type etype, const guint32 port_a, const guint32 port_b, const guint options);
@@ -183,19 +251,23 @@ WS_DLL_PUBLIC conversation_t *find_conversation_by_id(const guint32 frame, const
*/
WS_DLL_PUBLIC conversation_t *find_conversation_pinfo(packet_info *pinfo, const guint options);
-/** A helper function that calls find_conversation() and, if a conversation is
- * not found, calls conversation_new().
- * The frame number and addresses are taken from pinfo.
- * No options are used, though we could extend this API to include an options
- * parameter.
+/**
+ * A helper function that calls find_conversation() and, if a conversation is
+ * not found, calls conversation_new().
+ * The frame number and addresses are taken from pinfo.
+ * No options are used, though we could extend this API to include an options
+ * parameter.
+ *
+ * @param pinfo Packet info.
+ * @return The existing or new conversation.
*/
-WS_DLL_PUBLIC conversation_t *find_or_create_conversation(packet_info *pinfo);
+WS_DLL_PUBLIC WS_RETNONNULL conversation_t *find_or_create_conversation(packet_info *pinfo);
/** A helper function that calls find_conversation_by_id() and, if a
* conversation is not found, calls conversation_new_by_id().
* The frame number is taken from pinfo.
*/
-WS_DLL_PUBLIC conversation_t *find_or_create_conversation_by_id(packet_info *pinfo, const endpoint_type etype, const guint32 id);
+WS_DLL_PUBLIC WS_RETNONNULL conversation_t *find_or_create_conversation_by_id(packet_info *pinfo, const endpoint_type etype, const guint32 id);
/** Associate data with a conversation.
* @param conv Conversation. Must not be NULL.
diff --git a/epan/packet.c b/epan/packet.c
index 6a83263009..341a38672c 100644
--- a/epan/packet.c
+++ b/epan/packet.c
@@ -664,6 +664,7 @@ dissect_file(epan_dissect_t *edt, wtap_rec *rec,
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.layers = wmem_list_new(edt->pi.pool);
diff --git a/epan/packet_info.h b/epan/packet_info.h
index 6c723d46ff..41ba15856f 100644
--- a/epan/packet_info.h
+++ b/epan/packet_info.h
@@ -16,6 +16,7 @@
#include "address.h"
struct endpoint;
+struct conversation_element;
/** @file
* Dissected packet data and metadata.
@@ -72,6 +73,7 @@ typedef struct _packet_info {
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 */
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/packaging/debian/libwireshark0.symbols b/packaging/debian/libwireshark0.symbols
index 4950bf333e..7471c718a5 100644
--- a/packaging/debian/libwireshark0.symbols
+++ b/packaging/debian/libwireshark0.symbols
@@ -182,6 +182,7 @@ libwireshark.so.0 libwireshark0 #MINVER#
conversation_key_port2@Base 2.5.0
conversation_new@Base 1.9.1
conversation_new_by_id@Base 2.5.0
+ conversation_new_full@Base 3.7.1
conversation_pt_to_endpoint_type@Base 2.5.0
conversation_set_dissector@Base 1.9.1
conversation_set_dissector_from_frame_number@Base 2.0.0
@@ -673,6 +674,7 @@ libwireshark.so.0 libwireshark0 #MINVER#
find_capture_dissector@Base 2.3.0
find_conversation@Base 1.9.1
find_conversation_by_id@Base 2.5.0
+ find_conversation_full@Base 3.7.1
find_conversation_pinfo@Base 2.5.0
find_depend_dissector_list@Base 2.1.0
find_dissector@Base 1.9.1
diff --git a/plugins/epan/falco_bridge/packet-falco-bridge.c b/plugins/epan/falco_bridge/packet-falco-bridge.c
index a4475a7146..c5eadfa5de 100644
--- a/plugins/epan/falco_bridge/packet-falco-bridge.c
+++ b/plugins/epan/falco_bridge/packet-falco-bridge.c
@@ -31,6 +31,7 @@
#include <epan/packet.h>
#include <epan/proto.h>
#include <epan/proto_data.h>
+#include <epan/conversation.h>
#include <epan/conversation_filter.h>
#include <epan/tap.h>
#include <epan/stat_tap_ui.h>
@@ -183,7 +184,6 @@ configure_plugin(bridge_info* bi, char* config _U_)
if (addr_fields) {
bi->hf_id_to_addr_id = (int *)wmem_alloc(wmem_epan_scope(), bi->visible_fields * sizeof(int));
- memset(bi->hf_id_to_addr_id, -1, bi->visible_fields);
bi->hf_v4 = (hf_register_info*)wmem_alloc(wmem_epan_scope(), addr_fields * sizeof(hf_register_info));
bi->hf_v4_ids = (int*)wmem_alloc(wmem_epan_scope(), addr_fields * sizeof(int));
bi->hf_v6 = (hf_register_info*)wmem_alloc(wmem_epan_scope(), addr_fields * sizeof(hf_register_info));
@@ -295,8 +295,9 @@ configure_plugin(bridge_info* bi, char* config _U_)
}
};
*ri_v6 = finfo_v6;
-
addr_fld_cnt++;
+ } else {
+ bi->hf_id_to_addr_id[fld_cnt] = -1;
}
fld_cnt++;
}
@@ -482,6 +483,7 @@ dissect_sinsp_span(tvbuff_t* tvb, packet_info* pinfo, proto_tree* tree, void* da
bridge_info* bi = p_get_proto_data(pinfo->pool, pinfo, proto_falco_bridge, PROTO_DATA_BRIDGE_HANDLE);
guint plen = tvb_captured_length(tvb);
const char *source_name = get_sinsp_source_name(bi->ssi);
+ wmem_array_t *conversation_elements = wmem_array_new(pinfo->pool, sizeof(conversation_element_t));
col_set_str(pinfo->cinfo, COL_PROTOCOL, source_name);
/* Clear out stuff in the info column */
@@ -508,11 +510,16 @@ dissect_sinsp_span(tvbuff_t* tvb, packet_info* pinfo, proto_tree* tree, void* da
for (uint32_t fld_idx = 0; fld_idx < bi->visible_fields; fld_idx++) {
sinsp_field_extract_t *sfe = &sinsp_fields[fld_idx];
header_field_info* hfinfo = &(bi->hf[fld_idx].hfinfo);
+ conversation_element_t conv_el = {0};
if (!sfe->is_present) {
continue;
}
+ if ((bi->field_flags[fld_idx] & BFF_CONVERSATION) != 0) {
+ conv_vals_cnt++;
+ }
+
if (sfe->type == SFT_STRINGZ && hfinfo->type == FT_STRINGZ) {
proto_item *pi = proto_tree_add_string(fb_tree, bi->hf_ids[fld_idx], tvb, 0, plen, sfe->res_str);
if (bi->field_flags[fld_idx] & BFF_INFO) {
@@ -530,10 +537,6 @@ dissect_sinsp_span(tvbuff_t* tvb, packet_info* pinfo, proto_tree* tree, void* da
PROTO_DATA_CONVINFO_USER_BASE + conv_vals_cnt, cvalptr);
}
- if ((bi->field_flags[fld_idx] & BFF_CONVERSATION) != 0) {
- conv_vals_cnt++;
- }
-
int addr_fld_idx = bi->hf_id_to_addr_id[fld_idx];
if (addr_fld_idx >= 0) {
ws_in4_addr v4_addr;
@@ -552,21 +555,50 @@ dissect_sinsp_span(tvbuff_t* tvb, packet_info* pinfo, proto_tree* tree, void* da
if (addr_item) {
proto_item_set_generated(addr_item);
}
+ if ((bi->field_flags[fld_idx] & BFF_CONVERSATION) != 0) {
+ conv_el.type = CE_ADDRESS;
+ copy_address(&conv_el.addr_val, &pinfo->net_src);
+ }
+ } else {
+ if ((bi->field_flags[fld_idx] & BFF_CONVERSATION) != 0) {
+ conv_el.type = CE_STRING;
+ conv_el.str_val = wmem_strdup(pinfo->pool, sfe->res_str);
+ }
}
}
else if (sfe->type == SFT_UINT64 && hfinfo->type == FT_UINT64) {
proto_tree_add_uint64(fb_tree, bi->hf_ids[fld_idx], tvb, 0, plen, sfe->res_u64);
+ if ((bi->field_flags[fld_idx] & BFF_CONVERSATION) != 0) {
+ conv_el.type = CE_UINT64;
+ conv_el.uint64_val = sfe->res_u64;
+ }
}
else {
REPORT_DISSECTOR_BUG("Field %s has an unrecognized or mismatched type %u != %u",
hfinfo->abbrev, sfe->type, hfinfo->type);
}
+ if (conv_el.type != CE_ENDPOINT) {
+ wmem_array_append_one(conversation_elements, conv_el);
+ }
}
if (!rc) {
REPORT_DISSECTOR_BUG("Falco plugin %s extract error", get_sinsp_source_name(bi->ssi));
}
+ unsigned num_conv_els = wmem_array_get_count(conversation_elements);
+ if (num_conv_els > 0) {
+ conversation_element_t conv_el;
+ conv_el.type = CE_ENDPOINT;
+ conv_el.endpoint_type_val = ENDPOINT_LOG;
+ wmem_array_append_one(conversation_elements, conv_el);
+ pinfo->conv_elements = (conversation_element_t *) wmem_array_get_raw(conversation_elements);
+ conversation_t *conv = find_conversation_pinfo(pinfo, 0);
+ if (!conv) {
+ conversation_new_full(pinfo->fd->num, pinfo->conv_elements);
+ }
+ }
+
return plen;
}