diff options
author | Jakub Zawadzki <darkjames-ws@darkjames.pl> | 2017-03-31 20:35:51 +0200 |
---|---|---|
committer | Jakub Zawadzki <darkjames-ws@darkjames.pl> | 2017-04-08 07:29:44 +0000 |
commit | 99e0b39ba811796b48333540cf6f7edaa737c803 (patch) | |
tree | f28107e47dbf6a2556b586b910472ed79fd19374 | |
parent | b9b5703a41a52d9494c0179e42bbf5c62c7dcb05 (diff) | |
download | wireshark-99e0b39ba811796b48333540cf6f7edaa737c803.tar.gz |
sharkd: add tap for RTP stream analysis.
Change-Id: Idf88a891b69e4d89b2d0c62d505059ab073e266e
Reviewed-on: https://code.wireshark.org/review/20816
Petri-Dish: Jakub Zawadzki <darkjames-ws@darkjames.pl>
Tested-by: Petri Dish Buildbot <buildbot-no-reply@wireshark.org>
Reviewed-by: Jakub Zawadzki <darkjames-ws@darkjames.pl>
-rw-r--r-- | sharkd_session.c | 266 |
1 files changed, 266 insertions, 0 deletions
diff --git a/sharkd_session.c b/sharkd_session.c index 64550d4c31..dea261991a 100644 --- a/sharkd_session.c +++ b/sharkd_session.c @@ -61,6 +61,9 @@ #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> @@ -215,6 +218,66 @@ sharkd_session_filter_data(const char *filter) } } +struct sharkd_rtp_match +{ + 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; + + 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) { @@ -979,6 +1042,188 @@ sharkd_session_geoip_addr(address *addr, const char *suffix) 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() * @@ -1556,6 +1801,7 @@ sharkd_session_process_tap_rtp_cb(void *arg) * 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() @@ -1778,6 +2024,26 @@ sharkd_session_process_tap(char *buf, const jsmntok_t *tokens, int count) 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 { fprintf(stderr, "sharkd_session_process_tap() %s not recognized\n", tok_tap); |