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