diff options
author | Michael Mann <mmann78@netscape.net> | 2014-07-23 13:38:55 -0400 |
---|---|---|
committer | Gerald Combs <gerald@wireshark.org> | 2014-07-26 20:59:42 +0000 |
commit | 31ecdf5b06bff3bb2e706e840c28c519698e6f67 (patch) | |
tree | 71b3e59889e862560412d317df71113f66b094b6 /epan | |
parent | 507d07eda6ad562d4567cf0ee83aa9b03997beca (diff) |
Refactor "common" Conversation table functionality.
Refactor (non-GUI) conversation table functionality from gtk/Qt to epan. Also refactor "common GUI" conversation table functionality.
The idea is to not have to modify the GUI when a dissector adds a new "conversation type"
Change-Id: I11f08d0d7edd631218663ba4b902c4a4c849acda
Reviewed-on: https://code.wireshark.org/review/3113
Reviewed-by: Gerald Combs <gerald@wireshark.org>
Diffstat (limited to 'epan')
-rw-r--r-- | epan/CMakeLists.txt | 1 | ||||
-rw-r--r-- | epan/Makefile.common | 2 | ||||
-rw-r--r-- | epan/conversation_table.c | 581 | ||||
-rw-r--r-- | epan/conversation_table.h | 272 | ||||
-rw-r--r-- | epan/dissectors/packet-eth.c | 31 | ||||
-rw-r--r-- | epan/dissectors/packet-fc.c | 29 | ||||
-rw-r--r-- | epan/dissectors/packet-fddi.c | 28 | ||||
-rw-r--r-- | epan/dissectors/packet-ieee80211.c | 29 | ||||
-rw-r--r-- | epan/dissectors/packet-ip.c | 28 | ||||
-rw-r--r-- | epan/dissectors/packet-ipv6.c | 38 | ||||
-rw-r--r-- | epan/dissectors/packet-ipx.c | 30 | ||||
-rw-r--r-- | epan/dissectors/packet-jxta.c | 31 | ||||
-rw-r--r-- | epan/dissectors/packet-ncp.c | 30 | ||||
-rw-r--r-- | epan/dissectors/packet-rsvp.c | 23 | ||||
-rw-r--r-- | epan/dissectors/packet-sctp.c | 31 | ||||
-rw-r--r-- | epan/dissectors/packet-tcp.c | 31 | ||||
-rw-r--r-- | epan/dissectors/packet-tr.c | 30 | ||||
-rw-r--r-- | epan/dissectors/packet-udp.c | 29 | ||||
-rw-r--r-- | epan/dissectors/packet-usb.c | 37 | ||||
-rw-r--r-- | epan/proto.c | 22 | ||||
-rw-r--r-- | epan/proto.h | 5 | ||||
-rw-r--r-- | epan/stat_cmd_args.h | 7 |
22 files changed, 1336 insertions, 9 deletions
diff --git a/epan/CMakeLists.txt b/epan/CMakeLists.txt index 3998a7a497..3ecaf480da 100644 --- a/epan/CMakeLists.txt +++ b/epan/CMakeLists.txt @@ -1527,6 +1527,7 @@ set(LIBWIRESHARK_FILES column.c column-utils.c conversation.c + conversation_table.c crc16-tvb.c crc32-tvb.c crc8-tvb.c diff --git a/epan/Makefile.common b/epan/Makefile.common index 1707635e29..675d740428 100644 --- a/epan/Makefile.common +++ b/epan/Makefile.common @@ -35,6 +35,7 @@ LIBWIRESHARK_SRC = \ column.c \ column-utils.c \ conversation.c \ + conversation_table.c \ crc16-tvb.c \ crc32-tvb.c \ crc8-tvb.c \ @@ -163,6 +164,7 @@ LIBWIRESHARK_INCLUDES = \ column-utils.h \ conversation.h \ conversation_debug.h \ + conversation_table.h \ conv_id.h \ crc16-tvb.h \ crc32-tvb.h \ diff --git a/epan/conversation_table.c b/epan/conversation_table.c new file mode 100644 index 0000000000..50f1954ea9 --- /dev/null +++ b/epan/conversation_table.c @@ -0,0 +1,581 @@ +/* conversations_table.c + * conversations_table 2003 Ronnie Sahlberg + * Helper routines common to all endpoint conversations tap. + * + * Wireshark - Network traffic analyzer + * By Gerald Combs <gerald@wireshark.org> + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "config.h" + +#include <string.h> + +#include "packet_info.h" +#include "proto.h" +#include "conversation_table.h" +#include "addr_resolv.h" +#include "emem.h" + +#include "stat_cmd_args.h" + +GList *cmd_string_list_ = NULL; + +struct register_ct { + gboolean hide_ports; /* hide TCP / UDP port columns */ + int proto_id; /* protocol id (0-indexed) */ + tap_packet_cb packet_func; /* function to be called for new incoming packets */ + conv_gui_init_cb gui_init_cb; /* GUI specific function to initialize conversation */ +}; + +gboolean get_conversation_hide_ports(register_ct_t* ct) +{ + return ct->hide_ports; +} + +int get_conversation_proto_id(register_ct_t* ct) +{ + if (!ct) { + return -1; + } + return ct->proto_id; +} + +tap_packet_cb get_conversation_packet_func(register_ct_t* ct) +{ + return ct->packet_func; +} + +static GSList *registered_ct_tables = NULL; + +void +dissector_conversation_init(const char *opt_arg, void* userdata) +{ + register_ct_t *table = (register_ct_t*)userdata; + GString *cmd_str = g_string_new("conv,"); + const char *filter=NULL; + + g_string_append(cmd_str, proto_get_protocol_filter_name(table->proto_id)); + if(!strncmp(opt_arg, cmd_str->str, cmd_str->len)){ + filter = opt_arg + cmd_str->len; + } else { + filter = NULL; + } + g_string_free(cmd_str, TRUE); + + if (table->gui_init_cb) + table->gui_init_cb(table, filter); +} + +/** get conversation from protocol ID + * + * @param proto_id protocol ID + * @return tap function handler of conversation + */ +register_ct_t* get_conversation_by_proto_id(int proto_id) +{ + GSList *ct; + register_ct_t *table; + + for(ct = registered_ct_tables; ct != NULL; ct = g_slist_next(ct)){ + table = (register_ct_t*)ct->data; + if ((table) && (table->proto_id == proto_id)) + return table; + } + + return NULL; +} + +static gint +insert_sorted_by_table_name(gconstpointer aparam, gconstpointer bparam) +{ + const register_ct_t *a = (register_ct_t *)aparam; + const register_ct_t *b = (register_ct_t *)bparam; + + return g_ascii_strcasecmp(proto_get_protocol_short_name(find_protocol_by_id(a->proto_id)), proto_get_protocol_short_name(find_protocol_by_id(b->proto_id))); +} + +void +register_conversation_table(const int proto_id, gboolean hide_ports, tap_packet_cb packet_func) +{ + register_ct_t *table; + GString *cmd_str = g_string_new("conv,"); + + table = g_new(register_ct_t,1); + + table->hide_ports = hide_ports; + table->proto_id = proto_id; + table->packet_func = packet_func; + table->gui_init_cb = NULL; + + registered_ct_tables = g_slist_insert_sorted(registered_ct_tables, table, insert_sorted_by_table_name); + + g_string_append(cmd_str, proto_get_protocol_filter_name(table->proto_id)); + cmd_string_list_ = g_list_append(cmd_string_list_, cmd_str->str); + register_stat_cmd_arg(cmd_str->str, dissector_conversation_init, table); + g_string_free(cmd_str, FALSE); +} + +/* Set GUI fields for register_ct list */ +static void +set_gui_data(gpointer data, gpointer user_data) +{ + register_ct_t *table = (register_ct_t*)data; + table->gui_init_cb = (conv_gui_init_cb)user_data; +} + +void conversation_table_set_gui_info(conv_gui_init_cb init_cb) +{ + g_slist_foreach(registered_ct_tables, set_gui_data, init_cb); +} + +void conversation_table_iterate_tables(GFunc func, gpointer user_data) +{ + g_slist_foreach(registered_ct_tables, func, user_data); +} + +guint conversation_table_get_num(void) +{ + return g_slist_length(registered_ct_tables); +} + + +register_ct_t *get_conversation_table_by_num(guint table_num) +{ + return (register_ct_t *) g_slist_nth_data(registered_ct_tables, table_num); +} + +/** Compute the hash value for two given address/port pairs. + * (Parameter type is gconstpointer for GHashTable compatibility.) + * + * @param key Conversation. MUST point to a conv_key_t struct. + * @return Computed key hash. + */ +static guint +conversation_hash(gconstpointer v) +{ + const conv_key_t *key = (const conv_key_t *)v; + guint hash_val; + + hash_val = 0; + ADD_ADDRESS_TO_HASH(hash_val, &key->addr1); + hash_val += key->port1; + ADD_ADDRESS_TO_HASH(hash_val, &key->addr2); + hash_val += key->port2; + hash_val ^= key->conv_id; + + return hash_val; +} + +/** Compare two conversation keys for an exact match. + * (Parameter types are gconstpointer for GHashTable compatibility.) + * + * @param key1 First conversation. MUST point to a conv_key_t struct. + * @param key2 Second conversation. MUST point to a conv_key_t struct. + * @return TRUE if conversations are equal, FALSE otherwise. + */ +static gboolean +conversation_equal(gconstpointer key1, gconstpointer key2) +{ + const conv_key_t *ck1 = (const conv_key_t *)key1; + const conv_key_t *ck2 = (const conv_key_t *)key2; + + if (ck1->conv_id == ck2->conv_id) + { + if (ck1->port1 == ck2->port1 && + ck1->port2 == ck2->port2 && + ADDRESSES_EQUAL(&ck1->addr1, &ck2->addr1) && + ADDRESSES_EQUAL(&ck1->addr2, &ck2->addr2)) { + return TRUE; + } + + if (ck1->port2 == ck2->port1 && + ck1->port1 == ck2->port2 && + ADDRESSES_EQUAL(&ck1->addr2, &ck2->addr1) && + ADDRESSES_EQUAL(&ck1->addr1, &ck2->addr2)) { + return TRUE; + } + } + + /* + * The addresses, ports, or conversation IDs don't match. + */ + return FALSE; +} + +void +reset_conversation_table_data(conv_hash_t *ch) +{ + if (!ch) { + return; + } + + if (ch->conv_array != NULL) { + guint i; + for(i = 0; i < ch->conv_array->len; i++){ + conv_item_t *conv = &g_array_index(ch->conv_array, conv_item_t, i); + g_free((gpointer)conv->src_address.data); + g_free((gpointer)conv->dst_address.data); + } + + g_array_free(ch->conv_array, TRUE); + } + + if (ch->hashtable != NULL) { + g_hash_table_destroy(ch->hashtable); + } + + ch->conv_array=NULL; + ch->hashtable=NULL; +} + +const char *get_conversation_address(address *addr, gboolean resolve_names) +{ + if (resolve_names) { + return ep_address_to_display(addr); + } else { + return ep_address_to_str(addr); + } +} + +const char *get_conversation_port(guint32 port, port_type ptype, gboolean resolve_names) +{ + + if(!resolve_names) ptype = PT_NONE; + + switch(ptype) { + case(PT_TCP): + return ep_tcp_port_to_display(port); + case(PT_UDP): + return ep_udp_port_to_display(port); + case(PT_SCTP): + return ep_sctp_port_to_display(port); + default: + return ep_strdup_printf("%d", port); + } +} + +/* given an address (to distinguish between ipv4 and ipv6 for tcp/udp), + a port_type and a name_type (FN_...) + return a string for the filter name. + + Some addresses, like AT_ETHER may actually be any of multiple types + of protocols, either ethernet, tokenring, fddi, wlan etc so we must be + more specific there; that's why we need specific_addr_type. +*/ +static const char * +conversation_get_filter_name(conv_item_t *conv_item, conv_filter_type_e filter_type) +{ + + if ((conv_item == NULL) || (conv_item->dissector_info == NULL) || (conv_item->dissector_info->get_filter_type == NULL)) { + return CONV_FILTER_INVALID; + } + + return conv_item->dissector_info->get_filter_type(conv_item, filter_type); +} + +/* Convert a port number into a string or NULL */ +static char * +ct_port_to_str(port_type ptype, guint32 port) +{ + switch(ptype){ + case PT_TCP: + case PT_UDP: + case PT_SCTP: + case PT_NCP: + return g_strdup_printf("%d", port); + default: + break; + } + return NULL; +} + +const char *get_conversation_filter(conv_item_t *conv_item, conv_direction_e direction) +{ + char *sport, *dport; + const char *str = "INVALID"; + + sport = ct_port_to_str(conv_item->ptype, conv_item->src_port); + dport = ct_port_to_str(conv_item->ptype, conv_item->dst_port); + + switch(direction){ + case CONV_DIR_A_TO_FROM_B: + /* A <-> B */ + str = ep_strdup_printf("%s==%s%s%s%s%s && %s==%s%s%s%s%s", + conversation_get_filter_name(conv_item, CONV_FT_ANY_ADDRESS), + ep_address_to_str(&conv_item->src_address), + sport?" && ":"", + sport?conversation_get_filter_name(conv_item, CONV_FT_ANY_PORT):"", + sport?"==":"", + sport?sport:"", + conversation_get_filter_name(conv_item, CONV_FT_ANY_ADDRESS), + ep_address_to_str(&conv_item->dst_address), + dport?" && ":"", + dport?conversation_get_filter_name(conv_item, CONV_FT_ANY_PORT):"", + dport?"==":"", + dport?dport:"" + ); + break; + case CONV_DIR_A_TO_B: + /* A --> B */ + str = ep_strdup_printf("%s==%s%s%s%s%s && %s==%s%s%s%s%s", + conversation_get_filter_name(conv_item, CONV_FT_SRC_ADDRESS), + ep_address_to_str(&conv_item->src_address), + sport?" && ":"", + sport?conversation_get_filter_name(conv_item, CONV_FT_SRC_PORT):"", + sport?"==":"", + sport?sport:"", + conversation_get_filter_name(conv_item, CONV_FT_DST_ADDRESS), + ep_address_to_str(&conv_item->dst_address), + dport?" && ":"", + dport?conversation_get_filter_name(conv_item, CONV_FT_DST_PORT):"", + dport?"==":"", + dport?dport:"" + ); + break; + case CONV_DIR_A_FROM_B: + /* A <-- B */ + str = ep_strdup_printf("%s==%s%s%s%s%s && %s==%s%s%s%s%s", + conversation_get_filter_name(conv_item, CONV_FT_DST_ADDRESS), + ep_address_to_str(&conv_item->src_address), + sport?" && ":"", + sport?conversation_get_filter_name(conv_item, CONV_FT_DST_PORT):"", + sport?"==":"", + sport?sport:"", + conversation_get_filter_name(conv_item, CONV_FT_SRC_ADDRESS), + ep_address_to_str(&conv_item->dst_address), + dport?" && ":"", + dport?conversation_get_filter_name(conv_item, CONV_FT_SRC_PORT):"", + dport?"==":"", + dport?dport:"" + ); + break; + case CONV_DIR_A_TO_FROM_ANY: + /* A <-> ANY */ + str = ep_strdup_printf("%s==%s%s%s%s%s", + conversation_get_filter_name(conv_item, CONV_FT_ANY_ADDRESS), + ep_address_to_str(&conv_item->src_address), + sport?" && ":"", + sport?conversation_get_filter_name(conv_item, CONV_FT_ANY_PORT):"", + sport?"==":"", + sport?sport:"" + ); + break; + case CONV_DIR_A_TO_ANY: + /* A --> ANY */ + str = ep_strdup_printf("%s==%s%s%s%s%s", + conversation_get_filter_name(conv_item, CONV_FT_SRC_ADDRESS), + ep_address_to_str(&conv_item->src_address), + sport?" && ":"", + sport?conversation_get_filter_name(conv_item, CONV_FT_SRC_PORT):"", + sport?"==":"", + sport?sport:"" + ); + break; + case CONV_DIR_A_FROM_ANY: + /* A <-- ANY */ + str = ep_strdup_printf("%s==%s%s%s%s%s", + conversation_get_filter_name(conv_item, CONV_FT_DST_ADDRESS), + ep_address_to_str(&conv_item->src_address), + sport?" && ":"", + sport?conversation_get_filter_name(conv_item, CONV_FT_DST_PORT):"", + sport?"==":"", + sport?sport:"" + ); + break; + case CONV_DIR_ANY_TO_FROM_B: + /* ANY <-> B */ + str = ep_strdup_printf("%s==%s%s%s%s%s", + conversation_get_filter_name(conv_item, CONV_FT_ANY_ADDRESS), + ep_address_to_str(&conv_item->dst_address), + dport?" && ":"", + dport?conversation_get_filter_name(conv_item, CONV_FT_ANY_PORT):"", + dport?"==":"", + dport?dport:"" + ); + break; + case CONV_DIR_ANY_FROM_B: + /* ANY <-- B */ + str = ep_strdup_printf("%s==%s%s%s%s%s", + conversation_get_filter_name(conv_item, CONV_FT_SRC_ADDRESS), + ep_address_to_str(&conv_item->dst_address), + dport?" && ":"", + dport?conversation_get_filter_name(conv_item, CONV_FT_SRC_PORT):"", + dport?"==":"", + dport?dport:"" + ); + break; + case CONV_DIR_ANY_TO_B: + /* ANY --> B */ + str = ep_strdup_printf("%s==%s%s%s%s%s", + conversation_get_filter_name(conv_item, CONV_FT_DST_ADDRESS), + ep_address_to_str(&conv_item->dst_address), + dport?" && ":"", + dport?conversation_get_filter_name(conv_item, CONV_FT_DST_PORT):"", + dport?"==":"", + dport?dport:"" + ); + break; + default: + break; + } + g_free(sport); + g_free(dport); + return str; +} + +void +add_conversation_table_data(conv_hash_t *ch, const address *src, const address *dst, guint32 src_port, guint32 dst_port, int num_frames, int num_bytes, nstime_t *ts, ct_dissector_info_t *ct_info, port_type ptype) +{ + add_conversation_table_data_with_conv_id(ch, src, dst, src_port, dst_port, CONV_ID_UNSET, num_frames, num_bytes, ts, ct_info, ptype); +} + +void +add_conversation_table_data_with_conv_id( + conv_hash_t *ch, + const address *src, + const address *dst, + guint32 src_port, + guint32 dst_port, + conv_id_t conv_id, + int num_frames, + int num_bytes, + nstime_t *ts, + ct_dissector_info_t *ct_info, + port_type ptype) +{ + const address *addr1, *addr2; + guint32 port1, port2; + conv_item_t *conv_item = NULL; + unsigned int conversation_idx = 0; + + if (src_port > dst_port) { + addr1 = src; + addr2 = dst; + port1 = src_port; + port2 = dst_port; + } else if (src_port < dst_port) { + addr2 = src; + addr1 = dst; + port2 = src_port; + port1 = dst_port; + } else if (CMP_ADDRESS(src, dst) < 0) { + addr1 = src; + addr2 = dst; + port1 = src_port; + port2 = dst_port; + } else { + addr2 = src; + addr1 = dst; + port2 = src_port; + port1 = dst_port; + } + + /* if we dont have any entries at all yet */ + if (ch->conv_array == NULL) { + ch->conv_array = g_array_sized_new(FALSE, FALSE, sizeof(conv_item_t), 10000); + + ch->hashtable = g_hash_table_new_full(conversation_hash, + conversation_equal, /* key_equal_func */ + g_free, /* key_destroy_func */ + NULL); /* value_destroy_func */ + + } else { + /* try to find it among the existing known conversations */ + conv_key_t existing_key; + + existing_key.addr1 = *addr1; + existing_key.addr2 = *addr2; + existing_key.port1 = port1; + existing_key.port2 = port2; + existing_key.conv_id = conv_id; + if (g_hash_table_lookup_extended(ch->hashtable, &existing_key, NULL, (gpointer *) &conversation_idx)) { + conv_item = &g_array_index(ch->conv_array, conv_item_t, conversation_idx); + } + } + + /* if we still dont know what conversation this is it has to be a new one + and we have to allocate it and append it to the end of the list */ + if (conv_item == NULL) { + conv_key_t *new_key; + conv_item_t new_conv_item; + + COPY_ADDRESS(&new_conv_item.src_address, addr1); + COPY_ADDRESS(&new_conv_item.dst_address, addr2); + new_conv_item.dissector_info = ct_info; + new_conv_item.ptype = ptype; + new_conv_item.src_port = port1; + new_conv_item.dst_port = port2; + new_conv_item.conv_id = conv_id; + new_conv_item.rx_frames = 0; + new_conv_item.tx_frames = 0; + new_conv_item.rx_bytes = 0; + new_conv_item.tx_bytes = 0; + new_conv_item.modified = TRUE; + + if (ts) { + memcpy(&new_conv_item.start_time, ts, sizeof(new_conv_item.start_time)); + memcpy(&new_conv_item.stop_time, ts, sizeof(new_conv_item.stop_time)); + } else { + nstime_set_unset(&new_conv_item.start_time); + nstime_set_unset(&new_conv_item.stop_time); + } + g_array_append_val(ch->conv_array, new_conv_item); + conversation_idx = ch->conv_array->len - 1; + conv_item = &g_array_index(ch->conv_array, conv_item_t, conversation_idx); + + /* ct->conversations address is not a constant but src/dst_address.data are */ + new_key = g_new(conv_key_t, 1); + SET_ADDRESS(&new_key->addr1, conv_item->src_address.type, conv_item->src_address.len, conv_item->src_address.data); + SET_ADDRESS(&new_key->addr2, conv_item->dst_address.type, conv_item->dst_address.len, conv_item->dst_address.data); + new_key->port1 = port1; + new_key->port2 = port2; + new_key->conv_id = conv_id; + g_hash_table_insert(ch->hashtable, new_key, GUINT_TO_POINTER(conversation_idx)); + } + + /* update the conversation struct */ + conv_item->modified = TRUE; + if ( (!CMP_ADDRESS(src, addr1)) && (!CMP_ADDRESS(dst, addr2)) && (src_port==port1) && (dst_port==port2) ) { + conv_item->tx_frames += num_frames; + conv_item->tx_bytes += num_bytes; + } else { + conv_item->rx_frames += num_frames; + conv_item->rx_bytes += num_bytes; + } + + if (ts) { + if (nstime_cmp(ts, &conv_item->stop_time) > 0) { + memcpy(&conv_item->stop_time, ts, sizeof(conv_item->stop_time)); + } else if (nstime_cmp(ts, &conv_item->start_time) < 0) { + memcpy(&conv_item->start_time, ts, sizeof(conv_item->start_time)); + } + } +} + +/* + * Editor modelines + * + * Local Variables: + * c-basic-offset: 4 + * tab-width: 8 + * indent-tabs-mode: nil + * End: + * + * ex: set shiftwidth=4 tabstop=8 expandtab: + * :indentSize=4:tabSize=8:noTabs=true: + */ diff --git a/epan/conversation_table.h b/epan/conversation_table.h new file mode 100644 index 0000000000..d9e6f2bd01 --- /dev/null +++ b/epan/conversation_table.h @@ -0,0 +1,272 @@ +/* conversation_table.h + * GUI independent helper routines common to all conversations taps. + * Refactored original conversations_table by Ronnie Sahlberg + * + * Wireshark - Network traffic analyzer + * By Gerald Combs <gerald@wireshark.org> + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef __CONVERSATION_TABLE_H__ +#define __CONVERSATION_TABLE_H__ + +#include "conv_id.h" +#include "tap.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** @file + * Conversation definitions. + */ + +typedef enum { + CONV_FT_SRC_ADDRESS, + CONV_FT_DST_ADDRESS, + CONV_FT_ANY_ADDRESS, + CONV_FT_SRC_PORT, + CONV_FT_DST_PORT, + CONV_FT_ANY_PORT +} conv_filter_type_e; + +/* Filter direction */ +typedef enum { + CONV_DIR_A_TO_FROM_B, + CONV_DIR_A_TO_B, + CONV_DIR_A_FROM_B, + CONV_DIR_A_TO_FROM_ANY, + CONV_DIR_A_TO_ANY, + CONV_DIR_A_FROM_ANY, + CONV_DIR_ANY_TO_FROM_B, + CONV_DIR_ANY_TO_B, + CONV_DIR_ANY_FROM_B +} conv_direction_e; + +/** Conversation hash + value storage + * Hash table keys are conv_key_t. Hash table values are indexes into conv_array. + */ +typedef struct _conversation_hash_t { + GHashTable *hashtable; /**< conversations hash table */ + GArray *conv_array; /**< array of conversation values */ + void *user_data; /**< "GUI" specifics (if necessary) */ +} conv_hash_t; + +/** Key for hash lookups */ +typedef struct _conversation_key_t { + address addr1; + address addr2; + guint32 port1; + guint32 port2; + conv_id_t conv_id; +} conv_key_t; + +struct _conversation_item_t; +typedef const char* (*conv_get_filter_type)(struct _conversation_item_t* item, conv_filter_type_e filter); +typedef const char* (*conv_get_conversation_filter_type)(struct _conversation_item_t* item, conv_direction_e direction); + + + +typedef struct _ct_dissector_info { + conv_get_filter_type get_filter_type; +} ct_dissector_info_t; + +#define CONV_FILTER_INVALID "INVALID" + + +struct register_ct; +typedef void (*conv_gui_init_cb)(struct register_ct* ct, const char *filter); + +/** Structure for information about a registered conversation */ +typedef struct register_ct register_ct_t; + +/** Conversation information */ +typedef struct _conversation_item_t { + ct_dissector_info_t *dissector_info; /**< conversation information provided by dissector */ + address src_address; /**< source address */ + address dst_address; /**< destination address */ + port_type ptype; /**< port_type (e.g. PT_TCP) */ + guint32 src_port; /**< source port */ + guint32 dst_port; /**< destination port */ + conv_id_t conv_id; /**< conversation id */ + + guint64 rx_frames; /**< number of received packets */ + guint64 tx_frames; /**< number of transmitted packets */ + guint64 rx_bytes; /**< number of received bytes */ + guint64 tx_bytes; /**< number of transmitted bytes */ + + nstime_t start_time; /**< start time for the conversation */ + nstime_t stop_time; /**< stop time for the conversation */ + + gboolean modified; /**< new to redraw the row (only used in GTK+) */ +} conv_item_t; + +/** Register the conversation table for the multiple conversation window. + * + * @param hide_ports hide the port columns + * @param table_name the table name to be displayed + * @param tap_name the registered tap name + * @param packet_func the function to be called for each incoming packet + */ +extern void register_conversation_table(const int proto_id, gboolean hide_ports, tap_packet_cb packet_func); + +/** Should port columns be hidden? + * + * @param ct Registered conversation + * @return TRUE if port columns should be hidden for this conversation type. + */ +WS_DLL_PUBLIC gboolean get_conversation_hide_ports(register_ct_t* ct); + +/** Get protocol ID from conversation + * + * @param ct Registered conversation + * @return protocol id of conversation + */ +WS_DLL_PUBLIC int get_conversation_proto_id(register_ct_t* ct); + +/** Get tap function handler from conversation + * + * @param ct Registered conversation + * @return tap function handler of conversation + */ +WS_DLL_PUBLIC tap_packet_cb get_conversation_packet_func(register_ct_t* ct); + +/** get conversation from protocol ID + * + * @param proto_id protocol ID + * @return tap function handler of conversation + */ +WS_DLL_PUBLIC register_ct_t* get_conversation_by_proto_id(int proto_id); + +/** Register "initialization function" used by the GUI to create conversation + * table display in GUI + * + * @param init_cb callback function that will be called when converation table "display + * is instantiated in GUI + */ +WS_DLL_PUBLIC void conversation_table_set_gui_info(conv_gui_init_cb init_cb); + +/** Interator to walk converation tables and execute func + * a GUI menu (only used in GTK) + * + * @param func action to be performed on all converation tables + * @param user_data any data needed to help perform function + */ +WS_DLL_PUBLIC void conversation_table_iterate_tables(GFunc func, gpointer user_data); + +/** Total number of converation tables + */ +WS_DLL_PUBLIC guint conversation_table_get_num(void); + +/** Get conversation table by its number + * Tables are ordered alphabetically by title. + * + * @param table_num Item to fetch. + * @return table pointer or NULL. + */ +WS_DLL_PUBLIC register_ct_t* get_conversation_table_by_num(guint table_num); + +/** Remove all entries from the conversation table. + * + * @param ch the table to reset + */ +WS_DLL_PUBLIC void reset_conversation_table_data(conv_hash_t *ch); + +/** Initialize dissector converation for stats and (possibly) GUI. + * + * @param opt_arg filter string to compare with dissector + * @param userdata register_ct_t* for dissector conversation + */ +WS_DLL_PUBLIC void dissector_conversation_init(const char *opt_arg, void* userdata); + +/** Get the string representation of an address. + * + * @param addr The address. + * @param resolve_names Enable name resolution. + * @return An ep_allocated string representing the address. + */ +WS_DLL_PUBLIC const char *get_conversation_address(address *addr, gboolean resolve_names); + +/** Get the string representation of a port. + * + * @param port The port number. + * @param ptype The port type. + * @param resolve_names Enable name resolution. + * @return An ep_allocated string representing the port. + */ +WS_DLL_PUBLIC const char *get_conversation_port(guint32 port, port_type ptype, gboolean resolve_names); + +/** Get a display filter for the given conversation and direction. + * + * @param conv_item The conversation. + * @param direction The desired direction. + * @return An ep_allocated string representing the conversation. + */ +WS_DLL_PUBLIC const char *get_conversation_filter(conv_item_t *conv_item, conv_direction_e direction); + +/** Add some data to the conversation table. + * + * @param ch the table to add the data to + * @param src source address + * @param dst destination address + * @param src_port source port + * @param dst_port destination port + * @param num_frames number of packets + * @param num_bytes number of bytes + * @param ts timestamp + * @param ct_info callback handlers from the dissector + * @param ptype the port type (e.g. PT_TCP) + */ +extern void add_conversation_table_data(conv_hash_t *ch, const address *src, const address *dst, + guint32 src_port, guint32 dst_port, int num_frames, int num_bytes, nstime_t *ts, + ct_dissector_info_t *ct_info, port_type ptype); + +/** Add some data to the conversation table, passing a value to be used in + * addition to the address and port quadruple to uniquely identify the + * conversation. + * + * @param ch the table to add the data to + * @param src source address + * @param dst destination address + * @param src_port source port + * @param dst_port destination port + * @param num_frames number of packets + * @param num_bytes number of bytes + * @param ts timestamp + * @param ct_info callback handlers from the dissector + * @param ptype the port type (e.g. PT_TCP) + * @param conv_id a value to help differentiate the conversation in case the address and port quadruple is not sufficiently unique + */ +extern void +add_conversation_table_data_with_conv_id( + conv_hash_t *ch, + const address *src, + const address *dst, + guint32 src_port, + guint32 dst_port, + conv_id_t conv_id, + int num_frames, + int num_bytes, + nstime_t *ts, + ct_dissector_info_t *ct_info, + port_type ptype); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __CONVERSATION_TABLE_H__ */ diff --git a/epan/dissectors/packet-eth.c b/epan/dissectors/packet-eth.c index 21e7e1195e..f1974631c9 100644 --- a/epan/dissectors/packet-eth.c +++ b/epan/dissectors/packet-eth.c @@ -30,6 +30,7 @@ #include <epan/etypes.h> #include <epan/addr_resolv.h> #include <epan/expert.h> +#include <epan/conversation_table.h> #include <wsutil/pint.h> #include "packet-eth.h" #include "packet-ieee8023.h" @@ -106,6 +107,34 @@ static const true_false_string lg_tfs = { "Globally unique address (factory default)" }; + +static const char* eth_conv_get_filter_type(conv_item_t* conv, conv_filter_type_e filter) +{ + if ((filter == CONV_FT_SRC_ADDRESS) && (conv->src_address.type == AT_ETHER)) + return "eth.src"; + + if ((filter == CONV_FT_DST_ADDRESS) && (conv->dst_address.type == AT_ETHER)) + return "eth.dst"; + + if ((filter == CONV_FT_ANY_ADDRESS) && (conv->src_address.type == AT_ETHER)) + return "eth.addr"; + + return CONV_FILTER_INVALID; +} + +static ct_dissector_info_t eth_ct_dissector_info = {ð_conv_get_filter_type}; + +static int +eth_conversation_packet(void *pct, packet_info *pinfo, epan_dissect_t *edt _U_, const void *vip) +{ + conv_hash_t *hash = (conv_hash_t*) pct; + const eth_hdr *ehdr=(const eth_hdr *)vip; + + add_conversation_table_data(hash, &ehdr->src, &ehdr->dst, 0, 0, 1, pinfo->fd->pkt_len, &pinfo->rel_ts, ð_ct_dissector_info, PT_NONE); + + return 1; +} + /* These are the Netware-ish names for the different Ethernet frame types. EthernetII: The ethernet with a Type field instead of a length field Ethernet802.2: An 802.3 header followed by an 802.2 header @@ -941,6 +970,8 @@ proto_register_eth(void) register_dissector("eth_withfcs", dissect_eth_withfcs, proto_eth); register_dissector("eth", dissect_eth_maybefcs, proto_eth); eth_tap = register_tap("eth"); + + register_conversation_table(proto_eth, TRUE, eth_conversation_packet); } void diff --git a/epan/dissectors/packet-fc.c b/epan/dissectors/packet-fc.c index 737c7d1162..2ca116f2b5 100644 --- a/epan/dissectors/packet-fc.c +++ b/epan/dissectors/packet-fc.c @@ -34,6 +34,7 @@ #include <wiretap/wtap.h> #include <epan/reassemble.h> #include <epan/conversation.h> +#include <epan/conversation_table.h> #include <epan/etypes.h> #include "packet-fc.h" #include "packet-fclctl.h" @@ -205,6 +206,32 @@ fc_exchange_init_protocol(void) fcseq_req_hash = g_hash_table_new(fcseq_hash, fcseq_equal); } +static const char* fc_conv_get_filter_type(conv_item_t* conv, conv_filter_type_e filter) +{ + if ((filter == CONV_FT_SRC_ADDRESS) && (conv->src_address.type == AT_FC)) + return "fc.s_id"; + + if ((filter == CONV_FT_DST_ADDRESS) && (conv->dst_address.type == AT_FC)) + return "fc.d_id"; + + if ((filter == CONV_FT_ANY_ADDRESS) && (conv->src_address.type == AT_FC)) + return "fc.id"; + + return CONV_FILTER_INVALID; +} + +static ct_dissector_info_t fc_ct_dissector_info = {&fc_conv_get_filter_type}; + +static int +fc_conversation_packet(void *pct, packet_info *pinfo, epan_dissect_t *edt _U_, const void *vip) +{ + conv_hash_t *hash = (conv_hash_t*) pct; + const fc_hdr *fchdr=(const fc_hdr *)vip; + + add_conversation_table_data(hash, &fchdr->s_id, &fchdr->d_id, 0, 0, 1, pinfo->fd->pkt_len, &pinfo->rel_ts, &fc_ct_dissector_info, PT_NONE); + + return 1; +} const value_string fc_fc4_val[] = { {FC_TYPE_BLS, "Basic Link Svc"}, @@ -1579,6 +1606,8 @@ proto_register_fc(void) proto_register_subtree_array(sof_ett, array_length(sof_ett)); fcsof_handle = register_dissector("fcsof", dissect_fcsof, proto_fcsof); + + register_conversation_table(proto_fc, TRUE, fc_conversation_packet); } diff --git a/epan/dissectors/packet-fddi.c b/epan/dissectors/packet-fddi.c index 50856084da..76a2fda692 100644 --- a/epan/dissectors/packet-fddi.c +++ b/epan/dissectors/packet-fddi.c @@ -33,6 +33,7 @@ #include <epan/packet.h> #include <wsutil/bitswap.h> #include <epan/prefs.h> +#include <epan/conversation_table.h> #include "packet-fddi.h" #include "packet-llc.h" #include <epan/tap.h> @@ -142,6 +143,32 @@ swap_mac_addr(guint8 *swapped_addr, tvbuff_t *tvb, gint offset) bitswap_buf_inplace(swapped_addr, 6); } +static const char* fddi_conv_get_filter_type(conv_item_t* conv, conv_filter_type_e filter) +{ + if ((filter == CONV_FT_SRC_ADDRESS) && (conv->src_address.type == AT_ETHER)) + return "fddi.src"; + + if ((filter == CONV_FT_DST_ADDRESS) && (conv->dst_address.type == AT_ETHER)) + return "fddi.dst"; + + if ((filter == CONV_FT_ANY_ADDRESS) && (conv->src_address.type == AT_ETHER)) + return "fddi.addr"; + + return CONV_FILTER_INVALID; +} + +static ct_dissector_info_t fddi_ct_dissector_info = {&fddi_conv_get_filter_type}; + +static int +fddi_conversation_packet(void *pct, packet_info *pinfo, epan_dissect_t *edt _U_, const void *vip) +{ + conv_hash_t *hash = (conv_hash_t*) pct; + const fddi_hdr *ehdr=(const fddi_hdr *)vip; + + add_conversation_table_data(hash, &ehdr->src, &ehdr->dst, 0, 0, 1, pinfo->fd->pkt_len, &pinfo->rel_ts, &fddi_ct_dissector_info, PT_NONE); + + return 1; +} void capture_fddi(const guchar *pd, int len, packet_counts *ld) @@ -478,6 +505,7 @@ proto_register_fddi(void) &fddi_padding); fddi_tap = register_tap("fddi"); + register_conversation_table(proto_fddi, TRUE, fddi_conversation_packet); } void diff --git a/epan/dissectors/packet-ieee80211.c b/epan/dissectors/packet-ieee80211.c index a24f53b591..7e7f24606d 100644 --- a/epan/dissectors/packet-ieee80211.c +++ b/epan/dissectors/packet-ieee80211.c @@ -102,6 +102,7 @@ #include <epan/wmem/wmem.h> #include <epan/crypt/wep-wpadefs.h> #include <epan/expert.h> +#include <epan/conversation_table.h> #include <epan/uat.h> #include <epan/eapol_keydes_types.h> @@ -5172,6 +5173,33 @@ static const value_string ff_psmp_sta_info_flags[] = { {0, NULL} }; +static const char* wlan_conv_get_filter_type(conv_item_t* conv, conv_filter_type_e filter) +{ + if ((filter == CONV_FT_SRC_ADDRESS) && (conv->src_address.type == AT_ETHER)) + return "wlan.sa"; + + if ((filter == CONV_FT_DST_ADDRESS) && (conv->dst_address.type == AT_ETHER)) + return "wlan.da"; + + if ((filter == CONV_FT_ANY_ADDRESS) && (conv->src_address.type == AT_ETHER)) + return "wlan.addr"; + + return CONV_FILTER_INVALID; +} + +static ct_dissector_info_t wlan_ct_dissector_info = {&wlan_conv_get_filter_type}; + +static int +wlan_conversation_packet(void *pct, packet_info *pinfo, epan_dissect_t *edt _U_, const void *vip) +{ + conv_hash_t *hash = (conv_hash_t*) pct; + const wlan_hdr *whdr=(const wlan_hdr *)vip; + + add_conversation_table_data(hash, &whdr->src, &whdr->dst, 0, 0, 1, pinfo->fd->pkt_len, &pinfo->rel_ts, &wlan_ct_dissector_info, PT_NONE); + + return 1; +} + static void beacon_interval_base_custom(gchar *result, guint32 beacon_interval) { @@ -25898,6 +25926,7 @@ proto_register_ieee80211 (void) register_init_routine(ieee80211_gas_reassembly_init); wlan_tap = register_tap("wlan"); + register_conversation_table(proto_wlan, TRUE, wlan_conversation_packet); /* Register configuration options */ wlan_module = prefs_register_protocol(proto_wlan, init_wepkeys); diff --git a/epan/dissectors/packet-ip.c b/epan/dissectors/packet-ip.c index c9e16d315a..ec61d204b8 100644 --- a/epan/dissectors/packet-ip.c +++ b/epan/dissectors/packet-ip.c @@ -36,6 +36,7 @@ #include <epan/expert.h> #include <epan/ip_opts.h> #include <epan/prefs.h> +#include <epan/conversation_table.h> #include <epan/reassemble.h> #include <epan/etypes.h> #include <epan/greproto.h> @@ -473,6 +474,32 @@ static gpointer ip_value(packet_info *pinfo) return GUINT_TO_POINTER(pinfo->ipproto); } +static const char* ip_conv_get_filter_type(conv_item_t* conv, conv_filter_type_e filter) +{ + if ((filter == CONV_FT_SRC_ADDRESS) && (conv->src_address.type == AT_IPv4)) + return "ip.src"; + + if ((filter == CONV_FT_DST_ADDRESS) && (conv->dst_address.type == AT_IPv4)) + return "ip.dst"; + + if ((filter == CONV_FT_ANY_ADDRESS) && (conv->src_address.type == AT_IPv4)) + return "ip.addr"; + + return CONV_FILTER_INVALID; +} + +static ct_dissector_info_t ip_ct_dissector_info = {&ip_conv_get_filter_type}; + +static int +ip_conversation_packet(void *pct, packet_info *pinfo, epan_dissect_t *edt _U_, const void *vip) +{ + conv_hash_t *hash = (conv_hash_t*) pct; + const ws_ip *iph=(const ws_ip *)vip; + + add_conversation_table_data(hash, &iph->ip_src, &iph->ip_dst, 0, 0, 1, pinfo->fd->pkt_len, &pinfo->rel_ts, &ip_ct_dissector_info, PT_NONE); + + return 1; +} /* * defragmentation of IPv4 @@ -3050,6 +3077,7 @@ proto_register_ip(void) ip_tap = register_tap("ip"); register_decode_as(&ip_da); + register_conversation_table(proto_ip, TRUE, ip_conversation_packet); } void diff --git a/epan/dissectors/packet-ipv6.c b/epan/dissectors/packet-ipv6.c index 22a2eeaf0c..7191c2ca3d 100644 --- a/epan/dissectors/packet-ipv6.c +++ b/epan/dissectors/packet-ipv6.c @@ -33,6 +33,7 @@ #include <epan/ip_opts.h> #include <epan/addr_resolv.h> #include <epan/prefs.h> +#include <epan/conversation_table.h> #include <epan/reassemble.h> #include <epan/ipproto.h> #include <epan/ipv6-utils.h> @@ -347,6 +348,41 @@ static gpointer ipv6_next_header_value(packet_info *pinfo) return p_get_proto_data(pinfo->pool, pinfo, proto_ipv6, IPV6_PROTO_NXT_HDR); } +static const char* ipv6_conv_get_filter_type(conv_item_t* conv, conv_filter_type_e filter) +{ + if ((filter == CONV_FT_SRC_ADDRESS) && (conv->src_address.type == AT_IPv6)) + return "ipv6.src"; + + if ((filter == CONV_FT_DST_ADDRESS) && (conv->dst_address.type == AT_IPv6)) + return "ipv6.dst"; + + if ((filter == CONV_FT_ANY_ADDRESS) && (conv->src_address.type == AT_IPv6)) + return "ipv6.addr"; + + return CONV_FILTER_INVALID; +} + +static ct_dissector_info_t ipv6_ct_dissector_info = {&ipv6_conv_get_filter_type}; + +static int +ipv6_conversation_packet(void *pct, packet_info *pinfo, epan_dissect_t *edt _U_, const void *vip) +{ + conv_hash_t *hash = (conv_hash_t*) pct; + const struct ip6_hdr *ip6h = (const struct ip6_hdr *)vip; + address src; + address dst; + + /* Addresses aren't implemented as 'address' type in struct ip6_hdr */ + src.type = dst.type = AT_IPv6; + src.len = dst.len = sizeof(struct e_in6_addr); + src.data = &ip6h->ip6_src; + dst.data = &ip6h->ip6_dst; + + add_conversation_table_data(hash, &src, &dst, 0, 0, 1, pinfo->fd->pkt_len, &pinfo->rel_ts, &ipv6_ct_dissector_info, PT_NONE); + + return 1; +} + static const fragment_items ipv6_frag_items = { &ett_ipv6_fragment, &ett_ipv6_fragments, @@ -2908,6 +2944,8 @@ proto_register_ipv6(void) register_decode_as(&ipv6_da); register_decode_as(&ipv6_next_header_da); + + register_conversation_table(proto_ipv6, TRUE, ipv6_conversation_packet); } void diff --git a/epan/dissectors/packet-ipx.c b/epan/dissectors/packet-ipx.c index b845bdf3c9..74b0e2f3cd 100644 --- a/epan/dissectors/packet-ipx.c +++ b/epan/dissectors/packet-ipx.c @@ -38,6 +38,7 @@ #include <epan/aftypes.h> #include <epan/arcnet_pids.h> #include <epan/conversation.h> +#include <epan/conversation_table.h> #include <epan/tap.h> #include <epan/wmem/wmem.h> @@ -146,6 +147,33 @@ dissect_ipxmsg(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree); #define IPX_HEADER_LEN 30 /* It's *always* 30 bytes */ +static const char* ipx_conv_get_filter_type(conv_item_t* conv, conv_filter_type_e filter) +{ + if ((filter == CONV_FT_SRC_ADDRESS) && (conv->src_address.type == AT_IPX)) + return "ipx.src"; + + if ((filter == CONV_FT_DST_ADDRESS) && (conv->dst_address.type == AT_IPX)) + return "ipx.dst"; + + if ((filter == CONV_FT_ANY_ADDRESS) && (conv->src_address.type == AT_IPX)) + return "ipx.addr"; + + return CONV_FILTER_INVALID; +} + +static ct_dissector_info_t ipx_ct_dissector_info = {&ipx_conv_get_filter_type}; + +static int +ipx_conversation_packet(void *pct, packet_info *pinfo, epan_dissect_t *edt _U_, const void *vip) +{ + conv_hash_t *hash = (conv_hash_t*) pct; + const ipxhdr_t *ipxh=(const ipxhdr_t *)vip; + + add_conversation_table_data(hash, &ipxh->ipx_src, &ipxh->ipx_dst, 0, 0, 1, pinfo->fd->pkt_len, &pinfo->rel_ts, &ipx_ct_dissector_info, PT_NONE); + + return 1; +} + /* ================================================================= */ /* IPX */ /* ================================================================= */ @@ -1539,6 +1567,8 @@ proto_register_ipx(void) register_init_routine(&spx_init_protocol); register_postseq_cleanup_routine(&spx_postseq_cleanup); ipx_tap=register_tap("ipx"); + + register_conversation_table(proto_ipx, TRUE, ipx_conversation_packet); } void diff --git a/epan/dissectors/packet-jxta.c b/epan/dissectors/packet-jxta.c index 09a2cfc23a..bc39290d59 100644 --- a/epan/dissectors/packet-jxta.c +++ b/epan/dissectors/packet-jxta.c @@ -39,6 +39,7 @@ #include <epan/packet.h> #include <epan/conversation.h> +#include <epan/conversation_table.h> #include <epan/strutil.h> #include <epan/prefs.h> #include <epan/tap.h> @@ -194,6 +195,34 @@ struct jxta_stream_conversation_data { typedef struct jxta_stream_conversation_data jxta_stream_conversation_data; +static const char* jxta_conv_get_filter_type(conv_item_t* conv, conv_filter_type_e filter) +{ + if ((filter == CONV_FT_SRC_ADDRESS) && (conv->src_address.type == AT_URI)) + return "jxta.message.src"; + + if ((filter == CONV_FT_DST_ADDRESS) && (conv->dst_address.type == AT_URI)) + return "jxta.message.dst"; + + if ((filter == CONV_FT_ANY_ADDRESS) && (conv->src_address.type == AT_URI)) + return "jxta.message.address"; + + return CONV_FILTER_INVALID; +} + +static ct_dissector_info_t jxta_ct_dissector_info = {&jxta_conv_get_filter_type}; + +static int +jxta_conversation_packet(void *pct, packet_info *pinfo _U_, epan_dissect_t *edt _U_, const void *vip) +{ + conv_hash_t *hash = (conv_hash_t*) pct; + const jxta_tap_header *jxtahdr = (const jxta_tap_header *) vip; + + add_conversation_table_data(hash, &jxtahdr->src_address, &jxtahdr->dest_address, + 0, 0, 1, jxtahdr->size, NULL, &jxta_ct_dissector_info, PT_NONE); + + return 1; +} + /** * Prototypes **/ @@ -2322,6 +2351,8 @@ void proto_register_jxta(void) prefs_register_bool_preference(jxta_module, "sctp.heuristic", "Try to discover JXTA in SCTP connections", "Enable to inspect SCTP connections for JXTA conversations.", &gSCTP_HEUR); + + register_conversation_table(proto_jxta, TRUE, jxta_conversation_packet); } diff --git a/epan/dissectors/packet-ncp.c b/epan/dissectors/packet-ncp.c index 8398dc8264..c75c2430ee 100644 --- a/epan/dissectors/packet-ncp.c +++ b/epan/dissectors/packet-ncp.c @@ -54,6 +54,7 @@ #include "packet-ncp-int.h" #include <epan/reassemble.h> #include <epan/conversation.h> +#include <epan/conversation_table.h> #include <epan/tap.h> void proto_register_ncp(void); @@ -295,6 +296,31 @@ mncp_hash_lookup(conversation_t *conversation, guint32 nwconnection, guint8 nwta return (mncp_rhash_value *)g_hash_table_lookup(mncp_rhash, &key); } +static const char* ncp_conv_get_filter_type(conv_item_t* conv _U_, conv_filter_type_e filter) +{ + if ((filter == CONV_FT_SRC_PORT) || (filter == CONV_FT_DST_PORT) || (filter == CONV_FT_ANY_PORT)) + return "ncp.connection"; + + return CONV_FILTER_INVALID; +} + +static ct_dissector_info_t ncp_ct_dissector_info = {&ncp_conv_get_filter_type}; + +static int +ncp_conversation_packet(void *pct, packet_info *pinfo, epan_dissect_t *edt _U_, const void *vip) +{ + conv_hash_t *hash = (conv_hash_t*) pct; + const struct ncp_common_header *ncph=(const struct ncp_common_header *)vip; + guint32 connection; + + connection = (ncph->conn_high * 256)+ncph->conn_low; + if (connection < 65535) { + add_conversation_table_data(hash, &pinfo->src, &pinfo->dst, connection, connection, 1, pinfo->fd->pkt_len, &pinfo->rel_ts, &ncp_ct_dissector_info, PT_NCP); + } + + return 1; +} + /* * Burst packet system flags. */ @@ -1098,8 +1124,10 @@ proto_register_ncp(void) &ncp_echo_file); register_init_routine(&mncp_init_protocol); ncp_tap.stat=register_tap("ncp_srt"); - ncp_tap.hdr=register_tap("ncp_hdr"); + ncp_tap.hdr=register_tap("ncp"); register_postseq_cleanup_routine(&mncp_postseq_cleanup); + + register_conversation_table(proto_ncp, FALSE, ncp_conversation_packet); } void diff --git a/epan/dissectors/packet-rsvp.c b/epan/dissectors/packet-rsvp.c index 1eabc28539..a4c3363aa2 100644 --- a/epan/dissectors/packet-rsvp.c +++ b/epan/dissectors/packet-rsvp.c @@ -108,6 +108,7 @@ #include <epan/etypes.h> #include <epan/ipproto.h> #include <epan/conversation.h> +#include <epan/conversation_table.h> #include <epan/tap.h> #include <epan/sminmpec.h> #include <epan/wmem/wmem.h> @@ -1871,6 +1872,26 @@ rsvp_init_protocol(void) rsvp_request_hash = g_hash_table_new(rsvp_hash, rsvp_equal); } +static const char* rsvp_conv_get_filter_type(conv_item_t* conv _U_, conv_filter_type_e filter _U_) +{ + /* XXX - Not sure about this */ + return CONV_FILTER_INVALID; +} + +static ct_dissector_info_t rsvp_ct_dissector_info = {&rsvp_conv_get_filter_type}; + +static int +rsvp_conversation_packet(void *pct, packet_info *pinfo, epan_dissect_t *edt _U_, const void *vip) +{ + conv_hash_t *hash = (conv_hash_t*) pct; + const rsvp_conversation_info *rsvph = (const rsvp_conversation_info *)vip; + + add_conversation_table_data(hash, &rsvph->source, &rsvph->destination, + 0, 0, 1, pinfo->fd->pkt_len, &pinfo->rel_ts, &rsvp_ct_dissector_info, PT_NONE); + + return 1; +} + static inline int rsvp_class_to_filter_num(int classnum) { @@ -9156,6 +9177,8 @@ proto_register_rsvp(void) /* Initialization routine for RSVP conversations */ register_init_routine(&rsvp_init_protocol); + + register_conversation_table(proto_rsvp, TRUE, rsvp_conversation_packet); } void diff --git a/epan/dissectors/packet-sctp.c b/epan/dissectors/packet-sctp.c index b88ec19b0c..28f01b8335 100644 --- a/epan/dissectors/packet-sctp.c +++ b/epan/dissectors/packet-sctp.c @@ -64,6 +64,7 @@ #include <epan/uat.h> #include <epan/wmem/wmem.h> #include <epan/expert.h> +#include <epan/conversation_table.h> #include <epan/show_exception.h> #include <epan/decode_as.h> #include <wsutil/crc32.h> @@ -774,6 +775,34 @@ sctp_ppi_value2(packet_info *pinfo) return p_get_proto_data(pinfo->pool, pinfo, proto_sctp, 1); } +static const char* sctp_conv_get_filter_type(conv_item_t* conv _U_, conv_filter_type_e filter) +{ + if (filter == CONV_FT_SRC_PORT) + return "sctp.srcport"; + + if (filter == CONV_FT_DST_PORT) + return "sctp.dstport"; + + if (filter == CONV_FT_ANY_PORT) + return "sctp.port"; + + return CONV_FILTER_INVALID; +} + +static ct_dissector_info_t sctp_ct_dissector_info = {&sctp_conv_get_filter_type}; + +static int +sctp_conversation_packet(void *pct, packet_info *pinfo, epan_dissect_t *edt _U_, const void *vip) +{ + conv_hash_t *hash = (conv_hash_t*) pct; + const struct _sctp_info *sctphdr=(const struct _sctp_info *)vip; + + add_conversation_table_data(hash, &sctphdr->ip_src, &sctphdr->ip_dst, + sctphdr->sport, sctphdr->dport, 1, pinfo->fd->pkt_len, &pinfo->rel_ts, &sctp_ct_dissector_info, PT_SCTP); + + + return 1; +} static unsigned int sctp_adler32(const unsigned char *buf, unsigned int len) @@ -4834,6 +4863,8 @@ proto_register_sctp(void) register_decode_as(&sctp_da_port); register_decode_as(&sctp_da_ppi); + + register_conversation_table(proto_sctp, FALSE, sctp_conversation_packet); } void diff --git a/epan/dissectors/packet-tcp.c b/epan/dissectors/packet-tcp.c index 2d69807b96..871825e86d 100644 --- a/epan/dissectors/packet-tcp.c +++ b/epan/dissectors/packet-tcp.c @@ -38,6 +38,7 @@ #include <epan/wmem/wmem.h> #include <epan/show_exception.h> #include <epan/conversation.h> +#include <epan/conversation_table.h> #include <epan/reassemble.h> #include <epan/tap.h> #include <epan/decode_as.h> @@ -523,6 +524,34 @@ tcp_both_prompt(packet_info *pinfo, gchar *result) g_snprintf(result, MAX_DECODE_AS_PROMPT_LEN, "both (%u%s%u)", pinfo->srcport, UTF8_LEFT_RIGHT_ARROW, pinfo->destport); } +static const char* tcp_conv_get_filter_type(conv_item_t* conv _U_, conv_filter_type_e filter) +{ + if (filter == CONV_FT_SRC_PORT) + return "tcp.srcport"; + + if (filter == CONV_FT_DST_PORT) + return "tcp.dstport"; + + if (filter == CONV_FT_ANY_PORT) + return "tcp.port"; + + return CONV_FILTER_INVALID; +} + +static ct_dissector_info_t tcp_ct_dissector_info = {&tcp_conv_get_filter_type}; + +static int +tcpip_conversation_packet(void *pct, packet_info *pinfo, epan_dissect_t *edt _U_, const void *vip) +{ + conv_hash_t *hash = (conv_hash_t*) pct; + const struct tcpheader *tcphdr=(const struct tcpheader *)vip; + + add_conversation_table_data_with_conv_id(hash, &tcphdr->ip_src, &tcphdr->ip_dst, tcphdr->th_sport, tcphdr->th_dport, (conv_id_t) tcphdr->th_stream, 1, pinfo->fd->pkt_len, + &pinfo->rel_ts, &tcp_ct_dissector_info, PT_TCP); + + return 1; +} + /* TCP structs and definitions */ /* ************************************************************************** @@ -5818,6 +5847,8 @@ proto_register_tcp(void) register_init_routine(tcp_init); register_decode_as(&tcp_da); + + register_conversation_table(proto_tcp, FALSE, tcpip_conversation_packet); } void diff --git a/epan/dissectors/packet-tr.c b/epan/dissectors/packet-tr.c index 172b30af2c..30d7698897 100644 --- a/epan/dissectors/packet-tr.c +++ b/epan/dissectors/packet-tr.c @@ -27,6 +27,7 @@ #include <glib.h> #include <epan/packet.h> #include <epan/exceptions.h> +#include <epan/conversation_table.h> #include <wsutil/pint.h> #include "packet-tr.h" #include "packet-llc.h" @@ -127,6 +128,33 @@ static dissector_handle_t trmac_handle; static dissector_handle_t llc_handle; static dissector_handle_t data_handle; +static const char* tr_conv_get_filter_type(conv_item_t* conv, conv_filter_type_e filter) +{ + if ((filter == CONV_FT_SRC_ADDRESS) && (conv->src_address.type == AT_ETHER)) + return "tr.src"; + + if ((filter == CONV_FT_DST_ADDRESS) && (conv->dst_address.type == AT_ETHER)) + return "tr.dst"; + + if ((filter == CONV_FT_ANY_ADDRESS) && (conv->src_address.type == AT_ETHER)) + return "tr.addr"; + + return CONV_FILTER_INVALID; +} + +static ct_dissector_info_t tr_ct_dissector_info = {&tr_conv_get_filter_type}; + +static int +tr_conversation_packet(void *pct, packet_info *pinfo, epan_dissect_t *edt _U_, const void *vip) +{ + conv_hash_t *hash = (conv_hash_t*) pct; + const tr_hdr *trhdr=(const tr_hdr *)vip; + + add_conversation_table_data(hash, &trhdr->src, &trhdr->dst, 0, 0, 1, pinfo->fd->pkt_len, &pinfo->rel_ts, &tr_ct_dissector_info, PT_NONE); + + return 1; +} + /* * DODGY LINUX HACK DODGY LINUX HACK * Linux 2.0.x always passes frames to the Token Ring driver for transmission with @@ -734,6 +762,8 @@ proto_register_tr(void) register_dissector("tr", dissect_tr, proto_tr); tr_tap=register_tap("tr"); + + register_conversation_table(proto_tr, TRUE, tr_conversation_packet); } void diff --git a/epan/dissectors/packet-udp.c b/epan/dissectors/packet-udp.c index 1def80f2d3..4a730dcd3e 100644 --- a/epan/dissectors/packet-udp.c +++ b/epan/dissectors/packet-udp.c @@ -43,6 +43,7 @@ #include "packet-ip.h" #include <epan/conversation.h> +#include <epan/conversation_table.h> #include <epan/tap.h> #include <epan/decode_as.h> @@ -280,6 +281,33 @@ get_udp_conversation_data(conversation_t *conv, packet_info *pinfo) return udpd; } +static const char* udp_conv_get_filter_type(conv_item_t* conv _U_, conv_filter_type_e filter) +{ + if (filter == CONV_FT_SRC_PORT) + return "udp.srcport"; + + if (filter == CONV_FT_DST_PORT) + return "udp.dstport"; + + if (filter == CONV_FT_ANY_PORT) + return "udp.port"; + + return CONV_FILTER_INVALID; +} + +static ct_dissector_info_t udp_ct_dissector_info = {&udp_conv_get_filter_type}; + +static int +udpip_conversation_packet(void *pct, packet_info *pinfo, epan_dissect_t *edt _U_, const void *vip) +{ + conv_hash_t *hash = (conv_hash_t*) pct; + const e_udphdr *udphdr=(const e_udphdr *)vip; + + add_conversation_table_data(hash, &udphdr->ip_src, &udphdr->ip_dst, udphdr->uh_sport, udphdr->uh_dport, 1, pinfo->fd->pkt_len, &pinfo->rel_ts, &udp_ct_dissector_info, PT_UDP); + + return 1; +} + /* Attach process info to a flow */ /* XXX - We depend on the UDP dissector finding the conversation first */ void @@ -891,6 +919,7 @@ proto_register_udp(void) &udplite_check_checksum); register_decode_as(&udp_da); + register_conversation_table(proto_udp, FALSE, udpip_conversation_packet); register_init_routine(udp_init); diff --git a/epan/dissectors/packet-usb.c b/epan/dissectors/packet-usb.c index e94cf8d9d7..aebf750bfe 100644 --- a/epan/dissectors/packet-usb.c +++ b/epan/dissectors/packet-usb.c @@ -34,6 +34,7 @@ #include <epan/wmem/wmem.h> #include <epan/tap.h> #include <epan/conversation.h> +#include <epan/conversation_table.h> #include <epan/expert.h> #include <epan/prefs.h> #include <epan/decode_as.h> @@ -1101,6 +1102,30 @@ get_usb_iface_conv_info(packet_info *pinfo, guint8 interface_num) return get_usb_conv_info(conversation); } +static const char* usb_conv_get_filter_type(conv_item_t* conv, conv_filter_type_e filter) +{ + if ((filter == CONV_FT_SRC_ADDRESS) && (conv->src_address.type == AT_USB)) + return "usb.sa"; + + if ((filter == CONV_FT_DST_ADDRESS) && (conv->dst_address.type == AT_USB)) + return "usb.da"; + + if ((filter == CONV_FT_ANY_ADDRESS) && (conv->src_address.type == AT_USB)) + return "usb.addr"; + + return CONV_FILTER_INVALID; +} + +static ct_dissector_info_t usb_ct_dissector_info = {&usb_conv_get_filter_type}; + +static int +usb_conversation_packet(void *pct, packet_info *pinfo, epan_dissect_t *edt _U_, const void *vip _U_) +{ + conv_hash_t *hash = (conv_hash_t*) pct; + add_conversation_table_data(hash, &pinfo->src, &pinfo->dst, 0, 0, 1, pinfo->fd->pkt_len, &pinfo->rel_ts, &usb_ct_dissector_info, PT_NONE); + + return 1; +} /* SETUP dissectors */ @@ -4087,6 +4112,11 @@ proto_register_usb(void) expert_module_t* expert_usb; + proto_usb = proto_register_protocol("USB", "USB", "usb"); + proto_register_field_array(proto_usb, hf, array_length(hf)); + proto_register_subtree_array(usb_subtrees, array_length(usb_subtrees)); + linux_usb_handle = register_dissector("usb", dissect_linux_usb, proto_usb); + expert_usb = expert_register_protocol(proto_usb); expert_register_field_array(expert_usb, ei, array_length(ei)); @@ -4096,11 +4126,6 @@ proto_register_usb(void) protocol_to_dissector = register_dissector_table("usb.protocol", "USB protocol", FT_UINT32, BASE_HEX); product_to_dissector = register_dissector_table("usb.product", "USB product", FT_UINT32, BASE_HEX); - proto_usb = proto_register_protocol("USB", "USB", "usb"); - proto_register_field_array(proto_usb, hf, array_length(hf)); - proto_register_subtree_array(usb_subtrees, array_length(usb_subtrees)); - linux_usb_handle = register_dissector("usb", dissect_linux_usb, proto_usb); - usb_bulk_dissector_table = register_dissector_table("usb.bulk", "USB bulk endpoint", FT_UINT8, BASE_DEC); register_heur_dissector_list("usb.bulk", &heur_bulk_subdissector_list); @@ -4125,6 +4150,8 @@ proto_register_usb(void) register_decode_as(&usb_protocol_da); register_decode_as(&usb_product_da); register_decode_as(&usb_device_da); + + register_conversation_table(proto_usb, TRUE, usb_conversation_packet); } void diff --git a/epan/proto.c b/epan/proto.c index 05d7c9f119..059e18a495 100644 --- a/epan/proto.c +++ b/epan/proto.c @@ -4827,12 +4827,11 @@ proto_register_protocol(const char *name, const char *short_name, } g_hash_table_insert(proto_names, key, (gpointer)name); - existing_name = (const char *)g_hash_table_lookup(proto_short_names, (gpointer)short_name); - if (existing_name != NULL) { + existing_protocol = (const protocol_t *)g_hash_table_lookup(proto_short_names, (gpointer)short_name); + if (existing_protocol != NULL) { g_error("Duplicate protocol short_name \"%s\"!" " This might be caused by an inappropriate plugin or a development error.", short_name); } - g_hash_table_insert(proto_short_names, (gpointer)short_name, (gpointer)short_name); found_invalid = FALSE; for (i = 0; filter_name[i]; i++) { @@ -4865,6 +4864,7 @@ proto_register_protocol(const char *name, const char *short_name, /* list will be sorted later by name, when all protocols completed registering */ protocols = g_list_prepend(protocols, protocol); g_hash_table_insert(proto_filter_names, (gpointer)filter_name, protocol); + g_hash_table_insert(proto_short_names, (gpointer)short_name, protocol); /* Here we allocate a new header_field_info struct */ hfinfo = g_slice_new(header_field_info); @@ -5012,6 +5012,22 @@ int proto_get_id_by_filter_name(const gchar* filter_name) return protocol->proto_id; } +int proto_get_id_by_short_name(const gchar* short_name) +{ + const protocol_t *protocol = NULL; + + if(!short_name){ + fprintf(stderr, "No short name present"); + DISSECTOR_ASSERT(short_name); + } + + protocol = (const protocol_t *)g_hash_table_lookup(proto_short_names, (gpointer)short_name); + + if (protocol == NULL) + return -1; + return protocol->proto_id; +} + const char * proto_get_protocol_name(const int proto_id) { diff --git a/epan/proto.h b/epan/proto.h index cb456f8ebc..dada8a938e 100644 --- a/epan/proto.h +++ b/epan/proto.h @@ -1984,6 +1984,11 @@ WS_DLL_PUBLIC header_field_info *proto_get_next_protocol_field(const int proto_i @return proto_id */ WS_DLL_PUBLIC int proto_get_id_by_filter_name(const gchar* filter_name); +/** Given a protocol's short name. + @param short_name the protocol short name to search for + @return proto_id */ +WS_DLL_PUBLIC int proto_get_id_by_short_name(const gchar* short_name); + /** Can item # n decoding be disabled? @param proto_id protocol id (0-indexed) @return TRUE if it's a protocol, FALSE if it's not */ diff --git a/epan/stat_cmd_args.h b/epan/stat_cmd_args.h index a8bfaf60a2..499bf32a5d 100644 --- a/epan/stat_cmd_args.h +++ b/epan/stat_cmd_args.h @@ -30,6 +30,13 @@ extern "C" { #endif /* __cplusplus */ +/** Register a stat ("-z") command line argument. + * + * @param cmd The command name without arguments, e.g. "conv,tcp" or "io,stat". + * MUST be valid when other stat_cmd routines below are called. + * @param func Callbak to be invoked when the CLI argument is supplied. + * @param userdata Additional data for the callback. + */ WS_DLL_PUBLIC void register_stat_cmd_arg(const char *cmd, void (*func)(const char *arg,void* userdata), void* userdata); WS_DLL_PUBLIC gboolean process_stat_cmd_arg(char *optstr); |