diff options
Diffstat (limited to 'epan')
-rw-r--r-- | epan/dissectors/packet-http.c | 29 | ||||
-rw-r--r-- | epan/dissectors/packet-ssl-utils.h | 6 | ||||
-rw-r--r-- | epan/dissectors/packet-ssl.c | 63 | ||||
-rw-r--r-- | epan/dissectors/packet-tcp.c | 52 | ||||
-rw-r--r-- | epan/dissectors/packet-tcp.h | 5 | ||||
-rw-r--r-- | epan/dissectors/packet-udp.c | 50 | ||||
-rw-r--r-- | epan/follow.c | 367 | ||||
-rw-r--r-- | epan/follow.h | 183 | ||||
-rw-r--r-- | epan/to_str.h | 2 |
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 . |