diff options
author | Anders Broman <anders.broman@ericsson.com> | 2012-05-23 06:36:47 +0000 |
---|---|---|
committer | Anders Broman <anders.broman@ericsson.com> | 2012-05-23 06:36:47 +0000 |
commit | 0832853fa801c8d9399e7f495e1f09bb7963c170 (patch) | |
tree | 97ec67084cd56ac28513365250b5339a202e3fb5 /ui | |
parent | a6deef666c0af093bbbf76c57e1fae88cb180e7a (diff) |
From Robert Bullen:
The Wireshark and tshark TCP conversations stats tables aggregate reused connections into a single line item
https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=7248
svn path=/trunk/; revision=42806
Diffstat (limited to 'ui')
-rw-r--r-- | ui/cli/tap-iousers.c | 46 | ||||
-rw-r--r-- | ui/gtk/conversations_table.c | 179 | ||||
-rw-r--r-- | ui/gtk/conversations_table.h | 100 | ||||
-rw-r--r-- | ui/gtk/conversations_tcpip.c | 2 |
4 files changed, 206 insertions, 121 deletions
diff --git a/ui/cli/tap-iousers.c b/ui/cli/tap-iousers.c index c9595c79c3..486c8feac8 100644 --- a/ui/cli/tap-iousers.c +++ b/ui/cli/tap-iousers.c @@ -33,6 +33,7 @@ #include <epan/packet.h> #include <epan/addr_resolv.h> #include <epan/tap.h> +#include <epan/conv_id.h> #include <epan/conversation.h> #include <epan/stat_cmd_args.h> #include <epan/dissectors/packet-ip.h> @@ -54,27 +55,39 @@ typedef struct _io_users_t { } io_users_t; typedef struct _io_users_item_t { - struct _io_users_item_t *next; - char *name1; - char *name2; - address addr1; - address addr2; - guint32 frames1; - guint32 frames2; - guint64 bytes1; - guint64 bytes2; - nstime_t start_time; - nstime_t stop_time; + struct _io_users_item_t *next; + char *name1; + char *name2; + conv_id_t conv_id; + address addr1; + address addr2; + guint32 frames1; + guint32 frames2; + guint64 bytes1; + guint64 bytes2; + nstime_t start_time; + nstime_t stop_time; } io_users_item_t; +#define iousers_process_name_packet(iu, name1, name2, direction, pkt_len, ts) \ + iousers_process_name_packet_with_conv_id(iu, name1, name2, CONV_ID_UNSET, direction, pkt_len, ts) + void -iousers_process_name_packet(io_users_t *iu, char *name1, char *name2, int direction, guint64 pkt_len, nstime_t *ts) +iousers_process_name_packet_with_conv_id( + io_users_t *iu, + char *name1, + char *name2, + conv_id_t conv_id, + int direction, + guint64 pkt_len, + nstime_t *ts) { io_users_item_t *iui; for(iui=iu->items;iui;iui=iui->next){ - if((!strcmp(iui->name1, name1)) - && (!strcmp(iui->name2, name2)) ){ + if((iui->conv_id==conv_id) + && (!strcmp(iui->name1, name1)) + && (!strcmp(iui->name2, name2)) ){ break; } } @@ -83,10 +96,9 @@ iousers_process_name_packet(io_users_t *iu, char *name1, char *name2, int direct iui=g_malloc(sizeof(io_users_item_t)); iui->next=iu->items; iu->items=iui; -/* iui->addr1=NULL;*/ iui->name1=g_strdup(name1); -/* iui->addr2=NULL;*/ iui->name2=g_strdup(name2); + iui->conv_id=conv_id; iui->frames1=0; iui->frames2=0; iui->bytes1=0; @@ -253,7 +265,7 @@ iousers_tcpip_packet(void *arg, packet_info *pinfo, epan_dissect_t *edt _U_, con g_snprintf(name1,256,"%s:%s",ep_address_to_str(&tcph->ip_dst),get_tcp_port(tcph->th_dport)); } - iousers_process_name_packet(iu, name1, name2, direction, pinfo->fd->pkt_len, &pinfo->fd->rel_ts); + iousers_process_name_packet_with_conv_id(iu, name1, name2, tcph->th_stream, direction, pinfo->fd->pkt_len, &pinfo->fd->rel_ts); return 1; } diff --git a/ui/gtk/conversations_table.c b/ui/gtk/conversations_table.c index 4570b85eb3..dc703a949d 100644 --- a/ui/gtk/conversations_table.c +++ b/ui/gtk/conversations_table.c @@ -2467,7 +2467,7 @@ follow_stream_cb(GtkWidget *follow_stream_bt, gpointer data _U_) GtkTreeModel *model; GtkTreeSelection *sel; guint32 idx = 0; - gchar *filter; + gchar *filter = NULL; conv_t *conv; if (!ct) @@ -2486,25 +2486,42 @@ follow_stream_cb(GtkWidget *follow_stream_bt, gpointer data _U_) } conv = &g_array_index(ct->conversations, conv_t, idx); - filter = g_strdup_printf("%s==%s && %s==%s && %s==%s && %s==%s", - ct_get_filter_name(&conv->src_address, conv->sat, conv->port_type, FN_ANY_ADDRESS), - ep_address_to_str(&conv->src_address), - ct_get_filter_name(&conv->src_address, conv->sat, conv->port_type, FN_ANY_PORT), - ct_port_to_str(conv->port_type, conv->src_port), - ct_get_filter_name(&conv->dst_address, conv->sat, conv->port_type, FN_ANY_ADDRESS), - ep_address_to_str(&conv->dst_address), - ct_get_filter_name(&conv->dst_address, conv->sat, conv->port_type, FN_ANY_PORT), - ct_port_to_str(conv->port_type, conv->dst_port)); - - apply_selected_filter (ACTYPE_SELECTED|ACTION_MATCH, filter); + + /* Generate and apply a display filter to isolate the conversation. The + * TCP filter is a special case because it uses the stream identifier/index + * (tcp.stream, which is stored in conv_id) to ensure the filter results + * in a unique conversation even in the face of port reuse. All others use + * the address/port tuple. + */ + if ((strcmp(ct->name, "TCP") == 0) && (conv->conv_id != CONV_ID_UNSET)) + { + filter = g_strdup_printf("tcp.stream eq %d", conv->conv_id); + } + else + { + filter = g_strdup_printf("%s==%s && %s==%s && %s==%s && %s==%s", + ct_get_filter_name(&conv->src_address, conv->sat, conv->port_type, FN_ANY_ADDRESS), + ep_address_to_str(&conv->src_address), + ct_get_filter_name(&conv->src_address, conv->sat, conv->port_type, FN_ANY_PORT), + ct_port_to_str(conv->port_type, conv->src_port), + ct_get_filter_name(&conv->dst_address, conv->sat, conv->port_type, FN_ANY_ADDRESS), + ep_address_to_str(&conv->dst_address), + ct_get_filter_name(&conv->dst_address, conv->sat, conv->port_type, FN_ANY_PORT), + ct_port_to_str(conv->port_type, conv->dst_port)); + } + apply_selected_filter(ACTYPE_SELECTED|ACTION_MATCH, filter); + g_free(filter); + filter = NULL; + + /* For TCP or UDP conversations, take things one step further and present + * the Follow Stream dialog. Other conversation types? Not so much. + */ if (strcmp(ct->name, "TCP") == 0) - follow_tcp_stream_cb (follow_stream_bt, data); + follow_tcp_stream_cb(follow_stream_bt, data); else if (strcmp(ct->name, "UDP") == 0) - follow_udp_stream_cb (follow_stream_bt, data); + follow_udp_stream_cb(follow_stream_bt, data); else simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "Unknown stream: %s", ct->name); - - g_free (filter); } @@ -2838,6 +2855,7 @@ typedef struct _key { address addr2; guint32 port1; guint32 port2; + conv_id_t conv_id; } conv_key_t; @@ -2856,6 +2874,7 @@ conversation_hash(gconstpointer v) hash_val += key->port1; ADD_ADDRESS_TO_HASH(hash_val, &key->addr2); hash_val += key->port2; + hash_val ^= key->conv_id; return hash_val; } @@ -2869,22 +2888,25 @@ conversation_match(gconstpointer v, gconstpointer w) const conv_key_t *v1 = (const conv_key_t *)v; const conv_key_t *v2 = (const conv_key_t *)w; - if (v1->port1 == v2->port1 && - v1->port2 == v2->port2 && - ADDRESSES_EQUAL(&v1->addr1, &v2->addr1) && - ADDRESSES_EQUAL(&v1->addr2, &v2->addr2)) { - return 1; - } + if (v1->conv_id == v2->conv_id) + { + if (v1->port1 == v2->port1 && + v1->port2 == v2->port2 && + ADDRESSES_EQUAL(&v1->addr1, &v2->addr1) && + ADDRESSES_EQUAL(&v1->addr2, &v2->addr2)) { + return 1; + } - if (v1->port2 == v2->port1 && - v1->port1 == v2->port2 && - ADDRESSES_EQUAL(&v1->addr2, &v2->addr1) && - ADDRESSES_EQUAL(&v1->addr1, &v2->addr2)) { - return 1; + if (v1->port2 == v2->port1 && + v1->port1 == v2->port2 && + ADDRESSES_EQUAL(&v1->addr2, &v2->addr1) && + ADDRESSES_EQUAL(&v1->addr1, &v2->addr2)) { + return 1; + } } /* - * The addresses or the ports don't match. + * The addresses, ports, or conversation IDs don't match. */ return 0; } @@ -2893,44 +2915,60 @@ conversation_match(gconstpointer v, gconstpointer w) void add_conversation_table_data(conversations_table *ct, const address *src, const address *dst, guint32 src_port, guint32 dst_port, int num_frames, int num_bytes, nstime_t *ts, SAT_E sat, int port_type_val) { + add_conversation_table_data_with_conv_id(ct, src, dst, src_port, dst_port, CONV_ID_UNSET, num_frames, num_bytes, ts, sat, port_type_val); +} + +void +add_conversation_table_data_with_conv_id( + conversations_table *ct, + 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, + SAT_E sat, + int port_type_val) +{ const address *addr1, *addr2; guint32 port1, port2; - conv_t *conversation=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; + conv_t *conversation = 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; + addr2 = src; + addr1 = dst; + port2 = src_port; + port1 = dst_port; } /* if we dont have any entries at all yet */ - if(ct->conversations==NULL){ - ct->conversations= g_array_sized_new(FALSE, FALSE, sizeof(conv_t), 10000); + if (ct->conversations == NULL) { + ct->conversations = g_array_sized_new(FALSE, FALSE, sizeof(conv_t), 10000); ct->hashtable = g_hash_table_new_full(conversation_hash, conversation_match, /* key_equal_func */ g_free, /* key_destroy_func */ NULL); /* value_destroy_func */ - } - else { + } else { /* try to find it among the existing known conversations */ conv_key_t existing_key; @@ -2938,6 +2976,7 @@ add_conversation_table_data(conversations_table *ct, const address *src, const a existing_key.addr2 = *addr2; existing_key.port1 = port1; existing_key.port2 = port2; + existing_key.conv_id = conv_id; conversation_idx = GPOINTER_TO_UINT(g_hash_table_lookup(ct->hashtable, &existing_key)); if (conversation_idx) { conversation_idx--; @@ -2947,20 +2986,21 @@ add_conversation_table_data(conversations_table *ct, const address *src, const a /* 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(conversation==NULL){ + if (conversation == NULL) { conv_key_t *new_key; conv_t conv; COPY_ADDRESS(&conv.src_address, addr1); COPY_ADDRESS(&conv.dst_address, addr2); - conv.sat=sat; - conv.port_type=port_type_val; - conv.src_port=port1; - conv.dst_port=port2; - conv.rx_frames=0; - conv.tx_frames=0; - conv.rx_bytes=0; - conv.tx_bytes=0; + conv.sat = sat; + conv.port_type = port_type_val; + conv.src_port = port1; + conv.dst_port = port2; + conv.conv_id = conv_id; + conv.rx_frames = 0; + conv.tx_frames = 0; + conv.rx_bytes = 0; + conv.tx_bytes = 0; conv.iter_valid = FALSE; conv.modified = TRUE; @@ -2972,7 +3012,7 @@ add_conversation_table_data(conversations_table *ct, const address *src, const a nstime_set_unset(&conv.stop_time); } g_array_append_val(ct->conversations, conv); - conversation_idx=ct->num_conversations; + conversation_idx = ct->num_conversations; conversation=&g_array_index(ct->conversations, conv_t, conversation_idx); /* ct->conversations address is not a constant but src/dst_address.data are */ @@ -2981,6 +3021,7 @@ add_conversation_table_data(conversations_table *ct, const address *src, const a SET_ADDRESS(&new_key->addr2, conversation->dst_address.type, conversation->dst_address.len, conversation->dst_address.data); new_key->port1 = port1; new_key->port2 = port2; + new_key->conv_id = conv_id; g_hash_table_insert(ct->hashtable, new_key, GUINT_TO_POINTER(conversation_idx +1)); ct->num_conversations++; @@ -2988,12 +3029,12 @@ add_conversation_table_data(conversations_table *ct, const address *src, const a /* update the conversation struct */ conversation->modified = TRUE; - if( (!CMP_ADDRESS(src, addr1))&&(!CMP_ADDRESS(dst, addr2))&&(src_port==port1)&&(dst_port==port2) ){ - conversation->tx_frames+=num_frames; - conversation->tx_bytes+=num_bytes; + if ( (!CMP_ADDRESS(src, addr1)) && (!CMP_ADDRESS(dst, addr2)) && (src_port==port1) && (dst_port==port2) ) { + conversation->tx_frames += num_frames; + conversation->tx_bytes += num_bytes; } else { - conversation->rx_frames+=num_frames; - conversation->rx_bytes+=num_bytes; + conversation->rx_frames += num_frames; + conversation->rx_bytes += num_bytes; } if (ts) { diff --git a/ui/gtk/conversations_table.h b/ui/gtk/conversations_table.h index 42596982a2..e631592727 100644 --- a/ui/gtk/conversations_table.h +++ b/ui/gtk/conversations_table.h @@ -26,6 +26,7 @@ #ifndef __CONVERSATIONS_TABLE_H__ #define __CONVERSATIONS_TABLE_H__ +#include <epan/conv_id.h> #include "sat.h" /** @file @@ -34,45 +35,46 @@ /** Conversation information */ typedef struct _conversation_t { - address src_address; /**< source address */ - address dst_address; /**< destination address */ - SAT_E sat; /**< address type */ - guint32 port_type; /**< port_type (e.g. PT_TCP) */ - guint32 src_port; /**< source port */ - guint32 dst_port; /**< destination port */ + address src_address; /**< source address */ + address dst_address; /**< destination address */ + SAT_E sat; /**< address type */ + guint32 port_type; /**< 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 */ + 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 */ + 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 */ - GtkTreeIter iter; - gboolean iter_valid; /**< not a new row */ + gboolean modified; /**< new to redraw the row */ + GtkTreeIter iter; + gboolean iter_valid; /**< not a new row */ } conv_t; /** Conversation widget */ typedef struct _conversations_table { - const char *name; /**< the name of the table */ - const char *filter; /**< the filter used */ - gboolean use_dfilter; /**< use display filter */ - GtkWidget *win; /**< GTK window */ - GtkWidget *page_lb; /**< page label */ - GtkWidget *name_lb; /**< name label */ - GtkWidget *scrolled_window; /**< the scrolled window */ - GtkTreeView *table; /**< the GTK table */ - const char *default_titles[14]; /**< Column headers */ - GtkWidget *menu; /**< context menu */ - gboolean has_ports; /**< table has ports */ - guint32 num_conversations; /**< number of conversations */ - GArray *conversations; /**< array of conversation values */ - GHashTable *hashtable; /**< conversations hash table */ + const char *name; /**< the name of the table */ + const char *filter; /**< the filter used */ + gboolean use_dfilter; /**< use display filter */ + GtkWidget *win; /**< GTK window */ + GtkWidget *page_lb; /**< page label */ + GtkWidget *name_lb; /**< name label */ + GtkWidget *scrolled_window; /**< the scrolled window */ + GtkTreeView *table; /**< the GTK table */ + const char *default_titles[14]; /**< Column headers */ + GtkWidget *menu; /**< context menu */ + gboolean has_ports; /**< table has ports */ + guint32 num_conversations; /**< number of conversations */ + GArray *conversations; /**< array of conversation values */ + GHashTable *hashtable; /**< conversations hash table */ - gboolean fixed_col; /**< if switched to fixed column */ - gboolean resolve_names; /**< resolve address names? */ + gboolean fixed_col; /**< if switched to fixed column */ + gboolean resolve_names; /**< resolve address names? */ } conversations_table; /** Register the conversation table for the multiple conversation window. @@ -116,7 +118,37 @@ extern void init_conversation_notebook_cb(GtkWidget *widget, gpointer data); * @param port_type the port type (e.g. PT_TCP) */ extern void add_conversation_table_data(conversations_table *ct, const address *src, const address *dst, - guint32 src_port, guint32 dst_port, int num_frames, int num_bytes, nstime_t *ts, - SAT_E sat, int port_type); -#endif /* __CONVERSATIONS_TABLE_H__ */ + guint32 src_port, guint32 dst_port, int num_frames, int num_bytes, nstime_t *ts, + SAT_E sat, int port_type); +/** 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 ct 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 sat address type + * @param port_type 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( + conversations_table *ct, + 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, + SAT_E sat, + int port_type); + +#endif /* __CONVERSATIONS_TABLE_H__ */ diff --git a/ui/gtk/conversations_tcpip.c b/ui/gtk/conversations_tcpip.c index 8f0af74cb5..82607388f6 100644 --- a/ui/gtk/conversations_tcpip.c +++ b/ui/gtk/conversations_tcpip.c @@ -45,7 +45,7 @@ tcpip_conversation_packet(void *pct, packet_info *pinfo, epan_dissect_t *edt _U_ { const struct tcpheader *tcphdr=vip; - add_conversation_table_data((conversations_table *)pct, &tcphdr->ip_src, &tcphdr->ip_dst, tcphdr->th_sport, tcphdr->th_dport, 1, pinfo->fd->pkt_len, &pinfo->fd->rel_ts, SAT_NONE, PT_TCP); + add_conversation_table_data_with_conv_id((conversations_table *)pct, &tcphdr->ip_src, &tcphdr->ip_dst, tcphdr->th_sport, tcphdr->th_dport, (conv_id_t) tcphdr->th_stream, 1, pinfo->fd->pkt_len, &pinfo->fd->rel_ts, SAT_NONE, PT_TCP); return 1; } |