summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--debian/libwireshark0.symbols23
-rw-r--r--epan/dissectors/packet-http.c29
-rw-r--r--epan/dissectors/packet-ssl-utils.h6
-rw-r--r--epan/dissectors/packet-ssl.c63
-rw-r--r--epan/dissectors/packet-tcp.c52
-rw-r--r--epan/dissectors/packet-tcp.h5
-rw-r--r--epan/dissectors/packet-udp.c50
-rw-r--r--epan/follow.c367
-rw-r--r--epan/follow.h183
-rw-r--r--epan/to_str.h2
-rw-r--r--ui/Makefile.common1
-rw-r--r--ui/cli/tap-follow.c944
-rw-r--r--ui/follow.h99
-rw-r--r--ui/gtk/CMakeLists.txt4
-rw-r--r--ui/gtk/Makefile.common8
-rw-r--r--ui/gtk/conversations_table.c3
-rw-r--r--ui/gtk/follow_http.c313
-rw-r--r--ui/gtk/follow_http.h44
-rw-r--r--ui/gtk/follow_ssl.c352
-rw-r--r--ui/gtk/follow_ssl.h45
-rw-r--r--ui/gtk/follow_stream.c517
-rw-r--r--ui/gtk/follow_stream.h60
-rw-r--r--ui/gtk/follow_tcp.c327
-rw-r--r--ui/gtk/follow_tcp.h55
-rw-r--r--ui/gtk/follow_udp.c313
-rw-r--r--ui/gtk/follow_udp.h45
-rw-r--r--ui/gtk/font_utils.c4
-rw-r--r--ui/gtk/main.c1
-rw-r--r--ui/gtk/main_menubar.c5
-rw-r--r--ui/gtk/prefs_font_color.c4
-rw-r--r--ui/qt/conversation_dialog.cpp1
-rw-r--r--ui/qt/follow_stream_dialog.cpp508
-rw-r--r--ui/qt/follow_stream_dialog.h21
-rw-r--r--ui/qt/main_window.cpp2
-rw-r--r--ui/qt/traffic_table_dialog.h2
35 files changed, 1205 insertions, 3253 deletions
diff --git a/debian/libwireshark0.symbols b/debian/libwireshark0.symbols
index 7ced7b4469..eee6f7f4de 100644
--- a/debian/libwireshark0.symbols
+++ b/debian/libwireshark0.symbols
@@ -44,6 +44,7 @@ libwireshark.so.0 libwireshark0 #MINVER#
add_new_data_source@Base 1.9.1
add_srt_table_data@Base 1.99.8
address_to_display@Base 1.99.2
+ address_to_name@Base 2.1.0
address_to_str@Base 1.12.0~rc1
address_with_resolution_to_str@Base 1.99.3
address_to_str_buf@Base 1.9.1
@@ -80,8 +81,6 @@ libwireshark.so.0 libwireshark0 #MINVER#
bthci_evt_hci_version@Base 1.99.6
bthci_evt_lmp_version@Base 1.99.6
build_column_format_array@Base 1.9.1
- build_follow_conv_filter@Base 1.12.0~rc1
- build_follow_index_filter@Base 1.12.0~rc1
byte_array_dup@Base 1.9.1
byte_array_equal@Base 1.9.1
bytes_to_hexstr@Base 2.1.0
@@ -187,7 +186,6 @@ libwireshark.so.0 libwireshark0 #MINVER#
crc6_compute_tvb@Base 1.99.0
create_dissector_handle@Base 2.1.0
create_dissector_handle_with_name@Base 2.1.0
- data_out_file@Base 1.9.1
dcerpc_get_proto_hf_opnum@Base 2.1.0
dcerpc_get_proto_name@Base 1.9.1
dcerpc_get_proto_sub_dissector@Base 1.9.1
@@ -464,7 +462,6 @@ libwireshark.so.0 libwireshark0 #MINVER#
elem_tv_short@Base 1.9.1
elem_v@Base 1.9.1
elem_v_short@Base 1.9.1
- empty_tcp_stream@Base 1.9.1
epan_cleanup@Base 1.9.1
epan_dissect_cleanup@Base 1.9.1
epan_dissect_fake_protocols@Base 1.9.1
@@ -547,9 +544,9 @@ libwireshark.so.0 libwireshark0 #MINVER#
find_sid_name@Base 1.9.1
find_stream_circ@Base 1.9.1
find_tap_id@Base 1.9.1
- follow_addr@Base 1.99.2
- follow_index@Base 1.99.2
- follow_stats@Base 1.9.1
+ follow_iterate_followers@Base 2.1.0
+ follow_reset_stream@Base 2.1.0
+ follow_tvb_tap_listener@Base 2.1.0
format_text@Base 1.9.1
format_text_chr@Base 1.12.0~rc1
format_text_wsp@Base 1.9.1
@@ -683,8 +680,15 @@ libwireshark.so.0 libwireshark0 #MINVER#
get_ebcdic_string@Base 1.12.0~rc1
get_eth_hashtable@Base 1.12.0~rc1
get_ether_name@Base 1.9.1
+ get_follow_address_func@Base 2.1.0
+ get_follow_by_name@Base 2.1.0
+ get_follow_conv_func@Base 2.1.0
+ get_follow_index_func@Base 2.1.0
+ get_follow_port_to_display@Base 2.1.0
+ get_follow_proto_id@Base 2.1.0
+ get_follow_tap_handler@Base 2.1.0
+ get_follow_tap_string@Base 2.1.0
get_export_pdu_tap_list@Base 1.99.0
- get_follow_index@Base 1.99.2
get_hash_ether_status@Base 1.99.3
get_hash_ether_hexaddr@Base 1.99.3
get_hash_ether_resolved_name@Base 1.99.3
@@ -779,7 +783,6 @@ libwireshark.so.0 libwireshark0 #MINVER#
ieee80211_supported_rates_vals_ext@Base 1.99.1
ieee802a_add_oui@Base 1.9.1
in_cksum@Base 1.9.1
- incomplete_tcp_stream@Base 1.9.1
init_srt_table@Base 1.99.8
init_srt_table_row@Base 1.99.8
ip_checksum@Base 1.99.0
@@ -1140,6 +1143,7 @@ libwireshark.so.0 libwireshark0 #MINVER#
register_dissector@Base 2.1.0
register_dissector_table@Base 1.9.1
register_export_pdu_tap@Base 1.99.0
+ register_follow_stream@Base 2.1.0
register_final_registration_routine@Base 1.9.1
register_giop_user@Base 1.9.1
register_giop_user_module@Base 1.9.1
@@ -1167,7 +1171,6 @@ libwireshark.so.0 libwireshark0 #MINVER#
reset_rtd_table@Base 1.99.8
reset_srt_table@Base 1.99.8
reset_stat_table@Base 1.99.8
- reset_stream_follow@Base 2.1.0
reset_tap_listeners@Base 1.9.1
rose_ctx_clean_data@Base 1.9.1
rose_ctx_init@Base 1.9.1
diff --git a/epan/dissectors/packet-http.c b/epan/dissectors/packet-http.c
index d024dd52f0..0fb9a832e2 100644
--- a/epan/dissectors/packet-http.c
+++ b/epan/dissectors/packet-http.c
@@ -35,6 +35,8 @@
#include <epan/packet.h>
#include <epan/prefs.h>
#include <epan/expert.h>
+#include <epan/follow.h>
+#include <epan/addr_resolv.h>
#include <epan/uat.h>
#include <epan/strutil.h>
#include <epan/stats_tree.h>
@@ -605,6 +607,29 @@ http_stats_tree_packet(stats_tree* st, packet_info* pinfo _U_, epan_dissect_t* e
return 1;
}
+static gchar* http_add_http_filter(gchar* filter)
+{
+ gchar *http_buf = g_strdup_printf("((%s) && (http))", filter);
+ g_free(filter);
+
+ return http_buf;
+}
+
+static gchar* http_follow_conv_filter(packet_info *pinfo, int* stream)
+{
+ return http_add_http_filter(tcp_follow_conv_filter(pinfo, stream));
+}
+
+static gchar* http_follow_index_filter(int stream)
+{
+ return http_add_http_filter(tcp_follow_index_filter(stream));
+}
+
+static gchar* http_follow_address_filter(address* src_addr, address* dst_addr, int src_port, int dst_port)
+{
+ return http_add_http_filter(tcp_follow_address_filter(src_addr, dst_addr, src_port, dst_port));
+}
+
static void
dissect_http_ntlmssp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
@@ -3512,6 +3537,9 @@ proto_register_http(void)
http_tap = register_tap("http"); /* HTTP statistics tap */
http_eo_tap = register_tap("http_eo"); /* HTTP Export Object tap */
http_follow_tap = register_tap("http_follow"); /* HTTP Follow tap */
+
+ register_follow_stream(proto_http, "http_follow", http_follow_conv_filter, http_follow_index_filter, http_follow_address_filter,
+ tcp_port_to_display, follow_tvb_tap_listener);
}
/*
@@ -3566,7 +3594,6 @@ proto_reg_handoff_http(void)
stats_tree_register("http", "http", "HTTP/Packet Counter", 0, http_stats_tree_packet, http_stats_tree_init, NULL );
stats_tree_register("http", "http_req", "HTTP/Requests", 0, http_req_stats_tree_packet, http_req_stats_tree_init, NULL );
stats_tree_register("http", "http_srv", "HTTP/Load Distribution",0, http_reqs_stats_tree_packet, http_reqs_stats_tree_init, NULL );
-
}
/*
diff --git a/epan/dissectors/packet-ssl-utils.h b/epan/dissectors/packet-ssl-utils.h
index 3bbf44f858..739ac2159e 100644
--- a/epan/dissectors/packet-ssl-utils.h
+++ b/epan/dissectors/packet-ssl-utils.h
@@ -402,6 +402,12 @@ typedef struct _SslDecryptSession {
} SslDecryptSession;
+typedef struct {
+ gboolean is_from_server;
+ guint32 packet_num;
+ StringInfo data;
+} SslDecryptedRecord;
+
/* User Access Table */
typedef struct _ssldecrypt_assoc_t {
char* ipaddr;
diff --git a/epan/dissectors/packet-ssl.c b/epan/dissectors/packet-ssl.c
index 02e05dc320..98e1e38b2a 100644
--- a/epan/dissectors/packet-ssl.c
+++ b/epan/dissectors/packet-ssl.c
@@ -88,6 +88,8 @@
#include <epan/asn1.h>
#include <epan/tap.h>
#include <epan/uat.h>
+#include <epan/addr_resolv.h>
+#include <epan/follow.h>
#include <epan/exported_pdu.h>
#include <wsutil/str_util.h>
#include "packet-tcp.h"
@@ -451,6 +453,64 @@ ssl_parse_old_keys(void)
}
}
+
+static gboolean
+ssl_follow_tap_listener(void *tapdata, packet_info *pinfo, epan_dissect_t *edt _U_, const void *ssl)
+{
+ follow_info_t * follow_info = (follow_info_t*) tapdata;
+ SslDecryptedRecord * rec = NULL;
+ SslDataInfo * appl_data = NULL;
+ SslPacketInfo * pi = (SslPacketInfo*)ssl;
+ show_stream_t from = FROM_CLIENT;
+
+ /* Skip packets without decrypted payload data. */
+ if (!pi || !pi->appl_data) return FALSE;
+
+ /* Compute the packet's sender. */
+ if (follow_info->client_port == 0) {
+ follow_info->client_port = pinfo->srcport;
+ copy_address(&follow_info->client_ip, &pinfo->src);
+ }
+ if (addresses_equal(&follow_info->client_ip, &pinfo->src) &&
+ follow_info->client_port == pinfo->srcport) {
+ from = FROM_CLIENT;
+ } else {
+ from = FROM_SERVER;
+ }
+
+ for (appl_data = pi->appl_data; appl_data != NULL; appl_data = appl_data->next) {
+
+ /* TCP segments that contain the end of two or more SSL PDUs will be
+ queued to SSL taps for each of those PDUs. Therefore a single
+ packet could be processed by this SSL tap listener multiple times.
+ The following test handles that scenario by treating the
+ follow_info->bytes_written[] values as the next expected
+ appl_data->seq. Any appl_data instances that fall below that have
+ already been processed and must be skipped. */
+ if (appl_data->seq < follow_info->bytes_written[from]) continue;
+
+ /* Allocate a SslDecryptedRecord to hold the current appl_data
+ instance's decrypted data. Even though it would be possible to
+ consolidate multiple appl_data instances into a single rec, it is
+ beneficial to use a one-to-one mapping. This affords the Follow
+ Stream dialog view modes (ASCII, EBCDIC, Hex Dump, C Arrays, Raw)
+ the opportunity to accurately reflect SSL PDU boundaries. Currently
+ the Hex Dump view does by starting a new line, and the C Arrays
+ view does by starting a new array declaration. */
+ rec = (SslDecryptedRecord*) g_malloc(sizeof(SslDecryptedRecord) + appl_data->plain_data.data_len);
+ rec->is_from_server = from == FROM_SERVER;
+ rec->data.data = (guchar*) (rec + 1);
+ rec->data.data_len = appl_data->plain_data.data_len;
+ memcpy(rec->data.data, appl_data->plain_data.data, appl_data->plain_data.data_len);
+
+ /* Append the record to the follow_info structure. */
+ follow_info->payload = g_list_append(follow_info->payload, rec);
+ follow_info->bytes_written[from] += rec->data.data_len;
+ }
+
+ return FALSE;
+}
+
/*********************************************************************
*
* Forward Declarations
@@ -4068,6 +4128,9 @@ proto_register_ssl(void)
ssl_tap = register_tap("ssl");
ssl_debug_printf("proto_register_ssl: registered tap %s:%d\n",
"ssl", ssl_tap);
+
+ register_follow_stream(proto_ssl, "ssl", tcp_follow_conv_filter, tcp_follow_index_filter, tcp_follow_address_filter,
+ tcp_port_to_display, ssl_follow_tap_listener);
}
/* If this dissector uses sub-dissector registration add a registration
diff --git a/epan/dissectors/packet-tcp.c b/epan/dissectors/packet-tcp.c
index 2a47c773d6..0c7acf3526 100644
--- a/epan/dissectors/packet-tcp.c
+++ b/epan/dissectors/packet-tcp.c
@@ -745,6 +745,54 @@ tcp_build_filter(packet_info *pinfo)
return NULL;
}
+gchar* tcp_follow_conv_filter(packet_info* pinfo, int* stream)
+{
+ conversation_t *conv;
+ struct tcp_analysis *tcpd;
+
+ if (((pinfo->net_src.type == AT_IPv4 && pinfo->net_dst.type == AT_IPv4) ||
+ (pinfo->net_src.type == AT_IPv6 && pinfo->net_dst.type == AT_IPv6))
+ && (conv=find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
+ pinfo->srcport, pinfo->destport, 0)) != NULL )
+ {
+ /* TCP over IPv4/6 */
+ tcpd=get_tcp_conversation_data(conv, pinfo);
+ if (tcpd == NULL)
+ return NULL;
+
+ *stream = tcpd->stream;
+ return g_strdup_printf("tcp.stream eq %d", tcpd->stream);
+ }
+
+ return NULL;
+}
+
+gchar* tcp_follow_index_filter(int stream)
+{
+ return g_strdup_printf("tcp.stream eq %d", stream);
+}
+
+gchar* tcp_follow_address_filter(address* src_addr, address* dst_addr, int src_port, int dst_port)
+{
+ const gchar *ip_version = src_addr->type == AT_IPv6 ? "v6" : "";
+ gchar src_addr_str[MAX_IP6_STR_LEN];
+ gchar dst_addr_str[MAX_IP6_STR_LEN];
+
+ address_to_str_buf(src_addr, src_addr_str, sizeof(src_addr_str));
+ address_to_str_buf(dst_addr, dst_addr_str, sizeof(dst_addr_str));
+
+ return g_strdup_printf("((ip%s.src eq %s and tcp.srcport eq %d) and "
+ "(ip%s.dst eq %s and tcp.dstport eq %d))"
+ " or "
+ "((ip%s.src eq %s and tcp.srcport eq %d) and "
+ "(ip%s.dst eq %s and tcp.dstport eq %d))",
+ ip_version, src_addr_str, src_port,
+ ip_version, dst_addr_str, dst_port,
+ ip_version, dst_addr_str, dst_port,
+ ip_version, src_addr_str, src_port);
+
+}
+
/* TCP structs and definitions */
/* **************************************************************************
@@ -2265,7 +2313,7 @@ again:
/* Give the follow tap what we've currently dissected */
if(have_tap_listener(tcp_follow_tap)) {
- tap_queue_packet(tcp_follow_tap, pinfo, tvb_new_subset_length(tvb, 0, offset));
+ tap_queue_packet(tcp_follow_tap, pinfo, tvb_new_subset_remaining(tvb, offset));
}
process_tcp_payload(tvb, offset, pinfo, tree, tcp_tree,
@@ -6669,6 +6717,8 @@ proto_register_tcp(void)
&mptcp_analyze_mappings);
register_conversation_table(proto_mptcp, FALSE, mptcpip_conversation_packet, tcpip_hostlist_packet);
+ register_follow_stream(proto_tcp, "tcp_follow", tcp_follow_conv_filter, tcp_follow_index_filter, tcp_follow_address_filter,
+ tcp_port_to_display, follow_tvb_tap_listener);
}
void
diff --git a/epan/dissectors/packet-tcp.h b/epan/dissectors/packet-tcp.h
index 876a4b68ed..39009e00a9 100644
--- a/epan/dissectors/packet-tcp.h
+++ b/epan/dissectors/packet-tcp.h
@@ -424,6 +424,11 @@ WS_DLL_PUBLIC guint32 get_tcp_stream_count(void);
*/
WS_DLL_PUBLIC guint32 get_mptcp_stream_count(void);
+/* Follow Stream functionality shared with HTTP (and SSL?) */
+extern gchar* tcp_follow_conv_filter(packet_info* pinfo, int* stream);
+extern gchar* tcp_follow_index_filter(int stream);
+extern gchar* tcp_follow_address_filter(address* src_addr, address* dst_addr, int src_port, int dst_port);
+
#ifdef __cplusplus
}
#endif /* __cplusplus */
diff --git a/epan/dissectors/packet-udp.c b/epan/dissectors/packet-udp.c
index 4a1a6dbabe..cdda182c24 100644
--- a/epan/dissectors/packet-udp.c
+++ b/epan/dissectors/packet-udp.c
@@ -34,6 +34,7 @@
#include <epan/ipproto.h>
#include <epan/in_cksum.h>
#include <epan/prefs.h>
+#include <epan/follow.h>
#include <epan/expert.h>
#include <epan/exceptions.h>
#include <epan/show_exception.h>
@@ -400,6 +401,53 @@ udp_build_filter(packet_info *pinfo)
return NULL;
}
+static gchar* udp_follow_conv_filter(packet_info *pinfo, int* stream)
+{
+ conversation_t *conv;
+ struct udp_analysis *udpd;
+
+ if( ((pinfo->net_src.type == AT_IPv4 && pinfo->net_dst.type == AT_IPv4) ||
+ (pinfo->net_src.type == AT_IPv6 && pinfo->net_dst.type == AT_IPv6))
+ && (conv=find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
+ pinfo->srcport, pinfo->destport, 0)) != NULL )
+ {
+ /* UDP over IPv4/6 */
+ udpd=get_udp_conversation_data(conv, pinfo);
+ if (udpd == NULL)
+ return NULL;
+
+ *stream = udpd->stream;
+ return g_strdup_printf("udp.stream eq %d", udpd->stream);
+ }
+
+ return NULL;
+}
+
+static gchar* udp_follow_index_filter(int stream)
+{
+ return g_strdup_printf("udp.stream eq %d", stream);
+}
+
+static gchar* udp_follow_address_filter(address* src_addr, address* dst_addr, int src_port, int dst_port)
+{
+ const gchar *ip_version = src_addr->type == AT_IPv6 ? "v6" : "";
+ gchar src_addr_str[MAX_IP6_STR_LEN];
+ gchar dst_addr_str[MAX_IP6_STR_LEN];
+
+ address_to_str_buf(src_addr, src_addr_str, sizeof(src_addr_str));
+ address_to_str_buf(dst_addr, dst_addr_str, sizeof(dst_addr_str));
+
+ return g_strdup_printf("((ip%s.src eq %s and udp.srcport eq %d) and "
+ "(ip%s.dst eq %s and udp.dstport eq %d))"
+ " or "
+ "((ip%s.src eq %s and udp.srcport eq %d) and "
+ "(ip%s.dst eq %s and udp.dstport eq %d))",
+ ip_version, src_addr_str, src_port,
+ ip_version, dst_addr_str, dst_port,
+ ip_version, dst_addr_str, dst_port,
+ ip_version, src_addr_str, src_port);
+}
+
/* Attach process info to a flow */
/* XXX - We depend on the UDP dissector finding the conversation first */
@@ -1165,6 +1213,8 @@ proto_register_udp(void)
register_decode_as(&udp_da);
register_conversation_table(proto_udp, FALSE, udpip_conversation_packet, udpip_hostlist_packet);
register_conversation_filter("udp", "UDP", udp_filter_valid, udp_build_filter);
+ register_follow_stream(proto_udp, "udp_follow", udp_follow_conv_filter, udp_follow_index_filter, udp_follow_address_filter,
+ udp_port_to_display, follow_tvb_tap_listener);
register_init_routine(udp_init);
diff --git a/epan/follow.c b/epan/follow.c
index f8e23596dd..27e29fb67e 100644
--- a/epan/follow.c
+++ b/epan/follow.c
@@ -25,286 +25,177 @@
#include "config.h"
#include <stdlib.h>
-#include <stdio.h>
#include <string.h>
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
#include <glib.h>
#include <epan/packet.h>
-#include <epan/to_str.h>
-#include <epan/dissectors/packet-tcp.h>
-#include <epan/dissectors/packet-udp.h>
#include "follow.h"
-#include <epan/conversation.h>
#include <epan/tap.h>
-typedef struct _tcp_frag {
- guint32 seq;
- guint32 len;
- guint32 data_len;
- gchar *data;
- struct _tcp_frag *next;
-} tcp_frag;
-
-WS_DLL_PUBLIC_DEF
-FILE* data_out_file = NULL;
-
-gboolean empty_tcp_stream;
-gboolean incomplete_tcp_stream;
-
-static guint32 stream_to_follow[MAX_STREAM] = {0};
-static gboolean find_addr[MAX_STREAM] = {FALSE};
-static gboolean find_index[MAX_STREAM] = {FALSE};
-static address tcp_addr[2];
-static stream_addr ip_address[2];
-static guint port[2];
-static guint bytes_written[2];
-static gboolean is_ipv6 = FALSE;
+struct register_follow {
+ int proto_id; /* protocol id (0-indexed) */
+ const char* tap_listen_str; /* string used in register_tap_listener */
+ follow_conv_filter_func conv_filter; /* generate "conversation" filter to follow */
+ follow_index_filter_func index_filter; /* generate stream/index filter to follow */
+ follow_address_filter_func address_filter; /* generate address filter to follow */
+ follow_port_to_display_func port_to_display; /* port to name resolution for follow type */
+ follow_tap_func tap_handler; /* tap listener handler */
+};
-void
-follow_stats(follow_stats_t* stats)
+static GSList *registered_followers = NULL;
+
+static gint
+insert_sorted_by_name(gconstpointer aparam, gconstpointer bparam)
{
- int i;
+ const register_follow_t *a = (const register_follow_t *)aparam;
+ const register_follow_t *b = (const register_follow_t *)bparam;
- for (i = 0; i < 2 ; i++) {
- stats->ip_address[i] = ip_address[i];
- stats->port[i] = port[i];
- stats->bytes_written[i] = bytes_written[i];
- }
- stats->is_ipv6 = is_ipv6;
+ 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)));
}
-/* This will build a display filter text that will only
- pass the packets related to the stream. There is a
- chance that two streams could intersect, but not a
- very good one */
-gchar*
-build_follow_conv_filter( packet_info *pi, const char* append_filter ) {
- char* buf;
- int len;
- conversation_t *conv=NULL;
- struct tcp_analysis *tcpd;
- struct udp_analysis *udpd;
- wmem_list_frame_t* protos;
- int proto_id;
- const char* proto_name;
- gboolean is_tcp = FALSE, is_udp = FALSE;
-
- protos = wmem_list_head(pi->layers);
-
- /* walk the list of a available protocols in the packet to
- figure out if any of them affect context sensitivity */
- while (protos != NULL)
- {
- proto_id = GPOINTER_TO_INT(wmem_list_frame_data(protos));
- proto_name = proto_get_protocol_filter_name(proto_id);
-
- if (!strcmp(proto_name, "tcp")) {
- is_tcp = TRUE;
- } else if (!strcmp(proto_name, "udp")) {
- is_udp = TRUE;
- }
+void register_follow_stream(const int proto_id, const char* tap_listener,
+ follow_conv_filter_func conv_filter, follow_index_filter_func index_filter, follow_address_filter_func address_filter,
+ follow_port_to_display_func port_to_display, follow_tap_func tap_handler)
+{
+ register_follow_t *follower;
+ DISSECTOR_ASSERT(tap_listener);
+ DISSECTOR_ASSERT(conv_filter);
+ DISSECTOR_ASSERT(index_filter);
+ DISSECTOR_ASSERT(address_filter);
+ DISSECTOR_ASSERT(port_to_display);
+ DISSECTOR_ASSERT(tap_handler);
+
+ follower = g_new(register_follow_t,1);
+
+ follower->proto_id = proto_id;
+ follower->tap_listen_str = tap_listener;
+ follower->conv_filter = conv_filter;
+ follower->index_filter = index_filter;
+ follower->address_filter = address_filter;
+ follower->port_to_display = port_to_display;
+ follower->tap_handler = tap_handler;
+
+ registered_followers = g_slist_insert_sorted(registered_followers, follower, insert_sorted_by_name);
+}
- protos = wmem_list_frame_next(protos);
- }
+int get_follow_proto_id(register_follow_t* follower)
+{
+ if (follower == NULL)
+ return -1;
- if( ((pi->net_src.type == AT_IPv4 && pi->net_dst.type == AT_IPv4) ||
- (pi->net_src.type == AT_IPv6 && pi->net_dst.type == AT_IPv6))
- && is_tcp && (conv=find_conversation(pi->fd->num, &pi->src, &pi->dst, pi->ptype,
- pi->srcport, pi->destport, 0)) != NULL ) {
- /* TCP over IPv4/6 */
- tcpd=get_tcp_conversation_data(conv, pi);
- if (tcpd) {
- if (append_filter == NULL) {
- buf = g_strdup_printf("tcp.stream eq %d", tcpd->stream);
- } else {
- buf = g_strdup_printf("((tcp.stream eq %d) && (%s))", tcpd->stream, append_filter);
- }
- stream_to_follow[TCP_STREAM] = tcpd->stream;
- if (pi->net_src.type == AT_IPv4) {
- len = 4;
- is_ipv6 = FALSE;
- } else {
- len = 16;
- is_ipv6 = TRUE;
- }
- } else {
- return NULL;
- }
- }
- else if( ((pi->net_src.type == AT_IPv4 && pi->net_dst.type == AT_IPv4) ||
- (pi->net_src.type == AT_IPv6 && pi->net_dst.type == AT_IPv6))
- && is_udp && (conv=find_conversation(pi->fd->num, &pi->src, &pi->dst, pi->ptype,
- pi->srcport, pi->destport, 0)) != NULL ) {
- /* UDP over IPv4/6 */
- udpd=get_udp_conversation_data(conv, pi);
- if (udpd) {
- if (append_filter == NULL) {
- buf = g_strdup_printf("udp.stream eq %d", udpd->stream);
- } else {
- buf = g_strdup_printf("((udp.stream eq %d) && (%s))", udpd->stream, append_filter);
- }
- stream_to_follow[UDP_STREAM] = udpd->stream;
- if (pi->net_src.type == AT_IPv4) {
- len = 4;
- is_ipv6 = FALSE;
- } else {
- len = 16;
- is_ipv6 = TRUE;
- }
- } else {
- return NULL;
- }
- }
- else {
- return NULL;
- }
- memcpy(&ip_address[0], pi->net_src.data, len);
- memcpy(&ip_address[1], pi->net_dst.data, len);
- port[0] = pi->srcport;
- port[1] = pi->destport;
- return buf;
+ return follower->proto_id;
}
-static gboolean
-udp_follow_packet(void *tapdata _U_, packet_info *pinfo,
- epan_dissect_t *edt _U_, const void *data _U_)
+const char* get_follow_tap_string(register_follow_t* follower)
{
- if (find_addr[UDP_STREAM]) {
- if (pinfo->net_src.type == AT_IPv6) {
- is_ipv6 = TRUE;
- } else {
- is_ipv6 = FALSE;
- }
- memcpy(&ip_address[0], pinfo->net_src.data, pinfo->net_src.len);
- memcpy(&ip_address[1], pinfo->net_dst.data, pinfo->net_dst.len);
- port[0] = pinfo->srcport;
- port[1] = pinfo->destport;
- find_addr[UDP_STREAM] = FALSE;
- }
+ if (follower == NULL)
+ return "";
- return FALSE;
+ return follower->tap_listen_str;
}
+follow_conv_filter_func get_follow_conv_func(register_follow_t* follower)
+{
+ return follower->conv_filter;
+}
-/* here we are going to try and reconstruct the data portion of a TCP
- session. We will try and handle duplicates, TCP fragments, and out
- of order packets in a smart way. */
+follow_index_filter_func get_follow_index_func(register_follow_t* follower)
+{
+ return follower->index_filter;
+}
-static tcp_frag *frags[2] = { 0, 0 };
-static guint32 seq[2];
-static stream_addr src_addr[2];
-static guint src_port[2] = { 0, 0 };
+follow_address_filter_func get_follow_address_func(register_follow_t* follower)
+{
+ return follower->address_filter;
+}
-void
-reset_stream_follow(stream_type stream) {
- tcp_frag *current, *next;
- int i;
-
- remove_tap_listener(&stream_to_follow[stream]);
- find_addr[stream] = FALSE;
- find_index[stream] = FALSE;
- if (stream == TCP_STREAM) {
- empty_tcp_stream = TRUE;
- incomplete_tcp_stream = FALSE;
-
- for( i=0; i<2; i++ ) {
- seq[i] = 0;
- memset(&src_addr[i], 0, sizeof(src_addr[i]));
- src_port[i] = 0;
- memset(&ip_address[i], 0, sizeof(src_addr[i]));
- port[i] = 0;
- bytes_written[i] = 0;
- current = frags[i];
- while( current ) {
- next = current->next;
- g_free( current->data );
- g_free( current );
- current = next;
- }
- frags[i] = NULL;
- }
- }
+follow_port_to_display_func get_follow_port_to_display(register_follow_t* follower)
+{
+ return follower->port_to_display;
}
-gchar*
-build_follow_index_filter(stream_type stream) {
- gchar *buf;
-
- find_addr[stream] = TRUE;
- if (stream == TCP_STREAM) {
- buf = g_strdup_printf("tcp.stream eq %d", stream_to_follow[TCP_STREAM]);
- } else {
- GString * error_string;
- buf = g_strdup_printf("udp.stream eq %d", stream_to_follow[UDP_STREAM]);
- error_string = register_tap_listener("udp_follow", &stream_to_follow[UDP_STREAM], buf, 0, NULL, udp_follow_packet, NULL);
- if (error_string) {
- g_string_free(error_string, TRUE);
- }
- }
- return buf;
+follow_tap_func get_follow_tap_handler(register_follow_t* follower)
+{
+ return follower->tap_handler;
}
-/* select a tcp stream to follow via it's address/port pairs */
-gboolean
-follow_addr(stream_type stream, const address *addr0, guint port0,
- const address *addr1, guint port1)
+
+register_follow_t* get_follow_by_name(const char* proto_short_name)
{
- if (addr0 == NULL || addr1 == NULL || addr0->type != addr1->type ||
- port0 > G_MAXUINT16 || port1 > G_MAXUINT16 ) {
- return FALSE;
- }
+ guint i, size = g_slist_length(registered_followers);
+ register_follow_t *follower;
+ GSList *slist;
- if (find_index[stream] || find_addr[stream]) {
- return FALSE;
- }
+ for (i = 0; i < size; i++) {
+ slist = g_slist_nth(registered_followers, i);
+ follower = (register_follow_t*)slist->data;
- switch (addr0->type) {
- default:
- return FALSE;
- case AT_IPv4:
- case AT_IPv6:
- is_ipv6 = addr0->type == AT_IPv6;
- break;
+ if (strcmp(proto_short_name, proto_get_protocol_short_name(find_protocol_by_id(follower->proto_id))) == 0)
+ return follower;
}
+ return NULL;
+}
- memcpy(&ip_address[0], addr0->data, addr0->len);
- port[0] = port0;
-
- memcpy(&ip_address[1], addr1->data, addr1->len);
- port[1] = port1;
+void follow_iterate_followers(GFunc func, gpointer user_data)
+{
+ g_slist_foreach(registered_followers, func, user_data);
+}
- if (stream == TCP_STREAM) {
- find_index[TCP_STREAM] = TRUE;
- set_address(&tcp_addr[0], addr0->type, addr0->len, &ip_address[0]);
- set_address(&tcp_addr[1], addr1->type, addr1->len, &ip_address[1]);
- }
+gchar* follow_get_stat_tap_string(register_follow_t* follower)
+{
+ GString *cmd_str = g_string_new("follow,");
+ g_string_append(cmd_str, proto_get_protocol_filter_name(follower->proto_id));
+ return g_string_free(cmd_str, FALSE);
+}
- return TRUE;
+/* here we are going to try and reconstruct the data portion of a TCP
+ session. We will try and handle duplicates, TCP fragments, and out
+ of order packets in a smart way. */
+void
+follow_reset_stream(follow_info_t* info)
+{
+ info->bytes_written[0] = info->bytes_written[1] = 0;
+ info->client_port = 0;
+ info->server_port = 0;
+ info->client_ip.type = FT_NONE;
+ info->client_ip.len = 0;
+ info->server_ip.type = FT_NONE;
+ info->server_ip.len = 0;
}
-/* select a stream to follow via its index */
gboolean
-follow_index(stream_type stream, guint32 indx)
+follow_tvb_tap_listener(void *tapdata, packet_info *pinfo,
+ epan_dissect_t *edt _U_, const void *data)
{
- if (find_index[stream] || find_addr[stream]) {
- return FALSE;
- }
+ follow_record_t *follow_record;
+ follow_info_t *follow_info = (follow_info_t *)tapdata;
+ tvbuff_t *next_tvb = (tvbuff_t *)data;
+
+ follow_record = g_new(follow_record_t,1);
+
+ follow_record->data = g_byte_array_sized_new(tvb_captured_length(next_tvb));
+ follow_record->data = g_byte_array_append(follow_record->data,
+ tvb_get_ptr(next_tvb, 0, -1),
+ tvb_captured_length(next_tvb));
+
+ if (follow_info->client_port == 0) {
+ follow_info->client_port = pinfo->srcport;
+ copy_address(&follow_info->client_ip, &pinfo->src);
+ follow_info->server_port = pinfo->destport;
+ copy_address(&follow_info->server_ip, &pinfo->dst);
+ }
- find_addr[stream] = TRUE;
- stream_to_follow[stream] = indx;
- memset(ip_address, 0, sizeof ip_address);
- port[0] = port[1] = 0;
+ if (addresses_equal(&follow_info->client_ip, &pinfo->src) && follow_info->client_port == pinfo->srcport)
+ follow_record->is_server = FALSE;
+ else
+ follow_record->is_server = TRUE;
- return TRUE;
-}
+ /* update stream counter */
+ follow_info->bytes_written[follow_record->is_server] += follow_record->data->len;
-guint32
-get_follow_index(stream_type stream) {
- return stream_to_follow[stream];
+ follow_info->payload = g_list_append(follow_info->payload, follow_record);
+ return FALSE;
}
/*
diff --git a/epan/follow.h b/epan/follow.h
index e12be69253..2c9d237b9f 100644
--- a/epan/follow.h
+++ b/epan/follow.h
@@ -29,6 +29,7 @@
extern "C" {
#endif /* __cplusplus */
+#include <epan/epan.h>
#include <epan/packet.h>
#include <epan/ipv6.h>
#include "ws_symbol_export.h"
@@ -39,73 +40,165 @@ typedef enum {
MAX_STREAM
} stream_type;
+typedef enum {
+ FRS_OK,
+ FRS_OPEN_ERROR,
+ FRS_READ_ERROR,
+ FRS_PRINT_ERROR
+} frs_return_t;
+
+/* Type of follow we are doing */
+typedef enum {
+ FOLLOW_TCP,
+ FOLLOW_SSL,
+ FOLLOW_UDP,
+ FOLLOW_HTTP
+} follow_type_t;
+
+/* Show Type */
+typedef enum {
+ SHOW_ASCII,
+ SHOW_EBCDIC,
+ SHOW_HEXDUMP,
+ SHOW_CARRAY,
+ SHOW_RAW,
+ SHOW_YAML,
+ SHOW_UTF8
+} show_type_t;
+
+
+/* Show Stream */
+typedef enum {
+ FROM_CLIENT,
+ FROM_SERVER,
+ BOTH_HOSTS
+} show_stream_t;
+
typedef union _stream_addr {
guint32 ipv4;
struct e_in6_addr ipv6;
} stream_addr;
-/* With MSVC and a libwireshark.dll, we need a special declaration. */
-WS_DLL_PUBLIC gboolean empty_tcp_stream;
-WS_DLL_PUBLIC gboolean incomplete_tcp_stream;
+struct _follow_info;
-typedef struct _tcp_stream_chunk {
- stream_addr src_addr;
- guint16 src_port;
- guint32 dlen;
- guint32 packet_num;
-} tcp_stream_chunk;
+typedef gboolean (*follow_print_line_func)(char *, size_t, gboolean, void *);
+typedef frs_return_t (*follow_read_stream_func)(struct _follow_info *follow_info, follow_print_line_func follow_print, void *arg);
+
+typedef struct {
+ gboolean is_server;
+ guint32 packet_num;
+ GByteArray *data;
+} follow_record_t;
+
+typedef struct _follow_info {
+ show_stream_t show_stream;
+ char *filter_out_filter;
+ GList *payload;
+ guint bytes_written[2]; /* Index with FROM_CLIENT or FROM_SERVER for readability. */
+ guint client_port;
+ guint server_port;
+ address client_ip;
+ address server_ip;
+ void* gui_data;
+} follow_info_t;
+
+struct register_follow;
+typedef struct register_follow register_follow_t;
+
+typedef gchar* (*follow_conv_filter_func)(packet_info* pinfo, int* stream);
+typedef gchar* (*follow_index_filter_func)(int stream);
+typedef gchar* (*follow_address_filter_func)(address* src_addr, address* dst_addr, int src_port, int dst_port);
+typedef gchar* (*follow_port_to_display_func)(wmem_allocator_t *allocator, guint port);
+typedef gboolean (*follow_tap_func)(void *tapdata, packet_info *pinfo, epan_dissect_t *edt, const void *data);
-/** Build a follow filter based on the current packet's conversation.
+WS_DLL_PUBLIC
+void register_follow_stream(const int proto_id, const char* tap_listener,
+ follow_conv_filter_func conv_filter, follow_index_filter_func index_filter, follow_address_filter_func address_filter,
+ follow_port_to_display_func port_to_display, follow_tap_func tap_handler);
+
+/** Get protocol ID from registered follower
*
- * @param packet_info [in] The current packet.
- * @param append_filter [in] Optional filter to && (AND) to generated one.
- * @return A filter that specifies the conversation. Must be g_free()d
- * the caller.
+ * @param follower Registered follower
+ * @return protocol id of follower
*/
-WS_DLL_PUBLIC
-gchar* build_follow_conv_filter( packet_info * packet_info, const char* append_filter);
+WS_DLL_PUBLIC int get_follow_proto_id(register_follow_t* follower);
-/** Build a follow filter based on the current TCP/UDP stream index.
- * follow_index() must be called prior to calling this.
+/** Get tap name string from registered follower (used for register_tap_listener)
*
- * @return A filter that specifies the current stream. Must be g_free()d
- * the caller.
+ * @param follower Registered follower
+ * @return tap name string of follower
*/
-WS_DLL_PUBLIC
-gchar* build_follow_index_filter(stream_type stream);
+WS_DLL_PUBLIC const char* get_follow_tap_string(register_follow_t* follower);
-WS_DLL_PUBLIC
-gboolean follow_addr(stream_type, const address *, guint, const address *, guint );
+/** Get a registered follower by protocol short name
+ *
+ * @param proto_short_name Protocol short name
+ * @return tap registered follower if match, otherwise NULL
+ */
+WS_DLL_PUBLIC register_follow_t* get_follow_by_name(const char* proto_short_name);
-/** Select a TCP/UDP stream to follow via its index.
+/** Provide function that builds a follow filter based on the current packet's conversation.
*
- * @param stream [in] The stream type to follow(TCP_STREAM or UDP_STREAM)
- * @param addr [in] The stream index to follow.
- * @return TRUE on success, FALSE on failure.
+ * @param follower [in] Registered follower
+ * @return A filter function handler
*/
-WS_DLL_PUBLIC
-gboolean follow_index(stream_type stream, guint32 addr);
+WS_DLL_PUBLIC follow_conv_filter_func get_follow_conv_func(register_follow_t* follower);
-/** Get the current TCP/UDP index being followed.
+/** Provide function that builds a follow filter based on stream.
*
- * @return The current TCP/UDP index. The behavior is undefined
- * if no TCP/UDP stream is being followed.
+ * @param follower [in] Registered follower
+ * @return A filter function handler
*/
-WS_DLL_PUBLIC
-guint32 get_follow_index(stream_type stream);
+WS_DLL_PUBLIC follow_index_filter_func get_follow_index_func(register_follow_t* follower);
-WS_DLL_PUBLIC
-void reset_stream_follow(stream_type stream);
+/** Provide function that builds a follow filter based on address/port pairs.
+ *
+ * @param follower [in] Registered follower
+ * @return A filter function handler
+ */
+WS_DLL_PUBLIC follow_address_filter_func get_follow_address_func(register_follow_t* follower);
-typedef struct {
- stream_addr ip_address[2];
- guint32 port[2];
- guint bytes_written[2];
- gboolean is_ipv6;
-} follow_stats_t;
+/** Provide function that resolves port number to name based on follower.
+ *
+ * @param follower [in] Registered follower
+ * @return A port resolver function handler
+ */
+WS_DLL_PUBLIC follow_port_to_display_func get_follow_port_to_display(register_follow_t* follower);
-WS_DLL_PUBLIC
-void follow_stats(follow_stats_t* stats);
+/** Provide function that handles tap data (tap_packet_cb parameter of register_tap_listener)
+ *
+ * @param follower [in] Registered follower
+ * @return A tap data handler
+ */
+WS_DLL_PUBLIC follow_tap_func get_follow_tap_handler(register_follow_t* follower);
+
+
+/** Tap function handler when dissector's tap provides follow data as a tvb.
+ * Used by TCP, UDP and HTTP followers
+ */
+WS_DLL_PUBLIC gboolean
+follow_tvb_tap_listener(void *tapdata, packet_info *pinfo, epan_dissect_t *edt _U_, const void *data);
+
+/** Interator to walk all registered followers and execute func
+ *
+ * @param func action to be performed on all converation tables
+ * @param user_data any data needed to help perform function
+ */
+WS_DLL_PUBLIC void follow_iterate_followers(GFunc func, gpointer user_data);
+
+/** Generate -z stat (tap) name for a follower
+ * Currently used only by TShark
+ *
+ * @param follower [in] Registered follower
+ * @return A tap data handler
+ */
+WS_DLL_PUBLIC gchar* follow_get_stat_tap_string(register_follow_t* follower);
+
+/** Clear counters, addresses and ports of follow_info_t
+ *
+ * @param info [in] follower info
+ */
+WS_DLL_PUBLIC void follow_reset_stream(follow_info_t* info);
#ifdef __cplusplus
}
diff --git a/epan/to_str.h b/epan/to_str.h
index 20993eab6d..f8b16ff3b6 100644
--- a/epan/to_str.h
+++ b/epan/to_str.h
@@ -63,7 +63,7 @@ WS_DLL_PUBLIC gchar* tvb_address_with_resolution_to_str(wmem_allocator_t *scope,
*
* Otherwise, it returns NULL.
*/
-const gchar *address_to_name(const address *addr);
+WS_DLL_PUBLIC const gchar *address_to_name(const address *addr);
/*
* address_to_display takes as input an "address", as defined in address.h .
diff --git a/ui/Makefile.common b/ui/Makefile.common
index a4c689f773..94d33c3029 100644
--- a/ui/Makefile.common
+++ b/ui/Makefile.common
@@ -93,7 +93,6 @@ noinst_HEADERS = \
last_open_dir.h \
file_dialog.h \
filters.h \
- follow.h \
help_url.h \
packet_list_utils.h \
iface_lists.h \
diff --git a/ui/cli/tap-follow.c b/ui/cli/tap-follow.c
index ae757261af..3d69a19f8d 100644
--- a/ui/cli/tap-follow.c
+++ b/ui/cli/tap-follow.c
@@ -33,107 +33,53 @@
#include <glib.h>
#include <epan/addr_resolv.h>
#include <epan/charsets.h>
-#include <epan/epan_dissect.h>
#include <epan/follow.h>
#include <epan/stat_tap_ui.h>
#include <epan/tap.h>
-#include <epan/tvbuff-int.h>
-
-#include "wsutil/file_util.h"
-#include "wsutil/tempfile.h"
-
-#ifdef SSL_PLUGIN
-#include "packet-ssl-utils.h"
-#else
-#include <epan/dissectors/packet-ssl-utils.h>
-#endif
void register_tap_listener_follow(void);
-WS_DLL_PUBLIC FILE *data_out_file;
-
-typedef enum
-{
- type_TCP,
- type_UDP,
- type_SSL
-} type_e;
-
-typedef enum
-{
- mode_HEX,
- mode_ASCII,
- mode_EBCDIC,
- mode_RAW
-} mode_e;
+typedef struct _cli_follow_info {
+ show_type_t show_type;
+ register_follow_t* follower;
-typedef struct
-{
- type_e type;
- mode_e mode;
+ /* range */
+ guint32 chunkMin;
+ guint32 chunkMax;
/* filter */
- guint32 stream_index;
- address addr[2];
+ int stream_index;
int port[2];
+ address addr[2];
guint8 addrBuf[2][16];
- /* range */
- guint32 chunkMin;
- guint32 chunkMax;
+} cli_follow_info_t;
- /* stream chunk file */
- FILE *filep;
- gchar *filenamep;
-} follow_t;
#define STR_FOLLOW "follow,"
-#define STR_FOLLOW_TCP STR_FOLLOW "tcp"
-#define STR_FOLLOW_UDP STR_FOLLOW "udp"
-#define STR_FOLLOW_SSL STR_FOLLOW "ssl"
#define STR_HEX ",hex"
#define STR_ASCII ",ascii"
#define STR_EBCDIC ",ebcdic"
#define STR_RAW ",raw"
-static void
-followExit(
- const char *strp
- )
+static void follow_exit(const char *strp)
{
fprintf(stderr, "tshark: follow - %s\n", strp);
exit(1);
}
-static const char *
-followStrType(
- const follow_t *fp
- )
+static const char * follow_str_type(cli_follow_info_t* cli_follow_info)
{
- switch (fp->type)
+ switch (cli_follow_info->show_type)
{
- case type_TCP: return "tcp";
- case type_UDP: return "udp";
- case type_SSL: return "ssl";
- }
-
- g_assert_not_reached();
-
- return "<unknown-type>";
-}
-
-static const char *
-followStrMode(
- const follow_t *fp
- )
-{
- switch (fp->mode)
- {
- case mode_HEX: return "hex";
- case mode_ASCII: return "ascii";
- case mode_EBCDIC: return "ebcdic";
- case mode_RAW: return "raw";
+ case SHOW_HEXDUMP: return "hex";
+ case SHOW_ASCII: return "ascii";
+ case SHOW_EBCDIC: return "ebcdic";
+ case SHOW_RAW: return "raw";
+ default:
+ g_assert_not_reached();
+ break;
}
g_assert_not_reached();
@@ -141,305 +87,30 @@ followStrMode(
return "<unknown-mode>";
}
-static const char *
-followStrFilter(
- const follow_t *fp
- )
-{
- static char filter[512];
- int len = 0;
- const gchar *verp;
- gchar *udpfilter;
- gchar ip0[MAX_IP6_STR_LEN];
- gchar ip1[MAX_IP6_STR_LEN];
-
- if (fp->stream_index != G_MAXUINT32)
- {
- switch (fp->type)
- {
- case type_TCP:
- case type_SSL:
- len = g_snprintf(filter, sizeof filter,
- "tcp.stream eq %d", fp->stream_index);
- break;
- case type_UDP:
- udpfilter = build_follow_index_filter(UDP_STREAM);
- len = g_snprintf(filter, sizeof filter,
- "%s", udpfilter);
- g_free(udpfilter);
- break;
- }
- }
- else
- {
- verp = fp->addr[0].type == AT_IPv6 ? "v6" : "";
- address_to_str_buf(&fp->addr[0], ip0, sizeof ip0);
- address_to_str_buf(&fp->addr[1], ip1, sizeof ip1);
-
- switch (fp->type)
- {
- case type_TCP:
- len = g_snprintf(filter, sizeof filter,
- "((ip%s.src eq %s and tcp.srcport eq %d) and "
- "(ip%s.dst eq %s and tcp.dstport eq %d))"
- " or "
- "((ip%s.src eq %s and tcp.srcport eq %d) and "
- "(ip%s.dst eq %s and tcp.dstport eq %d))",
- verp, ip0, fp->port[0],
- verp, ip1, fp->port[1],
- verp, ip1, fp->port[1],
- verp, ip0, fp->port[0]);
- break;
- case type_UDP:
- len = g_snprintf(filter, sizeof filter,
- "((ip%s.src eq %s and udp.srcport eq %d) and "
- "(ip%s.dst eq %s and udp.dstport eq %d))"
- " or "
- "((ip%s.src eq %s and udp.srcport eq %d) and "
- "(ip%s.dst eq %s and udp.dstport eq %d))",
- verp, ip0, fp->port[0],
- verp, ip1, fp->port[1],
- verp, ip1, fp->port[1],
- verp, ip0, fp->port[0]);
- break;
- case type_SSL:
- break;
- }
- }
-
- if (len == 0)
- {
- followExit("Don't know how to create filter.");
- }
-
- if (len == sizeof filter)
- {
- followExit("Filter buffer overflow.");
- }
-
- return filter;
-}
-
-static void
-followFileClose(
- follow_t *fp
- )
-{
- if (fp->filep != NULL)
- {
- fclose(fp->filep);
- fp->filep = NULL;
- if (fp->type == type_TCP)
- {
- data_out_file = NULL;
- }
- }
-
- if (fp->filenamep != NULL)
- {
- ws_unlink(fp->filenamep);
- g_free(fp->filenamep);
- fp->filenamep = NULL;
- }
-}
-
static void
-followFileOpen(
- follow_t *fp
- )
+follow_free(follow_info_t *follow_info)
{
- int fd;
- char *tempfilep;
-
- if (fp->type == type_TCP && data_out_file != NULL)
- {
- followExit("Only one TCP stream can be followed at a time.");
- }
-
- followFileClose(fp);
-
- fd = create_tempfile(&tempfilep, "follow");
- if (fd == -1)
- {
- followExit("Error creating temp file.");
- }
-
- fp->filenamep = g_strdup(tempfilep);
- if (fp->filenamep == NULL)
- {
- ws_close(fd);
- ws_unlink(tempfilep);
- followExit("Error duping temp file name.");
- }
-
- fp->filep = ws_fdopen(fd, "w+b");
- if (fp->filep == NULL)
- {
- ws_close(fd);
- ws_unlink(fp->filenamep);
- g_free(fp->filenamep);
- fp->filenamep = NULL;
- followExit("Error opening temp file stream.");
- }
-
- if (fp->type == type_TCP)
- {
- data_out_file = fp->filep;
- }
-}
-
-static follow_t *
-followAlloc(
- type_e type
- )
-{
- follow_t *fp;
-
- fp = (follow_t *)g_malloc0(sizeof *fp);
-
- fp->type = type;
- set_address(&fp->addr[0], AT_NONE, 0, fp->addrBuf[0]);
- set_address(&fp->addr[1], AT_NONE, 0, fp->addrBuf[1]);
-
- return fp;
-}
-
-static void
-followFree(
- follow_t *fp
- )
-{
- followFileClose(fp);
- g_free(fp);
-}
-
-static int
-follow_common_stream_packet(
- void *contextp,
- packet_info *pip,
- epan_dissect_t *edp _U_,
- const void *datap
- )
-{
- follow_t *fp = (follow_t *)contextp;
- const tvbuff_t *tvbp = (const tvbuff_t *)datap;
- tcp_stream_chunk sc;
- size_t size;
-
- if (tvbp->length > 0)
- {
- memcpy(&sc.src_addr, pip->net_src.data, pip->net_src.len);
- sc.src_port = pip->srcport;
- sc.dlen = tvbp->length;
- sc.packet_num = pip->fd->num;
-
- size = fwrite(&sc, 1, sizeof sc, fp->filep);
- if (sizeof sc != size)
- {
- followExit("Error writing stream chunk header.");
- }
-
- size = fwrite(tvbp->real_data, 1, sc.dlen, fp->filep);
- if (sc.dlen != size)
- {
- followExit("Error writing stream chunk data.");
- }
- }
-
- return 0;
-}
-
-static int
-followSslPacket(
- void *contextp,
- packet_info *pip,
- epan_dissect_t *edp _U_,
- const void *datap
- )
-{
- follow_t *fp = (follow_t *)contextp;
- SslPacketInfo *spip = (SslPacketInfo *)datap;
- SslDataInfo *sdip;
- gint length;
- tcp_stream_chunk sc;
- size_t size;
-
- if (spip == NULL)
- {
- return 0;
- }
-
- if (fp->addr[0].type == AT_NONE)
- {
- memcpy(fp->addrBuf[0], pip->net_src.data, pip->net_src.len);
- set_address(&fp->addr[0], pip->net_src.type, pip->net_src.len,
- fp->addrBuf[0]);
- fp->port[0] = pip->srcport;
-
- memcpy(fp->addrBuf[1], pip->net_dst.data, pip->net_dst.len);
- set_address(&fp->addr[1], pip->net_dst.type, pip->net_dst.len,
- fp->addrBuf[1]);
- fp->port[1] = pip->destport;
- }
-
- /* total length */
- for (length = 0, sdip = spip->appl_data; sdip != NULL; sdip = sdip->next)
- {
- length += sdip->plain_data.data_len;
- }
-
-
- if (length > 0)
- {
- memcpy(&sc.src_addr, pip->net_src.data, pip->net_src.len);
- sc.src_port = pip->srcport;
- sc.dlen = length;
- sc.packet_num = pip->fd->num;
-
- size = fwrite(&sc, 1, sizeof sc, fp->filep);
- if (sizeof sc != size)
- {
- followExit("Error writing stream chunk header.");
- }
-
- for (sdip = spip->appl_data; sdip != NULL; sdip = sdip->next)
- {
- if (sdip->plain_data.data_len > 0)
- {
- size = fwrite(sdip->plain_data.data, 1, sdip->plain_data.data_len,
- fp->filep);
- if (sdip->plain_data.data_len != size)
- {
- followExit("Error writing stream chunk data.");
- }
- }
- }
- }
+ cli_follow_info_t* cli_follow_info = (cli_follow_info_t*)follow_info->gui_data;
- return 0;
+ g_free(cli_follow_info);
+ g_free(follow_info->filter_out_filter);
+ g_free(follow_info);
}
#define BYTES_PER_LINE 16
-#define OFFSET_START 0
#define OFFSET_LEN 8
#define OFFSET_SPACE 2
-#define HEX_START (OFFSET_START + OFFSET_LEN + OFFSET_SPACE)
+#define HEX_START (OFFSET_LEN + OFFSET_SPACE)
#define HEX_LEN (BYTES_PER_LINE * 3) /* extra space at column 8 */
#define HEX_SPACE 2
#define ASCII_START (HEX_START + HEX_LEN + HEX_SPACE)
#define ASCII_LEN (BYTES_PER_LINE + 1) /* extra space at column 8 */
-#define ASCII_SPACE 0
-#define LINE_LEN (ASCII_START + ASCII_LEN + ASCII_SPACE)
+#define LINE_LEN (ASCII_START + ASCII_LEN)
static const char bin2hex[] = {'0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
-static void
-followPrintHex(
- const char *prefixp,
- guint32 offset,
- void *datap,
- int len
- )
+
+static void follow_print_hex(const char *prefixp, guint32 offset, void *datap, int len)
{
int ii;
int jj;
@@ -492,248 +163,135 @@ followPrintHex(
}
}
-static void
-followDraw(
- void *contextp
- )
+static void follow_draw(void *contextp)
{
static const char separator[] =
"===================================================================\n";
- follow_t *fp = (follow_t *)contextp;
- tcp_stream_chunk sc;
- int node;
- const address *addr[2];
- int port[2];
+ follow_info_t *follow_info = (follow_info_t*)contextp;
+ cli_follow_info_t* cli_follow_info = (cli_follow_info_t*)follow_info->gui_data;
gchar buf[MAX_IP6_STR_LEN];
- guint32 ii;
- guint32 jj;
- guint32 len;
- guint32 chunk;
- guint32 offset[2];
- guint8 bin[4096];
- char data[(sizeof bin * 2) + 2];
+ guint32 global_client_pos = 0, global_server_pos = 0;
+ guint32 *global_pos;
+ guint32 ii, jj;
+ char *buffer;
+ GList *cur;
+ follow_record_t *follow_record;
+ guint chunk;
- g_assert(sizeof bin % BYTES_PER_LINE == 0);
+ printf("\n%s", separator);
+ printf("Follow: %s,%s\n", proto_get_protocol_filter_name(get_follow_proto_id(cli_follow_info->follower)), follow_str_type(cli_follow_info));
+ printf("Filter: %s\n", follow_info->filter_out_filter);
- if ((fp->type == type_TCP) || (fp->type == type_UDP))
- {
- static const stream_addr ip_zero = {0};
- follow_stats_t stats;
- address_type type;
+ address_to_str_buf(&follow_info->client_ip, buf, sizeof buf);
+ if (follow_info->client_ip.type == AT_IPv6)
+ printf("Node 0: [%s]:%d\n", buf, follow_info->client_port);
+ else
+ printf("Node 0: %s:%d\n", buf, follow_info->client_port);
- follow_stats(&stats);
+ address_to_str_buf(&follow_info->server_ip, buf, sizeof buf);
+ if (follow_info->client_ip.type == AT_IPv6)
+ printf("Node 1: [%s]:%d\n", buf, follow_info->server_port);
+ else
+ printf("Node 1: %s:%d\n", buf, follow_info->server_port);
- if (stats.port[0] == 0 && stats.port[1] == 0 &&
- memcmp(&stats.ip_address[0], &ip_zero, sizeof ip_zero) == 0 &&
- memcmp(&stats.ip_address[1], &ip_zero, sizeof ip_zero) == 0)
- {
- type = AT_NONE;
- len = 0;
- }
- else if (stats.is_ipv6)
- {
- type = AT_IPv6;
- len = 16;
- }
- else
- {
- type = AT_IPv4;
- len = 4;
+ for (cur = follow_info->payload, chunk = 0;
+ cur != NULL;
+ cur = g_list_next(cur), chunk++)
+ {
+ follow_record = (follow_record_t *)cur->data;
+ if (!follow_record->is_server) {
+ global_pos = &global_client_pos;
+ } else {
+ global_pos = &global_server_pos;
}
- for (node = 0; node < 2; node++)
- {
- memcpy(fp->addrBuf[node], &stats.ip_address[node], len);
- set_address(&fp->addr[node], type, len, fp->addrBuf[node]);
- fp->port[node] = stats.port[node];
+ /* ignore chunks not in range */
+ if ((chunk < cli_follow_info->chunkMin) || (chunk > cli_follow_info->chunkMax)) {
+ (*global_pos) += follow_record->data->len;
+ continue;
}
- }
- /* find first stream chunk */
- rewind(fp->filep);
- for (chunk = 0;;)
- {
- len = (guint32)fread(&sc, 1, sizeof sc, fp->filep);
- if (len != sizeof sc)
+ switch (cli_follow_info->show_type)
{
- /* no data */
- sc.dlen = 0;
- memcpy(&sc.src_addr, fp->addr[0].data, fp->addr[0].len) ;
- sc.src_port = fp->port[0];
+ case SHOW_HEXDUMP:
break;
- }
- if (sc.dlen > 0)
- {
- chunk++;
- break;
- }
- }
-
- /* node 0 is source of first chunk with data */
- if (memcmp(&sc.src_addr, fp->addr[0].data, fp->addr[0].len) == 0 &&
- sc.src_port == fp->port[0])
- {
- addr[0] = &fp->addr[0];
- port[0] = fp->port[0];
- addr[1] = &fp->addr[1];
- port[1] = fp->port[1];
- }
- else
- {
- addr[0] = &fp->addr[1];
- port[0] = fp->port[1];
- addr[1] = &fp->addr[0];
- port[1] = fp->port[0];
- }
-
- printf("\n%s", separator);
- printf("Follow: %s,%s\n", followStrType(fp), followStrMode(fp));
- printf("Filter: %s\n", followStrFilter(fp));
- for (node = 0; node < 2; node++)
- {
- address_to_str_buf(addr[node], buf, sizeof buf);
- if (addr[node]->type == AT_IPv6)
- {
- printf("Node %d: [%s]:%d\n", node, buf, port[node]);
- }
- else
- {
- printf("Node %d: %s:%d\n", node, buf, port[node]);
- }
- }
-
- offset[0] = offset[1] = 0;
-
- while (chunk <= fp->chunkMax)
- {
- node = (memcmp(addr[0]->data, &sc.src_addr, addr[0]->len) == 0 &&
- port[0] == sc.src_port) ? 0 : 1;
+ case SHOW_ASCII:
+ case SHOW_EBCDIC:
+ printf("%s%u\n", follow_record->is_server ? "\t" : "", follow_record->data->len);
+ break;
- if (chunk < fp->chunkMin)
- {
- while (sc.dlen > 0)
+ case SHOW_RAW:
+ if (follow_record->is_server)
{
- len = sc.dlen < sizeof bin ? sc.dlen : (guint32)sizeof bin;
- sc.dlen -= len;
- if (fread(bin, 1, len, fp->filep) != len)
- {
- followExit("Error reading stream chunk data.");
- }
- offset[node] += len;
+ putchar('\t');
}
+ break;
+ default:
+ g_assert_not_reached();
}
- else
- {
- switch (fp->mode)
- {
- case mode_HEX:
- break;
- case mode_ASCII:
- case mode_EBCDIC:
- printf("%s%u\n", node ? "\t" : "", sc.dlen);
- break;
+ switch (cli_follow_info->show_type)
+ {
+ case SHOW_HEXDUMP:
+ follow_print_hex(follow_record->is_server ? "\t" : "", *global_pos, follow_record->data->data, follow_record->data->len);
+ (*global_pos) += follow_record->data->len;
+ break;
- case mode_RAW:
- if (node)
- {
- putchar('\t');
- }
- break;
- }
+ case SHOW_ASCII:
+ case SHOW_EBCDIC:
+ buffer = (char *)g_malloc(follow_record->data->len+2);
- while (sc.dlen > 0)
+ for (ii = 0; ii < follow_record->data->len; ii++)
{
- len = sc.dlen < sizeof bin ? sc.dlen : (guint32)sizeof bin;
- sc.dlen -= len;
- if (fread(bin, 1, len, fp->filep) != len)
- {
- followExit("Error reading stream chunk data.");
- }
-
- switch (fp->mode)
+ switch (follow_record->data->data[ii])
{
- case mode_HEX:
- followPrintHex(node ? "\t" : "", offset[node], bin, len);
+ case '\r':
+ case '\n':
+ buffer[ii] = follow_record->data->data[ii];
break;
-
- case mode_ASCII:
- case mode_EBCDIC:
- for (ii = 0; ii < len; ii++)
- {
- switch (bin[ii])
- {
- case '\r':
- case '\n':
- data[ii] = bin[ii];
- break;
- default:
- data[ii] = g_ascii_isprint(bin[ii]) ? bin[ii] : '.';
- break;
- }
- }
- if (sc.dlen == 0)
- {
- data[ii++] = '\n';
- }
- data[ii] = 0;
- if (fp->mode == mode_EBCDIC) {
- EBCDIC_to_ASCII(data, ii);
- }
- printf("%s", data);
+ default:
+ buffer[ii] = g_ascii_isprint(follow_record->data->data[ii]) ? follow_record->data->data[ii] : '.';
break;
-
- case mode_RAW:
- for (ii = 0, jj = 0; ii < len; ii++)
- {
- data[jj++] = bin2hex[bin[ii] >> 4];
- data[jj++] = bin2hex[bin[ii] & 0xf];
- }
- if (sc.dlen == 0)
- {
- data[jj++] = '\n';
- }
- data[jj] = 0;
- printf("%s", data);
}
-
- offset[node] += len;
}
- }
- for (;;)
- {
- len = (guint32)fread(&sc, 1, sizeof sc, fp->filep);
- if (len != sizeof sc)
- {
- /* no more data */
- sc.dlen = 0;
- goto done;
+ buffer[ii++] = '\n';
+ buffer[ii] = 0;
+ if (cli_follow_info->show_type == SHOW_EBCDIC) {
+ EBCDIC_to_ASCII(buffer, ii);
}
- if (sc.dlen > 0)
+ printf("%s", buffer);
+ g_free(buffer);
+ break;
+
+ case SHOW_RAW:
+ buffer = (char *)g_malloc((follow_record->data->len*2)+2);
+
+ for (ii = 0, jj = 0; ii < follow_record->data->len; ii++)
{
- chunk++;
- break;
+ buffer[jj++] = bin2hex[follow_record->data->data[ii] >> 4];
+ buffer[jj++] = bin2hex[follow_record->data->data[ii] & 0xf];
}
+
+ buffer[jj++] = '\n';
+ buffer[jj] = 0;
+ printf("%s", buffer);
+ g_free(buffer);
+ break;
+
+ default:
+ g_assert_not_reached();
}
}
-done:
-
printf("%s", separator);
-
- followFileClose(fp);
}
-static gboolean
-followArgStrncmp(
- const char **opt_argp,
- const char *strp
- )
+static gboolean follow_arg_strncmp(const char **opt_argp, const char *strp)
{
- int len = (guint32)strlen(strp);
+ int len = strlen(strp);
if (strncmp(*opt_argp, strp, len) == 0)
{
@@ -744,39 +302,32 @@ followArgStrncmp(
}
static void
-followArgMode(
- const char **opt_argp,
- follow_t *fp
- )
+follow_arg_mode(const char **opt_argp, follow_info_t *follow_info)
{
- if (followArgStrncmp(opt_argp, STR_HEX))
+ cli_follow_info_t* cli_follow_info = (cli_follow_info_t*)follow_info->gui_data;
+
+ if (follow_arg_strncmp(opt_argp, STR_HEX))
{
- fp->mode = mode_HEX;
+ cli_follow_info->show_type = SHOW_HEXDUMP;
}
- else if (followArgStrncmp(opt_argp, STR_ASCII))
+ else if (follow_arg_strncmp(opt_argp, STR_ASCII))
{
- fp->mode = mode_ASCII;
+ cli_follow_info->show_type = SHOW_ASCII;
}
- else if (followArgStrncmp(opt_argp, STR_EBCDIC))
+ else if (follow_arg_strncmp(opt_argp, STR_EBCDIC))
{
- fp->mode = mode_EBCDIC;
+ cli_follow_info->show_type = SHOW_EBCDIC;
}
- else if (followArgStrncmp(opt_argp, STR_RAW))
+ else if (follow_arg_strncmp(opt_argp, STR_RAW))
{
- fp->mode = mode_RAW;
+ cli_follow_info->show_type = SHOW_RAW;
}
else
{
- followExit("Invalid display mode.");
+ follow_exit("Invalid display mode.");
}
}
-static void
-followArgFilter(
- const char **opt_argp,
- follow_t *fp
- )
-{
#define _STRING(s) # s
#define STRING(s) _STRING(s)
@@ -785,265 +336,170 @@ followArgFilter(
#define ADDRv6_FMT ",[%" STRING(ADDR_CHARS) "[^]]]:%d%n"
#define ADDRv4_FMT ",%" STRING(ADDR_CHARS) "[^:]:%d%n"
+static void
+follow_arg_filter(const char **opt_argp, follow_info_t *follow_info)
+{
int len;
unsigned int ii;
char addr[ADDR_LEN];
+ cli_follow_info_t* cli_follow_info = (cli_follow_info_t*)follow_info->gui_data;
- if (sscanf(*opt_argp, ",%u%n", &fp->stream_index, &len) == 1 &&
+ if (sscanf(*opt_argp, ",%u%n", &cli_follow_info->stream_index, &len) == 1 &&
((*opt_argp)[len] == 0 || (*opt_argp)[len] == ','))
{
*opt_argp += len;
}
else
{
- for (ii = 0; ii < sizeof fp->addr/sizeof *fp->addr; ii++)
+ for (ii = 0; ii < sizeof cli_follow_info->addr/sizeof *cli_follow_info->addr; ii++)
{
- if ((sscanf(*opt_argp, ADDRv6_FMT, addr, &fp->port[ii], &len) != 2 &&
- sscanf(*opt_argp, ADDRv4_FMT, addr, &fp->port[ii], &len) != 2) ||
- fp->port[ii] <= 0 || fp->port[ii] > G_MAXUINT16)
+ if ((sscanf(*opt_argp, ADDRv6_FMT, addr, &cli_follow_info->port[ii], &len) != 2 &&
+ sscanf(*opt_argp, ADDRv4_FMT, addr, &cli_follow_info->port[ii], &len) != 2) ||
+ cli_follow_info->port[ii] <= 0 || cli_follow_info->port[ii] > G_MAXUINT16)
{
- followExit("Invalid address:port pair.");
+ follow_exit("Invalid address:port pair.");
}
if (strcmp("ip6", host_ip_af(addr)) == 0)
{
- if (!get_host_ipaddr6(addr, (struct e_in6_addr *)fp->addrBuf[ii]))
+ if (!get_host_ipaddr6(addr, (struct e_in6_addr *)cli_follow_info->addrBuf[ii]))
{
- followExit("Can't get IPv6 address");
+ follow_exit("Can't get IPv6 address");
}
- set_address(&fp->addr[ii], AT_IPv6, 16, fp->addrBuf[ii]);
+ set_address(&cli_follow_info->addr[ii], AT_IPv6, 16, cli_follow_info->addrBuf[ii]);
}
else
{
- if (!get_host_ipaddr(addr, (guint32 *)fp->addrBuf[ii]))
+ if (!get_host_ipaddr(addr, (guint32 *)cli_follow_info->addrBuf[ii]))
{
- followExit("Can't get IPv4 address");
+ follow_exit("Can't get IPv4 address");
}
- set_address(&fp->addr[ii], AT_IPv4, 4, fp->addrBuf[ii]);
+ set_address(&cli_follow_info->addr[ii], AT_IPv4, 4, cli_follow_info->addrBuf[ii]);
}
*opt_argp += len;
}
- if (fp->addr[0].type != fp->addr[1].type)
+ if (cli_follow_info->addr[0].type != cli_follow_info->addr[1].type)
{
- followExit("Mismatched IP address types.");
+ follow_exit("Mismatched IP address types.");
}
- fp->stream_index = G_MAXUINT32;
+ cli_follow_info->stream_index = -1;
}
}
-static void
-followArgRange(
- const char **opt_argp,
- follow_t *fp
- )
+static void follow_arg_range(const char **opt_argp, cli_follow_info_t* cli_follow_info)
{
int len;
if (**opt_argp == 0)
{
- fp->chunkMin = 1;
- fp->chunkMax = G_MAXUINT32;
+ cli_follow_info->chunkMin = 1;
+ cli_follow_info->chunkMax = G_MAXUINT32;
}
else
{
- if (sscanf(*opt_argp, ",%u-%u%n", &fp->chunkMin, &fp->chunkMax, &len) == 2)
+ if (sscanf(*opt_argp, ",%u-%u%n", &cli_follow_info->chunkMin, &cli_follow_info->chunkMax, &len) == 2)
{
*opt_argp += len;
}
- else if (sscanf(*opt_argp, ",%u%n", &fp->chunkMin, &len) == 1)
+ else if (sscanf(*opt_argp, ",%u%n", &cli_follow_info->chunkMin, &len) == 1)
{
- fp->chunkMax = fp->chunkMin;
+ cli_follow_info->chunkMax = cli_follow_info->chunkMin;
*opt_argp += len;
}
else
{
- followExit("Invalid range.");
+ follow_exit("Invalid range.");
}
- if (fp->chunkMin < 1 || fp->chunkMin > fp->chunkMax)
+ if (cli_follow_info->chunkMin < 1 || cli_follow_info->chunkMin > cli_follow_info->chunkMax)
{
- followExit("Invalid range value.");
+ follow_exit("Invalid range value.");
}
}
}
static void
-followArgDone(
- const char *opt_argp
- )
+follow_arg_done(const char *opt_argp)
{
if (*opt_argp != 0)
{
- followExit("Invalid parameter.");
- }
-}
-
-static void
-followTcp(
- const char *opt_argp,
- void *userdata _U_
- )
-{
- follow_t *fp;
- GString *errp;
-
- opt_argp += strlen(STR_FOLLOW_TCP);
-
- fp = followAlloc(type_TCP);
-
- followArgMode(&opt_argp, fp);
- followArgFilter(&opt_argp, fp);
- followArgRange(&opt_argp, fp);
- followArgDone(opt_argp);
-
- reset_stream_follow(TCP_STREAM);
- if (fp->stream_index != G_MAXUINT32)
- {
- if (!follow_index(TCP_STREAM, fp->stream_index))
- {
- followExit("Can't follow TCP index.");
- }
- }
- else
- {
- if (!follow_addr(TCP_STREAM, &fp->addr[0], fp->port[0],
- &fp->addr[1], fp->port[1]))
- {
- followExit("Can't follow TCP address/port pairs.");
- }
- }
-
- followFileOpen(fp);
-
- errp = register_tap_listener("tcp_follow", fp, followStrFilter(fp), 0,
- NULL, follow_common_stream_packet, followDraw);
-
- if (errp != NULL)
- {
- followFree(fp);
- g_string_free(errp, TRUE);
- followExit("Error registering TCP tap listener.");
+ follow_exit("Invalid parameter.");
}
}
-static void
-followUdp(
- const char *opt_argp,
- void *userdata _U_
- )
+static void follow_stream(const char *opt_argp, void *userdata)
{
- follow_t *fp;
+ follow_info_t *follow_info;
+ cli_follow_info_t* cli_follow_info;
GString *errp;
+ register_follow_t* follower = (register_follow_t*)userdata;
+ follow_index_filter_func index_filter;
+ follow_address_filter_func address_filter;
- opt_argp += strlen(STR_FOLLOW_UDP);
+ opt_argp += strlen(STR_FOLLOW);
+ opt_argp += strlen(proto_get_protocol_filter_name(get_follow_proto_id(follower)));
- fp = followAlloc(type_UDP);
+ cli_follow_info = g_new0(cli_follow_info_t, 1);
+ follow_info = g_new0(follow_info_t, 1);
+ follow_info->gui_data = cli_follow_info;
+ cli_follow_info->follower = follower;
- followArgMode(&opt_argp, fp);
- followArgFilter(&opt_argp, fp);
- followArgRange(&opt_argp, fp);
- followArgDone(opt_argp);
+ follow_arg_mode(&opt_argp, follow_info);
+ follow_arg_filter(&opt_argp, follow_info);
+ follow_arg_range(&opt_argp, cli_follow_info);
+ follow_arg_done(opt_argp);
- reset_stream_follow(UDP_STREAM);
- if (fp->stream_index != G_MAXUINT32)
+ if (cli_follow_info->stream_index >= 0)
{
- if (!follow_index(UDP_STREAM, fp->stream_index))
+ index_filter = get_follow_index_func(follower);
+ follow_info->filter_out_filter = index_filter(cli_follow_info->stream_index);
+ if (follow_info->filter_out_filter == NULL)
{
- followExit("Can't follow UDP index.");
+ follow_exit("Error creating filter for this stream.");
}
}
else
{
- if (!follow_addr(UDP_STREAM, &fp->addr[0], fp->port[0],
- &fp->addr[1], fp->port[1]))
+ address_filter = get_follow_address_func(follower);
+ follow_info->filter_out_filter = address_filter(&cli_follow_info->addr[0], &cli_follow_info->addr[1], cli_follow_info->port[0], cli_follow_info->port[1]);
+ if (follow_info->filter_out_filter == NULL)
{
- followExit("Can't follow UDP address/port pairs.");
+ follow_exit("Error creating filter for this address/port pair.\n");
}
}
- followFileOpen(fp);
+ errp = register_tap_listener(get_follow_tap_string(follower), follow_info, follow_info->filter_out_filter, 0,
+ NULL, get_follow_tap_handler(follower), follow_draw);
- errp = register_tap_listener("udp_follow", fp, followStrFilter(fp), 0,
- NULL, follow_common_stream_packet, followDraw);
if (errp != NULL)
{
- followFree(fp);
+ follow_free(follow_info);
g_string_free(errp, TRUE);
- followExit("Error registering UDP tap listner.");
+ follow_exit("Error registering tap listener.");
}
}
static void
-followSsl(
- const char *opt_argp,
- void *userdata _U_
- )
+follow_register(gpointer data, gpointer user_data _U_)
{
- follow_t *fp;
- GString *errp;
-
- opt_argp += strlen(STR_FOLLOW_SSL);
-
- fp = followAlloc(type_SSL);
-
- followArgMode(&opt_argp, fp);
- followArgFilter(&opt_argp, fp);
- followArgRange(&opt_argp, fp);
- followArgDone(opt_argp);
-
- reset_stream_follow(TCP_STREAM);
- if (fp->stream_index == G_MAXUINT32)
- {
- followExit("SSL only supports index filters.");
- }
-
- followFileOpen(fp);
-
- errp = register_tap_listener("ssl", fp, followStrFilter(fp), 0,
- NULL, followSslPacket, followDraw);
- if (errp != NULL)
- {
- followFree(fp);
- g_string_free(errp, TRUE);
- followExit("Error registering SSL tap listener.");
- }
+ register_follow_t *follower = (register_follow_t*)data;
+ stat_tap_ui follow_ui;
+
+ follow_ui.group = REGISTER_STAT_GROUP_GENERIC;
+ follow_ui.title = NULL; /* construct this from the protocol info? */
+ follow_ui.cli_string = follow_get_stat_tap_string(follower);
+ follow_ui.tap_init_cb = follow_stream;
+ follow_ui.nparams = 0;
+ follow_ui.params = NULL;
+ register_stat_tap_ui(&follow_ui, follower);
}
-static stat_tap_ui followTcp_ui = {
- REGISTER_STAT_GROUP_GENERIC,
- NULL,
- STR_FOLLOW_TCP,
- followTcp,
- 0,
- NULL
-};
-
-static stat_tap_ui followUdp_ui = {
- REGISTER_STAT_GROUP_GENERIC,
- NULL,
- STR_FOLLOW_UDP,
- followUdp,
- 0,
- NULL
-};
-
-static stat_tap_ui followSsl_ui = {
- REGISTER_STAT_GROUP_GENERIC,
- NULL,
- STR_FOLLOW_SSL,
- followSsl,
- 0,
- NULL
-};
-
void
register_tap_listener_follow(void)
{
- register_stat_tap_ui(&followTcp_ui, NULL);
- register_stat_tap_ui(&followUdp_ui, NULL);
- register_stat_tap_ui(&followSsl_ui, NULL);
+ follow_iterate_followers(follow_register, NULL);
}
/*
diff --git a/ui/follow.h b/ui/follow.h
deleted file mode 100644
index f6da1021e3..0000000000
--- a/ui/follow.h
+++ /dev/null
@@ -1,99 +0,0 @@
-/* follow.h
- * Common routines for following data streams (qt/gtk)
- *
- * 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 __FOLLOW__H__
-#define __FOLLOW__H__
-
-#ifdef SSL_PLUGIN
-#include "packet-ssl-utils.h"
-#else
-#include <epan/dissectors/packet-ssl-utils.h>
-#endif
-
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-
-typedef struct {
- gboolean is_from_server;
- guint32 packet_num;
- StringInfo data;
-} SslDecryptedRecord;
-
-/* Type of follow we are doing */
-typedef enum {
- FOLLOW_TCP,
- FOLLOW_SSL,
- FOLLOW_UDP,
- FOLLOW_HTTP
-} follow_type_t;
-
-/* Show Stream */
-typedef enum {
- FROM_CLIENT,
- FROM_SERVER,
- BOTH_HOSTS
-} show_stream_t;
-
-/* Show Type */
-typedef enum {
- SHOW_ASCII,
- SHOW_EBCDIC,
- SHOW_HEXDUMP,
- SHOW_CARRAY,
- SHOW_RAW,
- SHOW_YAML,
- SHOW_UTF8
-} show_type_t;
-
-typedef enum {
- FRS_OK,
- FRS_OPEN_ERROR,
- FRS_READ_ERROR,
- FRS_PRINT_ERROR
-} frs_return_t;
-
-typedef struct {
- gboolean is_server;
- guint32 packet_num;
- GByteArray *data;
-} follow_record_t;
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
-
-/*
- * 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/ui/gtk/CMakeLists.txt b/ui/gtk/CMakeLists.txt
index b32db52c87..1d11eebac3 100644
--- a/ui/gtk/CMakeLists.txt
+++ b/ui/gtk/CMakeLists.txt
@@ -53,11 +53,7 @@ set(WIRESHARK_GTK_SRC
filter_utils.c
find_dlg.c
firewall_dlg.c
- follow_http.c
- follow_ssl.c
follow_stream.c
- follow_tcp.c
- follow_udp.c
font_utils.c
goto_dlg.c
graph_analysis.c
diff --git a/ui/gtk/Makefile.common b/ui/gtk/Makefile.common
index ffdb84e707..29675839f7 100644
--- a/ui/gtk/Makefile.common
+++ b/ui/gtk/Makefile.common
@@ -72,11 +72,7 @@ WIRESHARK_COMMON_GTK_SRC = \
filter_utils.c \
find_dlg.c \
firewall_dlg.c \
- follow_http.c \
- follow_ssl.c \
follow_stream.c \
- follow_tcp.c \
- follow_udp.c \
font_utils.c \
goto_dlg.c \
graph_analysis.c \
@@ -200,11 +196,7 @@ noinst_HEADERS = \
filter_utils.h \
find_dlg.h \
firewall_dlg.h \
- follow_http.h \
- follow_ssl.h \
follow_stream.h \
- follow_tcp.h \
- follow_udp.h \
font_utils.h \
goto_dlg.h \
graph_analysis.h \
diff --git a/ui/gtk/conversations_table.c b/ui/gtk/conversations_table.c
index f34085cb0b..91e4ab13b0 100644
--- a/ui/gtk/conversations_table.c
+++ b/ui/gtk/conversations_table.c
@@ -44,8 +44,7 @@
#include "ui/gtk/help_dlg.h"
#include "ui/gtk/main.h"
#include "ui/gtk/stock_icons.h"
-#include "ui/gtk/follow_tcp.h"
-#include "ui/gtk/follow_udp.h"
+#include "ui/gtk/follow_stream.h"
#include "ui/gtk/keys.h"
diff --git a/ui/gtk/follow_http.c b/ui/gtk/follow_http.c
deleted file mode 100644
index cf651f2018..0000000000
--- a/ui/gtk/follow_http.c
+++ /dev/null
@@ -1,313 +0,0 @@
-/* follow_http.c
- * HTTP specific routines for following traffic streams
- *
- * 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 <gtk/gtk.h>
-
-#include <epan/addr_resolv.h>
-#include <epan/epan_dissect.h>
-#include <epan/follow.h>
-#include <epan/tap.h>
-
-#include <ui/simple_dialog.h>
-#include <wsutil/utf8_entities.h>
-
-#include "gtkglobals.h"
-#include "ui/gtk/follow_stream.h"
-#include "ui/gtk/keys.h"
-#include "ui/gtk/main.h"
-#include "ui/gtk/follow_http.h"
-
-static frs_return_t
-follow_read_http_stream(follow_info_t *follow_info, follow_print_line_func follow_print, void *arg);
-
-static gboolean
-http_queue_packet_data(void *tapdata, packet_info *pinfo,
- epan_dissect_t *edt _U_, const void *data)
-{
- follow_record_t *follow_record;
- follow_info_t *follow_info = (follow_info_t *)tapdata;
- tvbuff_t *next_tvb = (tvbuff_t *)data;
-
- follow_record = g_new(follow_record_t,1);
-
- follow_record->data = g_byte_array_sized_new(tvb_captured_length(next_tvb));
- follow_record->data = g_byte_array_append(follow_record->data,
- tvb_get_ptr(next_tvb, 0, -1),
- tvb_captured_length(next_tvb));
-
- if (follow_info->client_port == 0) {
- follow_info->client_port = pinfo->srcport;
- copy_address(&follow_info->client_ip, &pinfo->src);
- }
-
- if (addresses_equal(&follow_info->client_ip, &pinfo->src) && follow_info->client_port == pinfo->srcport)
- follow_record->is_server = FALSE;
- else
- follow_record->is_server = TRUE;
-
- /* update stream counter */
- follow_info->bytes_written[follow_record->is_server] += follow_record->data->len;
-
- follow_info->payload = g_list_append(follow_info->payload, follow_record);
- return FALSE;
-}
-
-/* Follow the HTTP stream, if any, to which the last packet that we called
- a dissection routine on belongs (this might be the most recently
- selected packet, or it might be the last packet in the file). */
-void
-follow_http_stream_cb(GtkWidget *w _U_, gpointer data _U_)
-{
- GtkWidget *filter_te, *filter_cm;
- gchar *follow_filter;
- const gchar *previous_filter;
- int filter_out_filter_len, previous_filter_len;
- const char *hostname0, *hostname1;
- char *port0, *port1;
- gchar *server_to_client_string = NULL;
- gchar *client_to_server_string = NULL;
- gchar *both_directions_string = NULL;
- follow_stats_t stats;
- follow_info_t *follow_info;
- GString *msg;
- gboolean is_http = FALSE;
-
- is_http = proto_is_frame_protocol(cfile.edt->pi.layers, "http");
-
- if (!is_http) {
- simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
- "Error following stream. Please make\n"
- "sure you have a UDP packet selected.");
- return;
- }
-
- reset_stream_follow(TCP_STREAM);
-
- follow_info = g_new0(follow_info_t, 1);
- follow_info->follow_type = FOLLOW_HTTP;
- follow_info->read_stream = follow_read_http_stream;
-
- /* Create a new filter that matches all packets in the HTTP stream,
- and set the display filter entry accordingly */
- follow_filter = build_follow_conv_filter(&cfile.edt->pi, "http");
- if (!follow_filter)
- {
- simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
- "Error creating filter for this stream.\n"
- "A network layer header is needed");
- g_free(follow_info);
- return;
- }
-
- /* Set the display filter entry accordingly */
- filter_cm = (GtkWidget *)g_object_get_data(G_OBJECT(top_level), E_DFILTER_CM_KEY);
- filter_te = gtk_bin_get_child(GTK_BIN(filter_cm));
-
- /* needed in follow_filter_out_stream(), is there a better way? */
- follow_info->filter_te = filter_te;
-
- /* save previous filter, const since we're not supposed to alter */
- previous_filter =
- (const gchar *)gtk_entry_get_text(GTK_ENTRY(filter_te));
-
- /* allocate our new filter. API claims g_malloc terminates program on failure */
- /* my calc for max alloc needed is really +10 but when did a few extra bytes hurt ? */
- previous_filter_len = previous_filter?(int)strlen(previous_filter):0;
- filter_out_filter_len = (int)strlen(follow_filter) + previous_filter_len + 16;
- follow_info->filter_out_filter = (gchar *)g_malloc(filter_out_filter_len);
-
- /* append the negation */
- if(previous_filter_len) {
- g_snprintf(follow_info->filter_out_filter, filter_out_filter_len,
- "%s and !(%s)", previous_filter, follow_filter);
- } else {
- g_snprintf(follow_info->filter_out_filter, filter_out_filter_len,
- "!(%s)", follow_filter);
- }
-
- /* data will be passed via tap callback*/
- msg = register_tap_listener("http_follow", follow_info, follow_filter,
- 0, NULL, http_queue_packet_data, NULL);
- if (msg) {
- simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
- "Can't register http_follow tap: %s\n",
- msg->str);
- g_free(follow_info->filter_out_filter);
- g_free(follow_info);
- g_free(follow_filter);
- return;
- }
-
- gtk_entry_set_text(GTK_ENTRY(filter_te), follow_filter);
-
- /* Run the display filter so it goes in effect - even if it's the
- same as the previous display filter. */
- main_filter_packets(&cfile, follow_filter, TRUE);
-
- /* Free the filter string, as we're done with it. */
- g_free(follow_filter);
-
- remove_tap_listener(follow_info);
-
- /* Stream to show */
- follow_stats(&stats);
-
- if (stats.is_ipv6) {
- hostname0 = get_hostname6(&stats.ip_address[0].ipv6);
- hostname1 = get_hostname6(&stats.ip_address[1].ipv6);
- } else {
- hostname0 = get_hostname(stats.ip_address[0].ipv4);
- hostname1 = get_hostname(stats.ip_address[1].ipv4);
- }
-
- port0 = tcp_port_to_display(NULL, stats.port[0]);
- port1 = tcp_port_to_display(NULL, stats.port[1]);
-
- follow_info->is_ipv6 = stats.is_ipv6;
-
- /* Both Stream Directions */
- both_directions_string = g_strdup_printf("Entire conversation (%u bytes)", follow_info->bytes_written[0] + follow_info->bytes_written[1]);
-
- if ((follow_info->client_port == stats.port[0]) &&
- ((stats.is_ipv6 && (memcmp(follow_info->client_ip.data, &stats.ip_address[0], 16) == 0)) ||
- (!stats.is_ipv6 && (memcmp(follow_info->client_ip.data, &stats.ip_address[0], 4) == 0)))) {
- server_to_client_string =
- g_strdup_printf("%s:%s " UTF8_RIGHTWARDS_ARROW " %s:%s (%u bytes)",
- hostname0, port0,
- hostname1, port1,
- follow_info->bytes_written[0]);
-
- client_to_server_string =
- g_strdup_printf("%s:%s " UTF8_RIGHTWARDS_ARROW " %s:%s (%u bytes)",
- hostname1, port1,
- hostname0, port0,
- follow_info->bytes_written[1]);
- } else {
- server_to_client_string =
- g_strdup_printf("%s:%s " UTF8_RIGHTWARDS_ARROW " %s:%s (%u bytes)",
- hostname1, port1,
- hostname0, port0,
- follow_info->bytes_written[0]);
-
- client_to_server_string =
- g_strdup_printf("%s:%s " UTF8_RIGHTWARDS_ARROW " %s:%s (%u bytes)",
- hostname0, port0,
- hostname1, port1,
- follow_info->bytes_written[1]);
- }
-
- follow_stream("Follow HTTP Stream", follow_info, both_directions_string,
- server_to_client_string, client_to_server_string);
-
- wmem_free(NULL, port0);
- wmem_free(NULL, port1);
- g_free(both_directions_string);
- g_free(server_to_client_string);
- g_free(client_to_server_string);
-}
-
-#define FLT_BUF_SIZE 1024
-
-/*
- * XXX - the routine pointed to by "print_line_fcn_p" doesn't get handed lines,
- * it gets handed bufferfuls. That's fine for "follow_write_raw()"
- * and "follow_add_to_gtk_text()", but, as "follow_print_text()" calls
- * the "print_line()" routine from "print.c", and as that routine might
- * genuinely expect to be handed a line (if, for example, it's using
- * some OS or desktop environment's printing API, and that API expects
- * to be handed lines), "follow_print_text()" should probably accumulate
- * lines in a buffer and hand them "print_line()". (If there's a
- * complete line in a buffer - i.e., there's nothing of the line in
- * the previous buffer or the next buffer - it can just hand that to
- * "print_line()" after filtering out non-printables, as an
- * optimization.)
- *
- * This might or might not be the reason why C arrays display
- * correctly but get extra blank lines very other line when printed.
- */
-static frs_return_t
-follow_read_http_stream(follow_info_t *follow_info,
- follow_print_line_func follow_print,
- void *arg)
-{
- guint32 global_client_pos = 0, global_server_pos = 0;
- guint32 server_packet_count = 0;
- guint32 client_packet_count = 0;
- guint32 *global_pos;
- gboolean skip;
- GList* cur;
- frs_return_t frs_return;
- follow_record_t *follow_record;
- char *buffer;
-
-
- for (cur = follow_info->payload; cur; cur = g_list_next(cur)) {
- follow_record = (follow_record_t *)cur->data;
- skip = FALSE;
- if (!follow_record->is_server) {
- global_pos = &global_client_pos;
- if(follow_info->show_stream == FROM_SERVER) {
- skip = TRUE;
- }
- } else {
- global_pos = &global_server_pos;
- if (follow_info->show_stream == FROM_CLIENT) {
- skip = TRUE;
- }
- }
-
- if (!skip) {
- buffer = (char *)g_memdup(follow_record->data->data,
- follow_record->data->len);
-
- frs_return = follow_show(follow_info, follow_print,
- buffer,
- follow_record->data->len,
- follow_record->is_server, arg,
- global_pos,
- &server_packet_count,
- &client_packet_count);
- g_free(buffer);
- if(frs_return == FRS_PRINT_ERROR)
- return frs_return;
- }
- }
-
- return FRS_OK;
-}
-
-/*
- * Editor modelines - http://www.wireshark.org/tools/modelines.html
- *
- * Local variables:
- * c-basic-offset: 4
- * tab-width: 8
- * indent-tabs-mode: nil
- * End:
- *
- * vi: set shiftwidth=4 tabstop=8 expandtab:
- * :indentSize=4:tabSize=8:noTabs=true:
- */
diff --git a/ui/gtk/follow_http.h b/ui/gtk/follow_http.h
deleted file mode 100644
index 011fc353f4..0000000000
--- a/ui/gtk/follow_http.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/* follow_http.h
- * HTTP specific routines for following traffic streams
- *
- * 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 __FOLLOW_HTTP_H__
-#define __FOLLOW_HTTP_H__
-
-/* Follow the HTTP stream, if any, to which the last packet that we called
- a dissection routine on belongs (this might be the most recently
- selected packet, or it might be the last packet in the file). */
-void follow_http_stream_cb(GtkWidget * w, gpointer data _U_);
-
-#endif /* __FOLLOW_HTTP_H__ */
-
-/*
- * Editor modelines - http://www.wireshark.org/tools/modelines.html
- *
- * Local variables:
- * c-basic-offset: 4
- * tab-width: 8
- * indent-tabs-mode: nil
- * End:
- *
- * vi: set shiftwidth=4 tabstop=8 expandtab:
- * :indentSize=4:tabSize=8:noTabs=true:
- */
diff --git a/ui/gtk/follow_ssl.c b/ui/gtk/follow_ssl.c
deleted file mode 100644
index 053283e2b2..0000000000
--- a/ui/gtk/follow_ssl.c
+++ /dev/null
@@ -1,352 +0,0 @@
-/* follow_ssl.c
- * SSL specific routines for following traffic streams
- *
- * 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>
-
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-
-#include <gtk/gtk.h>
-
-#include <epan/follow.h>
-#include <epan/prefs.h>
-#include <epan/addr_resolv.h>
-#include <epan/epan_dissect.h>
-#include <wsutil/filesystem.h>
-#include <epan/tap.h>
-
-#include <ui/alert_box.h>
-#include <ui/simple_dialog.h>
-#include <wsutil/utf8_entities.h>
-#include <ui/util.h>
-
-#include "gtkglobals.h"
-#include "ui/gtk/color_utils.h"
-#include "ui/gtk/main.h"
-#include "ui/gtk/dlg_utils.h"
-#include "ui/gtk/file_dlg.h"
-#include "ui/gtk/keys.h"
-#include "ui/gtk/gui_utils.h"
-#include "ui/gtk/font_utils.h"
-#include "ui/follow.h"
-#include "ui/gtk/follow_ssl.h"
-#include "ui/gtk/follow_stream.h"
-
-#ifdef SSL_PLUGIN
-#include "packet-ssl-utils.h"
-#else
-#include <epan/dissectors/packet-ssl-utils.h>
-#endif
-
-static frs_return_t
-follow_read_ssl_stream(follow_info_t *follow_info, follow_print_line_func follow_print, void *arg);
-
-
-static gboolean
-ssl_queue_packet_data(void *tapdata, packet_info *pinfo, epan_dissect_t *edt _U_, const void *ssl)
-{
- follow_info_t * follow_info = (follow_info_t*) tapdata;
- SslDecryptedRecord * rec = NULL;
- SslDataInfo * appl_data = NULL;
- SslPacketInfo * pi = (SslPacketInfo*)ssl;
- show_stream_t from = FROM_CLIENT;
-
- /* Skip packets without decrypted payload data. */
- if (!pi || !pi->appl_data) return FALSE;
-
- /* Compute the packet's sender. */
- if (follow_info->client_port == 0) {
- follow_info->client_port = pinfo->srcport;
- copy_address(&follow_info->client_ip, &pinfo->src);
- }
- if (addresses_equal(&follow_info->client_ip, &pinfo->src) &&
- follow_info->client_port == pinfo->srcport) {
- from = FROM_CLIENT;
- } else {
- from = FROM_SERVER;
- }
-
- for (appl_data = pi->appl_data; appl_data != NULL; appl_data = appl_data->next) {
-
- /* TCP segments that contain the end of two or more SSL PDUs will be
- queued to SSL taps for each of those PDUs. Therefore a single
- packet could be processed by this SSL tap listener multiple times.
- The following test handles that scenario by treating the
- follow_info->bytes_written[] values as the next expected
- appl_data->seq. Any appl_data instances that fall below that have
- already been processed and must be skipped. */
- if (appl_data->seq < follow_info->bytes_written[from]) continue;
-
- /* Allocate a SslDecryptedRecord to hold the current appl_data
- instance's decrypted data. Even though it would be possible to
- consolidate multiple appl_data instances into a single rec, it is
- beneficial to use a one-to-one mapping. This affords the Follow
- Stream dialog view modes (ASCII, EBCDIC, Hex Dump, C Arrays, Raw)
- the opportunity to accurately reflect SSL PDU boundaries. Currently
- the Hex Dump view does by starting a new line, and the C Arrays
- view does by starting a new array declaration. */
- rec = (SslDecryptedRecord*) g_malloc(sizeof(SslDecryptedRecord) + appl_data->plain_data.data_len);
- rec->is_from_server = from == FROM_SERVER;
- rec->data.data = (guchar*) (rec + 1);
- rec->data.data_len = appl_data->plain_data.data_len;
- memcpy(rec->data.data, appl_data->plain_data.data, appl_data->plain_data.data_len);
-
- /* Append the record to the follow_info structure. */
- follow_info->payload = g_list_append(follow_info->payload, rec);
- follow_info->bytes_written[from] += rec->data.data_len;
- }
-
- return FALSE;
-}
-/* Follow the SSL stream, if any, to which the last packet that we called
- a dissection routine on belongs (this might be the most recently
- selected packet, or it might be the last packet in the file). */
-void
-follow_ssl_stream_cb(GtkWidget * w _U_, gpointer data _U_)
-{
- GtkWidget * filter_te;
- GtkWidget * filter_cm;
- gchar * follow_filter;
- const gchar * previous_filter;
- int filter_out_filter_len;
- int previous_filter_len;
- const char * hostname0;
- const char * hostname1;
- char *port0, *port1;
- const char * client_hostname;
- const char * server_hostname;
- const char * client_port;
- const char * server_port;
- gchar * server_to_client_string = NULL;
- gchar * client_to_server_string = NULL;
- gchar * both_directions_string = NULL;
- const gchar * single_direction_format = NULL;
- follow_stats_t stats;
- follow_info_t * follow_info;
- GString * msg;
-
- /* we got ssl so we can follow */
- if (!epan_dissect_packet_contains_field(cfile.edt, "ssl")) {
- simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
- "Error following stream. Please make\n"
- "sure you have an SSL packet selected.");
- return;
- }
-
- follow_info = g_new0(follow_info_t, 1);
- follow_info->follow_type = FOLLOW_SSL;
- follow_info->read_stream = follow_read_ssl_stream;
-
- /* Create a new filter that matches all packets in the SSL stream,
- and set the display filter entry accordingly */
- reset_stream_follow(TCP_STREAM);
- follow_filter = build_follow_conv_filter(&cfile.edt->pi, NULL);
- if (!follow_filter)
- {
- simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
- "Error creating filter for this stream.\n"
- "A network layer header is needed");
- g_free(follow_info);
- return;
- }
-
- /* Set the display filter entry accordingly */
- filter_cm = (GtkWidget *)g_object_get_data(G_OBJECT(top_level), E_DFILTER_CM_KEY);
- filter_te = gtk_bin_get_child(GTK_BIN(filter_cm));
-
- /* needed in follow_filter_out_stream(), is there a better way? */
- follow_info->filter_te = filter_te;
-
- /* save previous filter, const since we're not supposed to alter */
- previous_filter =
- (const gchar *)gtk_entry_get_text(GTK_ENTRY(filter_te));
-
- /* allocate our new filter. API claims g_malloc terminates program on failure */
- /* my calc for max alloc needed is really +10 but when did a few extra bytes hurt ? */
- previous_filter_len = previous_filter?(int)strlen(previous_filter):0;
- filter_out_filter_len = (int)strlen(follow_filter) + previous_filter_len + 16;
- follow_info->filter_out_filter = (gchar *)g_malloc(filter_out_filter_len);
-
- /* append the negation */
- if(previous_filter_len) {
- g_snprintf(follow_info->filter_out_filter, filter_out_filter_len,
- "%s and !(%s)", previous_filter, follow_filter);
- } else {
- g_snprintf(follow_info->filter_out_filter, filter_out_filter_len,
- "!(%s)", follow_filter);
- }
-
- /* data will be passed via tap callback*/
- msg = register_tap_listener("ssl", follow_info, follow_filter, 0,
- NULL, ssl_queue_packet_data, NULL);
- if (msg)
- {
- simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
- "Can't register ssl tap: %s\n",msg->str);
- g_free(follow_info->filter_out_filter);
- g_free(follow_info);
- g_free(follow_filter);
- return;
- }
- gtk_entry_set_text(GTK_ENTRY(filter_te), follow_filter);
-
- /* Run the display filter so it goes in effect - even if it's the
- same as the previous display filter. */
- main_filter_packets(&cfile, follow_filter, TRUE);
-
- /* Free the filter string, as we're done with it. */
- g_free(follow_filter);
-
- remove_tap_listener(follow_info);
-
- /* Stream to show */
- follow_stats(&stats);
-
- if (stats.is_ipv6) {
- hostname0 = get_hostname6(&stats.ip_address[0].ipv6);
- hostname1 = get_hostname6(&stats.ip_address[1].ipv6);
- } else {
- hostname0 = get_hostname(stats.ip_address[0].ipv4);
- hostname1 = get_hostname(stats.ip_address[1].ipv4);
- }
-
- port0 = tcp_port_to_display(NULL, stats.port[0]);
- port1 = tcp_port_to_display(NULL, stats.port[1]);
-
- follow_info->is_ipv6 = stats.is_ipv6;
-
- /* Generate the strings for the follow stream dialog's combo box,
- starting with both directions... */
- both_directions_string = g_strdup_printf("Entire conversation (%u bytes)", follow_info->bytes_written[0] + follow_info->bytes_written[1]);
-
- /* ...and then the server-to-client and client-to-server directions. */
- if ((follow_info->client_port == stats.port[0]) &&
- ((stats.is_ipv6 && (memcmp(follow_info->client_ip.data, &stats.ip_address[0], 16) == 0)) ||
- (!stats.is_ipv6 && (memcmp(follow_info->client_ip.data, &stats.ip_address[0], 4) == 0)))) {
- server_hostname = hostname0;
- server_port = port0;
- client_hostname = hostname1;
- client_port = port1;
- } else {
- server_hostname = hostname1;
- server_port = port1;
- client_hostname = hostname0;
- client_port = port0;
- }
-
- single_direction_format = "%s:%s " UTF8_RIGHTWARDS_ARROW " %s:%s (%u bytes)";
- server_to_client_string = g_strdup_printf(single_direction_format,
- server_hostname, server_port,
- client_hostname, client_port,
- follow_info->bytes_written[0]);
- client_to_server_string = g_strdup_printf(single_direction_format,
- client_hostname, client_port,
- server_hostname, server_port,
- follow_info->bytes_written[1]);
-
- /* Invoke the dialog. */
- follow_stream("Follow SSL Stream", follow_info, both_directions_string,
- server_to_client_string, client_to_server_string);
-
- wmem_free(NULL, port0);
- wmem_free(NULL, port1);
- g_free(both_directions_string);
- g_free(server_to_client_string);
- g_free(client_to_server_string);
-}
-
-#define FLT_BUF_SIZE 1024
-
-/*
- * XXX - the routine pointed to by "print_line_fcn_p" doesn't get handed lines,
- * it gets handed bufferfuls. That's fine for "follow_write_raw()"
- * and "follow_add_to_gtk_text()", but, as "follow_print_text()" calls
- * the "print_line()" routine from "print.c", and as that routine might
- * genuinely expect to be handed a line (if, for example, it's using
- * some OS or desktop environment's printing API, and that API expects
- * to be handed lines), "follow_print_text()" should probably accumulate
- * lines in a buffer and hand them "print_line()". (If there's a
- * complete line in a buffer - i.e., there's nothing of the line in
- * the previous buffer or the next buffer - it can just hand that to
- * "print_line()" after filtering out non-printables, as an
- * optimization.)
- *
- * This might or might not be the reason why C arrays display
- * correctly but get extra blank lines very other line when printed.
- */
-static frs_return_t
-follow_read_ssl_stream(follow_info_t *follow_info,
- follow_print_line_func follow_print,
- void *arg)
-{
- guint32 global_client_pos = 0, global_server_pos = 0;
- guint32 server_packet_count = 0;
- guint32 client_packet_count = 0;
- guint32 * global_pos;
- GList * cur;
- frs_return_t frs_return;
-
- for (cur = follow_info->payload; cur; cur = g_list_next(cur)) {
- SslDecryptedRecord * rec = (SslDecryptedRecord*) cur->data;
- gboolean include_rec = FALSE;
-
- if (rec->is_from_server) {
- global_pos = &global_server_pos;
- include_rec = (follow_info->show_stream == BOTH_HOSTS) ||
- (follow_info->show_stream == FROM_SERVER);
- } else {
- global_pos = &global_client_pos;
- include_rec = (follow_info->show_stream == BOTH_HOSTS) ||
- (follow_info->show_stream == FROM_CLIENT);
- }
-
- if (include_rec) {
- size_t nchars = rec->data.data_len;
- gchar *buffer = (gchar *)g_memdup(rec->data.data, (guint) nchars);
-
- frs_return = follow_show(follow_info, follow_print, buffer, nchars,
- rec->is_from_server, arg, global_pos,
- &server_packet_count, &client_packet_count);
- g_free(buffer);
- if (frs_return == FRS_PRINT_ERROR)
- return frs_return;
- }
- }
-
- return FRS_OK;
-}
-
-/*
- * Editor modelines - http://www.wireshark.org/tools/modelines.html
- *
- * Local variables:
- * c-basic-offset: 4
- * tab-width: 8
- * indent-tabs-mode: nil
- * End:
- *
- * vi: set shiftwidth=4 tabstop=8 expandtab:
- * :indentSize=4:tabSize=8:noTabs=true:
- */
diff --git a/ui/gtk/follow_ssl.h b/ui/gtk/follow_ssl.h
deleted file mode 100644
index a691261814..0000000000
--- a/ui/gtk/follow_ssl.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/* follow_ssl.h
- * SSL specific routines for following traffic streams
- *
- * 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 __FOLLOW_SSL_H__
-#define __FOLLOW_SSL_H__
-
-/* Follow the SSL stream, if any, to which the last packet that we called
- a dissection routine on belongs (this might be the most recently
- selected packet, or it might be the last packet in the file). */
-void follow_ssl_stream_cb(GtkWidget * w, gpointer data _U_);
-
-#endif /* __FOLLOW_SSL_H__ */
-
-/*
- * Editor modelines - http://www.wireshark.org/tools/modelines.html
- *
- * Local variables:
- * c-basic-offset: 4
- * tab-width: 8
- * indent-tabs-mode: nil
- * End:
- *
- * vi: set shiftwidth=4 tabstop=8 expandtab:
- * :indentSize=4:tabSize=8:noTabs=true:
- */
-
diff --git a/ui/gtk/follow_stream.c b/ui/gtk/follow_stream.c
index 79ae6c7c09..ff98dfb227 100644
--- a/ui/gtk/follow_stream.c
+++ b/ui/gtk/follow_stream.c
@@ -29,11 +29,14 @@
#include <epan/addr_resolv.h>
#include <epan/follow.h>
+#include <epan/epan_dissect.h>
#include <wsutil/filesystem.h>
#include <epan/prefs.h>
#include <epan/charsets.h>
+#include <epan/tap.h>
#include <epan/print.h>
+#include <epan/dissectors/packet-ssl-utils.h>
#include <ui/alert_box.h>
#include <ui/last_open_dir.h>
@@ -42,6 +45,8 @@
#include <wsutil/file_util.h>
#include <wsutil/ws_version_info.h>
+#include "gtkglobals.h"
+#include "ui/gtk/keys.h"
#include "ui/gtk/color_utils.h"
#include "ui/gtk/stock_icons.h"
#include "ui/gtk/dlg_utils.h"
@@ -53,6 +58,7 @@
#include "ui/gtk/main.h"
#include "ui/gtk/old-gtk-compat.h"
+#include <wsutil/utf8_entities.h>
#ifdef _WIN32
#include "wsutil/tempfile.h"
#include "ui/win32/print_win32.h"
@@ -69,22 +75,214 @@ static void follow_find_destroy_cb(GtkWidget * win _U_, gpointer data);
static void follow_find_button_cb(GtkWidget * w, gpointer data);
static void follow_destroy_cb(GtkWidget *w, gpointer data _U_);
-GList *follow_infos = NULL;
+static void follow_stream(const gchar *title, follow_info_t *follow_info,
+ gchar *both_directions_string, gchar *server_to_client_string, gchar *client_to_server_string);
+static frs_return_t follow_show(follow_info_t *follow_info,
+ follow_print_line_func follow_print,
+ char *buffer, size_t nchars, gboolean is_from_server, void *arg,
+ guint32 *global_pos, guint32 *server_packet_count,
+ guint32 *client_packet_count);
+static GList *follow_infos = NULL;
+
+/*
+ * XXX - the routine pointed to by "print_line_fcn_p" doesn't get handed lines,
+ * it gets handed bufferfuls. That's fine for "follow_write_raw()"
+ * and "follow_add_to_gtk_text()", but, as "follow_print_text()" calls
+ * the "print_line()" routine from "print.c", and as that routine might
+ * genuinely expect to be handed a line (if, for example, it's using
+ * some OS or desktop environment's printing API, and that API expects
+ * to be handed lines), "follow_print_text()" should probably accumulate
+ * lines in a buffer and hand them "print_line()". (If there's a
+ * complete line in a buffer - i.e., there's nothing of the line in
+ * the previous buffer or the next buffer - it can just hand that to
+ * "print_line()" after filtering out non-printables, as an
+ * optimization.)
+ *
+ * This might or might not be the reason why C arrays display
+ * correctly but get extra blank lines very other line when printed.
+ */
static frs_return_t
-follow_read_stream(follow_info_t *follow_info,
- gboolean (*print_line_fcn_p)(char *, size_t, gboolean, void *),
- void *arg)
+follow_common_read_stream(follow_info_t *follow_info,
+ follow_print_line_func follow_print,
+ void *arg)
{
- if (follow_info->read_stream == NULL) {
- g_assert_not_reached();
- return (frs_return_t)0;
+ guint32 global_client_pos = 0, global_server_pos = 0;
+ guint32 server_packet_count = 0;
+ guint32 client_packet_count = 0;
+ guint32 *global_pos;
+ gboolean skip;
+ GList* cur;
+ frs_return_t frs_return;
+ follow_record_t *follow_record;
+ char *buffer;
+
+
+ for (cur = follow_info->payload; cur; cur = g_list_next(cur)) {
+ follow_record = (follow_record_t *)cur->data;
+ skip = FALSE;
+ if (!follow_record->is_server) {
+ global_pos = &global_client_pos;
+ if(follow_info->show_stream == FROM_SERVER) {
+ skip = TRUE;
+ }
+ } else {
+ global_pos = &global_server_pos;
+ if (follow_info->show_stream == FROM_CLIENT) {
+ skip = TRUE;
+ }
+ }
+
+ if (!skip) {
+ buffer = (char *)g_memdup(follow_record->data->data,
+ follow_record->data->len);
+
+ frs_return = follow_show(follow_info, follow_print,
+ buffer,
+ follow_record->data->len,
+ follow_record->is_server, arg,
+ global_pos,
+ &server_packet_count,
+ &client_packet_count);
+ g_free(buffer);
+ if(frs_return == FRS_PRINT_ERROR)
+ return frs_return;
+ }
+ }
+
+ return FRS_OK;
+}
+
+static void follow_stream_cb(register_follow_t* follower, follow_read_stream_func read_stream_func, GtkWidget * w _U_, gpointer data _U_)
+{
+ GtkWidget *filter_cm;
+ GtkWidget *filter_te;
+ gchar *follow_filter;
+ const gchar *previous_filter;
+ int filter_out_filter_len;
+ const char *hostname0, *hostname1;
+ char *port0, *port1;
+ gchar *server_to_client_string = NULL;
+ gchar *client_to_server_string = NULL;
+ gchar *both_directions_string = NULL;
+ follow_info_t *follow_info;
+ gtk_follow_info_t *gtk_follow_info;
+ GString *msg;
+ gboolean is_follow = FALSE;
+ guint32 ignore_stream;
+ char stream_window_title[256];
+
+ is_follow = proto_is_frame_protocol(cfile.edt->pi.layers, proto_get_protocol_filter_name(get_follow_proto_id(follower)));
+
+ if (!is_follow) {
+ simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
+ "Error following stream. Please make\n"
+ "sure you have a %s packet selected.", proto_get_protocol_short_name(find_protocol_by_id(get_follow_proto_id(follower))));
+ return;
+ }
+
+ gtk_follow_info = g_new0(gtk_follow_info_t, 1);
+ follow_info = g_new0(follow_info_t, 1);
+ gtk_follow_info->read_stream = read_stream_func;
+ follow_info->gui_data = gtk_follow_info;
+
+ /* Create a new filter that matches all packets in the TCP stream,
+ and set the display filter entry accordingly */
+ follow_filter = get_follow_conv_func(follower)(&cfile.edt->pi, &ignore_stream);
+ if (!follow_filter) {
+ simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
+ "Error creating filter for this stream.\n"
+ "A transport or network layer header is needed");
+ g_free(gtk_follow_info);
+ g_free(follow_info);
+ return;
+ }
+
+ /* Set the display filter entry accordingly */
+ filter_cm = (GtkWidget *)g_object_get_data(G_OBJECT(top_level), E_DFILTER_CM_KEY);
+ filter_te = gtk_bin_get_child(GTK_BIN(filter_cm));
+
+ /* needed in follow_filter_out_stream(), is there a better way? */
+ gtk_follow_info->filter_te = filter_te;
+
+ /* save previous filter, const since we're not supposed to alter */
+ previous_filter =
+ (const gchar *)gtk_entry_get_text(GTK_ENTRY(filter_te));
+
+ /* allocate our new filter. API claims g_malloc terminates program on failure */
+ /* my calc for max alloc needed is really +10 but when did a few extra bytes hurt ? */
+ filter_out_filter_len = (int)(strlen(follow_filter) + strlen(previous_filter) + 16);
+ follow_info->filter_out_filter = (gchar *)g_malloc(filter_out_filter_len);
+
+ /* append the negation */
+ if(strlen(previous_filter)) {
+ g_snprintf(follow_info->filter_out_filter, filter_out_filter_len,
+ "%s and !(%s)", previous_filter, follow_filter);
+ } else {
+ g_snprintf(follow_info->filter_out_filter, filter_out_filter_len,
+ "!(%s)", follow_filter);
}
- return follow_info->read_stream(follow_info, print_line_fcn_p, arg);
+ /* data will be passed via tap callback*/
+ msg = register_tap_listener(get_follow_tap_string(follower), follow_info, follow_filter,
+ 0, NULL, get_follow_tap_handler(follower), NULL);
+ if (msg) {
+ simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
+ "Can't register %s tap: %s\n",
+ get_follow_tap_string(follower), msg->str);
+ g_free(gtk_follow_info);
+ g_free(follow_info->filter_out_filter);
+ g_free(follow_info);
+ g_free(follow_filter);
+ return;
+ }
+
+ gtk_entry_set_text(GTK_ENTRY(filter_te), follow_filter);
+
+ /* Run the display filter so it goes in effect - even if it's the
+ same as the previous display filter. */
+ main_filter_packets(&cfile, follow_filter, TRUE);
+
+ remove_tap_listener(follow_info);
+
+ hostname0 = address_to_name(&follow_info->client_ip);
+ hostname1 = address_to_name(&follow_info->server_ip);
+
+ port0 = get_follow_port_to_display(follower)(NULL, follow_info->client_port);
+ port1 = get_follow_port_to_display(follower)(NULL, follow_info->server_port);
+
+ /* Both Stream Directions */
+ both_directions_string = g_strdup_printf("Entire conversation (%u bytes)", follow_info->bytes_written[0] + follow_info->bytes_written[1]);
+
+ server_to_client_string =
+ g_strdup_printf("%s:%s " UTF8_RIGHTWARDS_ARROW " %s:%s (%u bytes)",
+ hostname0, port0,
+ hostname1, port1,
+ follow_info->bytes_written[0]);
+
+ client_to_server_string =
+ g_strdup_printf("%s:%s " UTF8_RIGHTWARDS_ARROW " %s:%s (%u bytes)",
+ hostname1, port1,
+ hostname0, port0,
+ follow_info->bytes_written[1]);
+
+ g_snprintf(stream_window_title, 256, "Follow %s Stream (%s)",
+ proto_get_protocol_short_name(find_protocol_by_id(get_follow_proto_id(follower))), follow_filter);
+ follow_stream(stream_window_title, follow_info, both_directions_string,
+ server_to_client_string, client_to_server_string);
+
+ /* Free the filter string, as we're done with it. */
+ g_free(follow_filter);
+
+ wmem_free(NULL, port0);
+ wmem_free(NULL, port1);
+ g_free(both_directions_string);
+ g_free(server_to_client_string);
+ g_free(client_to_server_string);
+
}
-gboolean
+static gboolean
follow_add_to_gtk_text(char *buffer, size_t nchars, gboolean is_from_server,
void *arg)
{
@@ -165,39 +363,13 @@ follow_write_raw(char *buffer, size_t nchars, gboolean is_from_server _U_, void
return TRUE;
}
-/* Handles the display style toggling */
static void
-follow_charset_toggle_cb(GtkWidget * w _U_, gpointer data)
-{
- follow_info_t *follow_info = (follow_info_t *)data;
-
- /*
- * A radio button toggles when it goes on and when it goes
- * off, so when you click a radio button two signals are
- * delivered. We only want to reprocess the display once,
- * so we do it only when the button goes on.
- */
- if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w))) {
- if (w == follow_info->ebcdic_bt)
- follow_info->show_type = SHOW_EBCDIC;
- else if (w == follow_info->hexdump_bt)
- follow_info->show_type = SHOW_HEXDUMP;
- else if (w == follow_info->carray_bt)
- follow_info->show_type = SHOW_CARRAY;
- else if (w == follow_info->ascii_bt)
- follow_info->show_type = SHOW_ASCII;
- else if (w == follow_info->raw_bt)
- follow_info->show_type = SHOW_RAW;
- follow_load_text(follow_info);
- }
-}
-
-void
follow_load_text(follow_info_t *follow_info)
{
GtkTextBuffer *buf;
+ gtk_follow_info_t *gtk_follow_info = (gtk_follow_info_t *)follow_info->gui_data;
- buf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(follow_info->text));
+ buf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(gtk_follow_info->text));
/* prepare colors one time for repeated use by follow_add_to_gtk_text */
color_t_to_gdkcolor(&server_fg, &prefs.st_server_fg);
@@ -218,27 +390,56 @@ follow_load_text(follow_info_t *follow_info)
/* Delete any info already in text box */
gtk_text_buffer_set_text(buf, "", -1);
- follow_read_stream(follow_info, follow_add_to_gtk_text,
- follow_info->text);
+ gtk_follow_info->read_stream(follow_info, follow_add_to_gtk_text,
+ gtk_follow_info->text);
}
-void
+/* Handles the display style toggling */
+static void
+follow_charset_toggle_cb(GtkWidget * w _U_, gpointer data)
+{
+ follow_info_t *follow_info = (follow_info_t *)data;
+ gtk_follow_info_t *gtk_follow_info = (gtk_follow_info_t *)follow_info->gui_data;
+
+ /*
+ * A radio button toggles when it goes on and when it goes
+ * off, so when you click a radio button two signals are
+ * delivered. We only want to reprocess the display once,
+ * so we do it only when the button goes on.
+ */
+ if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w))) {
+ if (w == gtk_follow_info->ebcdic_bt)
+ gtk_follow_info->show_type = SHOW_EBCDIC;
+ else if (w == gtk_follow_info->hexdump_bt)
+ gtk_follow_info->show_type = SHOW_HEXDUMP;
+ else if (w == gtk_follow_info->carray_bt)
+ gtk_follow_info->show_type = SHOW_CARRAY;
+ else if (w == gtk_follow_info->ascii_bt)
+ gtk_follow_info->show_type = SHOW_ASCII;
+ else if (w == gtk_follow_info->raw_bt)
+ gtk_follow_info->show_type = SHOW_RAW;
+ follow_load_text(follow_info);
+ }
+}
+
+static void
follow_filter_out_stream(GtkWidget * w _U_, gpointer data)
{
follow_info_t *follow_info = (follow_info_t *)data;
+ gtk_follow_info_t *gtk_follow_info = (gtk_follow_info_t *)follow_info->gui_data;
/* Lock out user from messing with us. (ie. don't free our data!) */
- gtk_widget_set_sensitive(follow_info->streamwindow, FALSE);
+ gtk_widget_set_sensitive(gtk_follow_info->streamwindow, FALSE);
/* Set the display filter. */
- gtk_entry_set_text(GTK_ENTRY(follow_info->filter_te),
+ gtk_entry_set_text(GTK_ENTRY(gtk_follow_info->filter_te),
follow_info->filter_out_filter);
/* Run the display filter so it goes in effect. */
main_filter_packets(&cfile, follow_info->filter_out_filter, FALSE);
/* we force a subsequent close */
- window_destroy(follow_info->streamwindow);
+ window_destroy(gtk_follow_info->streamwindow);
return;
}
@@ -247,22 +448,23 @@ static void
follow_find_cb(GtkWidget * w _U_, gpointer data)
{
follow_info_t *follow_info = (follow_info_t *)data;
+ gtk_follow_info_t *gtk_follow_info = (gtk_follow_info_t *)follow_info->gui_data;
GtkWidget *find_dlg_w, *main_vb, *buttons_row, *find_lb;
GtkWidget *find_hb, *find_text_box, *find_bt, *cancel_bt;
- if (follow_info->find_dlg_w != NULL) {
+ if (gtk_follow_info->find_dlg_w != NULL) {
/* There's already a dialog box; reactivate it. */
- reactivate_window(follow_info->find_dlg_w);
+ reactivate_window(gtk_follow_info->find_dlg_w);
return;
}
/* Create the find box */
find_dlg_w = dlg_window_new("Wireshark: Find text");
gtk_window_set_transient_for(GTK_WINDOW(find_dlg_w),
- GTK_WINDOW(follow_info->streamwindow));
+ GTK_WINDOW(gtk_follow_info->streamwindow));
gtk_widget_set_size_request(find_dlg_w, 225, -1);
gtk_window_set_destroy_with_parent(GTK_WINDOW(find_dlg_w), TRUE);
- follow_info->find_dlg_w = find_dlg_w;
+ gtk_follow_info->find_dlg_w = find_dlg_w;
g_signal_connect(find_dlg_w, "destroy", G_CALLBACK(follow_find_destroy_cb),
follow_info);
@@ -317,6 +519,7 @@ follow_find_button_cb(GtkWidget * w, gpointer data)
gboolean found;
const gchar *find_string;
follow_info_t *follow_info = (follow_info_t *)data;
+ gtk_follow_info_t *gtk_follow_info = (gtk_follow_info_t *)follow_info->gui_data;
GtkTextBuffer *buffer;
GtkTextIter iter, match_start, match_end;
GtkTextMark *last_pos_mark;
@@ -327,7 +530,7 @@ follow_find_button_cb(GtkWidget * w, gpointer data)
find_string = gtk_entry_get_text(GTK_ENTRY(find_string_w));
/* Get the buffer associated with the follow stream */
- buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(follow_info->text));
+ buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(gtk_follow_info->text));
gtk_text_buffer_get_start_iter(buffer, &iter);
/* Look for the search string in the buffer */
@@ -345,7 +548,7 @@ follow_find_button_cb(GtkWidget * w, gpointer data)
last_pos_mark = gtk_text_buffer_create_mark (buffer,
"last_position",
&match_end, FALSE);
- gtk_text_view_scroll_mark_onscreen(GTK_TEXT_VIEW(follow_info->text), last_pos_mark);
+ gtk_text_view_scroll_mark_onscreen(GTK_TEXT_VIEW(gtk_follow_info->text), last_pos_mark);
} else {
/* We didn't find a match */
simple_dialog(ESD_TYPE_INFO, ESD_BTN_OK,
@@ -362,10 +565,11 @@ follow_find_button_cb(GtkWidget * w, gpointer data)
static void
follow_find_destroy_cb(GtkWidget * win _U_, gpointer data)
{
- follow_info_t *follow_info = (follow_info_t *)data;
+ follow_info_t *follow_info = (follow_info_t *)data;
+ gtk_follow_info_t *gtk_follow_info = (gtk_follow_info_t *)follow_info->gui_data;
/* Note that we no longer have a dialog box. */
- follow_info->find_dlg_w = NULL;
+ gtk_follow_info->find_dlg_w = NULL;
}
static void
@@ -375,6 +579,7 @@ follow_print_stream(GtkWidget * w _U_, gpointer data)
gboolean to_file;
const char *print_dest;
follow_info_t *follow_info =(follow_info_t *) data;
+ gtk_follow_info_t *gtk_follow_info = (gtk_follow_info_t *)follow_info->gui_data;
#ifdef _WIN32
gboolean win_printer = FALSE;
int tmp_fd;
@@ -447,7 +652,7 @@ follow_print_stream(GtkWidget * w _U_, gpointer data)
if (!print_preamble(stream, cfile.filename, get_ws_vcs_version_info()))
goto print_error;
- switch (follow_read_stream(follow_info, follow_print_text, stream)) {
+ switch (gtk_follow_info->read_stream(follow_info, follow_print_text, stream)) {
case FRS_OK:
break;
case FRS_OPEN_ERROR:
@@ -525,8 +730,9 @@ follow_save_as_ok_cb(gchar *to_name, follow_info_t *follow_info)
{
FILE *fh;
print_stream_t *stream;
+ gtk_follow_info_t *gtk_follow_info = (gtk_follow_info_t *)follow_info->gui_data;
- if (follow_info->show_type == SHOW_RAW) {
+ if (gtk_follow_info->show_type == SHOW_RAW) {
/* Write the data out as raw binary data */
fh = ws_fopen(to_name, "wb");
} else {
@@ -538,8 +744,8 @@ follow_save_as_ok_cb(gchar *to_name, follow_info_t *follow_info)
return FALSE;
}
- if (follow_info->show_type == SHOW_RAW) {
- switch (follow_read_stream(follow_info, follow_write_raw, fh)) {
+ if (gtk_follow_info->show_type == SHOW_RAW) {
+ switch (gtk_follow_info->read_stream(follow_info, follow_write_raw, fh)) {
case FRS_OK:
if (fclose(fh) == EOF) {
write_failure_alert_box(to_name, errno);
@@ -559,7 +765,7 @@ follow_save_as_ok_cb(gchar *to_name, follow_info_t *follow_info)
}
} else {
stream = print_stream_text_stdio_new(fh);
- switch (follow_read_stream(follow_info, follow_print_text, stream)) {
+ switch (gtk_follow_info->read_stream(follow_info, follow_print_text, stream)) {
case FRS_OK:
if (!destroy_print_stream(stream)) {
write_failure_alert_box(to_name, errno);
@@ -637,7 +843,7 @@ remember_follow_info(follow_info_t *follow_info)
follow_infos = g_list_append(follow_infos, follow_info);
}
-#define IS_SHOW_TYPE(x) (follow_info->show_type == x ? 1 : 0)
+#define IS_SHOW_TYPE(x) (gtk_follow_info->show_type == x ? 1 : 0)
/* Remove a "follow_info_t" structure from the list. */
static void
forget_follow_info(follow_info_t *follow_info)
@@ -645,7 +851,7 @@ forget_follow_info(follow_info_t *follow_info)
follow_infos = g_list_remove(follow_infos, follow_info);
}
-void
+static void
follow_stream(const gchar *title, follow_info_t *follow_info,
gchar *both_directions_string,
gchar *server_to_client_string, gchar *client_to_server_string)
@@ -654,14 +860,14 @@ follow_stream(const gchar *title, follow_info_t *follow_info,
GtkWidget *hbox, *bbox, *button, *radio_bt;
GtkWidget *stream_fr, *stream_vb, *direction_hbox;
GtkWidget *stream_cmb;
- follow_stats_t stats;
+ gtk_follow_info_t *gtk_follow_info = (gtk_follow_info_t *)follow_info->gui_data;
- follow_info->show_type = SHOW_RAW;
+ gtk_follow_info->show_type = SHOW_RAW;
streamwindow = dlg_window_new(title);
/* needed in follow_filter_out_stream(), is there a better way? */
- follow_info->streamwindow = streamwindow;
+ gtk_follow_info->streamwindow = streamwindow;
gtk_widget_set_name(streamwindow, title);
gtk_window_set_default_size(GTK_WINDOW(streamwindow), DEF_WIDTH, DEF_HEIGHT);
@@ -672,11 +878,7 @@ follow_stream(const gchar *title, follow_info_t *follow_info,
gtk_container_add(GTK_CONTAINER(streamwindow), vbox);
/* content frame */
- if (incomplete_tcp_stream) {
- stream_fr = gtk_frame_new("Stream Content (incomplete)");
- } else {
- stream_fr = gtk_frame_new("Stream Content");
- }
+ stream_fr = gtk_frame_new("Stream Content");
gtk_box_pack_start(GTK_BOX (vbox), stream_fr, TRUE, TRUE, 0);
gtk_widget_show(stream_fr);
@@ -695,7 +897,7 @@ follow_stream(const gchar *title, follow_info_t *follow_info,
gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(text), GTK_WRAP_WORD_CHAR);
gtk_container_add(GTK_CONTAINER(txt_scrollw), text);
- follow_info->text = text;
+ gtk_follow_info->text = text;
/* direction hbox */
direction_hbox = ws_gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 1, FALSE);
@@ -740,18 +942,13 @@ follow_stream(const gchar *title, follow_info_t *follow_info,
gtk_widget_set_tooltip_text(button, "Print the content as currently displayed");
gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, TRUE, 0);
- /* Stream to show */
- follow_stats(&stats);
-
- follow_info->is_ipv6 = stats.is_ipv6;
-
/* ASCII radio button */
radio_bt = gtk_radio_button_new_with_label(NULL, "ASCII");
gtk_widget_set_tooltip_text(radio_bt, "Stream data output in \"ASCII\" format");
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(radio_bt), IS_SHOW_TYPE(SHOW_ASCII));
gtk_box_pack_start(GTK_BOX(hbox), radio_bt, TRUE, TRUE, 0);
g_signal_connect(radio_bt, "toggled", G_CALLBACK(follow_charset_toggle_cb), follow_info);
- follow_info->ascii_bt = radio_bt;
+ gtk_follow_info->ascii_bt = radio_bt;
/* EBCDIC radio button */
radio_bt = gtk_radio_button_new_with_label(gtk_radio_button_get_group(GTK_RADIO_BUTTON(radio_bt)),
@@ -760,7 +957,7 @@ follow_stream(const gchar *title, follow_info_t *follow_info,
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(radio_bt), IS_SHOW_TYPE(SHOW_EBCDIC));
gtk_box_pack_start(GTK_BOX(hbox), radio_bt, TRUE, TRUE, 0);
g_signal_connect(radio_bt, "toggled", G_CALLBACK(follow_charset_toggle_cb), follow_info);
- follow_info->ebcdic_bt = radio_bt;
+ gtk_follow_info->ebcdic_bt = radio_bt;
/* HEX DUMP radio button */
radio_bt = gtk_radio_button_new_with_label(gtk_radio_button_get_group(GTK_RADIO_BUTTON(radio_bt)),
@@ -769,7 +966,7 @@ follow_stream(const gchar *title, follow_info_t *follow_info,
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(radio_bt), IS_SHOW_TYPE(SHOW_HEXDUMP));
gtk_box_pack_start(GTK_BOX(hbox), radio_bt, TRUE, TRUE, 0);
g_signal_connect(radio_bt, "toggled", G_CALLBACK(follow_charset_toggle_cb),follow_info);
- follow_info->hexdump_bt = radio_bt;
+ gtk_follow_info->hexdump_bt = radio_bt;
/* C Array radio button */
radio_bt = gtk_radio_button_new_with_label(gtk_radio_button_get_group(GTK_RADIO_BUTTON(radio_bt)),
@@ -778,7 +975,7 @@ follow_stream(const gchar *title, follow_info_t *follow_info,
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(radio_bt), IS_SHOW_TYPE(SHOW_CARRAY));
gtk_box_pack_start(GTK_BOX(hbox), radio_bt, TRUE, TRUE, 0);
g_signal_connect(radio_bt, "toggled", G_CALLBACK(follow_charset_toggle_cb), follow_info);
- follow_info->carray_bt = radio_bt;
+ gtk_follow_info->carray_bt = radio_bt;
/* Raw radio button */
radio_bt = gtk_radio_button_new_with_label(gtk_radio_button_get_group(GTK_RADIO_BUTTON(radio_bt)),
@@ -790,7 +987,7 @@ follow_stream(const gchar *title, follow_info_t *follow_info,
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(radio_bt), IS_SHOW_TYPE(SHOW_RAW));
gtk_box_pack_start(GTK_BOX(hbox), radio_bt, TRUE, TRUE, 0);
g_signal_connect(radio_bt, "toggled", G_CALLBACK(follow_charset_toggle_cb), follow_info);
- follow_info->raw_bt = radio_bt;
+ gtk_follow_info->raw_bt = radio_bt;
/* Button row: help, filter out, close button */
bbox = dlg_button_row_new(WIRESHARK_STOCK_FILTER_OUT_STREAM, GTK_STOCK_CLOSE, GTK_STOCK_HELP,
@@ -840,56 +1037,32 @@ follow_destroy_cb(GtkWidget *w, gpointer data _U_)
{
follow_info_t *follow_info;
follow_record_t *follow_record;
+ gtk_follow_info_t *gtk_follow_info;
GList *cur;
- int i;
follow_info = (follow_info_t *)g_object_get_data(G_OBJECT(w), E_FOLLOW_INFO_KEY);
+ gtk_follow_info = (gtk_follow_info_t *)follow_info->gui_data;
- switch(follow_info->follow_type) {
+ for(cur = follow_info->payload; cur; cur = g_list_next(cur))
+ if(cur->data) {
+ follow_record = (follow_record_t *)cur->data;
+ if(follow_record->data)
+ g_byte_array_free(follow_record->data, TRUE);
- case FOLLOW_TCP :
- i = ws_unlink(follow_info->data_out_filename);
- if(i != 0) {
- g_warning("Follow: Couldn't remove temporary file: \"%s\", errno: %s (%u)",
- follow_info->data_out_filename, g_strerror(errno), errno);
+ g_free(follow_record);
}
- break;
-
- case FOLLOW_UDP :
- case FOLLOW_HTTP :
- for(cur = follow_info->payload; cur; cur = g_list_next(cur))
- if(cur->data) {
- follow_record = (follow_record_t *)cur->data;
- if(follow_record->data)
- g_byte_array_free(follow_record->data, TRUE);
-
- g_free(follow_record);
- }
- g_list_free(follow_info->payload);
- break;
+ g_list_free(follow_info->payload);
- case FOLLOW_SSL :
- /* free decrypted data list*/
- for (cur = follow_info->payload; cur; cur = g_list_next(cur))
- if (cur->data)
- {
- g_free(cur->data);
- cur->data = NULL;
- }
- g_list_free (follow_info->payload);
- break;
- }
-
- g_free(follow_info->data_out_filename);
g_free(follow_info->filter_out_filter);
g_free((gpointer)follow_info->client_ip.data);
forget_follow_info(follow_info);
+ g_free(gtk_follow_info);
g_free(follow_info);
gtk_widget_destroy(w);
}
-frs_return_t
+static frs_return_t
follow_show(follow_info_t *follow_info,
follow_print_line_func follow_print,
char *buffer, size_t nchars, gboolean is_from_server, void *arg,
@@ -899,8 +1072,9 @@ follow_show(follow_info_t *follow_info,
gchar initbuf[256];
guint32 current_pos;
static const gchar hexchars[16] = {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
+ gtk_follow_info_t *gtk_follow_info = (gtk_follow_info_t *)follow_info->gui_data;
- switch (follow_info->show_type) {
+ switch (gtk_follow_info->show_type) {
case SHOW_EBCDIC:
/* If our native arch is ASCII, call: */
@@ -1024,6 +1198,123 @@ follow_show(follow_info_t *follow_info,
return FRS_OK;
}
+/* Follow the TCP stream, if any, to which the last packet that we called
+ a dissection routine on belongs (this might be the most recently
+ selected packet, or it might be the last packet in the file). */
+void
+follow_tcp_stream_cb(GtkWidget * w _U_, gpointer data _U_)
+{
+ register_follow_t* follower = get_follow_by_name("TCP");
+
+ follow_stream_cb(follower, follow_common_read_stream, w, data);
+}
+
+/* Follow the UDP stream, if any, to which the last packet that we called
+ a dissection routine on belongs (this might be the most recently
+ selected packet, or it might be the last packet in the file). */
+void
+follow_udp_stream_cb(GtkWidget * w _U_, gpointer data _U_)
+{
+ register_follow_t* follower = get_follow_by_name("UDP");
+
+ follow_stream_cb(follower, follow_common_read_stream, w, data);
+}
+
+/* Follow the HTTP stream, if any, to which the last packet that we called
+ a dissection routine on belongs (this might be the most recently
+ selected packet, or it might be the last packet in the file). */
+void
+follow_http_stream_cb(GtkWidget * w _U_, gpointer data _U_)
+{
+ register_follow_t* follower = get_follow_by_name("HTTP");
+
+ follow_stream_cb(follower, follow_common_read_stream, w, data);
+}
+
+/*
+ * XXX - the routine pointed to by "print_line_fcn_p" doesn't get handed lines,
+ * it gets handed bufferfuls. That's fine for "follow_write_raw()"
+ * and "follow_add_to_gtk_text()", but, as "follow_print_text()" calls
+ * the "print_line()" routine from "print.c", and as that routine might
+ * genuinely expect to be handed a line (if, for example, it's using
+ * some OS or desktop environment's printing API, and that API expects
+ * to be handed lines), "follow_print_text()" should probably accumulate
+ * lines in a buffer and hand them "print_line()". (If there's a
+ * complete line in a buffer - i.e., there's nothing of the line in
+ * the previous buffer or the next buffer - it can just hand that to
+ * "print_line()" after filtering out non-printables, as an
+ * optimization.)
+ *
+ * This might or might not be the reason why C arrays display
+ * correctly but get extra blank lines very other line when printed.
+ */
+static frs_return_t
+follow_read_ssl_stream(follow_info_t *follow_info,
+ follow_print_line_func follow_print,
+ void *arg)
+{
+ guint32 global_client_pos = 0, global_server_pos = 0;
+ guint32 server_packet_count = 0;
+ guint32 client_packet_count = 0;
+ guint32 * global_pos;
+ GList * cur;
+ frs_return_t frs_return;
+
+ for (cur = follow_info->payload; cur; cur = g_list_next(cur)) {
+ SslDecryptedRecord * rec = (SslDecryptedRecord*) cur->data;
+ gboolean include_rec = FALSE;
+
+ if (rec->is_from_server) {
+ global_pos = &global_server_pos;
+ include_rec = (follow_info->show_stream == BOTH_HOSTS) ||
+ (follow_info->show_stream == FROM_SERVER);
+ } else {
+ global_pos = &global_client_pos;
+ include_rec = (follow_info->show_stream == BOTH_HOSTS) ||
+ (follow_info->show_stream == FROM_CLIENT);
+ }
+
+ if (include_rec) {
+ size_t nchars = rec->data.data_len;
+ gchar *buffer = (gchar *)g_memdup(rec->data.data, (guint) nchars);
+
+ frs_return = follow_show(follow_info, follow_print, buffer, nchars,
+ rec->is_from_server, arg, global_pos,
+ &server_packet_count, &client_packet_count);
+ g_free(buffer);
+ if (frs_return == FRS_PRINT_ERROR)
+ return frs_return;
+ }
+ }
+
+ return FRS_OK;
+}
+
+
+/* Follow the SSL stream, if any, to which the last packet that we called
+ a dissection routine on belongs (this might be the most recently
+ selected packet, or it might be the last packet in the file). */
+void
+follow_ssl_stream_cb(GtkWidget * w _U_, gpointer data _U_)
+{
+ register_follow_t* follower = get_follow_by_name("SSL");
+
+ follow_stream_cb(follower, follow_read_ssl_stream, w, data);
+}
+
+static void
+follow_redraw(gpointer data, gpointer user_data _U_)
+{
+ follow_load_text((follow_info_t *)data);
+}
+
+/* Redraw the text in all "Follow Stream" windows. */
+void
+follow_stream_redraw_all(void)
+{
+ g_list_foreach(follow_infos, follow_redraw, NULL);
+}
+
/*
* Editor modelines - http://www.wireshark.org/tools/modelines.html
*
diff --git a/ui/gtk/follow_stream.h b/ui/gtk/follow_stream.h
index cb5252b612..8b3f7d7eaa 100644
--- a/ui/gtk/follow_stream.h
+++ b/ui/gtk/follow_stream.h
@@ -25,18 +25,11 @@
#define __FOLLOW_STREAM_H__
#include <gtk/gtk.h>
-#include <ui/follow.h>
+#include <epan/follow.h>
-struct _follow_info;
-typedef gboolean (*follow_print_line_func)(char *, size_t, gboolean, void *);
-typedef frs_return_t (*follow_read_stream_func)(struct _follow_info *follow_info, follow_print_line_func follow_print, void *arg);
-
-typedef struct _follow_info {
- follow_type_t follow_type;
- show_stream_t show_stream;
+typedef struct _gtk_follow_info {
show_type_t show_type;
- char *data_out_filename;
GtkWidget *text;
GtkWidget *ascii_bt;
GtkWidget *ebcdic_bt;
@@ -44,37 +37,38 @@ typedef struct _follow_info {
GtkWidget *carray_bt;
GtkWidget *raw_bt;
GtkWidget *find_dlg_w;
- gboolean is_ipv6;
- char *filter_out_filter;
GtkWidget *filter_te;
GtkWidget *streamwindow;
- GList *payload;
- guint bytes_written[2]; /* Index with FROM_CLIENT or FROM_SERVER for readability. */
- guint client_port;
- address client_ip;
follow_read_stream_func read_stream;
-} follow_info_t;
+} gtk_follow_info_t;
#define E_FOLLOW_INFO_KEY "follow_info_key"
-/* List of "follow_info_t" structures for all "Follow TCP Stream" windows,
- so we can redraw them all if the colors or font changes. */
-extern GList *follow_infos;
+/** Redraw the text in all "Follow TCP Stream" windows. */
+extern void follow_stream_redraw_all(void);
+
+/** User requested the "Follow TCP Stream" dialog box by menu or toolbar.
+ *
+ * @param widget parent widget (unused)
+ * @param data unused
+ */
+extern void follow_tcp_stream_cb( GtkWidget *widget, gpointer data);
+
+/* Follow the UDP stream, if any, to which the last packet that we called
+ a dissection routine on belongs (this might be the most recently
+ selected packet, or it might be the last packet in the file). */
+void follow_udp_stream_cb(GtkWidget * w, gpointer data _U_);
+
+/* Follow the HTTP stream, if any, to which the last packet that we called
+ a dissection routine on belongs (this might be the most recently
+ selected packet, or it might be the last packet in the file). */
+void follow_http_stream_cb(GtkWidget * w, gpointer data _U_);
+
+/* Follow the SSL stream, if any, to which the last packet that we called
+ a dissection routine on belongs (this might be the most recently
+ selected packet, or it might be the last packet in the file). */
+void follow_ssl_stream_cb(GtkWidget * w, gpointer data _U_);
-void follow_load_text(follow_info_t *follow_info);
-void follow_filter_out_stream(GtkWidget * w, gpointer parent_w);
-void follow_stream(const gchar *title, follow_info_t *follow_info,
- gchar *both_directions_string,
- gchar *server_to_client_string,
- gchar *client_to_server_string);
-frs_return_t follow_show(follow_info_t *follow_info,
- follow_print_line_func follow_print,
- char *buffer, size_t nchars, gboolean is_server,
- void *arg, guint32 *global_pos,
- guint32 *server_packet_count,
- guint32 *client_packet_count);
-gboolean follow_add_to_gtk_text(char *buffer, size_t nchars, gboolean is_server,
- void *arg);
#endif /* __FOLLOW_STREAM_H__ */
diff --git a/ui/gtk/follow_tcp.c b/ui/gtk/follow_tcp.c
deleted file mode 100644
index edfbfac381..0000000000
--- a/ui/gtk/follow_tcp.c
+++ /dev/null
@@ -1,327 +0,0 @@
-/* follow_tcp.c
- * TCP specific routines for following traffic streams
- *
- * 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 <gtk/gtk.h>
-
-#include <epan/addr_resolv.h>
-#include <epan/epan_dissect.h>
-#include <epan/follow.h>
-#include <epan/tap.h>
-
-#include <ui/simple_dialog.h>
-#include <wsutil/utf8_entities.h>
-
-#include "gtkglobals.h"
-#include "ui/gtk/follow_stream.h"
-#include "ui/gtk/keys.h"
-#include "ui/gtk/main.h"
-#include "ui/gtk/follow_tcp.h"
-
-
-static frs_return_t
-follow_read_tcp_stream(follow_info_t *follow_info, follow_print_line_func follow_print, void *arg);
-
-static void
-follow_redraw(gpointer data, gpointer user_data _U_)
-{
- follow_load_text((follow_info_t *)data);
-}
-
-/* Redraw the text in all "Follow TCP Stream" windows. */
-void
-follow_tcp_redraw_all(void)
-{
- g_list_foreach(follow_infos, follow_redraw, NULL);
-}
-
-static gboolean
-tcp_queue_packet_data(void *tapdata, packet_info *pinfo,
- epan_dissect_t *edt _U_, const void *data)
-{
- follow_record_t *follow_record;
- follow_info_t *follow_info = (follow_info_t *)tapdata;
- tvbuff_t *next_tvb = (tvbuff_t *)data;
-
- follow_record = g_new(follow_record_t,1);
-
- follow_record->data = g_byte_array_sized_new(tvb_captured_length(next_tvb));
- follow_record->data = g_byte_array_append(follow_record->data,
- tvb_get_ptr(next_tvb, 0, -1),
- tvb_captured_length(next_tvb));
-
- if (follow_info->client_port == 0) {
- follow_info->client_port = pinfo->srcport;
- copy_address(&follow_info->client_ip, &pinfo->src);
- }
-
- if (addresses_equal(&follow_info->client_ip, &pinfo->src) && follow_info->client_port == pinfo->srcport)
- follow_record->is_server = FALSE;
- else
- follow_record->is_server = TRUE;
-
- /* update stream counter */
- follow_info->bytes_written[follow_record->is_server] += follow_record->data->len;
-
- follow_info->payload = g_list_append(follow_info->payload, follow_record);
- return FALSE;
-}
-
-/* Follow the TCP stream, if any, to which the last packet that we called
- a dissection routine on belongs (this might be the most recently
- selected packet, or it might be the last packet in the file). */
-void
-follow_tcp_stream_cb(GtkWidget * w _U_, gpointer data _U_)
-{
- GtkWidget *filter_cm;
- GtkWidget *filter_te;
- gchar *follow_filter;
- const gchar *previous_filter;
- int filter_out_filter_len;
- const char *hostname0, *hostname1;
- char *port0, *port1;
- gchar *server_to_client_string = NULL;
- gchar *client_to_server_string = NULL;
- gchar *both_directions_string = NULL;
- follow_stats_t stats;
- follow_info_t *follow_info;
- GString *msg;
- gboolean is_tcp = FALSE;
-
- is_tcp = proto_is_frame_protocol(cfile.edt->pi.layers, "tcp");
-
- if (!is_tcp) {
- simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
- "Error following stream. Please make\n"
- "sure you have a TCP packet selected.");
- return;
- }
-
- reset_stream_follow(TCP_STREAM);
-
- follow_info = g_new0(follow_info_t, 1);
- follow_info->follow_type = FOLLOW_TCP;
- follow_info->read_stream = follow_read_tcp_stream;
-
- /* Create a new filter that matches all packets in the TCP stream,
- and set the display filter entry accordingly */
- follow_filter = build_follow_conv_filter(&cfile.edt->pi, NULL);
- if (!follow_filter) {
- simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
- "Error creating filter for this stream.\n"
- "A transport or network layer header is needed");
- g_free(follow_info);
- return;
- }
-
- /* Set the display filter entry accordingly */
- filter_cm = (GtkWidget *)g_object_get_data(G_OBJECT(top_level), E_DFILTER_CM_KEY);
- filter_te = gtk_bin_get_child(GTK_BIN(filter_cm));
-
- /* needed in follow_filter_out_stream(), is there a better way? */
- follow_info->filter_te = filter_te;
-
- /* save previous filter, const since we're not supposed to alter */
- previous_filter =
- (const gchar *)gtk_entry_get_text(GTK_ENTRY(filter_te));
-
- /* allocate our new filter. API claims g_malloc terminates program on failure */
- /* my calc for max alloc needed is really +10 but when did a few extra bytes hurt ? */
- filter_out_filter_len = (int)(strlen(follow_filter) + strlen(previous_filter) + 16);
- follow_info->filter_out_filter = (gchar *)g_malloc(filter_out_filter_len);
-
- /* append the negation */
- if(strlen(previous_filter)) {
- g_snprintf(follow_info->filter_out_filter, filter_out_filter_len,
- "%s and !(%s)", previous_filter, follow_filter);
- } else {
- g_snprintf(follow_info->filter_out_filter, filter_out_filter_len,
- "!(%s)", follow_filter);
- }
-
- /* data will be passed via tap callback*/
- msg = register_tap_listener("tcp_follow", follow_info, follow_filter,
- 0, NULL, tcp_queue_packet_data, NULL);
- if (msg) {
- simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
- "Can't register tcp_follow tap: %s\n",
- msg->str);
- g_free(follow_info->filter_out_filter);
- g_free(follow_info);
- g_free(follow_filter);
- return;
- }
-
- gtk_entry_set_text(GTK_ENTRY(filter_te), follow_filter);
-
- /* Run the display filter so it goes in effect - even if it's the
- same as the previous display filter. */
- main_filter_packets(&cfile, follow_filter, TRUE);
-
- remove_tap_listener(follow_info);
-
- /* Stream to show */
- follow_stats(&stats);
-
- if (stats.is_ipv6) {
- hostname0 = get_hostname6(&stats.ip_address[0].ipv6);
- hostname1 = get_hostname6(&stats.ip_address[1].ipv6);
- } else {
- hostname0 = get_hostname(stats.ip_address[0].ipv4);
- hostname1 = get_hostname(stats.ip_address[1].ipv4);
- }
-
- follow_info->is_ipv6 = stats.is_ipv6;
-
- port0 = tcp_port_to_display(NULL, stats.port[0]);
- port1 = tcp_port_to_display(NULL, stats.port[1]);
-
- /* Both Stream Directions */
- both_directions_string = g_strdup_printf("Entire conversation (%u bytes)", follow_info->bytes_written[0] + follow_info->bytes_written[1]);
-
- if ((follow_info->client_port == stats.port[0]) &&
- ((stats.is_ipv6 && (memcmp(follow_info->client_ip.data, &stats.ip_address[0], 16) == 0)) ||
- (!stats.is_ipv6 && (memcmp(follow_info->client_ip.data, &stats.ip_address[0], 4) == 0)))) {
- server_to_client_string =
- g_strdup_printf("%s:%s " UTF8_RIGHTWARDS_ARROW " %s:%s (%u bytes)",
- hostname0, port0,
- hostname1, port1,
- follow_info->bytes_written[0]);
-
- client_to_server_string =
- g_strdup_printf("%s:%s " UTF8_RIGHTWARDS_ARROW " %s:%s (%u bytes)",
- hostname1, port1,
- hostname0, port0,
- follow_info->bytes_written[1]);
- } else {
- server_to_client_string =
- g_strdup_printf("%s:%s " UTF8_RIGHTWARDS_ARROW " %s:%s (%u bytes)",
- hostname1, port1,
- hostname0, port0,
- follow_info->bytes_written[0]);
-
- client_to_server_string =
- g_strdup_printf("%s:%s " UTF8_RIGHTWARDS_ARROW " %s:%s (%u bytes)",
- hostname0, port0,
- hostname1, port1,
- follow_info->bytes_written[1]);
- }
-
- follow_stream("Follow TCP Stream", follow_info, both_directions_string,
- server_to_client_string, client_to_server_string);
-
- /* Free the filter string, as we're done with it. */
- g_free(follow_filter);
-
- wmem_free(NULL, port0);
- wmem_free(NULL, port1);
- g_free(both_directions_string);
- g_free(server_to_client_string);
- g_free(client_to_server_string);
-}
-
-#define FLT_BUF_SIZE 1024
-
-/*
- * XXX - the routine pointed to by "print_line_fcn_p" doesn't get handed lines,
- * it gets handed bufferfuls. That's fine for "follow_write_raw()"
- * and "follow_add_to_gtk_text()", but, as "follow_print_text()" calls
- * the "print_line()" routine from "print.c", and as that routine might
- * genuinely expect to be handed a line (if, for example, it's using
- * some OS or desktop environment's printing API, and that API expects
- * to be handed lines), "follow_print_text()" should probably accumulate
- * lines in a buffer and hand them "print_line()". (If there's a
- * complete line in a buffer - i.e., there's nothing of the line in
- * the previous buffer or the next buffer - it can just hand that to
- * "print_line()" after filtering out non-printables, as an
- * optimization.)
- *
- * This might or might not be the reason why C arrays display
- * correctly but get extra blank lines very other line when printed.
- */
-static frs_return_t
-follow_read_tcp_stream(follow_info_t *follow_info,
- follow_print_line_func follow_print,
- void *arg)
-{
- guint32 global_client_pos = 0, global_server_pos = 0;
- guint32 server_packet_count = 0;
- guint32 client_packet_count = 0;
- guint32 *global_pos;
- gboolean skip;
- GList* cur;
- frs_return_t frs_return;
- follow_record_t *follow_record;
- char *buffer;
-
-
- for (cur = follow_info->payload; cur; cur = g_list_next(cur)) {
- follow_record = (follow_record_t *)cur->data;
- skip = FALSE;
- if (!follow_record->is_server) {
- global_pos = &global_client_pos;
- if(follow_info->show_stream == FROM_SERVER) {
- skip = TRUE;
- }
- } else {
- global_pos = &global_server_pos;
- if (follow_info->show_stream == FROM_CLIENT) {
- skip = TRUE;
- }
- }
-
- if (!skip) {
- buffer = (char *)g_memdup(follow_record->data->data,
- follow_record->data->len);
-
- frs_return = follow_show(follow_info, follow_print,
- buffer,
- follow_record->data->len,
- follow_record->is_server, arg,
- global_pos,
- &server_packet_count,
- &client_packet_count);
- g_free(buffer);
- if(frs_return == FRS_PRINT_ERROR)
- return frs_return;
- }
- }
-
- return FRS_OK;
-}
-
-/*
- * Editor modelines - http://www.wireshark.org/tools/modelines.html
- *
- * Local variables:
- * c-basic-offset: 4
- * tab-width: 8
- * indent-tabs-mode: nil
- * End:
- *
- * vi: set shiftwidth=4 tabstop=8 expandtab:
- * :indentSize=4:tabSize=8:noTabs=true:
- */
diff --git a/ui/gtk/follow_tcp.h b/ui/gtk/follow_tcp.h
deleted file mode 100644
index bb0e4c905b..0000000000
--- a/ui/gtk/follow_tcp.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/* follow_tcp.h
- * TCP specific routines for following traffic streams
- *
- * Wireshark - Network traffic analyzer
- * By Gerald Combs <gerald@wireshark.org>
- * Copyright 2000 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 __FOLLOW_TCP_H__
-#define __FOLLOW_TCP_H__
-
-/** @file
- * "Follow TCP Stream" dialog box.
- * @ingroup dialog_group
- */
-
-/** User requested the "Follow TCP Stream" dialog box by menu or toolbar.
- *
- * @param widget parent widget (unused)
- * @param data unused
- */
-extern void follow_tcp_stream_cb( GtkWidget *widget, gpointer data);
-
-/** Redraw the text in all "Follow TCP Stream" windows. */
-extern void follow_tcp_redraw_all(void);
-
-#endif /* __FOLLOW_TCP_H__ */
-
-/*
- * Editor modelines - http://www.wireshark.org/tools/modelines.html
- *
- * Local variables:
- * c-basic-offset: 4
- * tab-width: 8
- * indent-tabs-mode: nil
- * End:
- *
- * vi: set shiftwidth=4 tabstop=8 expandtab:
- * :indentSize=4:tabSize=8:noTabs=true:
- */
diff --git a/ui/gtk/follow_udp.c b/ui/gtk/follow_udp.c
deleted file mode 100644
index c519d82685..0000000000
--- a/ui/gtk/follow_udp.c
+++ /dev/null
@@ -1,313 +0,0 @@
-/* follow_udp.c
- * UDP specific routines for following traffic streams
- *
- * 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 <gtk/gtk.h>
-
-#include <epan/addr_resolv.h>
-#include <epan/epan_dissect.h>
-#include <epan/follow.h>
-#include <epan/tap.h>
-
-#include <ui/simple_dialog.h>
-#include <wsutil/utf8_entities.h>
-
-#include "gtkglobals.h"
-#include "ui/gtk/follow_stream.h"
-#include "ui/gtk/keys.h"
-#include "ui/gtk/main.h"
-#include "ui/gtk/follow_udp.h"
-
-static frs_return_t
-follow_read_udp_stream(follow_info_t *follow_info, follow_print_line_func follow_print, void *arg);
-
-static gboolean
-udp_queue_packet_data(void *tapdata, packet_info *pinfo,
- epan_dissect_t *edt _U_, const void *data)
-{
- follow_record_t *follow_record;
- follow_info_t *follow_info = (follow_info_t *)tapdata;
- tvbuff_t *next_tvb = (tvbuff_t *)data;
-
- follow_record = g_new(follow_record_t,1);
-
- follow_record->data = g_byte_array_sized_new(tvb_captured_length(next_tvb));
- follow_record->data = g_byte_array_append(follow_record->data,
- tvb_get_ptr(next_tvb, 0, -1),
- tvb_captured_length(next_tvb));
-
- if (follow_info->client_port == 0) {
- follow_info->client_port = pinfo->srcport;
- copy_address(&follow_info->client_ip, &pinfo->src);
- }
-
- if (addresses_equal(&follow_info->client_ip, &pinfo->src) && follow_info->client_port == pinfo->srcport)
- follow_record->is_server = FALSE;
- else
- follow_record->is_server = TRUE;
-
- /* update stream counter */
- follow_info->bytes_written[follow_record->is_server] += follow_record->data->len;
-
- follow_info->payload = g_list_append(follow_info->payload, follow_record);
- return FALSE;
-}
-
-/* Follow the UDP stream, if any, to which the last packet that we called
- a dissection routine on belongs (this might be the most recently
- selected packet, or it might be the last packet in the file). */
-void
-follow_udp_stream_cb(GtkWidget *w _U_, gpointer data _U_)
-{
- GtkWidget *filter_te, *filter_cm;
- gchar *follow_filter;
- const gchar *previous_filter;
- int filter_out_filter_len, previous_filter_len;
- const char *hostname0, *hostname1;
- char *port0, *port1;
- gchar *server_to_client_string = NULL;
- gchar *client_to_server_string = NULL;
- gchar *both_directions_string = NULL;
- follow_stats_t stats;
- follow_info_t *follow_info;
- GString *msg;
- gboolean is_udp = FALSE;
-
- is_udp = proto_is_frame_protocol(cfile.edt->pi.layers, "udp");
-
- if (!is_udp) {
- simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
- "Error following stream. Please make\n"
- "sure you have a UDP packet selected.");
- return;
- }
-
- reset_stream_follow(UDP_STREAM);
-
- follow_info = g_new0(follow_info_t, 1);
- follow_info->follow_type = FOLLOW_UDP;
- follow_info->read_stream = follow_read_udp_stream;
-
- /* Create a new filter that matches all packets in the UDP stream,
- and set the display filter entry accordingly */
- follow_filter = build_follow_conv_filter(&cfile.edt->pi, NULL);
- if (!follow_filter)
- {
- simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
- "Error creating filter for this stream.\n"
- "A network layer header is needed");
- g_free(follow_info);
- return;
- }
-
- /* Set the display filter entry accordingly */
- filter_cm = (GtkWidget *)g_object_get_data(G_OBJECT(top_level), E_DFILTER_CM_KEY);
- filter_te = gtk_bin_get_child(GTK_BIN(filter_cm));
-
- /* needed in follow_filter_out_stream(), is there a better way? */
- follow_info->filter_te = filter_te;
-
- /* save previous filter, const since we're not supposed to alter */
- previous_filter =
- (const gchar *)gtk_entry_get_text(GTK_ENTRY(filter_te));
-
- /* allocate our new filter. API claims g_malloc terminates program on failure */
- /* my calc for max alloc needed is really +10 but when did a few extra bytes hurt ? */
- previous_filter_len = previous_filter?(int)strlen(previous_filter):0;
- filter_out_filter_len = (int)strlen(follow_filter) + previous_filter_len + 16;
- follow_info->filter_out_filter = (gchar *)g_malloc(filter_out_filter_len);
-
- /* append the negation */
- if(previous_filter_len) {
- g_snprintf(follow_info->filter_out_filter, filter_out_filter_len,
- "%s and !(%s)", previous_filter, follow_filter);
- } else {
- g_snprintf(follow_info->filter_out_filter, filter_out_filter_len,
- "!(%s)", follow_filter);
- }
-
- /* data will be passed via tap callback*/
- msg = register_tap_listener("udp_follow", follow_info, follow_filter,
- 0, NULL, udp_queue_packet_data, NULL);
- if (msg) {
- simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
- "Can't register udp_follow tap: %s\n",
- msg->str);
- g_free(follow_info->filter_out_filter);
- g_free(follow_info);
- g_free(follow_filter);
- return;
- }
-
- gtk_entry_set_text(GTK_ENTRY(filter_te), follow_filter);
-
- /* Run the display filter so it goes in effect - even if it's the
- same as the previous display filter. */
- main_filter_packets(&cfile, follow_filter, TRUE);
-
- /* Free the filter string, as we're done with it. */
- g_free(follow_filter);
-
- remove_tap_listener(follow_info);
-
- /* Stream to show */
- follow_stats(&stats);
-
- if (stats.is_ipv6) {
- hostname0 = get_hostname6(&stats.ip_address[0].ipv6);
- hostname1 = get_hostname6(&stats.ip_address[1].ipv6);
- } else {
- hostname0 = get_hostname(stats.ip_address[0].ipv4);
- hostname1 = get_hostname(stats.ip_address[1].ipv4);
- }
-
- port0 = udp_port_to_display(NULL, stats.port[0]);
- port1 = udp_port_to_display(NULL, stats.port[1]);
-
- follow_info->is_ipv6 = stats.is_ipv6;
-
- /* Both Stream Directions */
- both_directions_string = g_strdup_printf("Entire conversation (%u bytes)", follow_info->bytes_written[0] + follow_info->bytes_written[1]);
-
- if ((follow_info->client_port == stats.port[0]) &&
- ((stats.is_ipv6 && (memcmp(follow_info->client_ip.data, &stats.ip_address[0], 16) == 0)) ||
- (!stats.is_ipv6 && (memcmp(follow_info->client_ip.data, &stats.ip_address[0], 4) == 0)))) {
- server_to_client_string =
- g_strdup_printf("%s:%s " UTF8_RIGHTWARDS_ARROW " %s:%s (%u bytes)",
- hostname0, port0,
- hostname1, port1,
- follow_info->bytes_written[0]);
-
- client_to_server_string =
- g_strdup_printf("%s:%s " UTF8_RIGHTWARDS_ARROW " %s:%s (%u bytes)",
- hostname1, port1,
- hostname0, port0,
- follow_info->bytes_written[1]);
- } else {
- server_to_client_string =
- g_strdup_printf("%s:%s " UTF8_RIGHTWARDS_ARROW " %s:%s (%u bytes)",
- hostname1, port1,
- hostname0, port0,
- follow_info->bytes_written[0]);
-
- client_to_server_string =
- g_strdup_printf("%s:%s " UTF8_RIGHTWARDS_ARROW " %s:%s (%u bytes)",
- hostname0, port0,
- hostname1, port1,
- follow_info->bytes_written[1]);
- }
-
- follow_stream("Follow UDP Stream", follow_info, both_directions_string,
- server_to_client_string, client_to_server_string);
-
- wmem_free(NULL, port0);
- wmem_free(NULL, port1);
- g_free(both_directions_string);
- g_free(server_to_client_string);
- g_free(client_to_server_string);
-}
-
-#define FLT_BUF_SIZE 1024
-
-/*
- * XXX - the routine pointed to by "print_line_fcn_p" doesn't get handed lines,
- * it gets handed bufferfuls. That's fine for "follow_write_raw()"
- * and "follow_add_to_gtk_text()", but, as "follow_print_text()" calls
- * the "print_line()" routine from "print.c", and as that routine might
- * genuinely expect to be handed a line (if, for example, it's using
- * some OS or desktop environment's printing API, and that API expects
- * to be handed lines), "follow_print_text()" should probably accumulate
- * lines in a buffer and hand them "print_line()". (If there's a
- * complete line in a buffer - i.e., there's nothing of the line in
- * the previous buffer or the next buffer - it can just hand that to
- * "print_line()" after filtering out non-printables, as an
- * optimization.)
- *
- * This might or might not be the reason why C arrays display
- * correctly but get extra blank lines very other line when printed.
- */
-static frs_return_t
-follow_read_udp_stream(follow_info_t *follow_info,
- follow_print_line_func follow_print,
- void *arg)
-{
- guint32 global_client_pos = 0, global_server_pos = 0;
- guint32 server_packet_count = 0;
- guint32 client_packet_count = 0;
- guint32 *global_pos;
- gboolean skip;
- GList* cur;
- frs_return_t frs_return;
- follow_record_t *follow_record;
- char *buffer;
-
-
- for (cur = follow_info->payload; cur; cur = g_list_next(cur)) {
- follow_record = (follow_record_t *)cur->data;
- skip = FALSE;
- if (!follow_record->is_server) {
- global_pos = &global_client_pos;
- if(follow_info->show_stream == FROM_SERVER) {
- skip = TRUE;
- }
- } else {
- global_pos = &global_server_pos;
- if (follow_info->show_stream == FROM_CLIENT) {
- skip = TRUE;
- }
- }
-
- if (!skip) {
- buffer = (char *)g_memdup(follow_record->data->data,
- follow_record->data->len);
-
- frs_return = follow_show(follow_info, follow_print,
- buffer,
- follow_record->data->len,
- follow_record->is_server, arg,
- global_pos,
- &server_packet_count,
- &client_packet_count);
- g_free(buffer);
- if(frs_return == FRS_PRINT_ERROR)
- return frs_return;
- }
- }
-
- return FRS_OK;
-}
-
-/*
- * Editor modelines - http://www.wireshark.org/tools/modelines.html
- *
- * Local variables:
- * c-basic-offset: 4
- * tab-width: 8
- * indent-tabs-mode: nil
- * End:
- *
- * vi: set shiftwidth=4 tabstop=8 expandtab:
- * :indentSize=4:tabSize=8:noTabs=true:
- */
diff --git a/ui/gtk/follow_udp.h b/ui/gtk/follow_udp.h
deleted file mode 100644
index b85b4f823f..0000000000
--- a/ui/gtk/follow_udp.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/* follow_udp.h
- * UDP specific routines for following traffic streams
- *
- * 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 __FOLLOW_UDP_H__
-#define __FOLLOW_UDP_H__
-
-/* Follow the UDP stream, if any, to which the last packet that we called
- a dissection routine on belongs (this might be the most recently
- selected packet, or it might be the last packet in the file). */
-void follow_udp_stream_cb(GtkWidget * w, gpointer data _U_);
-
-#endif /* __FOLLOW_UDP_H__ */
-
-/*
- * Editor modelines - http://www.wireshark.org/tools/modelines.html
- *
- * Local variables:
- * c-basic-offset: 4
- * tab-width: 8
- * indent-tabs-mode: nil
- * End:
- *
- * vi: set shiftwidth=4 tabstop=8 expandtab:
- * :indentSize=4:tabSize=8:noTabs=true:
- */
-
diff --git a/ui/gtk/font_utils.c b/ui/gtk/font_utils.c
index 4fb41dacf1..a58138c99c 100644
--- a/ui/gtk/font_utils.c
+++ b/ui/gtk/font_utils.c
@@ -42,7 +42,7 @@
#include "ui/gtk/gtkglobals.h"
#include "ui/gtk/font_utils.h"
#include "ui/gtk/packet_panes.h"
-#include "ui/gtk/follow_tcp.h"
+#include "ui/gtk/follow_stream.h"
#include "ui/gtk/packet_list.h"
@@ -235,7 +235,7 @@ user_font_apply(void) {
redraw_packet_bytes_all();
/* Redraw the "Follow TCP Stream" windows. */
- follow_tcp_redraw_all();
+ follow_stream_redraw_all();
/* We're no longer using the old fonts; unreference them. */
if (old_r_font != NULL)
diff --git a/ui/gtk/main.c b/ui/gtk/main.c
index 25001d813c..6e92da071c 100644
--- a/ui/gtk/main.c
+++ b/ui/gtk/main.c
@@ -172,7 +172,6 @@
#include "ui/gtk/packet_win.h"
#include "ui/gtk/stock_icons.h"
#include "ui/gtk/find_dlg.h"
-#include "ui/gtk/follow_tcp.h"
#include "ui/gtk/font_utils.h"
#include "ui/gtk/about_dlg.h"
#include "ui/gtk/help_dlg.h"
diff --git a/ui/gtk/main_menubar.c b/ui/gtk/main_menubar.c
index c31cb335ac..76bafd1d8f 100644
--- a/ui/gtk/main_menubar.c
+++ b/ui/gtk/main_menubar.c
@@ -65,10 +65,7 @@
#include "ui/gtk/summary_dlg.h"
#include "ui/gtk/prefs_dlg.h"
#include "ui/gtk/packet_win.h"
-#include "ui/gtk/follow_http.h"
-#include "ui/gtk/follow_tcp.h"
-#include "ui/gtk/follow_udp.h"
-#include "ui/gtk/follow_ssl.h"
+#include "ui/gtk/follow_stream.h"
#include "ui/gtk/decode_as_dlg.h"
#include "ui/gtk/help_dlg.h"
#include "ui/gtk/supported_protos_dlg.h"
diff --git a/ui/gtk/prefs_font_color.c b/ui/gtk/prefs_font_color.c
index a2486eeea1..c77fb1571d 100644
--- a/ui/gtk/prefs_font_color.c
+++ b/ui/gtk/prefs_font_color.c
@@ -35,7 +35,7 @@
#include "ui/gtk/old-gtk-compat.h"
#include "color_utils.h"
-#include "follow_tcp.h"
+#include "follow_stream.h"
#include "font_utils.h"
#include "packet_panes.h"
#include "prefs_font_color.h"
@@ -528,7 +528,7 @@ font_color_prefs_apply(GtkWidget *w _U_, gboolean redissect)
redraw_packet_bytes_all();
}
- follow_tcp_redraw_all();
+ follow_stream_redraw_all();
}
diff --git a/ui/qt/conversation_dialog.cpp b/ui/qt/conversation_dialog.cpp
index efbc383e7a..599bf4c545 100644
--- a/ui/qt/conversation_dialog.cpp
+++ b/ui/qt/conversation_dialog.cpp
@@ -21,6 +21,7 @@
#include "conversation_dialog.h"
+#include <epan/prefs.h>
#include <epan/dissectors/packet-tcp.h>
#include "ui/recent.h"
diff --git a/ui/qt/follow_stream_dialog.cpp b/ui/qt/follow_stream_dialog.cpp
index 1e74d92eef..acbda38bf1 100644
--- a/ui/qt/follow_stream_dialog.cpp
+++ b/ui/qt/follow_stream_dialog.cpp
@@ -28,6 +28,7 @@
#include "epan/follow.h"
#include "epan/dissectors/packet-tcp.h"
#include "epan/dissectors/packet-udp.h"
+#include "epan/dissectors/packet-ssl-utils.h"
#include "epan/prefs.h"
#include "epan/addr_resolv.h"
#include "epan/charsets.h"
@@ -38,7 +39,6 @@
#include "ui/simple_dialog.h"
#include <wsutil/utf8_entities.h>
-#include "wsutil/tempfile.h"
#include "wsutil/file_util.h"
#include "wsutil/str_util.h"
#include "wsutil/ws_version_info.h"
@@ -47,8 +47,6 @@
#include "color_utils.h"
-#include "ui/follow.h"
-
#include "progress_frame.h"
#include "qt_ui_utils.h"
@@ -71,13 +69,32 @@ FollowStreamDialog::FollowStreamDialog(QWidget &parent, CaptureFile &cf, follow_
WiresharkDialog(parent, cf),
ui(new Ui::FollowStreamDialog),
follow_type_(type),
+ follower_(NULL),
+ show_type_(SHOW_ASCII),
truncated_(false),
save_as_(false)
{
ui->setupUi(this);
+ switch(type)
+ {
+ case FOLLOW_TCP:
+ follower_ = get_follow_by_name("TCP");
+ break;
+ case FOLLOW_SSL:
+ follower_ = get_follow_by_name("SSL");
+ break;
+ case FOLLOW_UDP:
+ follower_ = get_follow_by_name("UDP");
+ break;
+ case FOLLOW_HTTP:
+ follower_ = get_follow_by_name("HTTP");
+ break;
+ default :
+ g_assert_not_reached();
+ }
+
memset(&follow_info_, 0, sizeof(follow_info_));
- follow_info_.show_type = SHOW_ASCII;
follow_info_.show_stream = BOTH_HOSTS;
ui->teStreamContent->installEventFilter(this);
@@ -229,7 +246,7 @@ void FollowStreamDialog::saveAs()
readStream();
- if ((follow_info_.show_type != SHOW_RAW) && (follow_info_.show_type != SHOW_UTF8))
+ if ((show_type_ != SHOW_RAW) && (show_type_ != SHOW_UTF8))
{
out << ui->teStreamContent->toPlainText();
}
@@ -275,7 +292,7 @@ void FollowStreamDialog::on_cbDirections_currentIndexChanged(int idx)
void FollowStreamDialog::on_cbCharset_currentIndexChanged(int idx)
{
if (idx < 0) return;
- follow_info_.show_type = static_cast<show_type_t>(ui->cbCharset->itemData(idx).toInt());
+ show_type_ = static_cast<show_type_t>(ui->cbCharset->itemData(idx).toInt());
readStream();
}
@@ -294,18 +311,7 @@ void FollowStreamDialog::on_streamNumberSpinBox_valueChanged(int stream_num)
if (file_closed_) return;
if (stream_num >= 0) {
- switch(follow_type_)
- {
- case FOLLOW_TCP:
- case FOLLOW_SSL:
- case FOLLOW_HTTP:
- follow_index(TCP_STREAM, stream_num);
- break;
- case FOLLOW_UDP:
- follow_index(UDP_STREAM, stream_num);
- break;
- }
- follow(QString(), true);
+ follow(QString(), true, stream_num);
}
}
@@ -331,10 +337,6 @@ void FollowStreamDialog::resetStream()
if (!data_out_filename_.isEmpty()) {
ws_unlink(data_out_filename_.toUtf8().constData());
}
- if (data_out_file) {
- fclose(data_out_file);
- data_out_file = NULL;
- }
for (cur = follow_info_.payload; cur; cur = g_list_next(cur)) {
g_free(cur->data);
}
@@ -378,167 +380,6 @@ FollowStreamDialog::readStream()
return ret;
}
-//Copy from ui/gtk/follow_tcp.c
-static gboolean
-tcp_queue_packet_data(void *tapdata, packet_info *pinfo,
- epan_dissect_t *, const void *data)
-{
- follow_record_t *follow_record;
- follow_info_t *follow_info = (follow_info_t *)tapdata;
- tvbuff_t *next_tvb = (tvbuff_t *)data;
-
- follow_record = g_new(follow_record_t,1);
-
- follow_record->data = g_byte_array_sized_new(tvb_captured_length(next_tvb));
- follow_record->data = g_byte_array_append(follow_record->data,
- tvb_get_ptr(next_tvb, 0, -1),
- tvb_captured_length(next_tvb));
- follow_record->packet_num = pinfo->fd->num;
-
- if (follow_info->client_port == 0) {
- follow_info->client_port = pinfo->srcport;
- copy_address(&follow_info->client_ip, &pinfo->src);
- }
-
- if (addresses_equal(&follow_info->client_ip, &pinfo->src) && follow_info->client_port == pinfo->srcport)
- follow_record->is_server = FALSE;
- else
- follow_record->is_server = TRUE;
-
- /* update stream counter */
- follow_info->bytes_written[follow_record->is_server] += follow_record->data->len;
-
- follow_info->payload = g_list_append(follow_info->payload, follow_record);
- return FALSE;
-}
-
-//Copy from ui/gtk/follow_udp.c
-static gboolean
-udp_queue_packet_data(void *tapdata, packet_info *pinfo,
- epan_dissect_t *, const void *data)
-{
- follow_record_t *follow_record;
- follow_info_t *follow_info = (follow_info_t *)tapdata;
- tvbuff_t *next_tvb = (tvbuff_t *)data;
-
- follow_record = g_new(follow_record_t,1);
-
- follow_record->data = g_byte_array_sized_new(tvb_captured_length(next_tvb));
- follow_record->data = g_byte_array_append(follow_record->data,
- tvb_get_ptr(next_tvb, 0, -1),
- tvb_captured_length(next_tvb));
- follow_record->packet_num = pinfo->fd->num;
-
- if (follow_info->client_port == 0) {
- follow_info->client_port = pinfo->srcport;
- copy_address(&follow_info->client_ip, &pinfo->src);
- }
-
- if (addresses_equal(&follow_info->client_ip, &pinfo->src) && follow_info->client_port == pinfo->srcport)
- follow_record->is_server = FALSE;
- else
- follow_record->is_server = TRUE;
-
- /* update stream counter */
- follow_info->bytes_written[follow_record->is_server] += follow_record->data->len;
-
- follow_info->payload = g_list_append(follow_info->payload, follow_record);
- return FALSE;
-}
-
-//Copy from ui/gtk/follow_ssl.c
-static gboolean
-ssl_queue_packet_data(void *tapdata, packet_info *pinfo, epan_dissect_t *, const void *ssl)
-{
- follow_info_t * follow_info = (follow_info_t*) tapdata;
- SslDecryptedRecord * rec = NULL;
- SslDataInfo * appl_data = NULL;
- SslPacketInfo * pi = (SslPacketInfo*)ssl;
- show_stream_t from = FROM_CLIENT;
-
- /* Skip packets without decrypted payload data. */
- if (!pi || !pi->appl_data) return 0;
-
- /* Compute the packet's sender. */
- if (follow_info->client_port == 0) {
- follow_info->client_port = pinfo->srcport;
- copy_address(&follow_info->client_ip, &pinfo->src);
- }
- if (addresses_equal(&follow_info->client_ip, &pinfo->src) &&
- follow_info->client_port == pinfo->srcport) {
- from = FROM_CLIENT;
- } else {
- from = FROM_SERVER;
- }
-
- for (appl_data = pi->appl_data; appl_data != NULL; appl_data = appl_data->next) {
-
- /* TCP segments that contain the end of two or more SSL PDUs will be
- queued to SSL taps for each of those PDUs. Therefore a single
- packet could be processed by this SSL tap listener multiple times.
- The following test handles that scenario by treating the
- follow_info->bytes_written[] values as the next expected
- appl_data->seq. Any appl_data instances that fall below that have
- already been processed and must be skipped. */
- if (appl_data->seq < follow_info->bytes_written[from]) continue;
-
- /* Allocate a SslDecryptedRecord to hold the current appl_data
- instance's decrypted data. Even though it would be possible to
- consolidate multiple appl_data instances into a single rec, it is
- beneficial to use a one-to-one mapping. This affords the Follow
- Stream dialog view modes (ASCII, EBCDIC, Hex Dump, C Arrays, Raw)
- the opportunity to accurately reflect SSL PDU boundaries. Currently
- the Hex Dump view does by starting a new line, and the C Arrays
- view does by starting a new array declaration. */
- rec = (SslDecryptedRecord*) g_malloc(sizeof(SslDecryptedRecord) + appl_data->plain_data.data_len);
- rec->is_from_server = from == FROM_SERVER;
- rec->packet_num = pinfo->fd->num;
- rec->data.data = (guchar*) (rec + 1);
- rec->data.data_len = appl_data->plain_data.data_len;
- memcpy(rec->data.data, appl_data->plain_data.data, appl_data->plain_data.data_len);
-
- /* Append the record to the follow_info structure. */
- follow_info->payload = g_list_append(follow_info->payload, rec);
- follow_info->bytes_written[from] += rec->data.data_len;
- }
-
- return FALSE;
-}
-
-//Copy from ui/gtk/follow_http.c
-static gboolean
-http_queue_packet_data(void *tapdata, packet_info *pinfo,
- epan_dissect_t *, const void *data)
-{
- follow_record_t *follow_record;
- follow_info_t *follow_info = (follow_info_t *)tapdata;
- tvbuff_t *next_tvb = (tvbuff_t *)data;
-
- follow_record = g_new(follow_record_t,1);
-
- follow_record->data = g_byte_array_sized_new(tvb_captured_length(next_tvb));
- follow_record->data = g_byte_array_append(follow_record->data,
- tvb_get_ptr(next_tvb, 0, -1),
- tvb_captured_length(next_tvb));
- follow_record->packet_num = pinfo->fd->num;
-
- if (follow_info->client_port == 0) {
- follow_info->client_port = pinfo->srcport;
- copy_address(&follow_info->client_ip, &pinfo->src);
- }
-
- if (addresses_equal(&follow_info->client_ip, &pinfo->src) && follow_info->client_port == pinfo->srcport)
- follow_record->is_server = FALSE;
- else
- follow_record->is_server = TRUE;
-
- /* update stream counter */
- follow_info->bytes_written[follow_record->is_server] += follow_record->data->len;
-
- follow_info->payload = g_list_append(follow_info->payload, follow_record);
- return FALSE;
-}
-
/*
* XXX - the routine pointed to by "print_line_fcn_p" doesn't get handed lines,
* it gets handed bufferfuls. That's fine for "follow_write_raw()"
@@ -596,13 +437,6 @@ FollowStreamDialog::readSslStream()
void
FollowStreamDialog::followStream()
{
- follow_stats_t stats;
-
- /* Stream to show */
- follow_stats(&stats);
-
- follow_info_.is_ipv6 = stats.is_ipv6;
-
readStream();
}
@@ -617,7 +451,7 @@ void FollowStreamDialog::addText(QString text, gboolean is_from_server, guint32
size_t nwritten;
int FileDescriptor = file_.handle();
FILE* fh = fdopen(dup(FileDescriptor), "wb");
- if (follow_info_.show_type == SHOW_RAW) {
+ if (show_type_ == SHOW_RAW) {
QByteArray binstream = QByteArray::fromHex(text.toUtf8());
nwritten = fwrite(binstream.constData(), binstream.length(), 1, fh);
} else {
@@ -738,7 +572,7 @@ FollowStreamDialog::showBuffer(char *buffer, size_t nchars, gboolean is_from_ser
guint32 current_pos;
static const gchar hexchars[16] = {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
- switch (follow_info_.show_type) {
+ switch (show_type_) {
case SHOW_EBCDIC:
{
@@ -918,17 +752,15 @@ FollowStreamDialog::showBuffer(char *buffer, size_t nchars, gboolean is_from_ser
return FRS_OK;
}
-bool FollowStreamDialog::follow(QString previous_filter, bool use_stream_index)
+bool FollowStreamDialog::follow(QString previous_filter, bool use_stream_index, int stream_num)
{
- int tmp_fd;
QString follow_filter;
const char *hostname0 = NULL, *hostname1 = NULL;
char *port0 = NULL, *port1 = NULL;
QString server_to_client_string;
QString client_to_server_string;
QString both_directions_string;
- follow_stats_t stats;
- gboolean is_tcp = FALSE, is_udp = FALSE, is_http = FALSE;
+ gboolean is_follower = FALSE;
resetStream();
@@ -944,76 +776,27 @@ bool FollowStreamDialog::follow(QString previous_filter, bool use_stream_index)
return false;
}
- proto_get_frame_protocols(cap_file_.capFile()->edt->pi.layers, NULL, &is_tcp, &is_udp, NULL, NULL, NULL, NULL);
- is_http = proto_is_frame_protocol(cap_file_.capFile()->edt->pi.layers, "http");
+ is_follower = proto_is_frame_protocol(cap_file_.capFile()->edt->pi.layers, proto_get_protocol_filter_name(get_follow_proto_id(follower_)));
+ if (!is_follower) {
+ QMessageBox::warning(this, tr("Error following stream."), tr("Please make sure you have a %1 packet selected.").arg
+ (proto_get_protocol_short_name(find_protocol_by_id(get_follow_proto_id(follower_)))));
+ return false;
+ }
- switch (follow_type_)
+ if (follow_type_ == FOLLOW_SSL)
{
- case FOLLOW_TCP:
- if (!is_tcp) {
- QMessageBox::warning(this, tr("Error following stream."), tr("Please make sure you have a TCP packet selected."));
- return false;
- }
- break;
- case FOLLOW_UDP:
- if (!is_udp) {
- QMessageBox::warning(this, tr("Error following stream."), tr("Please make sure you have a UDP packet selected."));
- return false;
- }
- break;
- case FOLLOW_SSL:
/* we got ssl so we can follow */
removeStreamControls();
- if (!epan_dissect_packet_contains_field(cap_file_.capFile()->edt, "ssl")) {
- QMessageBox::critical(this, tr("Error following stream."),
- tr("Please make sure you have an SSL packet selected."));
- return false;
- }
- break;
- case FOLLOW_HTTP:
- removeStreamControls();
- if (!is_http) {
- QMessageBox::warning(this, tr("Error following stream."), tr("Please make sure you have a HTTP packet selected."));
- return false;
- }
- break;
}
- switch (follow_type_)
- {
- case FOLLOW_TCP:
- case FOLLOW_SSL:
- case FOLLOW_HTTP:
- /* Create a new filter that matches all packets in the TCP stream,
- and set the display filter entry accordingly */
- reset_stream_follow(TCP_STREAM);
- break;
- case FOLLOW_UDP:
- reset_stream_follow(UDP_STREAM);
- break;
- }
+ follow_reset_stream(&follow_info_);
+ /* Create a new filter that matches all packets in the TCP stream,
+ and set the display filter entry accordingly */
if (use_stream_index) {
- switch(follow_type_)
- {
- case FOLLOW_TCP:
- case FOLLOW_SSL:
- follow_filter = gchar_free_to_qstring(build_follow_index_filter(TCP_STREAM));
- break;
- case FOLLOW_HTTP:
- follow_filter = gchar_free_to_qstring(build_follow_index_filter(TCP_STREAM));
- follow_filter = QString("((%1) && (http))").arg(follow_filter);
- break;
- case FOLLOW_UDP:
- follow_filter = gchar_free_to_qstring(build_follow_index_filter(UDP_STREAM));
- break;
- }
+ follow_filter = gchar_free_to_qstring(get_follow_index_func(follower_)(stream_num));
} else {
- if (follow_type_ == FOLLOW_HTTP) {
- follow_filter = gchar_free_to_qstring(build_follow_conv_filter(&cap_file_.capFile()->edt->pi, "http"));
- } else {
- follow_filter = gchar_free_to_qstring(build_follow_conv_filter(&cap_file_.capFile()->edt->pi, NULL));
- }
+ follow_filter = gchar_free_to_qstring(get_follow_conv_func(follower_)(&cap_file_.capFile()->edt->pi, &stream_num));
}
if (follow_filter.isEmpty()) {
QMessageBox::warning(this,
@@ -1022,40 +805,6 @@ bool FollowStreamDialog::follow(QString previous_filter, bool use_stream_index)
return false;
}
- if (follow_type_ == FOLLOW_SSL)
- {
- /* Create a temporary file into which to dump the reassembled data
- from the TCP stream, and set "data_out_file" to refer to it, so
- that the TCP code will write to it.
-
- XXX - it might be nicer to just have the TCP code directly
- append stuff to the text widget for the TCP stream window,
- if we can arrange that said window not pop up until we're
- done. */
- gchar *data_out_filename;
- tmp_fd = create_tempfile(&data_out_filename, "follow");
- data_out_filename_ = data_out_filename;
-
- if (tmp_fd == -1) {
- QMessageBox::warning(this, "Error",
- "Could not create temporary file %1: %2",
- data_out_filename_, g_strerror(errno));
- data_out_filename_.clear();
- return false;
- }
-
- data_out_file = fdopen(tmp_fd, "w+b");
- if (data_out_file == NULL) {
- QMessageBox::warning(this, "Error",
- "Could not create temporary file %1: %2",
- data_out_filename_, g_strerror(errno));
- //ws_close(tmp_fd);
- ws_unlink(data_out_filename_.toUtf8().constData());
- data_out_filename_.clear();
- return false;
- }
- }
-
/* append the negation */
if(!previous_filter.isEmpty()) {
filter_out_filter_ = QString("%1 and !(%2)")
@@ -1066,21 +815,21 @@ bool FollowStreamDialog::follow(QString previous_filter, bool use_stream_index)
filter_out_filter_ = QString("!(%1)").arg(follow_filter);
}
+ /* data will be passed via tap callback*/
+ if (!registerTapListener(get_follow_tap_string(follower_), &follow_info_,
+ follow_filter.toUtf8().constData(),
+ 0, NULL, get_follow_tap_handler(follower_), NULL)) {
+ return false;
+ }
+
switch (follow_type_)
{
case FOLLOW_TCP:
{
- /* data will be passed via tap callback*/
- if (!registerTapListener("tcp_follow", &follow_info_,
- follow_filter.toUtf8().constData(),
- 0, NULL, tcp_queue_packet_data, NULL)) {
- return false;
- }
-
int stream_count = get_tcp_stream_count();
ui->streamNumberSpinBox->blockSignals(true);
ui->streamNumberSpinBox->setMaximum(stream_count-1);
- ui->streamNumberSpinBox->setValue(get_follow_index(TCP_STREAM));
+ ui->streamNumberSpinBox->setValue(stream_num);
ui->streamNumberSpinBox->blockSignals(false);
ui->streamNumberSpinBox->setToolTip(tr("%Ln total stream(s).", "", stream_count));
ui->streamNumberLabel->setToolTip(ui->streamNumberSpinBox->toolTip());
@@ -1089,17 +838,10 @@ bool FollowStreamDialog::follow(QString previous_filter, bool use_stream_index)
}
case FOLLOW_UDP:
{
- /* data will be passed via tap callback*/
- if (!registerTapListener("udp_follow", &follow_info_,
- follow_filter.toUtf8().constData(),
- 0, NULL, udp_queue_packet_data, NULL)) {
- return false;
- }
-
int stream_count = get_udp_stream_count();
ui->streamNumberSpinBox->blockSignals(true);
ui->streamNumberSpinBox->setMaximum(stream_count-1);
- ui->streamNumberSpinBox->setValue(get_follow_index(UDP_STREAM));
+ ui->streamNumberSpinBox->setValue(stream_num);
ui->streamNumberSpinBox->blockSignals(false);
ui->streamNumberSpinBox->setToolTip(tr("%Ln total stream(s).", "", stream_count));
ui->streamNumberLabel->setToolTip(ui->streamNumberSpinBox->toolTip());
@@ -1107,20 +849,8 @@ bool FollowStreamDialog::follow(QString previous_filter, bool use_stream_index)
break;
}
case FOLLOW_SSL:
- /* we got ssl so we can follow */
- if (!registerTapListener("ssl", &follow_info_,
- follow_filter.toUtf8().constData(), 0,
- NULL, ssl_queue_packet_data, NULL)) {
- return false;
- }
- break;
case FOLLOW_HTTP:
- /* data will be passed via tap callback*/
- if (!registerTapListener("http_follow", &follow_info_,
- follow_filter.toUtf8().constData(),
- 0, NULL, http_queue_packet_data, NULL)) {
- return false;
- }
+ /* No extra handling */
break;
}
@@ -1131,118 +861,41 @@ bool FollowStreamDialog::follow(QString previous_filter, bool use_stream_index)
same as the previous display filter. */
emit updateFilter(follow_filter, TRUE);
- switch (follow_type_)
- {
- case FOLLOW_TCP:
- case FOLLOW_UDP:
- case FOLLOW_SSL:
- case FOLLOW_HTTP:
- removeTapListeners();
- break;
- }
+ removeTapListeners();
- /* Stream to show */
- follow_stats(&stats);
+ hostname0 = address_to_name(&follow_info_.client_ip);
+ hostname1 = address_to_name(&follow_info_.server_ip);
- if (stats.is_ipv6) {
- hostname0 = get_hostname6(&stats.ip_address[0].ipv6);
- hostname1 = get_hostname6(&stats.ip_address[1].ipv6);
- } else {
- hostname0 = get_hostname(stats.ip_address[0].ipv4);
- hostname1 = get_hostname(stats.ip_address[1].ipv4);
- }
+ port0 = get_follow_port_to_display(follower_)(NULL, follow_info_.client_port);
+ port1 = get_follow_port_to_display(follower_)(NULL, follow_info_.server_port);
- switch (follow_type_)
- {
- case FOLLOW_TCP:
- case FOLLOW_HTTP:
- case FOLLOW_SSL:
- port0 = tcp_port_to_display(NULL, stats.port[0]);
- port1 = tcp_port_to_display(NULL, stats.port[1]);
- break;
- case FOLLOW_UDP:
- port0 = udp_port_to_display(NULL, stats.port[0]);
- port1 = udp_port_to_display(NULL, stats.port[1]);
- break;
- }
+ server_to_client_string =
+ QString("%1:%2 %3 %4:%5 (%6)")
+ .arg(hostname0).arg(port0)
+ .arg(UTF8_RIGHTWARDS_ARROW)
+ .arg(hostname1).arg(port1)
+ .arg(gchar_free_to_qstring(format_size(
+ follow_info_.bytes_written[0],
+ format_size_unit_bytes|format_size_prefix_si)));
- follow_info_.is_ipv6 = stats.is_ipv6;
-
- if ((follow_info_.client_port == stats.port[0]) &&
- ((stats.is_ipv6 && (memcmp(follow_info_.client_ip.data, &stats.ip_address[0], 16) == 0)) ||
- (!stats.is_ipv6 && (memcmp(follow_info_.client_ip.data, &stats.ip_address[0], 4) == 0)))) {
- server_to_client_string =
- QString("%1:%2 %3 %4:%5 (%6)")
- .arg(hostname0).arg(port0)
- .arg(UTF8_RIGHTWARDS_ARROW)
- .arg(hostname1).arg(port1)
- .arg(gchar_free_to_qstring(format_size(
- follow_info_.bytes_written[0],
- format_size_unit_bytes|format_size_prefix_si)));
-
- client_to_server_string =
- QString("%1:%2 %3 %4:%5 (%6)")
- .arg(hostname1).arg(port1)
- .arg(UTF8_RIGHTWARDS_ARROW)
- .arg(hostname0).arg(port0)
- .arg(gchar_free_to_qstring(format_size(
- follow_info_.bytes_written[1],
- format_size_unit_bytes|format_size_prefix_si)));
- } else {
- server_to_client_string =
- QString("%1:%2 %3 %4:%5 (%6)")
- .arg(hostname1).arg(port1)
- .arg(UTF8_RIGHTWARDS_ARROW)
- .arg(hostname0).arg(port0)
- .arg(gchar_free_to_qstring(format_size(
- follow_info_.bytes_written[0],
- format_size_unit_bytes|format_size_prefix_si)));
-
- client_to_server_string =
- QString("%1:%2 %3 %4:%5 (%6)")
- .arg(hostname0).arg(port0)
- .arg(UTF8_RIGHTWARDS_ARROW)
- .arg(hostname1).arg(port1)
- .arg(gchar_free_to_qstring(format_size(
- follow_info_.bytes_written[1],
- format_size_unit_bytes|format_size_prefix_si)));
- }
+ client_to_server_string =
+ QString("%1:%2 %3 %4:%5 (%6)")
+ .arg(hostname1).arg(port1)
+ .arg(UTF8_RIGHTWARDS_ARROW)
+ .arg(hostname0).arg(port0)
+ .arg(gchar_free_to_qstring(format_size(
+ follow_info_.bytes_written[1],
+ format_size_unit_bytes|format_size_prefix_si)));
wmem_free(NULL, port0);
wmem_free(NULL, port1);
- /* Both Stream Directions */
- switch (follow_type_)
- {
- case FOLLOW_TCP:
- both_directions_string = QString("Entire conversation (%1)")
- .arg(gchar_free_to_qstring(format_size(
- stats.bytes_written[0] + stats.bytes_written[1],
- format_size_unit_bytes|format_size_prefix_si)));
- setWindowSubtitle(tr("Follow TCP Stream (%1)").arg(follow_filter));
- break;
- case FOLLOW_UDP:
- both_directions_string = QString("Entire conversation (%1)")
- .arg(gchar_free_to_qstring(format_size(
- follow_info_.bytes_written[0] + follow_info_.bytes_written[1],
- format_size_unit_bytes|format_size_prefix_si)));
- setWindowSubtitle(tr("Follow UDP Stream (%1)").arg(follow_filter));
- break;
- case FOLLOW_SSL:
- both_directions_string = QString("Entire conversation (%1)")
- .arg(gchar_free_to_qstring(format_size(
- follow_info_.bytes_written[0] + follow_info_.bytes_written[1],
- format_size_unit_bytes|format_size_prefix_si)));
- setWindowSubtitle(tr("Follow SSL Stream (%1)").arg(follow_filter));
- break;
- case FOLLOW_HTTP:
- both_directions_string = QString("Entire conversation (%1)")
- .arg(gchar_free_to_qstring(format_size(
- follow_info_.bytes_written[0] + follow_info_.bytes_written[1],
- format_size_unit_bytes|format_size_prefix_si)));
- setWindowSubtitle(tr("Follow HTTP Stream (%1)").arg(follow_filter));
- break;
- }
+ both_directions_string = QString("Entire conversation (%1)")
+ .arg(gchar_free_to_qstring(format_size(
+ follow_info_.bytes_written[0] + follow_info_.bytes_written[1],
+ format_size_unit_bytes|format_size_prefix_si)));
+ setWindowSubtitle(tr("Follow %1 Stream (%2)").arg(proto_get_protocol_short_name(find_protocol_by_id(get_follow_proto_id(follower_))))
+ .arg(follow_filter));
ui->cbDirections->clear();
ui->cbDirections->addItem(both_directions_string);
@@ -1252,11 +905,6 @@ bool FollowStreamDialog::follow(QString previous_filter, bool use_stream_index)
followStream();
fillHintLabel(-1);
- if (data_out_file) {
- fclose(data_out_file);
- data_out_file = NULL;
- }
-
updateWidgets(false);
endRetapPackets();
return true;
@@ -1270,8 +918,6 @@ void FollowStreamDialog::captureFileClosing()
WiresharkDialog::captureFileClosing();
}
-#define FLT_BUF_SIZE 1024
-
/*
* XXX - the routine pointed to by "print_line_fcn_p" doesn't get handed lines,
* it gets handed bufferfuls. That's fine for "follow_write_raw()"
diff --git a/ui/qt/follow_stream_dialog.h b/ui/qt/follow_stream_dialog.h
index da0457175c..8508034fe8 100644
--- a/ui/qt/follow_stream_dialog.h
+++ b/ui/qt/follow_stream_dialog.h
@@ -34,7 +34,7 @@
#include "file.h"
-#include "ui/follow.h"
+#include "epan/follow.h"
#include "wireshark_dialog.h"
@@ -42,21 +42,6 @@
#include <QMap>
#include <QPushButton>
-extern "C" {
-WS_DLL_PUBLIC FILE *data_out_file;
-}
-
-// Shouldn't these be member variables?
-typedef struct {
- show_stream_t show_stream;
- show_type_t show_type;
- gboolean is_ipv6;
- GList *payload;
- guint bytes_written[2]; /* Index with FROM_CLIENT or FROM_SERVER for readability. */
- guint client_port;
- address client_ip;
-} follow_info_t;
-
namespace Ui {
class FollowStreamDialog;
}
@@ -69,7 +54,7 @@ public:
explicit FollowStreamDialog(QWidget &parent, CaptureFile &cf, follow_type_t type = FOLLOW_TCP);
~FollowStreamDialog();
- bool follow(QString previous_filter = QString(), bool use_stream_index = false);
+ bool follow(QString previous_filter = QString(), bool use_stream_index = false, int stream_num = -1);
public slots:
void captureFileClosing();
@@ -125,6 +110,8 @@ private:
follow_type_t follow_type_;
follow_info_t follow_info_;
+ register_follow_t* follower_;
+ show_type_t show_type_;
QString data_out_filename_;
static const int max_document_length_;
bool truncated_;
diff --git a/ui/qt/main_window.cpp b/ui/qt/main_window.cpp
index 87a51b6d07..5135d332c4 100644
--- a/ui/qt/main_window.cpp
+++ b/ui/qt/main_window.cpp
@@ -627,7 +627,7 @@ MainWindow::~MainWindow()
QString MainWindow::getFilter()
{
- return df_combo_box_->itemText(df_combo_box_->count());
+ return df_combo_box_->currentText();
}
QMenu *MainWindow::createPopupMenu()
diff --git a/ui/qt/traffic_table_dialog.h b/ui/qt/traffic_table_dialog.h
index cc7c50418e..3921b7e955 100644
--- a/ui/qt/traffic_table_dialog.h
+++ b/ui/qt/traffic_table_dialog.h
@@ -28,7 +28,7 @@
#include "epan/conversation_table.h"
-#include "ui/follow.h"
+#include "epan/follow.h"
#include "capture_file.h"
#include "filter_action.h"