epan: Add the ability to add conversation filter protocols.

Convert our conversation protocols to a dynamic list and add
add_conversation_filter_protocol(). Use it in the Falco Bridge plugin to
add protocols with conversation filters.
This commit is contained in:
Gerald Combs 2022-04-14 17:49:03 -07:00
parent f6061c4a3c
commit 87b0288b8d
6 changed files with 45 additions and 8 deletions

View File

@ -20,6 +20,19 @@
GList *packet_conv_filter_list = NULL;
GList *log_conv_filter_list = NULL;
static GSList *conversation_proto_names = NULL;
void conversation_filters_init(void)
{
// add_conversation_filter_protocol prepends entries to the list. Add
// lower layers first so that upper-layer conversations take precedence.
add_conversation_filter_protocol("eth");
add_conversation_filter_protocol("ipv6");
add_conversation_filter_protocol("ip");
add_conversation_filter_protocol("udp");
add_conversation_filter_protocol("tcp");
}
static void do_register_conversation_filter(GList **conv_filter_list, const char *proto_name, const char *display_name,
is_filter_valid_func is_filter_valid, build_filter_string_func build_filter_string) {
conversation_filter_t *entry;
@ -52,6 +65,16 @@ void register_log_conversation_filter(const char *proto_name, const char *displa
build_filter_string);
}
void add_conversation_filter_protocol(const char *proto_name)
{
for (GSList *cur_entry = conversation_proto_names; cur_entry; cur_entry = g_slist_next(cur_entry)) {
if (strcmp(proto_name, cur_entry->data) == 0) {
return;
}
}
conversation_proto_names = g_slist_prepend(conversation_proto_names, (void *)proto_name);
}
static struct conversation_filter_s* find_conversation_filter(GList *conv_filter_list, const char *name)
{
GList *list_entry = conv_filter_list;
@ -79,17 +102,17 @@ void conversation_filters_cleanup(void)
g_list_free(packet_conv_filter_list);
g_list_foreach(log_conv_filter_list, conversation_filter_free, NULL);
g_list_free(log_conv_filter_list);
g_slist_free(conversation_proto_names);
}
static gchar *conversation_filter_from_pinfo(GList *conv_filter_list, struct _packet_info *pinfo)
{
const char *layers[] = { "tcp", "udp", "ip", "ipv6", "eth" };
conversation_filter_t *conv_filter;
gchar *filter;
size_t i;
for (i = 0; i < G_N_ELEMENTS(layers); i++) {
conv_filter = find_conversation_filter(conv_filter_list, layers[i]);
for (GSList *cur_entry = conversation_proto_names; cur_entry; cur_entry = g_slist_next(cur_entry)) {
conv_filter = find_conversation_filter(conv_filter_list, (const char *) cur_entry->data);
if (conv_filter && conv_filter->is_filter_valid(pinfo)) {
if ((filter = conv_filter->build_filter_string(pinfo)) != NULL)
return filter;

View File

@ -21,6 +21,9 @@ extern "C" {
/** @file
*/
/** Initialize internal structures */
extern void conversation_filters_init(void);
/** callback function definition: is a filter available for this packet? */
typedef gboolean (*is_filter_valid_func)(struct _packet_info *pinfo);
@ -35,8 +38,13 @@ WS_DLL_PUBLIC void register_conversation_filter(const char *proto_name, const ch
/** register a dissector filter for logs */
WS_DLL_PUBLIC void register_log_conversation_filter(const char *proto_name, const char *display_name,
is_filter_valid_func is_filter_valid, build_filter_string_func build_filter_string);
/**
* Prepend a protocol to the list of filterable protocols.
* @param A valid protocol name.
*/
WS_DLL_PUBLIC void add_conversation_filter_protocol(const char *proto_name);
/* Cleanup internal structures */
/** Cleanup internal structures */
extern void conversation_filters_cleanup(void);
/**

View File

@ -302,6 +302,7 @@ epan_init(register_cb cb, gpointer client_data, gboolean load_plugins)
conversation_init();
capture_dissector_init();
reassembly_tables_init();
conversation_filters_init();
g_slist_foreach(epan_plugins, epan_plugin_init, NULL);
proto_init(epan_plugin_register_all_procotols, epan_plugin_register_all_handoffs, cb, client_data);
g_slist_foreach(epan_plugins, epan_plugin_register_all_tap_listeners, NULL);

View File

@ -22,6 +22,7 @@ libwireshark.so.0 libwireshark0 #MINVER#
abs_time_secs_to_str_ex@Base 3.7.0
abs_time_to_str_ex@Base 3.7.0
add_ber_encoded_label@Base 3.7.0
add_conversation_filter_protocol@Base 3.7.0
add_conversation_table_data@Base 2.5.0
add_conversation_table_data_with_conv_id@Base 2.5.0
add_hostlist_table_data@Base 2.5.0

View File

@ -123,7 +123,6 @@ static conv_fld_info conv_fld_infos[MAX_N_CONV_FILTERS];
DECLARE_CONV_FLTS()
static char conv_flt_vals[MAX_N_CONV_FILTERS][MAX_CONV_FILTER_STR_LEN];
static guint conv_vals_cnt = 0;
static guint conv_fld_cnt = 0;
void
register_conversation_filters_mappings(void)
@ -161,6 +160,8 @@ configure_plugin(bridge_info* bi, char* config _U_)
bi->field_flags = (guint32*)wmem_alloc(wmem_epan_scope(), bi->visible_fields * sizeof(guint32));
uint32_t fld_cnt = 0;
size_t conv_fld_cnt = 0;
for (uint32_t j = 0; j < tot_fields; j++)
{
bi->hf_ids[fld_cnt] = -1;
@ -227,13 +228,16 @@ configure_plugin(bridge_info* bi, char* config _U_)
conv_fld_infos[conv_fld_cnt].field_info = ri;
const char *source_name = get_sinsp_source_name(bi->ssi);
conv_fld_infos[conv_fld_cnt].proto_name = source_name;
// XXX We currently build a filter per field. Should we "and" them instead?
register_log_conversation_filter(source_name, finfo.hfinfo.name, fv_func[conv_fld_cnt], bfs_func[conv_fld_cnt]);
conv_fld_cnt++;
}
fld_cnt++;
}
proto_register_field_array(proto_falco_bridge, bi->hf, fld_cnt);
if (conv_fld_cnt > 0) {
add_conversation_filter_protocol(get_sinsp_source_name(bi->ssi));
}
}
}

View File

@ -2493,7 +2493,7 @@ void LogwolfMainWindow::colorizeConversation(bool create_rule)
if (capture_file_.capFile() && selectedRows().count() > 0) {
packet_info *pi = capture_file_.packetInfo();
guint8 cc_num = colorize_action->data().toUInt();
gchar *filter = conversation_filter_from_packet(pi);
gchar *filter = conversation_filter_from_log(pi);
if (filter == NULL) {
mainApp->pushStatus(WiresharkApplication::TemporaryStatus, tr("Unable to build conversation filter."));
return;