aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--epan/dissectors/packet-tcp.c5
-rw-r--r--epan/dissectors/packet-tcp.h1
-rw-r--r--ui/cli/tap-iousers.c46
-rw-r--r--ui/gtk/conversations_table.c179
-rw-r--r--ui/gtk/conversations_table.h100
-rw-r--r--ui/gtk/conversations_tcpip.c2
6 files changed, 212 insertions, 121 deletions
diff --git a/epan/dissectors/packet-tcp.c b/epan/dissectors/packet-tcp.c
index 35919998db..8953404977 100644
--- a/epan/dissectors/packet-tcp.c
+++ b/epan/dissectors/packet-tcp.c
@@ -4140,6 +4140,11 @@ dissect_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
if (tcpd) {
item = proto_tree_add_uint(tcp_tree, hf_tcp_stream, tvb, offset, 0, tcpd->stream);
PROTO_ITEM_SET_GENERATED(item);
+
+ /* Copy the stream index into the header as well to make it available
+ * to tap listeners.
+ */
+ tcph->th_stream = tcpd->stream;
}
/* Do we need to calculate timestamps relative to the tcp-stream? */
diff --git a/epan/dissectors/packet-tcp.h b/epan/dissectors/packet-tcp.h
index a89d6b1629..f93c2d5ba2 100644
--- a/epan/dissectors/packet-tcp.h
+++ b/epan/dissectors/packet-tcp.h
@@ -59,6 +59,7 @@ typedef struct tcpheader {
guint16 th_dport;
guint8 th_hlen;
guint16 th_flags;
+ guint32 th_stream; /* this stream index field is included to help differentiate when address/port pairs are reused */
address ip_src;
address ip_dst;
} tcp_info_t;
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;
}