#include <glib.h>
#include <wsutil/wsjsmn.h>
+#include <wsutil/ws_printf.h>
#include <file.h>
#include <epan/exceptions.h>
#include <epan/column.h>
+#include <ui/ssl_key_export.h>
+
#include <epan/stats_tree_priv.h>
#include <epan/stat_tap_ui.h>
#include <epan/conversation_table.h>
+#include <epan/expert.h>
+#include <epan/export_object.h>
+#include <epan/follow.h>
+#include <epan/rtd_table.h>
+#include <epan/srt_table.h>
#include <epan/dissectors/packet-h225.h>
#include <epan/rtp_pt.h>
#include <ui/tap-rtp-common.h>
#include <epan/to_str.h>
+#include <epan/addr_resolv.h>
+#include <epan/dissectors/packet-rtp.h>
+
#ifdef HAVE_GEOIP
# include <GeoIP.h>
# include <epan/geoip_db.h>
# include <wsutil/pint.h>
#endif
+#include <wsutil/glib-compat.h>
#include <wsutil/strtoi.h>
#include "sharkd.h"
-static struct register_ct *
-_get_conversation_table_by_name(const char *name)
-{
- guint count = conversation_table_get_num();
- guint i;
-
- /* XXX, wow O(n^2), move to libwireshark */
- for (i = 0; i < count; i++)
- {
- struct register_ct *table = get_conversation_table_by_num(i);
- const char *label = proto_get_protocol_short_name(find_protocol_by_id(get_conversation_proto_id(table)));
-
- if (!strcmp(label, name))
- return table;
- }
-
- return NULL;
-}
-
static void
json_unescape_str(char *input)
{
}
static void
-json_print_base64(const guint8 *data, int len)
+json_print_base64(const guint8 *data, size_t len)
{
- int i;
+ size_t i;
int base64_state1 = 0;
int base64_state2 = 0;
gsize wrote;
- gchar buf[(1 / 3 + 1) * 4 + 4];
+ gchar buf[(1 / 3 + 1) * 4 + 4 + 1];
putchar('"');
{
wrote = g_base64_encode_step(&data[i], 1, FALSE, buf, &base64_state1, &base64_state2);
if (wrote > 0)
- fwrite(buf, 1, wrote, stdout);
+ {
+ buf[wrote] = '\0';
+ printf("%s", buf);
+ }
}
wrote = g_base64_encode_close(FALSE, buf, &base64_state1, &base64_state2);
if (wrote > 0)
- fwrite(buf, 1, wrote, stdout);
+ {
+ buf[wrote] = '\0';
+ printf("%s", buf);
+ }
putchar('"');
}
}
}
-static void
-sharkd_session_process_info_conv_cb(gpointer data, gpointer user_data)
+struct sharkd_rtp_match
{
- struct register_ct *table = (struct register_ct *) data;
- int *pi = (int *) user_data;
+ guint32 addr_src, addr_dst;
+ address src_addr;
+ address dst_addr;
+ guint16 src_port;
+ guint16 dst_port;
+ guint32 ssrc;
+};
+
+static gboolean
+sharkd_rtp_match_init(struct sharkd_rtp_match *req, const char *init_str)
+{
+ gboolean ret = FALSE;
+ char **arr;
+
+ arr = g_strsplit(init_str, "_", 7); /* pass larger value, so we'll catch incorrect input :) */
+ if (g_strv_length(arr) != 5)
+ goto fail;
+
+ /* TODO, for now only IPv4 */
+ if (!get_host_ipaddr(arr[0], &req->addr_src))
+ goto fail;
+
+ if (!ws_strtou16(arr[1], NULL, &req->src_port))
+ goto fail;
- const char *label = proto_get_protocol_short_name(find_protocol_by_id(get_conversation_proto_id(table)));
+ if (!get_host_ipaddr(arr[2], &req->addr_dst))
+ goto fail;
+
+ if (!ws_strtou16(arr[3], NULL, &req->dst_port))
+ goto fail;
+
+ if (!ws_hexstrtou32(arr[4], NULL, &req->ssrc))
+ goto fail;
+
+ set_address(&req->src_addr, AT_IPv4, 4, &req->addr_src);
+ set_address(&req->dst_addr, AT_IPv4, 4, &req->addr_dst);
+ ret = TRUE;
+
+fail:
+ g_strfreev(arr);
+ return ret;
+}
+
+static gboolean
+sharkd_rtp_match_check(const struct sharkd_rtp_match *req, const packet_info *pinfo, const struct _rtp_info *rtp_info)
+{
+ if (rtp_info->info_sync_src == req->ssrc &&
+ pinfo->srcport == req->src_port &&
+ pinfo->destport == req->dst_port &&
+ addresses_equal(&pinfo->src, &req->src_addr) &&
+ addresses_equal(&pinfo->dst, &req->dst_addr))
+ {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static gboolean
+sharkd_session_process_info_conv_cb(const void* key, void* value, void* userdata)
+{
+ struct register_ct *table = (struct register_ct *) value;
+ int *pi = (int *) userdata;
+
+ const char *label = (const char*)key;
if (get_conversation_packet_func(table))
{
*pi = *pi + 1;
}
+ return FALSE;
+}
+
+static gboolean
+sharkd_export_object_visit_cb(const void *key _U_, void *value, void *user_data)
+{
+ register_eo_t *eo = (register_eo_t*)value;
+ int *pi = (int *) user_data;
+
+ const int proto_id = get_eo_proto_id(eo);
+ const char *filter = proto_get_protocol_filter_name(proto_id);
+ const char *label = proto_get_protocol_short_name(find_protocol_by_id(proto_id));
+
+ printf("%s{", (*pi) ? "," : "");
+ printf("\"name\":\"Export Object/%s\"", label);
+ printf(",\"tap\":\"eo:%s\"", filter);
+ printf("}");
+
+ *pi = *pi + 1;
+ return FALSE;
+}
+
+static gboolean
+sharkd_srt_visit_cb(const void *key _U_, void *value, void *user_data)
+{
+ register_srt_t *srt = (register_srt_t *) value;
+ int *pi = (int *) user_data;
+
+ const int proto_id = get_srt_proto_id(srt);
+ const char *filter = proto_get_protocol_filter_name(proto_id);
+ const char *label = proto_get_protocol_short_name(find_protocol_by_id(proto_id));
+
+ printf("%s{", (*pi) ? "," : "");
+ printf("\"name\":\"Service Response Time/%s\"", label);
+ printf(",\"tap\":\"srt:%s\"", filter);
+ printf("}");
+
+ *pi = *pi + 1;
+ return FALSE;
+}
+
+static gboolean
+sharkd_rtd_visit_cb(const void *key _U_, void *value, void *user_data)
+{
+ register_rtd_t *rtd = (register_rtd_t *) value;
+ int *pi = (int *) user_data;
+
+ const int proto_id = get_rtd_proto_id(rtd);
+ const char *filter = proto_get_protocol_filter_name(proto_id);
+ const char *label = proto_get_protocol_short_name(find_protocol_by_id(proto_id));
+
+ printf("%s{", (*pi) ? "," : "");
+ printf("\"name\":\"Response Time Delay/%s\"", label);
+ printf(",\"tap\":\"rtd:%s\"", filter);
+ printf("}");
+
+ *pi = *pi + 1;
+ return FALSE;
+}
+
+static gboolean
+sharkd_follower_visit_cb(const void *key _U_, void *value, void *user_data)
+{
+ register_follow_t *follower = (register_follow_t*) value;
+ int *pi = (int *) user_data;
+
+ const int proto_id = get_follow_proto_id(follower);
+ const char *label = proto_get_protocol_short_name(find_protocol_by_id(proto_id));
+ const char *filter = label; /* correct: get_follow_by_name() is registered by short name */
+
+ printf("%s{", (*pi) ? "," : "");
+ printf("\"name\":\"Follow/%s\"", label);
+ printf(",\"tap\":\"follow:%s\"", filter);
+ printf("}");
+
+ *pi = *pi + 1;
+ return FALSE;
}
/**
* 'name' - conversation name
* 'tap' - sharkd tap-name for conversation
*
+ * (m) eo - available export object list, array of object with attributes:
+ * 'name' - export object name
+ * 'tap' - sharkd tap-name for eo
+ *
+ * (m) srt - available service response time list, array of object with attributes:
+ * 'name' - service response time name
+ * 'tap' - sharkd tap-name for srt
+ *
+ * (m) rtd - available response time delay list, array of object with attributes:
+ * 'name' - response time delay name
+ * 'tap' - sharkd tap-name for rtd
+ *
* (m) taps - available taps, array of object with attributes:
* 'name' - tap name
* 'tap' - sharkd tap-name
*
+ * (m) follow - available followers, array of object with attributes:
+ * 'name' - tap name
+ * 'tap' - sharkd tap-name
+ *
* (m) ftypes - conversation table for FT_ number to string
*/
static void
printf("]");
printf(",\"taps\":[");
+ {
+ printf("{\"name\":\"%s\",\"tap\":\"%s\"}", "RTP streams", "rtp-streams");
+ printf(",{\"name\":\"%s\",\"tap\":\"%s\"}", "Expert Information", "expert");
+ }
+ printf("]");
+
+ printf(",\"eo\":[");
+ i = 0;
+ eo_iterate_tables(sharkd_export_object_visit_cb, &i);
+ printf("]");
+
+ printf(",\"srt\":[");
+ i = 0;
+ srt_table_iterate_tables(sharkd_srt_visit_cb, &i);
+ printf("]");
+
+ printf(",\"rtd\":[");
+ i = 0;
+ rtd_table_iterate_tables(sharkd_rtd_visit_cb, &i);
+ printf("]");
+
+ printf(",\"follow\":[");
+ i = 0;
+ follow_iterate_followers(sharkd_follower_visit_cb, &i);
printf("]");
printf("}\n");
static void
sharkd_session_process_status(void)
{
- printf("{\"frames\":%d", cfile.count);
+ printf("{\"frames\":%u", cfile.count);
printf("}\n");
}
if (pi->layers)
{
- wmem_list_frame_t *frame = wmem_list_head(pi->layers);
+ wmem_list_frame_t *frame;
for (frame = wmem_list_head(pi->layers); frame; frame = wmem_list_frame_next(frame))
{
analyser.last_time = NULL;
analyser.protocols_set = g_hash_table_new(NULL /* g_direct_hash() */, NULL /* g_direct_equal */);
- printf("{\"frames\":%d", cfile.count);
+ printf("{\"frames\":%u", cfile.count);
printf(",\"protocols\":[");
for (framenum = 1; framenum <= cfile.count; framenum++)
{
/* code based on stats_tree_get_values_from_node() */
printf("%s{\"name\":\"%s\"", sepa, node->name);
- printf(",\"count\":%u", node->counter);
+ printf(",\"count\":%d", node->counter);
if (node->counter && ((node->st_flags & ST_FLG_AVERAGE) || node->rng))
{
printf(",\"avg\":%.2f", ((float)node->total) / node->counter);
- printf(",\"min\":%u", node->minvalue);
- printf(",\"max\":%u", node->maxvalue);
+ printf(",\"min\":%d", node->minvalue);
+ printf(",\"max\":%d", node->maxvalue);
}
if (node->st->elapsed)
static void
sharkd_session_process_tap_stats_cb(void *psp)
{
- stats_tree *st = (stats_tree *)psp;
+ stats_tree *st = (stats_tree *) psp;
printf("{\"tap\":\"stats:%s\",\"type\":\"stats\"", st->cfg->abbr);
printf("},");
}
+static void
+sharkd_session_free_tap_stats_cb(void *psp)
+{
+ stats_tree *st = (stats_tree *) psp;
+
+ stats_tree_free(st);
+}
+
+struct sharkd_expert_tap
+{
+ GSList *details;
+ GStringChunk *text;
+};
+
+/**
+ * sharkd_session_process_tap_expert_cb()
+ *
+ * Output expert tap:
+ *
+ * (m) tap - tap name
+ * (m) type:expert - tap output type
+ * (m) details - array of object with attributes:
+ * (m) f - frame number, which generated expert information
+ * (o) s - severity
+ * (o) g - group
+ * (m) m - expert message
+ * (o) p - protocol
+ */
+static void
+sharkd_session_process_tap_expert_cb(void *tapdata)
+{
+ struct sharkd_expert_tap *etd = (struct sharkd_expert_tap *) tapdata;
+ GSList *list;
+ const char *sepa = "";
+
+ printf("{\"tap\":\"%s\",\"type\":\"%s\"", "expert", "expert");
+
+ printf(",\"details\":[");
+ for (list = etd->details; list; list = list->next)
+ {
+ expert_info_t *ei = (expert_info_t *) list->data;
+ const char *tmp;
+
+ printf("%s{", sepa);
+
+ printf("\"f\":%u,", ei->packet_num);
+
+ tmp = try_val_to_str(ei->severity, expert_severity_vals);
+ if (tmp)
+ printf("\"s\":\"%s\",", tmp);
+
+ tmp = try_val_to_str(ei->group, expert_group_vals);
+ if (tmp)
+ printf("\"g\":\"%s\",", tmp);
+
+ printf("\"m\":");
+ json_puts_string(ei->summary);
+ printf(",");
+
+ if (ei->protocol)
+ {
+ printf("\"p\":");
+ json_puts_string(ei->protocol);
+ }
+
+ printf("}");
+ sepa = ",";
+ }
+ printf("]");
+
+ printf("},");
+}
+
+static gboolean
+sharkd_session_packet_tap_expert_cb(void *tapdata, packet_info *pinfo _U_, epan_dissect_t *edt _U_, const void *pointer)
+{
+ struct sharkd_expert_tap *etd = (struct sharkd_expert_tap *) tapdata;
+ expert_info_t *ei = (expert_info_t *) pointer;
+
+ ei = (expert_info_t *) g_memdup(ei, sizeof(*ei));
+ ei->protocol = g_string_chunk_insert_const(etd->text, ei->protocol);
+ ei->summary = g_string_chunk_insert_const(etd->text, ei->summary);
+
+ etd->details = g_slist_prepend(etd->details, ei);
+
+ return TRUE;
+}
+
+static void
+sharkd_session_free_tap_expert_cb(void *tapdata)
+{
+ struct sharkd_expert_tap *etd = (struct sharkd_expert_tap *) tapdata;
+
+ g_slist_free_full(etd->details, g_free);
+ g_string_chunk_free(etd->text);
+ g_free(etd);
+}
+
struct sharkd_conv_tap_data
{
const char *type;
#ifdef HAVE_GEOIP
if (addr->type == AT_IPv4)
{
- uint32_t ip = pntoh32(addr->data);
+ guint32 ip = pntoh32(addr->data);
guint num_dbs = geoip_db_num_dbs();
guint dbnum;
}
}
}
-#endif
#ifdef HAVE_GEOIP_V6
if (addr->type == AT_IPv6)
{
}
}
}
-#endif
+#endif /* HAVE_GEOIP_V6 */
+#endif /* HAVE_GEOIP */
return with_geoip;
}
+struct sharkd_analyse_rtp_items
+{
+ guint32 frame_num;
+ guint32 sequence_num;
+
+ double delta;
+ double jitter;
+ double skew;
+ double bandwidth;
+ gboolean marker;
+
+ double arrive_offset;
+
+ /* from tap_rtp_stat_t */
+ guint32 flags;
+ guint16 pt;
+};
+
+struct sharkd_analyse_rtp
+{
+ const char *tap_name;
+ struct sharkd_rtp_match rtp;
+
+ GSList *packets;
+ double start_time;
+ tap_rtp_stat_t statinfo;
+};
+
+static void
+sharkd_session_process_tap_rtp_free_cb(void *tapdata)
+{
+ struct sharkd_analyse_rtp *rtp_req = (struct sharkd_analyse_rtp *) tapdata;
+
+ g_slist_free_full(rtp_req->packets, g_free);
+ g_free(rtp_req);
+}
+
+static gboolean
+sharkd_session_packet_tap_rtp_analyse_cb(void *tapdata, packet_info *pinfo, epan_dissect_t *edt _U_, const void *pointer)
+{
+ struct sharkd_analyse_rtp *rtp_req = (struct sharkd_analyse_rtp *) tapdata;
+ const struct _rtp_info *rtpinfo = (const struct _rtp_info *) pointer;
+
+ if (sharkd_rtp_match_check(&rtp_req->rtp, pinfo, rtpinfo))
+ {
+ tap_rtp_stat_t *statinfo = &(rtp_req->statinfo);
+ struct sharkd_analyse_rtp_items *item;
+
+ rtp_packet_analyse(statinfo, pinfo, rtpinfo);
+
+ item = (struct sharkd_analyse_rtp_items *) g_malloc(sizeof(struct sharkd_analyse_rtp_items));
+
+ if (!rtp_req->packets)
+ rtp_req->start_time = nstime_to_sec(&pinfo->abs_ts);
+
+ item->frame_num = pinfo->num;
+ item->sequence_num = rtpinfo->info_seq_num;
+ item->delta = (statinfo->flags & STAT_FLAG_FIRST) ? 0.0 : statinfo->delta;
+ item->jitter = (statinfo->flags & STAT_FLAG_FIRST) ? 0.0 : statinfo->jitter;
+ item->skew = (statinfo->flags & STAT_FLAG_FIRST) ? 0.0 : statinfo->skew;
+ item->bandwidth = statinfo->bandwidth;
+ item->marker = rtpinfo->info_marker_set ? TRUE : FALSE;
+ item->arrive_offset= nstime_to_sec(&pinfo->abs_ts) - rtp_req->start_time;
+
+ item->flags = statinfo->flags;
+ item->pt = statinfo->pt;
+
+ /* XXX, O(n) optimize */
+ rtp_req->packets = g_slist_append(rtp_req->packets, item);
+ }
+
+ return TRUE;
+}
+
+/**
+ * sharkd_session_process_tap_rtp_analyse_cb()
+ *
+ * Output rtp analyse tap:
+ * (m) tap - tap name
+ * (m) type - tap output type
+ * (m) ssrc - RTP SSRC
+ * (m) max_delta - Max delta (ms)
+ * (m) max_delta_nr - Max delta packet #
+ * (m) max_jitter - Max jitter (ms)
+ * (m) mean_jitter - Mean jitter (ms)
+ * (m) max_skew - Max skew (ms)
+ * (m) total_nr - Total number of RTP packets
+ * (m) seq_err - Number of sequence errors
+ * (m) duration - Duration (ms)
+ * (m) items - array of object with attributes:
+ * (m) f - frame number
+ * (m) o - arrive offset
+ * (m) sn - sequence number
+ * (m) d - delta
+ * (m) j - jitter
+ * (m) sk - skew
+ * (m) bw - bandwidth
+ * (o) s - status string
+ * (o) t - status type
+ * (o) mark - rtp mark
+ */
+static void
+sharkd_session_process_tap_rtp_analyse_cb(void *tapdata)
+{
+ const int RTP_TYPE_CN = 1;
+ const int RTP_TYPE_ERROR = 2;
+ const int RTP_TYPE_WARN = 3;
+ const int RTP_TYPE_PT_EVENT = 4;
+
+ const struct sharkd_analyse_rtp *rtp_req = (struct sharkd_analyse_rtp *) tapdata;
+ const tap_rtp_stat_t *statinfo = &rtp_req->statinfo;
+
+ const char *sepa = "";
+ GSList *l;
+
+ printf("{\"tap\":\"%s\",\"type\":\"rtp-analyse\"", rtp_req->tap_name);
+
+ printf(",\"ssrc\":%u", rtp_req->rtp.ssrc);
+
+ printf(",\"max_delta\":%f", statinfo->max_delta);
+ printf(",\"max_delta_nr\":%u", statinfo->max_nr);
+ printf(",\"max_jitter\":%f", statinfo->max_jitter);
+ printf(",\"mean_jitter\":%f", statinfo->mean_jitter);
+ printf(",\"max_skew\":%f", statinfo->max_skew);
+ printf(",\"total_nr\":%u", statinfo->total_nr);
+ printf(",\"seq_err\":%u", statinfo->sequence);
+ printf(",\"duration\":%f", statinfo->time - statinfo->start_time);
+
+ printf(",\"items\":[");
+ for (l = rtp_req->packets; l; l = l->next)
+ {
+ struct sharkd_analyse_rtp_items *item = (struct sharkd_analyse_rtp_items *) l->data;
+
+ printf("%s{", sepa);
+
+ printf("\"f\":%u", item->frame_num);
+ printf(",\"o\":%.9f", item->arrive_offset);
+ printf(",\"sn\":%u", item->sequence_num);
+ printf(",\"d\":%.2f", item->delta);
+ printf(",\"j\":%.2f", item->jitter);
+ printf(",\"sk\":%.2f", item->skew);
+ printf(",\"bw\":%.2f", item->bandwidth);
+
+ if (item->pt == PT_CN)
+ printf(",\"s\":\"%s\",\"t\":%d", "Comfort noise (PT=13, RFC 3389)", RTP_TYPE_CN);
+ else if (item->pt == PT_CN_OLD)
+ printf(",\"s\":\"%s\",\"t\":%d", "Comfort noise (PT=19, reserved)", RTP_TYPE_CN);
+ else if (item->flags & STAT_FLAG_WRONG_SEQ)
+ printf(",\"s\":\"%s\",\"t\":%d", "Wrong sequence number", RTP_TYPE_ERROR);
+ else if (item->flags & STAT_FLAG_DUP_PKT)
+ printf(",\"s\":\"%s\",\"t\":%d", "Suspected duplicate (MAC address) only delta time calculated", RTP_TYPE_WARN);
+ else if (item->flags & STAT_FLAG_REG_PT_CHANGE)
+ printf(",\"s\":\"Payload changed to PT=%u%s\",\"t\":%d",
+ item->pt,
+ (item->flags & STAT_FLAG_PT_T_EVENT) ? " telephone/event" : "",
+ RTP_TYPE_WARN);
+ else if (item->flags & STAT_FLAG_WRONG_TIMESTAMP)
+ printf(",\"s\":\"%s\",\"t\":%d", "Incorrect timestamp", RTP_TYPE_WARN);
+ else if ((item->flags & STAT_FLAG_PT_CHANGE)
+ && !(item->flags & STAT_FLAG_FIRST)
+ && !(item->flags & STAT_FLAG_PT_CN)
+ && (item->flags & STAT_FLAG_FOLLOW_PT_CN)
+ && !(item->flags & STAT_FLAG_MARKER))
+ {
+ printf(",\"s\":\"%s\",\"t\":%d", "Marker missing?", RTP_TYPE_WARN);
+ }
+ else if (item->flags & STAT_FLAG_PT_T_EVENT)
+ printf(",\"s\":\"PT=%u telephone/event\",\"t\":%d", item->pt, RTP_TYPE_PT_EVENT);
+ else if (item->flags & STAT_FLAG_MARKER)
+ printf(",\"t\":%d", RTP_TYPE_WARN);
+
+ if (item->marker)
+ printf(",\"mark\":1");
+
+ printf("}");
+ sepa = ",";
+ }
+ printf("]");
+
+ printf("},");
+}
+
/**
* sharkd_session_process_tap_conv_cb()
*
char *host_str, *port_str;
char *filter_str;
- printf("%s{", i ? "," : "");
+ printf("%s{", i ? "," : "");
+
+ printf("\"host\":\"%s\"", (host_str = get_conversation_address(NULL, &host->myaddress, iu->resolve_name)));
+
+ if (proto_with_port)
+ {
+ printf(",\"port\":\"%s\"", (port_str = get_conversation_port(NULL, host->port, host->ptype, iu->resolve_port)));
+
+ wmem_free(NULL, port_str);
+ }
+
+ printf(",\"rxf\":%" G_GUINT64_FORMAT, host->rx_frames);
+ printf(",\"rxb\":%" G_GUINT64_FORMAT, host->rx_bytes);
+
+ printf(",\"txf\":%" G_GUINT64_FORMAT, host->tx_frames);
+ printf(",\"txb\":%" G_GUINT64_FORMAT, host->tx_bytes);
+
+ filter_str = get_hostlist_filter(host);
+ if (filter_str)
+ {
+ printf(",\"filter\":\"%s\"", filter_str);
+ g_free(filter_str);
+ }
+
+ wmem_free(NULL, host_str);
+
+ if (sharkd_session_geoip_addr(&(host->myaddress), ""))
+ with_geoip = 1;
+ printf("}");
+ }
+ }
+
+ printf("],\"proto\":\"%s\",\"geoip\":%s},", proto, with_geoip ? "true" : "false");
+}
+
+static void
+sharkd_session_free_tap_conv_cb(void *arg)
+{
+ conv_hash_t *hash = (conv_hash_t *) arg;
+ struct sharkd_conv_tap_data *iu = (struct sharkd_conv_tap_data *) hash->user_data;
+
+ if (!strncmp(iu->type, "conv:", 5))
+ {
+ reset_conversation_table_data(hash);
+ }
+ else if (!strncmp(iu->type, "endpt:", 6))
+ {
+ reset_hostlist_table_data(hash);
+ }
+
+ g_free(iu);
+}
+
+/**
+ * sharkd_session_process_tap_rtd_cb()
+ *
+ * Output rtd tap:
+ * (m) tap - tap name
+ * (m) type - tap output type
+ * (m) stats - statistics rows - array object with attributes:
+ * (m) type - statistic name
+ * (m) num - number of messages
+ * (m) min - minimum SRT time
+ * (m) max - maximum SRT time
+ * (m) tot - total SRT time
+ * (m) min_frame - minimal SRT
+ * (m) max_frame - maximum SRT
+ * (o) open_req - Open Requests
+ * (o) disc_rsp - Discarded Responses
+ * (o) req_dup - Duplicated Requests
+ * (o) rsp_dup - Duplicated Responses
+ * (o) open_req - Open Requests
+ * (o) disc_rsp - Discarded Responses
+ * (o) req_dup - Duplicated Requests
+ * (o) rsp_dup - Duplicated Responses
+ */
+static void
+sharkd_session_process_tap_rtd_cb(void *arg)
+{
+ rtd_data_t *rtd_data = (rtd_data_t *) arg;
+ register_rtd_t *rtd = (register_rtd_t *) rtd_data->user_data;
+
+ guint i, j;
+
+ const char *filter = proto_get_protocol_filter_name(get_rtd_proto_id(rtd));
+
+ /* XXX, some dissectors are having single table and multiple timestats (mgcp, megaco),
+ * some multiple table and single timestat (radius, h225)
+ * and it seems that value_string is used one for timestamp-ID, other one for table-ID
+ * I wonder how it will gonna work with multiple timestats and multiple timestat...
+ * (for usage grep for: register_rtd_table)
+ */
+ const value_string *vs = get_rtd_value_string(rtd);
+ const char *sepa = "";
+
+ printf("{\"tap\":\"rtd:%s\",\"type\":\"rtd\"", filter);
+
+ if (rtd_data->stat_table.num_rtds == 1)
+ {
+ const rtd_timestat *ms = &rtd_data->stat_table.time_stats[0];
+
+ printf(",\"open_req\":%u", ms->open_req_num);
+ printf(",\"disc_rsp\":%u", ms->disc_rsp_num);
+ printf(",\"req_dup\":%u", ms->req_dup_num);
+ printf(",\"rsp_dup\":%u", ms->rsp_dup_num);
+ }
+
+ printf(",\"stats\":[");
+ for (i = 0; i < rtd_data->stat_table.num_rtds; i++)
+ {
+ const rtd_timestat *ms = &rtd_data->stat_table.time_stats[i];
+
+ for (j = 0; j < ms->num_timestat; j++)
+ {
+ const char *type_str;
+
+ if (ms->rtd[j].num == 0)
+ continue;
+
+ printf("%s{", sepa);
+
+ if (rtd_data->stat_table.num_rtds == 1)
+ type_str = val_to_str_const(j, vs, "Other"); /* 1 table - description per row */
+ else
+ type_str = val_to_str_const(i, vs, "Other"); /* multiple table - description per table */
+ printf("\"type\":");
+ json_puts_string(type_str);
+
+ printf(",\"num\":%u", ms->rtd[j].num);
+ printf(",\"min\":%.9f", nstime_to_sec(&(ms->rtd[j].min)));
+ printf(",\"max\":%.9f", nstime_to_sec(&(ms->rtd[j].max)));
+ printf(",\"tot\":%.9f", nstime_to_sec(&(ms->rtd[j].tot)));
+ printf(",\"min_frame\":%u", ms->rtd[j].min_num);
+ printf(",\"max_frame\":%u", ms->rtd[j].max_num);
+
+ if (rtd_data->stat_table.num_rtds != 1)
+ {
+ /* like in tshark, display it on every row */
+ printf(",\"open_req\":%u", ms->open_req_num);
+ printf(",\"disc_rsp\":%u", ms->disc_rsp_num);
+ printf(",\"req_dup\":%u", ms->req_dup_num);
+ printf(",\"rsp_dup\":%u", ms->rsp_dup_num);
+ }
+
+ printf("}");
+ sepa = ",";
+ }
+ }
+ printf("]},");
+}
+
+static void
+sharkd_session_free_tap_rtd_cb(void *arg)
+{
+ rtd_data_t *rtd_data = (rtd_data_t *) arg;
+
+ free_rtd_table(&rtd_data->stat_table, NULL, NULL);
+ g_free(rtd_data);
+}
+
+/**
+ * sharkd_session_process_tap_srt_cb()
+ *
+ * Output srt tap:
+ * (m) tap - tap name
+ * (m) type - tap output type
+ *
+ * (m) tables - array of object with attributes:
+ * (m) n - table name
+ * (m) f - table filter
+ * (o) c - table column name
+ * (m) r - table rows - array object with attributes:
+ * (m) n - row name
+ * (m) idx - procedure index
+ * (m) num - number of events
+ * (m) min - minimum SRT time
+ * (m) max - maximum SRT time
+ * (m) tot - total SRT time
+ */
+static void
+sharkd_session_process_tap_srt_cb(void *arg)
+{
+ srt_data_t *srt_data = (srt_data_t *) arg;
+ register_srt_t *srt = (register_srt_t *) srt_data->user_data;
+
+ const char *filter = proto_get_protocol_filter_name(get_srt_proto_id(srt));
+
+ guint i;
+
+ printf("{\"tap\":\"srt:%s\",\"type\":\"srt\"", filter);
+
+ printf(",\"tables\":[");
+ for (i = 0; i < srt_data->srt_array->len; i++)
+ {
+ /* SRT table */
+ srt_stat_table *rst = g_array_index(srt_data->srt_array, srt_stat_table *, i);
+ const char *sepa = "";
+
+ int j;
+
+ if (i)
+ printf(",");
+ printf("{");
+
+ printf("\"n\":");
+ if (rst->name)
+ json_puts_string(rst->name);
+ else if (rst->short_name)
+ json_puts_string(rst->short_name);
+ else
+ printf("\"table%u\"", i);
+
+ if (rst->filter_string)
+ {
+ printf(",\"f\":");
+ json_puts_string(rst->filter_string);
+ }
+
+ if (rst->proc_column_name)
+ {
+ printf(",\"c\":");
+ json_puts_string(rst->proc_column_name);
+ }
+
+ printf(",\"r\":[");
+ for (j = 0; j < rst->num_procs; j++)
+ {
+ /* SRT row */
+ srt_procedure_t *proc = &rst->procedures[j];
+
+ if (proc->stats.num == 0)
+ continue;
+
+ printf("%s{", sepa);
+
+ printf("\"n\":");
+ json_puts_string(proc->procedure);
+
+ if (rst->filter_string)
+ printf(",\"idx\":%d", proc->proc_index);
+
+ printf(",\"num\":%u", proc->stats.num);
+
+ printf(",\"min\":%.9f", nstime_to_sec(&proc->stats.min));
+ printf(",\"max\":%.9f", nstime_to_sec(&proc->stats.max));
+ printf(",\"tot\":%.9f", nstime_to_sec(&proc->stats.tot));
+
+ printf("}");
+ sepa = ",";
+ }
+ printf("]}");
+ }
+
+ printf("]},");
+}
+
+static void
+sharkd_session_free_tap_srt_cb(void *arg)
+{
+ srt_data_t *srt_data = (srt_data_t *) arg;
+ register_srt_t *srt = (register_srt_t *) srt_data->user_data;
+
+ free_srt_table(srt, srt_data->srt_array, NULL, NULL);
+ g_array_free(srt_data->srt_array, TRUE);
+ g_free(srt_data);
+}
+
+struct sharkd_export_object_list
+{
+ struct sharkd_export_object_list *next;
+
+ char *type;
+ const char *proto;
+ GSList *entries;
+};
+
+static struct sharkd_export_object_list *sharkd_eo_list;
+
+/**
+ * sharkd_session_process_tap_eo_cb()
+ *
+ * Output eo tap:
+ * (m) tap - tap name
+ * (m) type - tap output type
+ * (m) proto - protocol short name
+ * (m) objects - array of object with attributes:
+ * (m) pkt - packet number
+ * (o) hostname - hostname
+ * (o) type - content type
+ * (o) filename - filename
+ * (m) len - object length
+ */
+static void
+sharkd_session_process_tap_eo_cb(void *tapdata)
+{
+ export_object_list_t *tap_object = (export_object_list_t *) tapdata;
+ struct sharkd_export_object_list *object_list = (struct sharkd_export_object_list*) tap_object->gui_data;
+ GSList *slist;
+ int i = 0;
+
+ printf("{\"tap\":\"%s\",\"type\":\"eo\"", object_list->type);
+ printf(",\"proto\":\"%s\"", object_list->proto);
+ printf(",\"objects\":[");
+
+ for (slist = object_list->entries; slist; slist = slist->next)
+ {
+ const export_object_entry_t *eo_entry = (export_object_entry_t *) slist->data;
+
+ printf("%s{", i ? "," : "");
+
+ printf("\"pkt\":%u", eo_entry->pkt_num);
+
+ if (eo_entry->hostname)
+ {
+ printf(",\"hostname\":");
+ json_puts_string(eo_entry->hostname);
+ }
+
+ if (eo_entry->content_type)
+ {
+ printf(",\"type\":");
+ json_puts_string(eo_entry->content_type);
+ }
+
+ if (eo_entry->filename)
+ {
+ printf(",\"filename\":");
+ json_puts_string(eo_entry->filename);
+ }
+
+ printf(",\"_download\":\"%s_%d\"", object_list->type, i);
+
+ printf(",\"len\":%" G_GINT64_FORMAT, eo_entry->payload_len);
+
+ printf("}");
+
+ i++;
+ }
+
+ printf("]},");
+}
+
+static void
+sharkd_eo_object_list_add_entry(void *gui_data, export_object_entry_t *entry)
+{
+ struct sharkd_export_object_list *object_list = (struct sharkd_export_object_list *) gui_data;
+
+ object_list->entries = g_slist_append(object_list->entries, entry);
+}
+
+static export_object_entry_t *
+sharkd_eo_object_list_get_entry(void *gui_data, int row)
+{
+ struct sharkd_export_object_list *object_list = (struct sharkd_export_object_list *) gui_data;
+
+ return (export_object_entry_t *) g_slist_nth_data(object_list->entries, row);
+}
+
+/**
+ * sharkd_session_process_tap_rtp_cb()
+ *
+ * Output RTP streams tap:
+ * (m) tap - tap name
+ * (m) type - tap output type
+ * (m) streams - array of object with attributes:
+ * (m) ssrc - RTP synchronization source identifier
+ * (m) payload - stream payload
+ * (m) saddr - source address
+ * (m) sport - source port
+ * (m) daddr - destination address
+ * (m) dport - destination port
+ * (m) pkts - packets count
+ * (m) max_delta - max delta (ms)
+ * (m) max_jitter - max jitter (ms)
+ * (m) mean_jitter - mean jitter (ms)
+ * (m) expectednr -
+ * (m) totalnr -
+ * (m) problem - if analyser found the problem
+ * (m) ipver - address IP version (4 or 6)
+ */
+static void
+sharkd_session_process_tap_rtp_cb(void *arg)
+{
+ rtpstream_tapinfo_t *rtp_tapinfo = (rtpstream_tapinfo_t *) arg;
+
+ GList *listx;
+ const char *sepa = "";
+
+ printf("{\"tap\":\"%s\",\"type\":\"%s\"", "rtp-streams", "rtp-streams");
+
+ printf(",\"streams\":[");
+ for (listx = g_list_first(rtp_tapinfo->strinfo_list); listx; listx = listx->next)
+ {
+ rtp_stream_info_t *streaminfo = (rtp_stream_info_t *) listx->data;
+
+ char *src_addr, *dst_addr;
+ char *payload;
+ guint32 expected;
- printf("\"host\":\"%s\"", (host_str = get_conversation_address(NULL, &host->myaddress, iu->resolve_name)));
+ src_addr = address_to_display(NULL, &(streaminfo->src_addr));
+ dst_addr = address_to_display(NULL, &(streaminfo->dest_addr));
- if (proto_with_port)
- {
- printf(",\"port\":\"%s\"", (port_str = get_conversation_port(NULL, host->port, host->ptype, iu->resolve_port)));
+ if (streaminfo->payload_type_name != NULL)
+ payload = wmem_strdup(NULL, streaminfo->payload_type_name);
+ else
+ payload = val_to_str_ext_wmem(NULL, streaminfo->payload_type, &rtp_payload_type_short_vals_ext, "Unknown (%u)");
- wmem_free(NULL, port_str);
- }
+ printf("%s{\"ssrc\":%u", sepa, streaminfo->ssrc);
+ printf(",\"payload\":\"%s\"", payload);
- printf(",\"rxf\":%" G_GUINT64_FORMAT, host->rx_frames);
- printf(",\"rxb\":%" G_GUINT64_FORMAT, host->rx_bytes);
+ printf(",\"saddr\":\"%s\"", src_addr);
+ printf(",\"sport\":%u", streaminfo->src_port);
- printf(",\"txf\":%" G_GUINT64_FORMAT, host->tx_frames);
- printf(",\"txb\":%" G_GUINT64_FORMAT, host->tx_bytes);
+ printf(",\"daddr\":\"%s\"", dst_addr);
+ printf(",\"dport\":%u", streaminfo->dest_port);
- filter_str = get_hostlist_filter(host);
- if (filter_str)
- {
- printf(",\"filter\":\"%s\"", filter_str);
- g_free(filter_str);
- }
+ printf(",\"pkts\":%u", streaminfo->packet_count);
- wmem_free(NULL, host_str);
+ printf(",\"max_delta\":%f", streaminfo->rtp_stats.max_delta);
+ printf(",\"max_jitter\":%f", streaminfo->rtp_stats.max_jitter);
+ printf(",\"mean_jitter\":%f", streaminfo->rtp_stats.mean_jitter);
- if (sharkd_session_geoip_addr(&(host->myaddress), ""))
- with_geoip = 1;
- printf("}");
- }
- }
+ expected = (streaminfo->rtp_stats.stop_seq_nr + streaminfo->rtp_stats.cycles * 65536) - streaminfo->rtp_stats.start_seq_nr + 1;
+ printf(",\"expectednr\":%u", expected);
+ printf(",\"totalnr\":%u", streaminfo->rtp_stats.total_nr);
- printf("],\"proto\":\"%s\",\"geoip\":%s},", proto, with_geoip ? "true" : "false");
+ printf(",\"problem\":%s", streaminfo->problem ? "true" : "false");
+
+ /* for filter */
+ printf(",\"ipver\":%d", (streaminfo->src_addr.type == AT_IPv6) ? 6 : 4);
+
+ wmem_free(NULL, src_addr);
+ wmem_free(NULL, dst_addr);
+ wmem_free(NULL, payload);
+
+ printf("}");
+ sepa = ",";
+ }
+ printf("]},");
}
/**
* for type:stats see sharkd_session_process_tap_stats_cb()
* for type:conv see sharkd_session_process_tap_conv_cb()
* for type:host see sharkd_session_process_tap_conv_cb()
+ * for type:rtp-streams see sharkd_session_process_tap_rtp_cb()
+ * for type:rtp-analyse see sharkd_session_process_tap_rtp_analyse_cb()
+ * for type:eo see sharkd_session_process_tap_eo_cb()
+ * for type:expert see sharkd_session_process_tap_expert_cb()
+ * for type:rtd see sharkd_session_process_tap_rtd_cb()
+ * for type:srt see sharkd_session_process_tap_srt_cb()
*
* (m) err - error code
*/
sharkd_session_process_tap(char *buf, const jsmntok_t *tokens, int count)
{
void *taps_data[16];
+ GFreeFunc taps_free[16];
int taps_count = 0;
int i;
+ rtpstream_tapinfo_t rtp_tapinfo =
+ {NULL, NULL, NULL, NULL, 0, NULL, 0, TAP_ANALYSE, NULL, NULL, NULL, FALSE};
+
for (i = 0; i < 16; i++)
{
char tapbuf[32];
const char *tok_tap;
- tap_packet_cb tap_func = NULL;
void *tap_data = NULL;
+ GFreeFunc tap_free = NULL;
const char *tap_filter = "";
GString *tap_error = NULL;
- taps_data[i] = NULL;
-
- snprintf(tapbuf, sizeof(tapbuf), "tap%d", i);
+ ws_snprintf(tapbuf, sizeof(tapbuf), "tap%d", i);
tok_tap = json_find_attr(buf, tokens, count, tapbuf);
if (!tok_tap)
break;
tap_error = register_tap_listener(st->cfg->tapname, st, st->filter, st->cfg->flags, stats_tree_reset, stats_tree_packet, sharkd_session_process_tap_stats_cb);
- tap_data = st;
-
if (!tap_error && cfg->init)
cfg->init(st);
+
+ tap_data = st;
+ tap_free = sharkd_session_free_tap_stats_cb;
+ }
+ else if (!strcmp(tok_tap, "expert"))
+ {
+ struct sharkd_expert_tap *expert_tap;
+
+ expert_tap = g_new0(struct sharkd_expert_tap, 1);
+ expert_tap->text = g_string_chunk_new(100);
+
+ tap_error = register_tap_listener("expert", expert_tap, NULL, 0, NULL, sharkd_session_packet_tap_expert_cb, sharkd_session_process_tap_expert_cb);
+
+ tap_data = expert_tap;
+ tap_free = sharkd_session_free_tap_expert_cb;
}
else if (!strncmp(tok_tap, "conv:", 5) || !strncmp(tok_tap, "endpt:", 6))
{
struct register_ct *ct = NULL;
const char *ct_tapname;
struct sharkd_conv_tap_data *ct_data;
+ tap_packet_cb tap_func = NULL;
if (!strncmp(tok_tap, "conv:", 5))
{
- ct = _get_conversation_table_by_name(tok_tap + 5);
+ ct = get_conversation_by_proto_id(proto_get_id_by_short_name(tok_tap + 5));
if (!ct || !(tap_func = get_conversation_packet_func(ct)))
{
}
else if (!strncmp(tok_tap, "endpt:", 6))
{
- ct = _get_conversation_table_by_name(tok_tap + 6);
+ ct = get_conversation_by_proto_id(proto_get_id_by_short_name(tok_tap + 6));
if (!ct || !(tap_func = get_hostlist_packet_func(ct)))
{
- fprintf(stderr, "sharkd_session_process_tap() endpt %s not found\n", tok_tap + 5);
+ fprintf(stderr, "sharkd_session_process_tap() endpt %s not found\n", tok_tap + 6);
continue;
}
}
tap_error = register_tap_listener(ct_tapname, &ct_data->hash, tap_filter, 0, NULL, tap_func, sharkd_session_process_tap_conv_cb);
tap_data = &ct_data->hash;
+ tap_free = sharkd_session_free_tap_conv_cb;
+ }
+ else if (!strncmp(tok_tap, "rtd:", 4))
+ {
+ register_rtd_t *rtd = get_rtd_table_by_name(tok_tap + 4);
+ rtd_data_t *rtd_data;
+ char *err;
+
+ if (!rtd)
+ {
+ fprintf(stderr, "sharkd_session_process_tap() rtd=%s not found\n", tok_tap + 4);
+ continue;
+ }
+
+ rtd_table_get_filter(rtd, "", &tap_filter, &err);
+ if (err != NULL)
+ {
+ fprintf(stderr, "sharkd_session_process_tap() rtd=%s err=%s\n", tok_tap + 4, err);
+ g_free(err);
+ continue;
+ }
+
+ rtd_data = g_new0(rtd_data_t, 1);
+ rtd_data->user_data = rtd;
+ rtd_table_dissector_init(rtd, &rtd_data->stat_table, NULL, NULL);
+
+ tap_error = register_tap_listener(get_rtd_tap_listener_name(rtd), rtd_data, tap_filter, 0, NULL, get_rtd_packet_func(rtd), sharkd_session_process_tap_rtd_cb);
+
+ tap_data = rtd_data;
+ tap_free = sharkd_session_free_tap_rtd_cb;
+ }
+ else if (!strncmp(tok_tap, "srt:", 4))
+ {
+ register_srt_t *srt = get_srt_table_by_name(tok_tap + 4);
+ srt_data_t *srt_data;
+ char *err;
+
+ if (!srt)
+ {
+ fprintf(stderr, "sharkd_session_process_tap() srt=%s not found\n", tok_tap + 4);
+ continue;
+ }
+
+ srt_table_get_filter(srt, "", &tap_filter, &err);
+ if (err != NULL)
+ {
+ fprintf(stderr, "sharkd_session_process_tap() srt=%s err=%s\n", tok_tap + 4, err);
+ g_free(err);
+ continue;
+ }
+
+ srt_data = g_new0(srt_data_t, 1);
+ srt_data->srt_array = g_array_new(FALSE, TRUE, sizeof(srt_stat_table *));
+ srt_data->user_data = srt;
+ srt_table_dissector_init(srt, srt_data->srt_array, NULL, NULL);
+
+ tap_error = register_tap_listener(get_srt_tap_listener_name(srt), srt_data, tap_filter, 0, NULL, get_srt_packet_func(srt), sharkd_session_process_tap_srt_cb);
+
+ tap_data = srt_data;
+ tap_free = sharkd_session_free_tap_srt_cb;
+ }
+ else if (!strncmp(tok_tap, "eo:", 3))
+ {
+ register_eo_t *eo = get_eo_by_name(tok_tap + 3);
+ export_object_list_t *eo_object;
+ struct sharkd_export_object_list *object_list;
+
+ if (!eo)
+ {
+ fprintf(stderr, "sharkd_session_process_tap() eo=%s not found\n", tok_tap + 3);
+ continue;
+ }
+
+ for (object_list = sharkd_eo_list; object_list; object_list = object_list->next)
+ {
+ if (!strcmp(object_list->type, tok_tap))
+ {
+ g_slist_free_full(object_list->entries, (GDestroyNotify) eo_free_entry);
+ object_list->entries = NULL;
+ break;
+ }
+ }
+
+ if (!object_list)
+ {
+ object_list = g_new(struct sharkd_export_object_list, 1);
+ object_list->type = g_strdup(tok_tap);
+ object_list->proto = proto_get_protocol_short_name(find_protocol_by_id(get_eo_proto_id(eo)));
+ object_list->entries = NULL;
+ object_list->next = sharkd_eo_list;
+ sharkd_eo_list = object_list;
+ }
+
+ eo_object = g_new0(export_object_list_t, 1);
+ eo_object->add_entry = sharkd_eo_object_list_add_entry;
+ eo_object->get_entry = sharkd_eo_object_list_get_entry;
+ eo_object->gui_data = (void *) object_list;
+
+ tap_error = register_tap_listener(get_eo_tap_listener_name(eo), eo_object, NULL, 0, NULL, get_eo_packet_func(eo), sharkd_session_process_tap_eo_cb);
+
+ tap_data = eo_object;
+ tap_free = g_free; /* need to free only eo_object, object_list need to be kept for potential download */
+ }
+ else if (!strcmp(tok_tap, "rtp-streams"))
+ {
+ tap_error = register_tap_listener("rtp", &rtp_tapinfo, tap_filter, 0, rtpstream_reset_cb, rtpstream_packet, sharkd_session_process_tap_rtp_cb);
+
+ tap_data = &rtp_tapinfo;
+ tap_free = rtpstream_reset_cb;
+ }
+ else if (!strncmp(tok_tap, "rtp-analyse:", 12))
+ {
+ struct sharkd_analyse_rtp *rtp_req;
+
+ rtp_req = (struct sharkd_analyse_rtp *) g_malloc0(sizeof(*rtp_req));
+ if (!sharkd_rtp_match_init(&rtp_req->rtp, tok_tap + 12))
+ {
+ g_free(rtp_req);
+ continue;
+ }
+
+ rtp_req->tap_name = tok_tap;
+ rtp_req->statinfo.first_packet = TRUE;
+ rtp_req->statinfo.reg_pt = PT_UNDEFINED;
+
+ tap_error = register_tap_listener("rtp", rtp_req, tap_filter, 0, NULL, sharkd_session_packet_tap_rtp_analyse_cb, sharkd_session_process_tap_rtp_analyse_cb);
+
+ tap_data = rtp_req;
+ tap_free = sharkd_session_process_tap_rtp_free_cb;
}
else
{
if (tap_error)
{
- /* XXX, tap data memleaks */
fprintf(stderr, "sharkd_session_process_tap() name=%s error=%s", tok_tap, tap_error->str);
g_string_free(tap_error, TRUE);
+ if (tap_free)
+ tap_free(tap_data);
continue;
}
- taps_data[i] = tap_data;
+ taps_data[taps_count] = tap_data;
+ taps_free[taps_count] = tap_free;
taps_count++;
}
sharkd_retap();
printf("null],\"err\":0}\n");
- for (i = 0; i < 16; i++)
+ for (i = 0; i < taps_count; i++)
{
if (taps_data[i])
remove_tap_listener(taps_data[i]);
- /* XXX, taps data memleaks */
+ if (taps_free[i])
+ taps_free[i](taps_data[i]);
+ }
+}
+
+/**
+ * sharkd_session_process_follow()
+ *
+ * Process follow request
+ *
+ * Input:
+ * (m) follow - follow protocol request (e.g. HTTP)
+ * (m) filter - filter request (e.g. tcp.stream == 1)
+ *
+ * Output object with attributes:
+ *
+ * (m) err - error code
+ * (m) shost - server host
+ * (m) sport - server port
+ * (m) sbytes - server send bytes count
+ * (m) chost - client host
+ * (m) cport - client port
+ * (m) cbytes - client send bytes count
+ * (o) payloads - array of object with attributes:
+ * (o) s - set if server sent, else client
+ * (m) n - packet number
+ * (m) d - data base64 encoded
+ */
+static void
+sharkd_session_process_follow(char *buf, const jsmntok_t *tokens, int count)
+{
+ const char *tok_follow = json_find_attr(buf, tokens, count, "follow");
+ const char *tok_filter = json_find_attr(buf, tokens, count, "filter");
+
+ register_follow_t *follower;
+ GString *tap_error;
+
+ follow_info_t *follow_info;
+ const char *host;
+ char *port;
+
+ if (!tok_follow || !tok_filter)
+ return;
+
+ follower = get_follow_by_name(tok_follow);
+ if (!follower)
+ {
+ fprintf(stderr, "sharkd_session_process_follow() follower=%s not found\n", tok_follow);
+ return;
+ }
+
+ /* follow_reset_stream ? */
+ follow_info = g_new0(follow_info_t, 1);
+ /* gui_data, filter_out_filter not set, but not used by dissector */
+
+ tap_error = register_tap_listener(get_follow_tap_string(follower), follow_info, tok_filter, 0, NULL, get_follow_tap_handler(follower), NULL);
+ if (tap_error)
+ {
+ fprintf(stderr, "sharkd_session_process_follow() name=%s error=%s", tok_follow, tap_error->str);
+ g_string_free(tap_error, TRUE);
+ g_free(follow_info);
+ return;
+ }
+
+ sharkd_retap();
+
+ printf("{");
+
+ printf("\"err\":0");
+
+ /* Server information: hostname, port, bytes sent */
+ host = address_to_name(&follow_info->server_ip);
+ printf(",\"shost\":");
+ json_puts_string(host);
+
+ port = get_follow_port_to_display(follower)(NULL, follow_info->server_port);
+ printf(",\"sport\":");
+ json_puts_string(port);
+ wmem_free(NULL, port);
+
+ printf(",\"sbytes\":%u", follow_info->bytes_written[0]);
+
+ /* Client information: hostname, port, bytes sent */
+ host = address_to_name(&follow_info->client_ip);
+ printf(",\"chost\":");
+ json_puts_string(host);
+
+ port = get_follow_port_to_display(follower)(NULL, follow_info->client_port);
+ printf(",\"cport\":");
+ json_puts_string(port);
+ wmem_free(NULL, port);
+
+ printf(",\"cbytes\":%u", follow_info->bytes_written[1]);
+
+ if (follow_info->payload)
+ {
+ follow_record_t *follow_record;
+ GList *cur;
+ const char *sepa = "";
+
+ printf(",\"payloads\":[");
+
+ for (cur = follow_info->payload; cur; cur = g_list_next(cur))
+ {
+ follow_record = (follow_record_t *) cur->data;
+
+ printf("%s{", sepa);
+
+ printf("\"n\":%u", follow_record->packet_num);
+
+ printf(",\"d\":");
+ json_print_base64(follow_record->data->data, follow_record->data->len);
+
+ if (follow_record->is_server)
+ printf(",\"s\":%d", 1);
+
+ printf("}");
+ sepa = ",";
+ }
+
+ printf("]");
}
+
+ printf("}\n");
+
+ remove_tap_listener(follow_info);
+ follow_info_free(follow_info);
}
static void
}
if (finfo->start >= 0 && finfo->length > 0)
- printf(",\"h\":[%u,%u]", finfo->start, finfo->length);
+ printf(",\"h\":[%d,%d]", finfo->start, finfo->length);
if (finfo->appendix_start >= 0 && finfo->appendix_length > 0)
- printf(",\"i\":[%u,%u]", finfo->appendix_start, finfo->appendix_length);
+ printf(",\"i\":[%d,%d]", finfo->appendix_start, finfo->appendix_length);
- if (finfo->hfinfo && finfo->hfinfo->type == FT_PROTOCOL)
- printf(",\"t\":\"proto\"");
- if (FI_GET_FLAG(finfo, PI_SEVERITY_MASK))
+ if (finfo->hfinfo)
{
- const char *severity = NULL;
-
- switch (FI_GET_FLAG(finfo, PI_SEVERITY_MASK))
+ if (finfo->hfinfo->type == FT_PROTOCOL)
{
- case PI_COMMENT:
- severity = "comment";
- break;
-
- case PI_CHAT:
- severity = "chat";
- break;
+ printf(",\"t\":\"proto\"");
+ }
+ else if (finfo->hfinfo->type == FT_FRAMENUM)
+ {
+ printf(",\"t\":\"framenum\",\"fnum\":%u", finfo->value.value.uinteger);
+ }
+ else if (FI_GET_FLAG(finfo, FI_URL) && IS_FT_STRING(finfo->hfinfo->type))
+ {
+ char *url = fvalue_to_string_repr(NULL, &finfo->value, FTREPR_DISPLAY, finfo->hfinfo->display);
- case PI_NOTE:
- severity = "note";
- break;
+ printf(",\"t\":\"url\",\"url\":");
+ json_puts_string(url);
+ wmem_free(NULL, url);
+ }
+ }
- case PI_WARN:
- severity = "warn";
- break;
+ if (FI_GET_FLAG(finfo, PI_SEVERITY_MASK))
+ {
+ const char *severity = try_val_to_str(FI_GET_FLAG(finfo, PI_SEVERITY_MASK), expert_severity_vals);
- case PI_ERROR:
- severity = "error";
- break;
- }
g_assert(severity != NULL);
printf(",\"s\":\"%s\"", severity);
printf("]");
}
+static gboolean
+sharkd_follower_visit_layers_cb(const void *key _U_, void *value, void *user_data)
+{
+ register_follow_t *follower = (register_follow_t *) value;
+ packet_info *pi = (packet_info *) user_data;
+
+ const int proto_id = get_follow_proto_id(follower);
+
+ guint32 ignore_stream;
+
+ if (proto_is_frame_protocol(pi->layers, proto_get_protocol_filter_name(proto_id)))
+ {
+ const char *layer_proto = proto_get_protocol_short_name(find_protocol_by_id(proto_id));
+ char *follow_filter;
+
+ follow_filter = get_follow_conv_func(follower)(pi, &ignore_stream);
+
+ printf(",[\"%s\",", layer_proto);
+ json_puts_string(follow_filter);
+ printf("]");
+
+ g_free(follow_filter);
+ }
+
+ return FALSE;
+}
+
static void
sharkd_session_process_frame_cb(packet_info *pi, proto_tree *tree, struct epan_column_info *cinfo, const GSList *data_src, void *data)
{
printf("]");
}
+ printf(",\"fol\":[0");
+ follow_iterate_followers(sharkd_follower_visit_layers_cb, pi);
+ printf("]");
+
printf("}\n");
}
{
unsigned int frames;
guint64 bytes;
- } stat, stat_total;
+ } st, st_total;
nstime_t *start_ts = NULL;
const char *sepa = "";
unsigned int framenum;
- int idx;
- int max_idx = 0;
+ gint64 idx;
+ gint64 max_idx = 0;
- if (tok_interval)
- (void) ws_strtou32(tok_interval, NULL, &interval_ms);
+ if (tok_interval) {
+ if (!ws_strtou32(tok_interval, NULL, &interval_ms) || interval_ms == 0) {
+ fprintf(stderr, "Invalid interval parameter: %s.\n", tok_interval);
+ return;
+ }
+ }
if (tok_filter)
{
return;
}
- stat_total.frames = 0;
- stat_total.bytes = 0;
+ st_total.frames = 0;
+ st_total.bytes = 0;
- stat.frames = 0;
- stat.bytes = 0;
+ st.frames = 0;
+ st.bytes = 0;
idx = 0;
for (framenum = 1; framenum <= cfile.count; framenum++)
{
frame_data *fdata = frame_data_sequence_find(cfile.frames, framenum);
- int msec_rel;
- int new_idx;
+ gint64 msec_rel;
+ gint64 new_idx;
if (start_ts == NULL)
start_ts = &fdata->abs_ts;
if (filter_data && !(filter_data[framenum / 8] & (1 << (framenum % 8))))
continue;
- /* TODO, make it 64-bit, to avoid msec overflow after 24days */
- msec_rel = ((fdata->abs_ts.secs - start_ts->secs) * 1000 + (fdata->abs_ts.nsecs - start_ts->nsecs) / 1000000);
+ msec_rel = (fdata->abs_ts.secs - start_ts->secs) * (gint64) 1000 + (fdata->abs_ts.nsecs - start_ts->nsecs) / 1000000;
new_idx = msec_rel / interval_ms;
if (idx != new_idx)
{
- if (stat.frames != 0)
+ if (st.frames != 0)
{
- printf("%s[%d,%u,%" G_GUINT64_FORMAT "]", sepa, idx, stat.frames, stat.bytes);
+ printf("%s[%" G_GINT64_FORMAT ",%u,%" G_GUINT64_FORMAT "]", sepa, idx, st.frames, st.bytes);
sepa = ",";
}
if (idx > max_idx)
max_idx = idx;
- stat.frames = 0;
- stat.bytes = 0;
+ st.frames = 0;
+ st.bytes = 0;
}
- stat.frames += 1;
- stat.bytes += fdata->pkt_len;
+ st.frames += 1;
+ st.bytes += fdata->pkt_len;
- stat_total.frames += 1;
- stat_total.bytes += fdata->pkt_len;
+ st_total.frames += 1;
+ st_total.bytes += fdata->pkt_len;
}
- if (stat.frames != 0)
+ if (st.frames != 0)
{
- printf("%s[%d,%u,%" G_GUINT64_FORMAT "]", sepa, idx, stat.frames, stat.bytes);
+ printf("%s[%" G_GINT64_FORMAT ",%u,%" G_GUINT64_FORMAT "]", sepa, idx, st.frames, st.bytes);
/* sepa = ","; */
}
- printf("],\"last\":%d,\"frames\":%u,\"bytes\":%" G_GUINT64_FORMAT "}\n", max_idx, stat_total.frames, stat_total.bytes);
+ printf("],\"last\":%" G_GINT64_FORMAT ",\"frames\":%u,\"bytes\":%" G_GUINT64_FORMAT "}\n", max_idx, st_total.frames, st_total.bytes);
}
/**
* (m) err - 0 if succeed
* (o) tree - array of frame nodes with attributes:
* l - label
- * t: 'proto'
+ * t: 'proto', 'framenum', 'url' - type of node
* s - severity
* e - subtree ett index
* n - array of subtree nodes
* i - two item array: (appendix start, appendix length)
* p - [RESERVED] two item array: (protocol start, protocol length)
* ds- data src index
+ * url - only for t:'url', url
+ * fnum - only for t:'framenum', frame number
*
* (o) col - array of column data
* (o) bytes - base64 of frame bytes
* (o) ds - array of other data srcs
+ * (o) fol - array of follow filters:
+ * [0] - protocol
+ * [1] - filter string
*/
static void
sharkd_session_process_frame(char *buf, const jsmntok_t *tokens, int count)
if (!tok_name || tok_name[0] == '\0' || !tok_value)
return;
- snprintf(pref, sizeof(pref), "%s:%s", tok_name, tok_value);
+ ws_snprintf(pref, sizeof(pref), "%s:%s", tok_name, tok_value);
ret = prefs_set_pref(pref);
printf("{\"err\":%d}\n", ret);
struct sharkd_session_process_dumpconf_data *data = (struct sharkd_session_process_dumpconf_data *) d;
const char *pref_name = prefs_get_name(pref);
- printf("%s\"%s.%s\":{}", data->sepa, data->module->name, pref_name);
+ printf("%s\"%s.%s\":{", data->sepa, data->module->name, pref_name);
+
+ switch (prefs_get_type(pref))
+ {
+ case PREF_UINT:
+ case PREF_DECODE_AS_UINT:
+ printf("\"u\":%u", prefs_get_uint_value_real(pref, pref_current));
+ if (prefs_get_uint_base(pref) != 10)
+ printf(",\"ub\":%u", prefs_get_uint_base(pref));
+ break;
+
+ case PREF_BOOL:
+ printf("\"b\":%s", prefs_get_bool_value(pref, pref_current) ? "1" : "0");
+ break;
+
+ case PREF_STRING:
+ printf("\"s\":");
+ json_puts_string(prefs_get_string_value(pref, pref_current));
+ break;
+
+ case PREF_ENUM:
+ {
+ const enum_val_t *enums;
+ const char *enum_sepa = "";
+
+ printf("\"e\":[");
+ for (enums = prefs_get_enumvals(pref); enums->name; enums++)
+ {
+ printf("%s{\"v\":%d", enum_sepa, enums->value);
+
+ if (enums->value == prefs_get_enum_value(pref, pref_current))
+ printf(",\"s\":1");
+
+ printf(",\"d\":");
+ json_puts_string(enums->description);
+
+ printf("}");
+ enum_sepa = ",";
+ }
+ printf("]");
+ break;
+ }
+
+ case PREF_RANGE:
+ case PREF_DECODE_AS_RANGE:
+ {
+ char *range_str = range_convert_range(NULL, prefs_get_range_value_real(pref, pref_current));
+ printf("\"r\":\"%s\"", range_str);
+ wmem_free(NULL, range_str);
+ break;
+ }
+
+ case PREF_UAT:
+ case PREF_COLOR:
+ case PREF_CUSTOM:
+ case PREF_STATIC_TEXT:
+ case PREF_OBSOLETE:
+ /* TODO */
+ break;
+ }
+
+#if 0
+ printf(",\"t\":");
+ json_puts_string(prefs_get_title(pref));
+#endif
+ printf("}");
data->sepa = ",";
return 0; /* continue */
}
}
+/**
+ * sharkd_session_process_download()
+ *
+ * Process download request
+ *
+ * Input:
+ * (m) token - token to download
+ *
+ * Output object with attributes:
+ * (o) file - suggested name of file
+ * (o) mime - suggested content type
+ * (o) data - payload base64 encoded
+ */
+static void
+sharkd_session_process_download(char *buf, const jsmntok_t *tokens, int count)
+{
+ const char *tok_token = json_find_attr(buf, tokens, count, "token");
+
+ if (!tok_token)
+ return;
+
+ if (!strncmp(tok_token, "eo:", 3))
+ {
+ struct sharkd_export_object_list *object_list;
+ const export_object_entry_t *eo_entry = NULL;
+
+ for (object_list = sharkd_eo_list; object_list; object_list = object_list->next)
+ {
+ size_t eo_type_len = strlen(object_list->type);
+
+ if (!strncmp(tok_token, object_list->type, eo_type_len) && tok_token[eo_type_len] == '_')
+ {
+ int row;
+
+ if (sscanf(&tok_token[eo_type_len + 1], "%d", &row) != 1)
+ break;
+
+ eo_entry = (export_object_entry_t *) g_slist_nth_data(object_list->entries, row);
+ break;
+ }
+ }
+
+ if (eo_entry)
+ {
+ const char *mime = (eo_entry->content_type) ? eo_entry->content_type : "application/octet-stream";
+ const char *filename = (eo_entry->filename) ? eo_entry->filename : tok_token;
+
+ printf("{\"file\":");
+ json_puts_string(filename);
+ printf(",\"mime\":");
+ json_puts_string(mime);
+ printf(",\"data\":");
+ json_print_base64(eo_entry->payload_data, (int) eo_entry->payload_len); /* XXX, export object will be truncated if >= 2^31 */
+ printf("}\n");
+ }
+ }
+ else if (!strcmp(tok_token, "ssl-secrets"))
+ {
+ char *str = ssl_export_sessions();
+
+ if (str)
+ {
+ const char *mime = "text/plain";
+ const char *filename = "keylog.txt";
+
+ printf("{\"file\":");
+ json_puts_string(filename);
+ printf(",\"mime\":");
+ json_puts_string(mime);
+ printf(",\"data\":");
+ json_print_base64(str, strlen(str));
+ printf("}\n");
+ }
+ g_free(str);
+ }
+}
+
static void
sharkd_session_process(char *buf, const jsmntok_t *tokens, int count)
{
if (!tok_req)
{
- fprintf(stderr, "sanity check(4): no \"req\"!\n");
+ fprintf(stderr, "sanity check(4): no \"req\".\n");
return;
}
sharkd_session_process_frames(buf, tokens, count);
else if (!strcmp(tok_req, "tap"))
sharkd_session_process_tap(buf, tokens, count);
+ else if (!strcmp(tok_req, "follow"))
+ sharkd_session_process_follow(buf, tokens, count);
else if (!strcmp(tok_req, "intervals"))
sharkd_session_process_intervals(buf, tokens, count);
else if (!strcmp(tok_req, "frame"))
sharkd_session_process_setconf(buf, tokens, count);
else if (!strcmp(tok_req, "dumpconf"))
sharkd_session_process_dumpconf(buf, tokens, count);
+ else if (!strcmp(tok_req, "download"))
+ sharkd_session_process_download(buf, tokens, count);
else if (!strcmp(tok_req, "bye"))
- _Exit(0);
+ exit(0);
else
fprintf(stderr, "::: req = %s\n", tok_req);
+ /* reply for every command are 0+ lines of JSON reply (outputed above), finished by empty new line */
printf("\n");
+
+ /*
+ * We do an explicit fflush after every line, because
+ * we want output to be written to the socket as soon
+ * as the line is complete.
+ *
+ * The stream is fully-buffered by default, so it's
+ * only flushed when the buffer fills or the FILE *
+ * is closed. On UN*X, we could set it to be line
+ * buffered, but the MSVC standard I/O routines don't
+ * support line buffering - they only support *byte*
+ * buffering, doing a write for every byte written,
+ * which is too inefficient, and full buffering,
+ * which is what you get if you request line buffering.
+ */
+ fflush(stdout);
}
}
jsmntok_t *tokens = NULL;
int tokens_max = -1;
- fprintf(stderr, "Hello in child!\n");
- setlinebuf(stdout);
+ fprintf(stderr, "Hello in child.\n");
while (fgets(buf, sizeof(buf), stdin))
{