From 94d7500a7d2589548f210ef0e9cb6d9eba796239 Mon Sep 17 00:00:00 2001 From: Robert Jongbloed Date: Tue, 23 Jan 2018 12:13:43 +0000 Subject: [PATCH] SDP/RTP: Support for "bundled" media. Modern SDP usage (e.g. SIP, WebRTC) can "bundle" multiple RTP media streams on a single port. Thus the RTP dissector has to be able to handle audio and video at the same time, so the gboolean flag in _rtp_info was changed to a bit mask. The SDP parsing was then changed to detect multiple "m=" lines using the same port, and combine their audio/video bit masks, and the rtp_dyn_payload used has all the audio and video payload descriptions. Change-Id: Ifa3c034260f892ed005fe28647d28f3b0b1b05cf Reviewed-on: https://code.wireshark.org/review/25431 Petri-Dish: Jaap Keuter Tested-by: Petri Dish Buildbot Reviewed-by: Anders Broman --- epan/dissectors/packet-btavdtp.c | 4 +- epan/dissectors/packet-rtp.c | 29 +++++++------- epan/dissectors/packet-rtp.h | 15 +++++--- epan/dissectors/packet-sdp.c | 66 ++++++++++++++++++++++++++++---- epan/dissectors/packet-zrtp.c | 4 +- 5 files changed, 86 insertions(+), 32 deletions(-) diff --git a/epan/dissectors/packet-btavdtp.c b/epan/dissectors/packet-btavdtp.c index 1e2b0138b0..259fc98221 100644 --- a/epan/dissectors/packet-btavdtp.c +++ b/epan/dissectors/packet-btavdtp.c @@ -3076,7 +3076,7 @@ dissect_bta2dp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) if (bta2dp_codec_info.content_protection_type == 0 && codec_dissector == aptx_handle) { call_dissector_with_data(aptx_handle, tvb, pinfo, tree, &bta2dp_codec_info); } else { - bluetooth_add_address(pinfo, &pinfo->net_dst, sep_data.stream_number, "BT A2DP", pinfo->num, FALSE, &bta2dp_codec_info); + bluetooth_add_address(pinfo, &pinfo->net_dst, sep_data.stream_number, "BT A2DP", pinfo->num, RTP_MEDIA_AUDIO, &bta2dp_codec_info); call_dissector(rtp_handle, tvb, pinfo, tree); } offset += tvb_reported_length_remaining(tvb, offset); @@ -3309,7 +3309,7 @@ dissect_btvdp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) pinfo->destport = sep_data.stream_number; #endif - bluetooth_add_address(pinfo, &pinfo->net_dst, 0, "BT VDP", pinfo->num, TRUE, &btvdp_codec_info); + bluetooth_add_address(pinfo, &pinfo->net_dst, 0, "BT VDP", pinfo->num, RTP_MEDIA_VIDEO, &btvdp_codec_info); call_dissector(rtp_handle, tvb, pinfo, tree); offset += tvb_reported_length_remaining(tvb, offset); diff --git a/epan/dissectors/packet-rtp.c b/epan/dissectors/packet-rtp.c index 0b90ab225a..24ee93a7d6 100644 --- a/epan/dissectors/packet-rtp.c +++ b/epan/dissectors/packet-rtp.c @@ -1181,7 +1181,7 @@ rtp_dyn_payload_free(rtp_dyn_payload_t *rtp_dyn_payload) void bluetooth_add_address(packet_info *pinfo, address *addr, guint32 stream_number, const gchar *setup_method, guint32 setup_frame_number, - gboolean is_video, void *data) + guint32 media_types, void *data) { address null_addr; conversation_t* p_conv; @@ -1237,13 +1237,10 @@ bluetooth_add_address(packet_info *pinfo, address *addr, guint32 stream_number, p_conv_data->rtp_conv_info->multisegment_pdus = wmem_tree_new(wmem_file_scope()); conversation_add_proto_data(p_conv, proto_rtp, p_conv_data); - if (is_video) { - p_conv_data->bta2dp_info = NULL; - p_conv_data->btvdp_info = (btvdp_codec_info_t *) wmem_memdup(wmem_file_scope(), data, sizeof(btvdp_codec_info_t)); - } else { + if (media_types&RTP_MEDIA_AUDIO) p_conv_data->bta2dp_info = (bta2dp_codec_info_t *) wmem_memdup(wmem_file_scope(), data, sizeof(bta2dp_codec_info_t)); - p_conv_data->btvdp_info = NULL; - } + if (media_types&RTP_MEDIA_VIDEO) + p_conv_data->btvdp_info = (btvdp_codec_info_t *) wmem_memdup(wmem_file_scope(), data, sizeof(btvdp_codec_info_t)); } /* @@ -1254,7 +1251,7 @@ bluetooth_add_address(packet_info *pinfo, address *addr, guint32 stream_number, g_strlcpy(p_conv_data->method, setup_method, MAX_RTP_SETUP_METHOD_SIZE+1); p_conv_data->frame_number = setup_frame_number; - p_conv_data->is_video = is_video; + p_conv_data->media_types = media_types; p_conv_data->rtp_dyn_payload = NULL; p_conv_data->srtp_info = NULL; } @@ -1263,7 +1260,7 @@ bluetooth_add_address(packet_info *pinfo, address *addr, guint32 stream_number, void srtp_add_address(packet_info *pinfo, const port_type ptype, address *addr, int port, int other_port, const gchar *setup_method, guint32 setup_frame_number, - gboolean is_video _U_, rtp_dyn_payload_t *rtp_dyn_payload, + guint32 media_types _U_, rtp_dyn_payload_t *rtp_dyn_payload, struct srtp_info *srtp_info) { address null_addr; @@ -1359,7 +1356,7 @@ srtp_add_address(packet_info *pinfo, const port_type ptype, address *addr, int p g_strlcpy(p_conv_data->method, setup_method, MAX_RTP_SETUP_METHOD_SIZE+1); p_conv_data->frame_number = setup_frame_number; - p_conv_data->is_video = is_video; + p_conv_data->media_types = media_types; p_conv_data->srtp_info = srtp_info; p_conv_data->bta2dp_info = NULL; p_conv_data->btvdp_info = NULL; @@ -1369,9 +1366,9 @@ srtp_add_address(packet_info *pinfo, const port_type ptype, address *addr, int p void rtp_add_address(packet_info *pinfo, const port_type ptype, address *addr, int port, int other_port, const gchar *setup_method, guint32 setup_frame_number, - gboolean is_video , rtp_dyn_payload_t *rtp_dyn_payload) + guint32 media_types , rtp_dyn_payload_t *rtp_dyn_payload) { - srtp_add_address(pinfo, ptype, addr, port, other_port, setup_method, setup_frame_number, is_video, rtp_dyn_payload, NULL); + srtp_add_address(pinfo, ptype, addr, port, other_port, setup_method, setup_frame_number, media_types, rtp_dyn_payload, NULL); } static gboolean @@ -1441,7 +1438,7 @@ dissect_rtp_heur_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, voi } g_strlcpy(p_conv_data->method, "HEUR RTP", MAX_RTP_SETUP_METHOD_SIZE+1); p_conv_data->frame_number = pinfo->num; - p_conv_data->is_video = FALSE; + p_conv_data->media_types = 0; p_conv_data->srtp_info = NULL; p_conv_data->bta2dp_info = NULL; p_conv_data->btvdp_info = NULL; @@ -2127,7 +2124,7 @@ dissect_rtp( tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_ rtp_info->info_padding_set = padding_set; rtp_info->info_padding_count = 0; rtp_info->info_marker_set = marker_set; - rtp_info->info_is_video = FALSE; + rtp_info->info_media_types = 0; rtp_info->info_payload_type = payload_type; rtp_info->info_seq_num = seq_num; rtp_info->info_timestamp = timestamp; @@ -2176,7 +2173,7 @@ dissect_rtp( tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_ p_conv_data = get_conv_info(pinfo, rtp_info); if (p_conv_data) - rtp_info->info_is_video = p_conv_data->is_video; + rtp_info->info_media_types = p_conv_data->media_types; if (p_conv_data && p_conv_data->srtp_info) is_srtp = TRUE; rtp_info->info_is_srtp = is_srtp; @@ -2788,7 +2785,7 @@ get_conv_info(packet_info *pinfo, struct _rtp_info *rtp_info) p_conv_packet_data = wmem_new(wmem_file_scope(), struct _rtp_conversation_info); g_strlcpy(p_conv_packet_data->method, p_conv_data->method, MAX_RTP_SETUP_METHOD_SIZE+1); p_conv_packet_data->frame_number = p_conv_data->frame_number; - p_conv_packet_data->is_video = p_conv_data->is_video; + p_conv_packet_data->media_types = p_conv_data->media_types; /* do not increment ref count for the rtp_dyn_payload */ p_conv_packet_data->rtp_dyn_payload = p_conv_data->rtp_dyn_payload; p_conv_packet_data->rtp_conv_info = p_conv_data->rtp_conv_info; diff --git a/epan/dissectors/packet-rtp.h b/epan/dissectors/packet-rtp.h index 18a726fcad..91746721e7 100644 --- a/epan/dissectors/packet-rtp.h +++ b/epan/dissectors/packet-rtp.h @@ -30,11 +30,16 @@ #include "packet-btavdtp.h" + +#define RTP_MEDIA_AUDIO 1 +#define RTP_MEDIA_VIDEO 2 +#define RTP_MEDIA_OTHER 4 + struct _rtp_info { unsigned int info_version; gboolean info_padding_set; gboolean info_marker_set; - gboolean info_is_video; + guint32 info_media_types; unsigned int info_payload_type; unsigned int info_padding_count; guint16 info_seq_num; @@ -177,7 +182,7 @@ struct _rtp_conversation_info { gchar method[MAX_RTP_SETUP_METHOD_SIZE + 1]; guint32 frame_number; /* the frame where this conversation is started */ - gboolean is_video; + guint32 media_types; rtp_dyn_payload_t *rtp_dyn_payload; /* the dynamic RTP payload info - see comments above */ guint32 extended_seqno; /* the sequence number, extended to a 32-bit @@ -200,7 +205,7 @@ void rtp_add_address(packet_info *pinfo, int other_port, const gchar *setup_method, guint32 setup_frame_number, - gboolean is_video, + guint32 media_types, rtp_dyn_payload_t *rtp_dyn_payload); /* Add an SRTP conversation with the given details */ @@ -211,7 +216,7 @@ void srtp_add_address(packet_info *pinfo, int other_port, const gchar *setup_method, guint32 setup_frame_number, - gboolean is_video, + guint32 media_types, rtp_dyn_payload_t *rtp_dyn_payload, struct srtp_info *srtp_info); @@ -219,4 +224,4 @@ void srtp_add_address(packet_info *pinfo, void bluetooth_add_address(packet_info *pinfo, address *addr, guint32 stream_number, const gchar *setup_method, guint32 setup_frame_number, - gboolean is_video, void *data); + guint32 media_types, void *data); diff --git a/epan/dissectors/packet-sdp.c b/epan/dissectors/packet-sdp.c index 1a3e2cc1eb..928a5d02c2 100644 --- a/epan/dissectors/packet-sdp.c +++ b/epan/dissectors/packet-sdp.c @@ -248,7 +248,8 @@ typedef struct { */ typedef struct { transport_proto_t proto; /**< Protocol, parsed from "m=" line. */ - gboolean is_video; /**< Whether "m=video" */ + guint32 media_types; /**< Whether "m=video" or others */ + gboolean bundled; /**< "m=" lines are "bundled", that is, all on same port */ guint16 media_port; /**< Port number, parsed from "m=" line. */ guint16 control_port; /**< Port number, parsed from "a=rtcp" or "a=rtcp-mux" line. */ address conn_addr; /**< The address from the "c=" line (default @@ -1026,7 +1027,12 @@ dissect_sdp_media(tvbuff_t *tvb, packet_info* pinfo, proto_item *ti, ENC_UTF_8|ENC_NA, wmem_packet_scope(), &media_type_str); if (media_desc) { /* for RTP statistics (supposedly?) */ - media_desc->is_video = strcmp(media_type_str, "video") == 0; + if (strcmp(media_type_str, "audio") == 0) + media_desc->media_types |= RTP_MEDIA_AUDIO; + else if (strcmp(media_type_str, "video") == 0) + media_desc->media_types |= RTP_MEDIA_VIDEO; + else + media_desc->media_types |= RTP_MEDIA_OTHER; } DPRINT(("parsed media_type=%s", media_type_str)); @@ -2101,13 +2107,49 @@ complete_descriptions(transport_info_t *transport_info, guint answer_offset) { guint media_count = wmem_array_get_count(transport_info->media_descriptions); media_description_t *media_descs = (media_description_t *)wmem_array_get_raw(transport_info->media_descriptions); + media_description_t *bundle_media_desc = NULL; DPRINT(("complete_descriptions called with answer_offset=%d media_count=%d", answer_offset, media_count)); + for (guint i = answer_offset; i < media_count && !bundle_media_desc; i++) { + for (guint j = i+1; j < media_count && !bundle_media_desc; j++) { + if (media_descs[i].media_port == media_descs[j].media_port) + bundle_media_desc = &media_descs[i]; + } + } + + if (bundle_media_desc) { + /* We have "bundling" of media, so now combine all the media bit masks + and merge the rtp_dyn_payload so that the first media description + has all the data for every media desciption. */ + for (guint i = answer_offset; i < media_count; i++) { + media_description_t *media_desc = &media_descs[i]; + + if (bundle_media_desc->media_port == media_desc->media_port) { + media_desc->bundled = TRUE; + + if (media_desc != bundle_media_desc) { + bundle_media_desc->media_types |= media_desc->media_types; + for (guint pt = 0; pt < 128; ++pt) { + const char * encoding_name; + int sample_rate; + if (rtp_dyn_payload_get_full(media_desc->media.rtp_dyn_payload, + pt, &encoding_name, &sample_rate)) + rtp_dyn_payload_insert(bundle_media_desc->media.rtp_dyn_payload, + pt, encoding_name, sample_rate); + } + } + } + } + } + for (guint i = answer_offset; i < media_count; i++) { media_description_t *media_desc = &media_descs[i]; + if (media_desc->control_port == 0) + media_desc->control_port = media_desc->media_port + 1; + if (media_desc->control_port == 0) media_desc->control_port = media_desc->media_port + 1; @@ -2169,6 +2211,8 @@ apply_sdp_transport(packet_info *pinfo, transport_info_t *transport_info, int re establish_frame = request_frame; } + gboolean bundled_media_set = FALSE; + for (guint i = 0; i < wmem_array_get_count(transport_info->media_descriptions); i++) { media_description_t *media_desc = (media_description_t *)wmem_array_index(transport_info->media_descriptions, i); @@ -2176,11 +2220,20 @@ apply_sdp_transport(packet_info *pinfo, transport_info_t *transport_info, int re /* Add (s)rtp and (s)rtcp conversation, if available (overrides t38 if conversation already set) */ if ((media_desc->media_port != 0) && + !media_desc->media.set_rtp && (media_desc->proto == SDP_PROTO_RTP || media_desc->proto == SDP_PROTO_SRTP) && (media_desc->conn_addr.type == AT_IPv4 || media_desc->conn_addr.type == AT_IPv6)) { + media_desc->media.set_rtp = TRUE; + + if (media_desc->bundled) { + if (bundled_media_set) + continue; + bundled_media_set = TRUE; + } + if (media_desc->proto == SDP_PROTO_SRTP) { srtp_info = wmem_new0(wmem_file_scope(), struct srtp_info); if (transport_info->encryption_algorithm != SRTP_ENC_ALG_NOT_SET) { @@ -2196,7 +2249,7 @@ apply_sdp_transport(packet_info *pinfo, transport_info_t *transport_info, int re /* srtp_add_address and rtp_add_address are given the request_frame's not this frame's number, because that's where the RTP flow started, and thus conversation needs to check against */ srtp_add_address(pinfo, PT_UDP, &media_desc->conn_addr, media_desc->media_port, 0, "SDP", establish_frame, - media_desc->is_video, + media_desc->media_types, media_desc->media.rtp_dyn_payload, srtp_info); DENDENT(); } else { @@ -2204,23 +2257,22 @@ apply_sdp_transport(packet_info *pinfo, transport_info_t *transport_info, int re i, media_desc->media_port)); DINDENT(); rtp_add_address(pinfo, PT_UDP, &media_desc->conn_addr, media_desc->media_port, 0, "SDP", establish_frame, - media_desc->is_video, + media_desc->media_types, media_desc->media.rtp_dyn_payload); DENDENT(); } - media_desc->media.set_rtp = TRUE; /* SPRT might use the same port... */ current_rtp_port = media_desc->media_port; if (rtcp_handle && media_desc->media_port != media_desc->control_port) { if (media_desc->proto == SDP_PROTO_SRTP) { - DPRINT(("calling rtcp_add_address, channel=%d, media_port=%d", + DPRINT(("calling rtcp_add_address, channel=%d, control_port=%d", i, media_desc->control_port)); DINDENT(); srtcp_add_address(pinfo, &media_desc->conn_addr, media_desc->control_port, 0, "SDP", establish_frame, srtp_info); DENDENT(); } else { - DPRINT(("calling rtcp_add_address, channel=%d, media_port=%d", + DPRINT(("calling rtcp_add_address, channel=%d, control_port=%d", i, media_desc->control_port)); DINDENT(); rtcp_add_address(pinfo, &media_desc->conn_addr, media_desc->control_port, 0, "SDP", establish_frame); diff --git a/epan/dissectors/packet-zrtp.c b/epan/dissectors/packet-zrtp.c index b899b88b6b..262abd65de 100644 --- a/epan/dissectors/packet-zrtp.c +++ b/epan/dissectors/packet-zrtp.c @@ -455,10 +455,10 @@ dissect_Conf2ACK(packet_info *pinfo) { dummy_srtp_info->auth_tag_len = 4; srtp_add_address(pinfo, PT_UDP, &pinfo->net_src, pinfo->srcport, pinfo->destport, - "ZRTP", pinfo->num, FALSE, NULL, dummy_srtp_info); + "ZRTP", pinfo->num, RTP_MEDIA_AUDIO, NULL, dummy_srtp_info); srtp_add_address(pinfo, PT_UDP, &pinfo->net_dst, pinfo->destport, pinfo->srcport, - "ZRTP", pinfo->num, FALSE, NULL, dummy_srtp_info); + "ZRTP", pinfo->num, RTP_MEDIA_AUDIO, NULL, dummy_srtp_info); srtcp_add_address(pinfo, &pinfo->net_src, pinfo->srcport+1, pinfo->destport+1, "ZRTP", pinfo->num, dummy_srtp_info);