diff options
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" |