aboutsummaryrefslogtreecommitdiffstats
path: root/epan
diff options
context:
space:
mode:
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 .