diff options
-rw-r--r-- | doc/README.dissector | 62 | ||||
-rw-r--r-- | epan/conversation.c | 301 | ||||
-rw-r--r-- | epan/conversation.h | 108 | ||||
-rw-r--r-- | epan/packet.c | 1 | ||||
-rw-r--r-- | epan/packet_info.h | 2 | ||||
-rw-r--r-- | packaging/debian/libwireshark0.symbols | 2 | ||||
-rw-r--r-- | plugins/epan/falco_bridge/packet-falco-bridge.c | 44 |
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; } |