diff options
-rw-r--r-- | debian/libwireshark0.symbols | 14 | ||||
-rw-r--r-- | epan/CMakeLists.txt | 1 | ||||
-rw-r--r-- | epan/Makefile.am | 2 | ||||
-rw-r--r-- | epan/dissectors/packet-frame.c | 118 | ||||
-rw-r--r-- | epan/dissectors/packet-tcp.c | 164 | ||||
-rw-r--r-- | epan/sequence_analysis.c | 275 | ||||
-rw-r--r-- | epan/sequence_analysis.h | 196 | ||||
-rw-r--r-- | ui/gtk/flow_graph.c | 88 | ||||
-rw-r--r-- | ui/gtk/lbm_uimflow_dlg.c | 2 | ||||
-rw-r--r-- | ui/qt/sequence_diagram.cpp | 2 | ||||
-rw-r--r-- | ui/qt/sequence_dialog.cpp | 52 | ||||
-rw-r--r-- | ui/qt/sequence_dialog.h | 2 | ||||
-rw-r--r-- | ui/qt/voip_calls_dialog.cpp | 2 | ||||
-rw-r--r-- | ui/tap-sequence-analysis.c | 374 | ||||
-rw-r--r-- | ui/tap-sequence-analysis.h | 84 |
15 files changed, 819 insertions, 557 deletions
diff --git a/debian/libwireshark0.symbols b/debian/libwireshark0.symbols index c6c7283a66..220b020e5d 100644 --- a/debian/libwireshark0.symbols +++ b/debian/libwireshark0.symbols @@ -1293,6 +1293,7 @@ libwireshark.so.0 libwireshark0 #MINVER# register_postdissector@Base 1.9.1 register_postseq_cleanup_routine@Base 1.9.1 register_rtd_table@Base 1.99.8 + register_seq_analysis@Base 2.5.0 register_shutdown_routine@Base 2.3.0 register_srt_table@Base 1.99.8 register_stat_tap_table_ui@Base 2.1.0 @@ -1364,6 +1365,19 @@ libwireshark.so.0 libwireshark0 #MINVER# scsi_smc_vals_ext@Base 1.12.0~rc1 scsi_ssc_vals_ext@Base 1.12.0~rc1 sctp_port_to_display@Base 1.99.2 + sequence_analysis_find_by_name@Base 2.5.0 + sequence_analysis_free_nodes@Base 2.5.0 + sequence_analysis_get_name@Base 2.5.0 + sequence_analysis_get_nodes@Base 2.5.0 + sequence_analysis_get_packet_func@Base 2.5.0 + sequence_analysis_get_tap_flags@Base 2.5.0 + sequence_analysis_get_tap_listener_name@Base 2.5.0 + sequence_analysis_get_ui_name@Base 2.5.0 + sequence_analysis_info_free@Base 2.5.0 + sequence_analysis_info_new@Base 2.5.0 + sequence_analysis_list_free@Base 2.5.0 + sequence_analysis_list_sort@Base 2.5.0 + sequence_analysis_table_iterate_tables@Base 2.5.0 serv_name_lookup@Base 2.1.0 set_actual_length@Base 1.9.1 set_column_custom_fields@Base 2.1.0 diff --git a/epan/CMakeLists.txt b/epan/CMakeLists.txt index 02cfcc5fa2..3f6d04266e 100644 --- a/epan/CMakeLists.txt +++ b/epan/CMakeLists.txt @@ -256,6 +256,7 @@ set(LIBWIRESHARK_FILES reedsolomon.c req_resp_hdrs.c rtd_table.c + sequence_analysis.c show_exception.c srt_table.c stat_tap_ui.c diff --git a/epan/Makefile.am b/epan/Makefile.am index b1c4afb693..d782b03f1f 100644 --- a/epan/Makefile.am +++ b/epan/Makefile.am @@ -106,6 +106,7 @@ LIBWIRESHARK_SRC = \ reedsolomon.c \ req_resp_hdrs.c \ rtd_table.c \ + sequence_analysis.c \ show_exception.c \ srt_table.c \ stat_tap_ui.c \ @@ -263,6 +264,7 @@ LIBWIRESHARK_INCLUDES_PUBLIC = \ rtd_table.h \ rtp_pt.h \ sctpppids.h \ + sequence_analysis.h \ show_exception.h \ slow_protocol_subtypes.h \ sminmpec.h \ diff --git a/epan/dissectors/packet-frame.c b/epan/dissectors/packet-frame.c index aa9d1f443a..9b9a0dbaf6 100644 --- a/epan/dissectors/packet-frame.c +++ b/epan/dissectors/packet-frame.c @@ -35,16 +35,20 @@ #include <epan/timestamp.h> #include <epan/prefs.h> #include <epan/to_str.h> +#include <epan/sequence_analysis.h> #include <wiretap/wtap.h> #include <epan/tap.h> #include <epan/expert.h> #include <wsutil/wsgcrypt.h> #include <wsutil/str_util.h> +#include <epan/proto_data.h> #include <wmem/wmem.h> #include "packet-frame.h" +#include "packet-icmp.h" #include "log.h" +#include <epan/column-info.h> #include <epan/color_filters.h> void proto_register_frame(void); @@ -157,6 +161,118 @@ static const value_string packet_word_reception_types[] = { static dissector_table_t wtap_encap_dissector_table; static dissector_table_t wtap_fts_rec_dissector_table; +/****************************************************************************/ +/* whenever a frame packet is seen by the tap listener */ +/* Add a new frame into the graph */ +static gboolean +frame_seq_analysis_packet( void *ptr, packet_info *pinfo, epan_dissect_t *edt _U_, const void *dummy _U_) +{ + seq_analysis_info_t *sainfo = (seq_analysis_info_t *) ptr; + + if ((sainfo->all_packets) || (pinfo->fd->flags.passed_dfilter == 1)) { + gchar *protocol = NULL; + gchar *colinfo = NULL; + seq_analysis_item_t *sai = NULL; + + if (sainfo->any_addr) { + if (pinfo->net_src.type!=AT_NONE && pinfo->net_dst.type!=AT_NONE) { + sai = g_new0(seq_analysis_item_t, 1); + copy_address(&(sai->src_addr),&(pinfo->net_src)); + copy_address(&(sai->dst_addr),&(pinfo->net_dst)); + } + + } else { + if (pinfo->src.type!=AT_NONE && pinfo->dst.type!=AT_NONE) { + sai = g_new0(seq_analysis_item_t, 1); + copy_address(&(sai->src_addr),&(pinfo->src)); + copy_address(&(sai->dst_addr),&(pinfo->dst)); + } + } + + if (!sai) + return FALSE; + + sai->frame_number = pinfo->num; + + if (pinfo->fd->color_filter) { + sai->bg_color = color_t_to_rgb(&pinfo->fd->color_filter->bg_color); + sai->fg_color = color_t_to_rgb(&pinfo->fd->color_filter->fg_color); + sai->has_color_filter = TRUE; + } + + sai->port_src=pinfo->srcport; + sai->port_dst=pinfo->destport; + sai->protocol = g_strdup(port_type_to_str(pinfo->ptype)); + + if (pinfo->cinfo) { + col_item_t *col_item; + int i; + + if (pinfo->cinfo->col_first[COL_INFO] >= 0) { + for (i = pinfo->cinfo->col_first[COL_INFO]; i <= pinfo->cinfo->col_last[COL_INFO]; i++) { + col_item = &pinfo->cinfo->columns[i]; + if (col_item->fmt_matx[COL_INFO]) { + colinfo = g_strdup(col_item->col_data); + /* break; ? or g_free(colinfo); before g_strdup() */ + } + } + } + + if (pinfo->cinfo->col_first[COL_PROTOCOL] >= 0) { + for (i = pinfo->cinfo->col_first[COL_PROTOCOL]; i <= pinfo->cinfo->col_last[COL_PROTOCOL]; i++) { + col_item = &pinfo->cinfo->columns[i]; + if (col_item->fmt_matx[COL_PROTOCOL]) { + protocol = g_strdup(col_item->col_data); + /* break; ? or g_free(protocol); before g_strdup() */ + } + } + } + } + + if (colinfo != NULL) { + sai->frame_label = g_strdup(colinfo); + if (protocol != NULL) { + sai->comment = g_strdup_printf("%s: %s", protocol, colinfo); + } else { + sai->comment = g_strdup(colinfo); + } + } else { + /* This will probably never happen...*/ + if (protocol != NULL) { + sai->frame_label = g_strdup(protocol); + sai->comment = g_strdup(protocol); + } + } + + if (pinfo->ptype == PT_NONE) { + icmp_info_t *p_icmp_info; + + if ((p_icmp_info = (icmp_info_t *) p_get_proto_data(wmem_file_scope(), pinfo, proto_get_id_by_short_name("ICMP"), 0))) { + g_free(sai->protocol); + sai->protocol = g_strdup("ICMP"); + sai->port_src = 0; + sai->port_dst = p_icmp_info->type * 256 + p_icmp_info->code; + } else if ((p_icmp_info = (icmp_info_t *) p_get_proto_data(wmem_file_scope(), pinfo, proto_get_id_by_short_name("ICMPv6"), 0))) { + g_free(sai->protocol); + sai->protocol = g_strdup("ICMPv6"); + sai->port_src = 0; + sai->port_dst = p_icmp_info->type * 256 + p_icmp_info->code; + } + } + + g_free(protocol); + g_free(colinfo); + + sai->line_style = 1; + sai->conv_num = 0; + sai->display = TRUE; + + g_queue_push_tail(sainfo->items, sai); + } + + return TRUE; +} + /* * Routine used to register frame end routine. The routine should only * be registered when the dissector is used in the frame, not in the @@ -952,6 +1068,8 @@ proto_register_frame(void) tantamount to not doing any dissection whatsoever. */ proto_set_cant_toggle(proto_frame); + register_seq_analysis("any", "All Flows", proto_frame, NULL, TL_REQUIRES_COLUMNS, frame_seq_analysis_packet); + /* Our preferences */ frame_module = prefs_register_protocol(proto_frame, NULL); prefs_register_bool_preference(frame_module, "show_file_off", diff --git a/epan/dissectors/packet-tcp.c b/epan/dissectors/packet-tcp.c index e7997439f5..899326f6a6 100644 --- a/epan/dissectors/packet-tcp.c +++ b/epan/dissectors/packet-tcp.c @@ -35,6 +35,7 @@ #include <epan/show_exception.h> #include <epan/conversation_table.h> #include <epan/dissector_filters.h> +#include <epan/sequence_analysis.h> #include <epan/reassemble.h> #include <epan/decode_as.h> #include <epan/exported_pdu.h> @@ -618,6 +619,60 @@ static const int *tcp_option_mptcp_dss_flags[] = { const unit_name_string units_64bit_version = { " (64bits version)", NULL }; + +static const char * +tcp_flags_to_str(wmem_allocator_t *scope, const struct tcpheader *tcph) +{ + static const char flags[][4] = { "FIN", "SYN", "RST", "PSH", "ACK", "URG", "ECN", "CWR", "NS" }; + const int maxlength = 64; /* upper bounds, max 53B: 8 * 3 + 2 + strlen("Reserved") + 9 * 2 + 1 */ + + char *pbuf; + const char *buf; + + int i; + + buf = pbuf = (char *) wmem_alloc(scope, maxlength); + *pbuf = '\0'; + + for (i = 0; i < 9; i++) { + if (tcph->th_flags & (1 << i)) { + if (buf[0]) + pbuf = g_stpcpy(pbuf, ", "); + pbuf = g_stpcpy(pbuf, flags[i]); + } + } + + if (tcph->th_flags & TH_RES) { + if (buf[0]) + pbuf = g_stpcpy(pbuf, ", "); + g_stpcpy(pbuf, "Reserved"); + } + + if (buf[0] == '\0') + buf = "<None>"; + + return buf; +} +static const char * +tcp_flags_to_str_first_letter(const struct tcpheader *tcph) +{ + wmem_strbuf_t *buf = wmem_strbuf_new(wmem_packet_scope(), ""); + unsigned i; + const unsigned flags_count = 12; + const char first_letters[] = "RRRNCEUAPRSF"; + + /* upper three bytes are marked as reserved ('R'). */ + for (i = 0; i < flags_count; i++) { + if (((tcph->th_flags >> (flags_count - 1 - i)) & 1)) { + wmem_strbuf_append_c(buf, first_letters[i]); + } else { + wmem_strbuf_append(buf, UTF8_MIDDLE_DOT); + } + } + + return wmem_strbuf_finalize(buf); +} + static void tcp_src_prompt(packet_info *pinfo, gchar *result) { @@ -806,6 +861,59 @@ tcp_build_filter(packet_info *pinfo) return NULL; } +/****************************************************************************/ +/* whenever a TCP packet is seen by the tap listener */ +/* Add a new tcp frame into the graph */ +static gboolean +tcp_seq_analysis_packet( void *ptr, packet_info *pinfo, epan_dissect_t *edt _U_, const void *tcp_info) +{ + seq_analysis_info_t *sainfo = (seq_analysis_info_t *) ptr; + const struct tcpheader *tcph = (const struct tcpheader *)tcp_info; + + if ((sainfo->all_packets)||(pinfo->fd->flags.passed_dfilter==1)){ + const char* flags; + seq_analysis_item_t *sai; + + sai = g_new0(seq_analysis_item_t, 1); + sai->frame_number = pinfo->num; + if (sainfo->any_addr) { + copy_address(&(sai->src_addr),&(pinfo->net_src)); + copy_address(&(sai->dst_addr),&(pinfo->net_dst)); + } else { + copy_address(&(sai->src_addr),&(pinfo->src)); + copy_address(&(sai->dst_addr),&(pinfo->dst)); + } + sai->port_src=pinfo->srcport; + sai->port_dst=pinfo->destport; + sai->protocol=g_strdup(port_type_to_str(pinfo->ptype)); + + flags = tcp_flags_to_str(NULL, tcph); + + if ((tcph->th_have_seglen)&&(tcph->th_seglen!=0)){ + sai->frame_label = g_strdup_printf("%s - Len: %u",flags, tcph->th_seglen); + } + else{ + sai->frame_label = g_strdup(flags); + } + + wmem_free(NULL, (void*)flags); + + if (tcph->th_flags & TH_ACK) + sai->comment = g_strdup_printf("Seq = %u Ack = %u",tcph->th_seq, tcph->th_ack); + else + sai->comment = g_strdup_printf("Seq = %u",tcph->th_seq); + + sai->line_style = 1; + sai->conv_num = (guint16) tcph->th_stream; + sai->display = TRUE; + + g_queue_push_tail(sainfo->items, sai); + } + + return TRUE; +} + + gchar* tcp_follow_conv_filter(packet_info* pinfo, int* stream) { conversation_t *conv; @@ -5603,59 +5711,6 @@ dissect_tcp_payload(tvbuff_t *tvb, packet_info *pinfo, int offset, guint32 seq, } } -static const char * -tcp_flags_to_str(const struct tcpheader *tcph) -{ - static const char flags[][4] = { "FIN", "SYN", "RST", "PSH", "ACK", "URG", "ECN", "CWR", "NS" }; - const int maxlength = 64; /* upper bounds, max 53B: 8 * 3 + 2 + strlen("Reserved") + 9 * 2 + 1 */ - - char *pbuf; - const char *buf; - - int i; - - buf = pbuf = (char *) wmem_alloc(wmem_packet_scope(), maxlength); - *pbuf = '\0'; - - for (i = 0; i < 9; i++) { - if (tcph->th_flags & (1 << i)) { - if (buf[0]) - pbuf = g_stpcpy(pbuf, ", "); - pbuf = g_stpcpy(pbuf, flags[i]); - } - } - - if (tcph->th_flags & TH_RES) { - if (buf[0]) - pbuf = g_stpcpy(pbuf, ", "); - g_stpcpy(pbuf, "Reserved"); - } - - if (buf[0] == '\0') - buf = "<None>"; - - return buf; -} -static const char * -tcp_flags_to_str_first_letter(const struct tcpheader *tcph) -{ - wmem_strbuf_t *buf = wmem_strbuf_new(wmem_packet_scope(), ""); - unsigned i; - const unsigned flags_count = 12; - const char first_letters[] = "RRRNCEUAPRSF"; - - /* upper three bytes are marked as reserved ('R'). */ - for (i = 0; i < flags_count; i++) { - if (((tcph->th_flags >> (flags_count - 1 - i)) & 1)) { - wmem_strbuf_append_c(buf, first_letters[i]); - } else { - wmem_strbuf_append(buf, UTF8_MIDDLE_DOT); - } - } - - return wmem_strbuf_finalize(buf); -} - static gboolean capture_tcp(const guchar *pd, int offset, int len, capture_packet_info_t *cpinfo, const union wtap_pseudo_header *pseudo_header) { @@ -5950,7 +6005,7 @@ dissect_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_) } else tcph->th_have_seglen = FALSE; - flags_str = tcp_flags_to_str(tcph); + flags_str = tcp_flags_to_str(wmem_packet_scope(), tcph); flags_str_first_letter = tcp_flags_to_str_first_letter(tcph); col_append_lstr(pinfo->cinfo, COL_INFO, @@ -7493,6 +7548,7 @@ proto_register_tcp(void) register_conversation_table(proto_tcp, FALSE, tcpip_conversation_packet, tcpip_hostlist_packet); register_conversation_filter("tcp", "TCP", tcp_filter_valid, tcp_build_filter); + register_seq_analysis("tcp", "TCP Flows", proto_tcp, NULL, 0, tcp_seq_analysis_packet); /* considers MPTCP as a distinct protocol (even if it's a TCP option) */ proto_mptcp = proto_register_protocol("Multipath Transmission Control Protocol", "MPTCP", "mptcp"); diff --git a/epan/sequence_analysis.c b/epan/sequence_analysis.c new file mode 100644 index 0000000000..7d8f03064f --- /dev/null +++ b/epan/sequence_analysis.c @@ -0,0 +1,275 @@ +/* sequence-analysis.c + * Flow sequence analysis + * + * Some code from from gtk/flow_graph.c + * + * Wireshark - Network traffic analyzer + * By Gerald Combs <gerald@wireshark.org> + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "config.h" + +#include "sequence_analysis.h" + +#include "addr_resolv.h" +#include "proto.h" +#include "tap.h" +#include "wmem/wmem.h" + +#define NODE_OVERFLOW MAX_NUM_NODES+1 + +struct register_analysis { + const char* name; /* Name (used for lookup) */ + const char* ui_name; /* Name used for UI */ + int proto_id; /* protocol id (0-indexed) */ + const char* tap_listen_str; /* string used in register_tap_listener (NULL to use protocol name) */ + guint tap_flags; + tap_packet_cb analysis_func; /* function to be called for new incoming packets for sequence analysis */ +}; + +static wmem_tree_t *registered_seq_analysis = NULL; + +void +register_seq_analysis(const char* name, const char* ui_name, const int proto_id, const char* tap_listener, guint tap_flags, tap_packet_cb tap_func) +{ + register_analysis_t* analysis; + + DISSECTOR_ASSERT(tap_func); + + analysis = wmem_new0(wmem_epan_scope(), register_analysis_t); + + analysis->name = name; + analysis->ui_name = ui_name; + analysis->proto_id = proto_id; + if (tap_listener != NULL) + analysis->tap_listen_str = tap_listener; + else + analysis->tap_listen_str = proto_get_protocol_filter_name(proto_id); + analysis->tap_flags = tap_flags; + analysis->analysis_func = tap_func; + + if (registered_seq_analysis == NULL) + registered_seq_analysis = wmem_tree_new(wmem_epan_scope()); + + wmem_tree_insert_string(registered_seq_analysis, name, analysis, 0); +} + +const char* sequence_analysis_get_name(register_analysis_t* analysis) +{ + return analysis->name; +} + +const char* sequence_analysis_get_ui_name(register_analysis_t* analysis) +{ + return analysis->ui_name; +} + +const char* sequence_analysis_get_tap_listener_name(register_analysis_t* analysis) +{ + return analysis->tap_listen_str; +} + +tap_packet_cb sequence_analysis_get_packet_func(register_analysis_t* analysis) +{ + return analysis->analysis_func; +} + +guint sequence_analysis_get_tap_flags(register_analysis_t* analysis) +{ + return analysis->tap_flags; +} + + +register_analysis_t* sequence_analysis_find_by_name(const char* name) +{ + return (register_analysis_t*)wmem_tree_lookup_string(registered_seq_analysis, name, 0); +} + +void sequence_analysis_table_iterate_tables(wmem_foreach_func func, gpointer user_data) +{ + wmem_tree_foreach(registered_seq_analysis, func, user_data); +} + +seq_analysis_info_t * +sequence_analysis_info_new(void) +{ + seq_analysis_info_t *sainfo = g_new0(seq_analysis_info_t, 1); + + /* SEQ_ANALYSIS_DEBUG("adding new item"); */ + sainfo->items = g_queue_new(); + sainfo->ht= g_hash_table_new(g_int_hash, g_int_equal); + return sainfo; +} + +void sequence_analysis_info_free(seq_analysis_info_t *sainfo) +{ + if (!sainfo) return; + + /* SEQ_ANALYSIS_DEBUG("%d items", g_queue_get_length(sainfo->items)); */ + sequence_analysis_list_free(sainfo); + + g_queue_free(sainfo->items); + g_hash_table_destroy(sainfo->ht); + + g_free(sainfo); +} + +static void sequence_analysis_item_free(gpointer data) +{ + seq_analysis_item_t *seq_item = (seq_analysis_item_t *)data; + g_free(seq_item->frame_label); + g_free(seq_item->time_str); + g_free(seq_item->comment); + g_free(seq_item->protocol); + free_address(&seq_item->src_addr); + free_address(&seq_item->dst_addr); + g_free(data); +} + + +/* compare two list entries by packet no */ +static gint +sequence_analysis_sort_compare(gconstpointer a, gconstpointer b, gpointer user_data _U_) +{ + const seq_analysis_item_t *entry_a = (const seq_analysis_item_t *)a; + const seq_analysis_item_t *entry_b = (const seq_analysis_item_t *)b; + + if(entry_a->frame_number < entry_b->frame_number) + return -1; + + if(entry_a->frame_number > entry_b->frame_number) + return 1; + + return 0; +} + + +void +sequence_analysis_list_sort(seq_analysis_info_t *sainfo) +{ + if (!sainfo) return; + g_queue_sort(sainfo->items, sequence_analysis_sort_compare, NULL); +} + +void +sequence_analysis_list_free(seq_analysis_info_t *sainfo) +{ + if (!sainfo) return; + /* SEQ_ANALYSIS_DEBUG("%d items", g_queue_get_length(sainfo->items)); */ + + /* free the graph data items */ + +#if GLIB_CHECK_VERSION (2, 32, 0) + g_queue_free_full(sainfo->items, sequence_analysis_item_free); + sainfo->items = g_queue_new(); +#else + { + GList *list = g_queue_peek_nth_link(sainfo->items, 0); + while (list) + { + sequence_analysis_item_free(list->data); + list = g_list_next(list); + } + g_queue_clear(sainfo->items); + } +#endif + + if (NULL != sainfo->ht) { + g_hash_table_remove_all(sainfo->ht); + } + sainfo->nconv = 0; + + sequence_analysis_free_nodes(sainfo); +} + +/* Return the index array if the node is in the array. Return -1 if there is room in the array + * and Return -2 if the array is full + */ +/****************************************************************************/ +static guint add_or_get_node(seq_analysis_info_t *sainfo, address *node) { + guint i; + + if (node->type == AT_NONE) return NODE_OVERFLOW; + + for (i=0; i<MAX_NUM_NODES && i < sainfo->num_nodes ; i++) { + if ( cmp_address(&(sainfo->nodes[i]), node) == 0 ) return i; /* it is in the array */ + } + + if (i >= MAX_NUM_NODES) { + return NODE_OVERFLOW; + } else { + sainfo->num_nodes++; + copy_address(&(sainfo->nodes[i]), node); + return i; + } +} + +struct sainfo_counter { + seq_analysis_info_t *sainfo; + int num_items; +}; + +static void sequence_analysis_get_nodes_item_proc(gpointer data, gpointer user_data) +{ + seq_analysis_item_t *gai = (seq_analysis_item_t *)data; + struct sainfo_counter *sc = (struct sainfo_counter *)user_data; + if (gai->display) { + (sc->num_items)++; + gai->src_node = add_or_get_node(sc->sainfo, &(gai->src_addr)); + gai->dst_node = add_or_get_node(sc->sainfo, &(gai->dst_addr)); + } +} + +/* Get the nodes from the list */ +/****************************************************************************/ +int +sequence_analysis_get_nodes(seq_analysis_info_t *sainfo) +{ + struct sainfo_counter sc = {sainfo, 0}; + + /* Fill the node array */ + g_queue_foreach(sainfo->items, sequence_analysis_get_nodes_item_proc, &sc); + + return sc.num_items; +} + +/* Free the node address list */ +/****************************************************************************/ +void +sequence_analysis_free_nodes(seq_analysis_info_t *sainfo) +{ + int i; + + for (i=0; i<MAX_NUM_NODES; i++) { + free_address(&sainfo->nodes[i]); + } + sainfo->num_nodes = 0; +} + +/* + * Editor modelines + * + * Local Variables: + * c-basic-offset: 4 + * tab-width: 8 + * indent-tabs-mode: nil + * End: + * + * ex: set shiftwidth=4 tabstop=8 expandtab: + * :indentSize=4:tabSize=8:noTabs=true: + */ diff --git a/epan/sequence_analysis.h b/epan/sequence_analysis.h new file mode 100644 index 0000000000..bcebdef3a5 --- /dev/null +++ b/epan/sequence_analysis.h @@ -0,0 +1,196 @@ +/* sequence-analysis.h + * Flow sequence analysis + * + * Copied from gtk/graph_analysis.h + * + * Copyright 2004, Verso Technologies Inc. + * By Alejandro Vaquero <alejandrovaquero@yahoo.com> + * + * based on rtp_analysis.c and io_stat + * + * + * Wireshark - Network traffic analyzer + * By Gerald Combs <gerald@wireshark.org> + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef __EPAN_SEQUENCE_ANALYSIS_H__ +#define __EPAN_SEQUENCE_ANALYSIS_H__ + +#include "ws_symbol_export.h" + +#include <glib.h> + +#include "packet_info.h" +#include "tap.h" +#include "address.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#define MAX_NUM_NODES 40 + +/** defines an entry for the graph analysis */ +typedef struct _seq_analysis_item { + guint32 frame_number; + address src_addr; + guint16 port_src; + address dst_addr; + guint16 port_dst; + gchar *frame_label; /**< the label on top of the arrow */ + gchar *time_str; /**< timestamp */ + gchar *comment; /**< a comment that appears at the right of the graph */ + guint16 conv_num; /**< The conversation number. Used for coloring VoIP calls. */ + unsigned fg_color; /**< Foreground color, 0xRRGGBB. Qt only. */ + unsigned bg_color; /**< Background color, 0xRRGGBB. Qt only. */ + gboolean has_color_filter; /**< Set if packet has color filter. Qt only. */ + gboolean display; /**< indicate if the packet is displayed or not in the graph */ + guint src_node; /**< this is used by graph_analysis.c to identify the node */ + guint dst_node; /**< a node is an IP address that will be displayed in columns */ + guint16 line_style; /**< the arrow line width in pixels*/ + gchar *protocol; /**< the label of the protocol defined in the IP packet */ +} seq_analysis_item_t; + +/** defines the graph analysis structure */ +typedef struct _seq_analysis_info { + const char* name; /**< Name of sequence analysis */ + gboolean all_packets; /**< all packets vs only displayed */ + gboolean any_addr; /**< any addr (DL+net) vs net-only */ + int nconv; /**< number of conversations in the list */ + GQueue* items; /**< list of seq_analysis_info_t */ + GHashTable *ht; /**< hash table of seq_analysis_info_t */ + address nodes[MAX_NUM_NODES]; /**< horizontal node list */ + guint32 num_nodes; /**< actual number of nodes */ +} seq_analysis_info_t; + +/** Structure for information about a registered sequence analysis function */ +typedef struct register_analysis register_analysis_t; + +#if 0 +#define SEQ_ANALYSIS_DEBUG(...) { \ + char *SEQ_ANALYSIS_DEBUG_MSG = g_strdup_printf(__VA_ARGS__); \ + g_warning("sequence analysis: %s:%d %s", G_STRFUNC, __LINE__, SEQ_ANALYSIS_DEBUG_MSG); \ + g_free(SEQ_ANALYSIS_DEBUG_MSG); \ +} +#else +#define SEQ_ANALYSIS_DEBUG() +#endif + +WS_DLL_PUBLIC void register_seq_analysis(const char* name, const char* ui_name, const int proto_id, const char* tap_listener, guint tap_flags, tap_packet_cb tap_func); + +/** Helper function to get sequence analysis name + * + * @param analysis Registered sequence analysis + * @return sequence analysis name string + */ +WS_DLL_PUBLIC const char* sequence_analysis_get_name(register_analysis_t* analysis); + +/** Helper function to get tap listener name + * + * @param analysis Registered sequence analysis + * @return sequence analysis tap listener string + */ +WS_DLL_PUBLIC const char* sequence_analysis_get_tap_listener_name(register_analysis_t* analysis); + +/** Helper function to get UI name + * + * @param analysis Registered sequence analysis + * @return sequence analysis UI string + */ +WS_DLL_PUBLIC const char* sequence_analysis_get_ui_name(register_analysis_t* analysis); + +/** Get tap function handler from sequence analysis + * + * @param analysis Registered sequence analysis + * @return tap function handler of sequence analysis + */ +WS_DLL_PUBLIC tap_packet_cb sequence_analysis_get_packet_func(register_analysis_t* analysis); + +/** Helper function to get tap flags + * + * @param analysis Registered sequence analysis + * @return sequence analysis tap flags + */ +WS_DLL_PUBLIC guint sequence_analysis_get_tap_flags(register_analysis_t* analysis); + +/** Find a registered sequence analysis "protocol" by name + * + * @param name Registered sequence analysis to find + * @return registered sequence analysis, NULL if not found + */ +WS_DLL_PUBLIC register_analysis_t* sequence_analysis_find_by_name(const char* name); + +/** Interator to walk sequence_analysis tables and execute func + * + * @param func action to be performed on all sequence_analysis tables + * @param user_data any data needed to help perform function + */ +WS_DLL_PUBLIC void sequence_analysis_table_iterate_tables(wmem_foreach_func func, gpointer user_data); + +/** Create and initialize a seq_analysis_info_t struct + * @return A pointer to a newly allocated seq_analysis_info_t struct. + */ +WS_DLL_PUBLIC seq_analysis_info_t *sequence_analysis_info_new(void); + +/** Free a seq_analysis_info_t struct. + * @param sainfo A pointer to the seq_analysis_info_t struct to be freed. + */ +WS_DLL_PUBLIC void sequence_analysis_info_free(seq_analysis_info_t * sainfo); + +/** Sort a seq_analysis_info_t struct. + * @param sainfo A pointer to the seq_analysis_info_t struct to be sorted + */ +WS_DLL_PUBLIC void sequence_analysis_list_sort(seq_analysis_info_t *sainfo); + +/** Free the segment list + * + * @param sainfo Sequence analysis information. + */ +WS_DLL_PUBLIC void sequence_analysis_list_free(seq_analysis_info_t *sainfo); + +/** Fill in the node address list + * + * @param sainfo Sequence analysis information. + * @return The number of transaction items (not nodes) processed. + */ +WS_DLL_PUBLIC int sequence_analysis_get_nodes(seq_analysis_info_t *sainfo); + +/** Free the node address list + * + * @param sainfo Sequence analysis information. + */ +WS_DLL_PUBLIC void sequence_analysis_free_nodes(seq_analysis_info_t *sainfo); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __EPAN_SEQUENCE_ANALYSIS_H__ */ + +/* + * Editor modelines + * + * Local Variables: + * c-basic-offset: 4 + * tab-width: 8 + * indent-tabs-mode: nil + * End: + * + * ex: set shiftwidth=4 tabstop=8 expandtab: + * :indentSize=4:tabSize=8:noTabs=true: + */ diff --git a/ui/gtk/flow_graph.c b/ui/gtk/flow_graph.c index 75680c0009..5475be457b 100644 --- a/ui/gtk/flow_graph.c +++ b/ui/gtk/flow_graph.c @@ -47,17 +47,16 @@ static GtkWidget *flow_graph_dlg = NULL; static GtkWidget *select_all_rb; static GtkWidget *select_displayed_rb; -static GtkWidget *select_general_rb; -static GtkWidget *select_tcp_rb; static GtkWidget *src_dst_rb; static GtkWidget *net_src_dst_rb; +static GtkWidget *select_analysis_combo; /****************************************************************************/ static void flow_graph_data_init(void) { graph_analysis = sequence_analysis_info_new(); - graph_analysis->type = SEQ_ANALYSIS_ANY; + graph_analysis->name = "any"; graph_analysis->all_packets = TRUE; } @@ -82,44 +81,47 @@ flow_graph_on_destroy(GObject *object _U_, gpointer user_data _U_) flow_graph_dlg = NULL; } - -/****************************************************************************/ -static void -toggle_select_all(GtkWidget *widget _U_, gpointer user_data _U_) +static gboolean +find_seq_name(const void *key, void *value, void *userdata) { - /* is the button now active? */ - if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(select_all_rb))) { - graph_analysis->all_packets = TRUE; + const char* name = (const char*)key; + register_analysis_t* analysis = (register_analysis_t*)value; + const char* ui_name = (const char*)userdata; + + if (strcmp(ui_name, sequence_analysis_get_ui_name(analysis)) == 0) + { + graph_analysis->name = name; + return TRUE; } + + return FALSE; } -/****************************************************************************/ static void -toggle_select_displayed(GtkWidget *widget _U_, gpointer user_data _U_) +sequence_combo_box_changed_cb(GtkComboBox *combo_box, gpointer user_data _U_) { - /* is the button now active? */ - if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(select_displayed_rb))) { - graph_analysis->all_packets = FALSE; - } + gchar* ui_name = gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(combo_box)); + + sequence_analysis_table_iterate_tables(find_seq_name, ui_name); } /****************************************************************************/ static void -toggle_select_general(GtkWidget *widget _U_, gpointer user_data _U_) +toggle_select_all(GtkWidget *widget _U_, gpointer user_data _U_) { /* is the button now active? */ - if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(select_general_rb))) { - graph_analysis->type = SEQ_ANALYSIS_ANY; + if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(select_all_rb))) { + graph_analysis->all_packets = TRUE; } } /****************************************************************************/ static void -toggle_select_tcp(GtkWidget *widget _U_, gpointer user_data _U_) +toggle_select_displayed(GtkWidget *widget _U_, gpointer user_data _U_) { /* is the button now active? */ - if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(select_tcp_rb))) { - graph_analysis->type = SEQ_ANALYSIS_TCP; + if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(select_displayed_rb))) { + graph_analysis->all_packets = FALSE; } } @@ -184,6 +186,16 @@ flow_graph_on_delete(GtkButton *button _U_, /****************************************************************************/ /* INTERFACE */ /****************************************************************************/ +static gboolean +add_flow_sequence_item(const void *key _U_, void *value, void *userdata) +{ + register_analysis_t* analysis = (register_analysis_t*)value; + GtkWidget* combo_box = (GtkWidget*)userdata; + + gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo_box), sequence_analysis_get_ui_name(analysis)); + return FALSE; +} + static void flow_graph_dlg_create(void) @@ -230,7 +242,7 @@ flow_graph_dlg_create(void) if (graph_analysis->all_packets) { gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(select_all_rb),TRUE); } - gtk_widget_show(select_all_rb); + gtk_widget_show(select_all_rb); /* Process displayed packets */ select_displayed_rb = gtk_radio_button_new_with_mnemonic_from_widget(GTK_RADIO_BUTTON(select_all_rb), @@ -255,28 +267,14 @@ flow_graph_dlg_create(void) gtk_container_set_border_width(GTK_CONTAINER(flow_type_grid), 5); gtk_container_add(GTK_CONTAINER(flow_type_fr), flow_type_grid); - /* General information */ - select_general_rb = gtk_radio_button_new_with_mnemonic_from_widget(NULL, "_General flow"); - gtk_widget_set_tooltip_text (select_general_rb, ("Show all packets, with general information")); - g_signal_connect(select_general_rb, "toggled", G_CALLBACK(toggle_select_general), NULL); - ws_gtk_grid_attach_extended(GTK_GRID(flow_type_grid), select_general_rb, 0, 0, 1, 1, - (GtkAttachOptions)(GTK_FILL), (GtkAttachOptions)(0), 0, 0); - if (graph_analysis->type == SEQ_ANALYSIS_ANY) { - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(select_general_rb),TRUE); - } - gtk_widget_show(select_general_rb); - - /* TCP specific information */ - select_tcp_rb = gtk_radio_button_new_with_mnemonic_from_widget(GTK_RADIO_BUTTON(select_general_rb), - "_TCP flow"); - gtk_widget_set_tooltip_text (select_tcp_rb, ("Show only TCP packets, with TCP specific information")); - g_signal_connect(select_tcp_rb, "toggled", G_CALLBACK(toggle_select_tcp), NULL); - ws_gtk_grid_attach_extended(GTK_GRID(flow_type_grid), select_tcp_rb, 0, 1, 1, 1, - (GtkAttachOptions)(GTK_FILL), (GtkAttachOptions)(0), 0, 0); - if (graph_analysis->type == SEQ_ANALYSIS_TCP) { - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(select_tcp_rb),TRUE); - } - gtk_widget_show(select_tcp_rb); + select_analysis_combo = gtk_combo_box_text_new(); + g_signal_connect(select_analysis_combo, "changed", G_CALLBACK(sequence_combo_box_changed_cb), NULL); + sequence_analysis_table_iterate_tables(add_flow_sequence_item, select_analysis_combo); + gtk_combo_box_set_active(GTK_COMBO_BOX(select_analysis_combo), 0); + + ws_gtk_grid_attach_extended(GTK_GRID(flow_type_grid), select_analysis_combo, 0, 0, 1, 1, + (GtkAttachOptions)(GTK_FILL), (GtkAttachOptions)(0), 0, 0); + gtk_widget_show(select_analysis_combo); gtk_widget_show(flow_type_grid); gtk_widget_show(flow_type_fr); diff --git a/ui/gtk/lbm_uimflow_dlg.c b/ui/gtk/lbm_uimflow_dlg.c index 61ea3eb5ea..0a5f1fbd4c 100644 --- a/ui/gtk/lbm_uimflow_dlg.c +++ b/ui/gtk/lbm_uimflow_dlg.c @@ -58,7 +58,7 @@ static lbm_uimflow_dialog_t dialog_data = { FALSE, -1, NULL, NULL, NULL, select_ static void lbmc_uim_flow_graph_data_init(void) { dialog_data.graph_analysis = sequence_analysis_info_new(); - dialog_data.graph_analysis->type = SEQ_ANALYSIS_ANY; + dialog_data.graph_analysis->name = "any"; dialog_data.graph_analysis->all_packets = TRUE; dialog_data.graph_analysis->any_addr = TRUE; } diff --git a/ui/qt/sequence_diagram.cpp b/ui/qt/sequence_diagram.cpp index 0dd52c59b1..98071b18a6 100644 --- a/ui/qt/sequence_diagram.cpp +++ b/ui/qt/sequence_diagram.cpp @@ -263,7 +263,7 @@ void SequenceDiagram::draw(QCPPainter *painter) fg_pen.setColor(sel_pal.color(QPalette::HighlightedText)); bg_color = sel_pal.color(QPalette::Highlight); selected_key_ = cur_key; - } else if (sainfo_->type == SEQ_ANALYSIS_ANY) { + } else if (strcmp(sainfo_->name, "any") == 0) { if (sai->has_color_filter) { fg_pen.setColor(QColor().fromRgb(sai->fg_color)); bg_color = QColor().fromRgb(sai->bg_color); diff --git a/ui/qt/sequence_dialog.cpp b/ui/qt/sequence_dialog.cpp index 0d058fe556..786a73076d 100644 --- a/ui/qt/sequence_dialog.cpp +++ b/ui/qt/sequence_dialog.cpp @@ -33,6 +33,7 @@ #include <ui/qt/utils/qt_ui_utils.h> #include "sequence_diagram.h" #include "wireshark_application.h" +#include <ui/qt/utils/variant_pointer.h> #include <QDir> #include <QFileDialog> @@ -65,6 +66,12 @@ static const double min_top_ = -1.0; static const double min_left_ = -0.5; +typedef struct { + int curr_index; + QComboBox *flow; + SequenceInfo *info; +} sequence_items_t; + SequenceDialog::SequenceDialog(QWidget &parent, CaptureFile &cf, SequenceInfo *info) : WiresharkDialog(parent, cf), ui(new Ui::SequenceDialog), @@ -80,7 +87,7 @@ SequenceDialog::SequenceDialog(QWidget &parent, CaptureFile &cf, SequenceInfo *i if (!info_) { info_ = new SequenceInfo(sequence_analysis_info_new()); - info_->sainfo()->type = SEQ_ANALYSIS_ANY; + info_->sainfo()->name = "any"; info_->sainfo()->all_packets = TRUE; } else { info_->ref(); @@ -153,13 +160,16 @@ SequenceDialog::SequenceDialog(QWidget &parent, CaptureFile &cf, SequenceInfo *i ui->showComboBox->setCurrentIndex(0); ui->addressComboBox->setCurrentIndex(0); - QComboBox *fcb = ui->flowComboBox; - fcb->addItem(ui->actionFlowAny->text(), SEQ_ANALYSIS_ANY); - fcb->addItem(ui->actionFlowTcp->text(), SEQ_ANALYSIS_TCP); + sequence_items_t item_data; + + item_data.curr_index = 0; + item_data.flow = ui->flowComboBox; + item_data.info = info_; - ui->flowComboBox->setCurrentIndex(info_->sainfo()->type); + //Add all registered analysis to combo box + sequence_analysis_table_iterate_tables(addFlowSequenceItem, &item_data); - if (info_->sainfo()->type == SEQ_ANALYSIS_VOIP) { + if (strcmp(info_->sainfo()->name, "voip") == 0) { ui->flowComboBox->blockSignals(true); ui->controlFrame->hide(); } @@ -405,7 +415,7 @@ void SequenceDialog::fillDiagram() QCustomPlot *sp = ui->sequencePlot; - if (info_->sainfo()->type == SEQ_ANALYSIS_VOIP) { + if (strcmp(info_->sainfo()->name, "voip") == 0) { seq_diagram_->setData(info_->sainfo()); } else { seq_diagram_->clearData(); @@ -587,9 +597,12 @@ void SequenceDialog::on_showComboBox_activated(int index) void SequenceDialog::on_flowComboBox_activated(int index) { - if (!info_->sainfo() || info_->sainfo()->type == SEQ_ANALYSIS_VOIP || index < 0) return; + if (!info_->sainfo() || (strcmp(info_->sainfo()->name, "voip") == 0) || index < 0) + return; + + register_analysis_t* analysis = VariantPointer<register_analysis_t>::asPtr(ui->flowComboBox->itemData(index)); + info_->sainfo()->name = sequence_analysis_get_name(analysis); - info_->sainfo()->type = static_cast<seq_analysis_type>(ui->flowComboBox->itemData(index).toInt()); fillDiagram(); } @@ -673,6 +686,27 @@ void SequenceDialog::zoomXAxis(bool in) sp->replot(); } +gboolean SequenceDialog::addFlowSequenceItem(const void* key, void *value, void *userdata) +{ + const char* name = (const char*)key; + register_analysis_t* analysis = (register_analysis_t*)value; + sequence_items_t* item_data = (sequence_items_t*)userdata; + + /* XXX - Although "voip" isn't a registered name yet, it appears to have special + handling that will be done outside of registered data */ + if (strcmp(name, "voip") == 0) + return FALSE; + + item_data->flow->addItem(sequence_analysis_get_ui_name(analysis), VariantPointer<register_analysis_t>::asQVariant(analysis)); + + if (item_data->flow->itemData(item_data->curr_index).toString().compare(item_data->info->sainfo()->name) == 0) + item_data->flow->setCurrentIndex(item_data->curr_index); + + item_data->curr_index++; + + return FALSE; +} + SequenceInfo::SequenceInfo(seq_analysis_info_t *sainfo) : sainfo_(sainfo), count_(1) diff --git a/ui/qt/sequence_dialog.h b/ui/qt/sequence_dialog.h index e6f0afef11..110e1f948e 100644 --- a/ui/qt/sequence_dialog.h +++ b/ui/qt/sequence_dialog.h @@ -117,6 +117,8 @@ private: void panAxes(int x_pixels, int y_pixels); void resetAxes(bool keep_lower = false); void goToAdjacentPacket(bool next); + + static gboolean addFlowSequenceItem(const void *key, void *value, void *userdata); }; #endif // SEQUENCE_DIALOG_H diff --git a/ui/qt/voip_calls_dialog.cpp b/ui/qt/voip_calls_dialog.cpp index ef7ce35760..2016c01eaa 100644 --- a/ui/qt/voip_calls_dialog.cpp +++ b/ui/qt/voip_calls_dialog.cpp @@ -103,7 +103,7 @@ VoipCallsDialog::VoipCallsDialog(QWidget &parent, CaptureFile &cf, bool all_flow tapinfo_.h225_cstype = H225_OTHER; tapinfo_.fs_option = all_flows ? FLOW_ALL : FLOW_ONLY_INVITES; /* flow show option */ tapinfo_.graph_analysis = sequence_analysis_info_new(); - tapinfo_.graph_analysis->type = SEQ_ANALYSIS_VOIP; + tapinfo_.graph_analysis->name = "voip"; sequence_info_ = new SequenceInfo(tapinfo_.graph_analysis); voip_calls_init_all_taps(&tapinfo_); diff --git a/ui/tap-sequence-analysis.c b/ui/tap-sequence-analysis.c index eda3b049f8..2ec1fc8333 100644 --- a/ui/tap-sequence-analysis.c +++ b/ui/tap-sequence-analysis.c @@ -29,19 +29,13 @@ #include "tap-sequence-analysis.h" #include "epan/addr_resolv.h" -#include "epan/color_filters.h" #include "epan/packet.h" #include "epan/tap.h" -#include "epan/proto_data.h" -#include "epan/dissectors/packet-tcp.h" -#include "epan/dissectors/packet-icmp.h" #include "ui/alert_box.h" #include <wsutil/file_util.h> -#define NODE_OVERFLOW MAX_NUM_NODES+1 - #define NODE_CHARS_WIDTH 20 #define CONV_TIME_HEADER "Conv.| Time " #define TIME_HEADER "|Time " @@ -50,210 +44,6 @@ #define CONV_TIME_HEADER_LENGTH 16 #define TIME_HEADER_LENGTH 10 -seq_analysis_info_t * -sequence_analysis_info_new(void) -{ - seq_analysis_info_t *sainfo = g_new0(seq_analysis_info_t, 1); - - /* SEQ_ANALYSIS_DEBUG("adding new item"); */ - sainfo->items = g_queue_new(); - sainfo->ht= g_hash_table_new(g_int_hash, g_int_equal); - return sainfo; -} - -void sequence_analysis_info_free(seq_analysis_info_t *sainfo) -{ - if (!sainfo) return; - - /* SEQ_ANALYSIS_DEBUG("%d items", g_queue_get_length(sainfo->items)); */ - sequence_analysis_list_free(sainfo); - - g_queue_free(sainfo->items); - g_hash_table_destroy(sainfo->ht); - - g_free(sainfo); -} - -/****************************************************************************/ -/* whenever a frame packet is seen by the tap listener */ -/* Add a new frame into the graph */ -static gboolean -seq_analysis_frame_packet( void *ptr, packet_info *pinfo, epan_dissect_t *edt _U_, const void *dummy _U_) -{ - seq_analysis_info_t *sainfo = (seq_analysis_info_t *) ptr; - col_item_t* col_item; - - if ((sainfo->all_packets)||(pinfo->fd->flags.passed_dfilter==1)){ - int i; - gchar *protocol = NULL; - gchar *colinfo = NULL; - seq_analysis_item_t *sai = NULL; - icmp_info_t *p_icmp_info; - - if (sainfo->any_addr) { - if (pinfo->net_src.type!=AT_NONE && pinfo->net_dst.type!=AT_NONE) { - sai = (seq_analysis_item_t *)g_malloc0(sizeof(seq_analysis_item_t)); - copy_address(&(sai->src_addr),&(pinfo->net_src)); - copy_address(&(sai->dst_addr),&(pinfo->net_dst)); - } - - } else { - if (pinfo->src.type!=AT_NONE && pinfo->dst.type!=AT_NONE) { - sai = (seq_analysis_item_t *)g_malloc0(sizeof(seq_analysis_item_t)); - copy_address(&(sai->src_addr),&(pinfo->src)); - copy_address(&(sai->dst_addr),&(pinfo->dst)); - } - } - - if (!sai) return FALSE; - - sai->frame_number = pinfo->num; - - if (pinfo->fd->color_filter) { - sai->bg_color = color_t_to_rgb(&pinfo->fd->color_filter->bg_color); - sai->fg_color = color_t_to_rgb(&pinfo->fd->color_filter->fg_color); - sai->has_color_filter = TRUE; - } - - sai->port_src=pinfo->srcport; - sai->port_dst=pinfo->destport; - sai->protocol = g_strdup(port_type_to_str(pinfo->ptype)); - - if(pinfo->cinfo) { - if (pinfo->cinfo->col_first[COL_INFO]>=0){ - - for (i = pinfo->cinfo->col_first[COL_INFO]; i <= pinfo->cinfo->col_last[COL_INFO]; i++) { - col_item = &pinfo->cinfo->columns[i]; - if (col_item->fmt_matx[COL_INFO]) { - colinfo = g_strdup(col_item->col_data); - /* break; ? or g_free(colinfo); before g_strdup() */ - } - } - } - - if (pinfo->cinfo->col_first[COL_PROTOCOL]>=0){ - - for (i = pinfo->cinfo->col_first[COL_PROTOCOL]; i <= pinfo->cinfo->col_last[COL_PROTOCOL]; i++) { - col_item = &pinfo->cinfo->columns[i]; - if (col_item->fmt_matx[COL_PROTOCOL]) { - protocol = g_strdup(col_item->col_data); - /* break; ? or g_free(protocol); before g_strdup() */ - } - } - } - } - - if (colinfo != NULL) { - sai->frame_label = g_strdup(colinfo); - if (protocol != NULL) { - sai->comment = g_strdup_printf("%s: %s", protocol, colinfo); - } else { - sai->comment = g_strdup(colinfo); - } - } else { - /* This will probably never happen...*/ - if (protocol != NULL) { - sai->frame_label = g_strdup(protocol); - sai->comment = g_strdup(protocol); - } - } - - if (pinfo->ptype == PT_NONE) { - if ((p_icmp_info = (icmp_info_t *)p_get_proto_data(wmem_file_scope(), - pinfo, proto_get_id_by_short_name("ICMP"), 0)) != NULL) { - g_free(sai->protocol); - sai->protocol = g_strdup("ICMP"); - sai->port_src = 0; - sai->port_dst = p_icmp_info->type * 256 + p_icmp_info->code; - } else if ((p_icmp_info = (icmp_info_t *)p_get_proto_data(wmem_file_scope(), - pinfo, proto_get_id_by_short_name("ICMPv6"), 0)) != NULL) { - g_free(sai->protocol); - sai->protocol = g_strdup("ICMPv6"); - sai->port_src = 0; - sai->port_dst = p_icmp_info->type * 256 + p_icmp_info->code; - } - } - - g_free(protocol); - g_free(colinfo); - - sai->line_style=1; - sai->conv_num=0; - sai->display=TRUE; - - g_queue_push_tail(sainfo->items, sai); - } - - return TRUE; -} - -/****************************************************************************/ -/* whenever a TCP packet is seen by the tap listener */ -/* Add a new tcp frame into the graph */ -static gboolean -seq_analysis_tcp_packet( void *ptr, packet_info *pinfo, epan_dissect_t *edt _U_, const void *tcp_info) -{ - seq_analysis_info_t *sainfo = (seq_analysis_info_t *) ptr; - const struct tcpheader *tcph = (const struct tcpheader *)tcp_info; - - if ((sainfo->all_packets)||(pinfo->fd->flags.passed_dfilter==1)){ - /* copied from packet-tcp */ - static const gchar *fstr[] = {"FIN", "SYN", "RST", "PSH", "ACK", "URG", "ECN", "CWR" }; - guint i, bpos; - gboolean flags_found = FALSE; - gchar flags[64]; - seq_analysis_item_t *sai; - - sai = (seq_analysis_item_t *)g_malloc0(sizeof(seq_analysis_item_t)); - sai->frame_number = pinfo->num; - if (sainfo->any_addr) { - copy_address(&(sai->src_addr),&(pinfo->net_src)); - copy_address(&(sai->dst_addr),&(pinfo->net_dst)); - } else { - copy_address(&(sai->src_addr),&(pinfo->src)); - copy_address(&(sai->dst_addr),&(pinfo->dst)); - } - sai->port_src=pinfo->srcport; - sai->port_dst=pinfo->destport; - sai->protocol=g_strdup(port_type_to_str(pinfo->ptype)); - - flags[0] = '\0'; - for (i = 0; i < 8; i++) { - bpos = 1 << i; - if (tcph->th_flags & bpos) { - if (flags_found) { - g_strlcat(flags, ", ", sizeof(flags)); - } - g_strlcat(flags, fstr[i], sizeof(flags)); - flags_found = TRUE; - } - } - if (flags[0] == '\0') { - g_snprintf (flags, sizeof(flags), "<None>"); - } - - if ((tcph->th_have_seglen)&&(tcph->th_seglen!=0)){ - sai->frame_label = g_strdup_printf("%s - Len: %u",flags, tcph->th_seglen); - } - else{ - sai->frame_label = g_strdup(flags); - } - - if (tcph->th_flags & TH_ACK) - sai->comment = g_strdup_printf("Seq = %u Ack = %u",tcph->th_seq, tcph->th_ack); - else - sai->comment = g_strdup_printf("Seq = %u",tcph->th_seq); - - sai->line_style = 1; - sai->conv_num = (guint16) tcph->th_stream; - sai->display = TRUE; - - g_queue_push_tail(sainfo->items, sai); - } - - return TRUE; -} - static void sequence_analysis_item_set_timestamp(gpointer data, gpointer user_data) { gchar time_str[COL_MAX_LEN]; @@ -267,29 +57,17 @@ static void sequence_analysis_item_set_timestamp(gpointer data, gpointer user_da void sequence_analysis_list_get(capture_file *cf, seq_analysis_info_t *sainfo) { - if (!cf || !sainfo) return; - - switch (sainfo->type) { - case SEQ_ANALYSIS_ANY: - register_tap_listener("frame", sainfo, NULL, - TL_REQUIRES_COLUMNS, - NULL, - seq_analysis_frame_packet, - NULL - ); - break; - case SEQ_ANALYSIS_TCP: - register_tap_listener("tcp", sainfo, NULL, - 0, - NULL, - seq_analysis_tcp_packet, - NULL - ); - break; - case SEQ_ANALYSIS_VOIP: - default: + register_analysis_t* analysis = NULL; + + if (!cf || !sainfo) return; - } + + analysis = sequence_analysis_find_by_name(sainfo->name); + if (analysis == NULL) + return; + + register_tap_listener(sequence_analysis_get_tap_listener_name(analysis), sainfo, NULL, sequence_analysis_get_tap_flags(analysis), + NULL, sequence_analysis_get_packet_func(analysis), NULL); cf_retap_packets(cf); remove_tap_listener(sainfo); @@ -299,74 +77,6 @@ sequence_analysis_list_get(capture_file *cf, seq_analysis_info_t *sainfo) g_queue_foreach(sainfo->items, sequence_analysis_item_set_timestamp, cf); } -static void sequence_analysis_item_free(gpointer data) -{ - seq_analysis_item_t *seq_item = (seq_analysis_item_t *)data; - g_free(seq_item->frame_label); - g_free(seq_item->time_str); - g_free(seq_item->comment); - g_free(seq_item->protocol); - free_address(&seq_item->src_addr); - free_address(&seq_item->dst_addr); - g_free(data); -} - - -/* compare two list entries by packet no */ -static gint -sequence_analysis_sort_compare(gconstpointer a, gconstpointer b, gpointer user_data _U_) -{ - const seq_analysis_item_t *entry_a = (const seq_analysis_item_t *)a; - const seq_analysis_item_t *entry_b = (const seq_analysis_item_t *)b; - - if(entry_a->frame_number < entry_b->frame_number) - return -1; - - if(entry_a->frame_number > entry_b->frame_number) - return 1; - - return 0; -} - - -void -sequence_analysis_list_sort(seq_analysis_info_t *sainfo) -{ - if (!sainfo) return; - g_queue_sort(sainfo->items, sequence_analysis_sort_compare, NULL); -} - -void -sequence_analysis_list_free(seq_analysis_info_t *sainfo) -{ - if (!sainfo) return; - /* SEQ_ANALYSIS_DEBUG("%d items", g_queue_get_length(sainfo->items)); */ - - /* free the graph data items */ - -#if GLIB_CHECK_VERSION (2, 32, 0) - g_queue_free_full(sainfo->items, sequence_analysis_item_free); - sainfo->items = g_queue_new(); -#else - { - GList *list = g_queue_peek_nth_link(sainfo->items, 0); - while (list) - { - sequence_analysis_item_free(list->data); - list = g_list_next(list); - } - g_queue_clear(sainfo->items); - } -#endif - - if (NULL != sainfo->ht) { - g_hash_table_remove_all(sainfo->ht); - } - sainfo->nconv = 0; - - sequence_analysis_free_nodes(sainfo); -} - /****************************************************************************/ /* Adds trailing characters to complete the requested length. */ /****************************************************************************/ @@ -427,70 +137,6 @@ static void overwrite (GString *gstr, char *text_to_insert, guint32 p1, guint32 g_free(ins_str); } -/* Return the index array if the node is in the array. Return -1 if there is room in the array - * and Return -2 if the array is full - */ -/****************************************************************************/ -static guint add_or_get_node(seq_analysis_info_t *sainfo, address *node) { - guint i; - - if (node->type == AT_NONE) return NODE_OVERFLOW; - - for (i=0; i<MAX_NUM_NODES && i < sainfo->num_nodes ; i++) { - if ( cmp_address(&(sainfo->nodes[i]), node) == 0 ) return i; /* it is in the array */ - } - - if (i >= MAX_NUM_NODES) { - return NODE_OVERFLOW; - } else { - sainfo->num_nodes++; - copy_address(&(sainfo->nodes[i]), node); - return i; - } -} - -struct sainfo_counter { - seq_analysis_info_t *sainfo; - int num_items; -}; - -static void sequence_analysis_get_nodes_item_proc(gpointer data, gpointer user_data) -{ - seq_analysis_item_t *gai = (seq_analysis_item_t *)data; - struct sainfo_counter *sc = (struct sainfo_counter *)user_data; - if (gai->display) { - (sc->num_items)++; - gai->src_node = add_or_get_node(sc->sainfo, &(gai->src_addr)); - gai->dst_node = add_or_get_node(sc->sainfo, &(gai->dst_addr)); - } -} - -/* Get the nodes from the list */ -/****************************************************************************/ -int -sequence_analysis_get_nodes(seq_analysis_info_t *sainfo) -{ - struct sainfo_counter sc = {sainfo, 0}; - - /* Fill the node array */ - g_queue_foreach(sainfo->items, sequence_analysis_get_nodes_item_proc, &sc); - - return sc.num_items; -} - -/* Free the node address list */ -/****************************************************************************/ -void -sequence_analysis_free_nodes(seq_analysis_info_t *sainfo) -{ - int i; - - for (i=0; i<MAX_NUM_NODES; i++) { - free_address(&sainfo->nodes[i]); - } - sainfo->num_nodes = 0; -} - /****************************************************************************/ gboolean sequence_analysis_dump_to_file(const char *pathname, seq_analysis_info_t *sainfo, capture_file *cf, unsigned int first_node) diff --git a/ui/tap-sequence-analysis.h b/ui/tap-sequence-analysis.h index 39b09839f2..f6d6d3267a 100644 --- a/ui/tap-sequence-analysis.h +++ b/ui/tap-sequence-analysis.h @@ -36,71 +36,12 @@ #include "cfile.h" #include "epan/address.h" +#include <epan/sequence_analysis.h> + #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ -#define MAX_NUM_NODES 40 - -typedef enum seq_analysis_type_ { - SEQ_ANALYSIS_ANY, - SEQ_ANALYSIS_TCP, - SEQ_ANALYSIS_VOIP -} seq_analysis_type; - -/** defines an entry for the graph analysis */ -typedef struct _seq_analysis_item { - guint32 frame_number; - address src_addr; - guint16 port_src; - address dst_addr; - guint16 port_dst; - gchar *frame_label; /**< the label on top of the arrow */ - gchar *time_str; /**< timestamp */ - gchar *comment; /**< a comment that appears at the right of the graph */ - guint16 conv_num; /**< The conversation number. Used for coloring VoIP calls. */ - unsigned fg_color; /**< Foreground color, 0xRRGGBB. Qt only. */ - unsigned bg_color; /**< Background color, 0xRRGGBB. Qt only. */ - gboolean has_color_filter; /**< Set if packet has color filter. Qt only. */ - gboolean display; /**< indicate if the packet is displayed or not in the graph */ - guint src_node; /**< this is used by graph_analysis.c to identify the node */ - guint dst_node; /**< a node is an IP address that will be displayed in columns */ - guint16 line_style; /**< the arrow line width in pixels*/ - gchar *protocol; /**< the label of the protocol defined in the IP packet */ -} seq_analysis_item_t; - -/** defines the graph analysis structure */ -typedef struct _seq_analysis_info { - seq_analysis_type type; /**< sequence type */ - gboolean all_packets; /**< all packets vs only displayed */ - gboolean any_addr; /**< any addr (DL+net) vs net-only */ - int nconv; /**< number of conversations in the list */ - GQueue* items; /**< list of seq_analysis_info_t */ - GHashTable *ht; /**< hash table of seq_analysis_info_t */ - address nodes[MAX_NUM_NODES]; /**< horizontal node list */ - guint32 num_nodes; /**< actual number of nodes */ -} seq_analysis_info_t; - -#if 0 -#define SEQ_ANALYSIS_DEBUG(...) { \ - char *SEQ_ANALYSIS_DEBUG_MSG = g_strdup_printf(__VA_ARGS__); \ - g_warning("sequence analysis: %s:%d %s", G_STRFUNC, __LINE__, SEQ_ANALYSIS_DEBUG_MSG); \ - g_free(SEQ_ANALYSIS_DEBUG_MSG); \ -} -#else -#define SEQ_ANALYSIS_DEBUG() -#endif - -/** Create and initialize a seq_analysis_info_t struct - * @return A pointer to a newly allocated seq_analysis_info_t struct. - */ -seq_analysis_info_t *sequence_analysis_info_new(void); - -/** Free a seq_analysis_info_t struct. - * @param sainfo A pointer to the seq_analysis_info_t struct to be freed. - */ -void sequence_analysis_info_free(seq_analysis_info_t * sainfo); - /** Fill in the segment list for sequence analysis * * @param cf Capture file to scan @@ -108,27 +49,6 @@ void sequence_analysis_info_free(seq_analysis_info_t * sainfo); */ void sequence_analysis_list_get(capture_file *cf, seq_analysis_info_t *sainfo); -void sequence_analysis_list_sort(seq_analysis_info_t *sainfo); - -/** Free the segment list - * - * @param sainfo Sequence analysis information. - */ -void sequence_analysis_list_free(seq_analysis_info_t *sainfo); - -/** Fill in the node address list - * - * @param sainfo Sequence analysis information. - * @return The number of transaction items (not nodes) processed. - */ -int sequence_analysis_get_nodes(seq_analysis_info_t *sainfo); - -/** Free the node address list - * - * @param sainfo Sequence analysis information. - */ -void sequence_analysis_free_nodes(seq_analysis_info_t *sainfo); - /** Write an ASCII version of the sequence diagram to a file. * * @param pathname Pathname of the file to write. |