aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Mann <mmann78@netscape.net>2016-01-08 08:25:17 -0500
committerMichael Mann <mmann78@netscape.net>2016-01-12 15:08:18 +0000
commitc62547b9510eb1a0efe08972387bfa8559f444d5 (patch)
tree6a186a7b7111c71ae64e3da965b447ed9f48d699
parentb65d30dbd5d86092e6e4739a4da6075cf08b115d (diff)
Refactor "Follow Stream" functionality on all GUI interfaces.
Create a "registration" system for Follow functionality so most of the work can be abstracted into a dissector and GUI can just be responsible for "display". This also removes the global variables in follow.c to open up multithreading possibilities. TCP, UDP and HTTP all have the same "tap interface" for Follow functionality (passing a tvb with byte data to "follow"). SSL still has it's own behavior, so Follow structures have to take that into account. TShark through the Follow registration now has support for HTTP. The only thing possibly missing is dynamic menu generation to further reduce explicit knowledge of Follow "type" (and rely on registration) Bug: 11988 Change-Id: I559d9ee1312406ad0986d4dce9fa67ea2103b339 Reviewed-on: https://code.wireshark.org/review/13161 Reviewed-by: Michael Mann <mmann78@netscape.net>
-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"