diff --git a/daemon/media_socket.c b/daemon/media_socket.c index b1b5c968a..20b8be9cc 100644 --- a/daemon/media_socket.c +++ b/daemon/media_socket.c @@ -70,6 +70,7 @@ struct intf_rr { struct packet_handler_ctx { // inputs: str s; // raw input packet + bool kernel_handled; // parse and read contents but do not forward GQueue *sinks; // where to send output packets to (forward destination) rewrite_func decrypt_func, encrypt_func; // handlers for decrypt/encrypt @@ -1487,6 +1488,7 @@ static const char *kernelize_one(struct rtpengine_target_info *reti, GQueue *out if (proto_is_rtp(media->protocol)) { reti->rtp = 1; if (!media->monologue->transcoding) { + reti->rtcp_fw = 1; if (media->protocol->avpf) reti->rtcp_fb_fw = 1; } @@ -1679,7 +1681,7 @@ void kernelize(struct packet_stream *stream) { struct packet_stream *sink = sh->sink; if (PS_ISSET(sink, NAT_WAIT) && !PS_ISSET(sink, RECEIVED)) continue; - const char *err = kernelize_one(&reti, &outputs, stream, sh, NULL, NULL); + const char *err = kernelize_one(&reti, &outputs, stream, sh, &stream->rtp_sinks, NULL); if (err) ilog(LOG_WARNING, "No support for kernel packet forwarding available (%s)", err); } @@ -2564,6 +2566,8 @@ static int do_rtcp_parse(struct packet_handler_ctx *phc) { static int do_rtcp_output(struct packet_handler_ctx *phc) { if (phc->rtcp_discard) return 0; + if (phc->kernel_handled) + return 0; if (phc->rtcp_filter) if (phc->rtcp_filter(&phc->mp, &phc->rtcp_list)) @@ -3127,6 +3131,18 @@ restart: if (ret >= MAX_RTP_PACKET_SIZE) ilog(LOG_WARNING | LOG_FLAG_LIMIT, "UDP packet possibly truncated"); + if (phc.mp.tv.tv_sec < 0) { + // kernel-handled RTCP + phc.kernel_handled = true; + // restore original actual timestamp + if (G_UNLIKELY(phc.mp.tv.tv_usec == 0)) + phc.mp.tv.tv_sec = -phc.mp.tv.tv_sec; + else { + phc.mp.tv.tv_sec = -phc.mp.tv.tv_sec - 1; + phc.mp.tv.tv_usec = 1000000 - phc.mp.tv.tv_usec; + } + } + str_init_len(&phc.s, buf + RTP_BUFFER_HEAD_ROOM, ret); if (sfd->stream && sfd->stream->jb) { diff --git a/kernel-module/xt_RTPENGINE.c b/kernel-module/xt_RTPENGINE.c index 3201462e8..f6b16a734 100644 --- a/kernel-module/xt_RTPENGINE.c +++ b/kernel-module/xt_RTPENGINE.c @@ -1758,6 +1758,8 @@ static int proc_list_show(struct seq_file *f, void *v) { seq_printf(f, " SSRC-tracking"); if (g->target.do_intercept) seq_printf(f, " intercept"); + if (g->target.rtcp_fw) + seq_printf(f, " forward-RTCP"); if (g->target.rtcp_fb_fw) seq_printf(f, " forward-RTCP-FB"); seq_printf(f, "\n"); @@ -5271,7 +5273,8 @@ static void rtp_stats(struct rtpengine_target *g, struct rtp_parsed *rtp, s64 ar } -static unsigned int rtpengine46(struct sk_buff *skb, struct rtpengine_table *t, struct re_address *src, +static unsigned int rtpengine46(struct sk_buff *skb, struct sk_buff *oskb, + struct rtpengine_table *t, struct re_address *src, struct re_address *dst, uint8_t in_tos, const struct xt_action_param *par) { struct udphdr *uh; @@ -5279,6 +5282,7 @@ static unsigned int rtpengine46(struct sk_buff *skb, struct rtpengine_table *t, struct sk_buff *skb2; int err; int error_nf_action = XT_CONTINUE; + int nf_action = NF_DROP; int rtp_pt_idx = -2; int ssrc_idx = -1; unsigned int datalen, datalen_out; @@ -5291,7 +5295,7 @@ static unsigned int rtpengine46(struct sk_buff *skb, struct rtpengine_table *t, unsigned long flags; unsigned int i; unsigned int start_idx, end_idx; - int is_rtcp; + enum {NOT_RTCP = 0, RTCP, RTCP_FORWARD} is_rtcp; #if (RE_HAS_MEASUREDELAY) uint64_t starttime, endtime, delay; @@ -5357,18 +5361,18 @@ static unsigned int rtpengine46(struct sk_buff *skb, struct rtpengine_table *t, // RTP processing rtp.ok = 0; rtp.rtcp = 0; - is_rtcp = 0; + is_rtcp = NOT_RTCP; if (g->target.rtp) { if (g->target.rtcp) { if (g->target.rtcp_mux) { if (is_muxed_rtcp(skb)) - is_rtcp = 1; + is_rtcp = RTCP; } else - is_rtcp = 1; + is_rtcp = RTCP; } - if (!is_rtcp) { + if (is_rtcp == NOT_RTCP) { parse_rtp(&rtp, skb); if (!rtp.ok && g->target.rtp_only) goto out; // pass to userspace @@ -5376,6 +5380,8 @@ static unsigned int rtpengine46(struct sk_buff *skb, struct rtpengine_table *t, else { if (g->target.rtcp_fb_fw && is_rtcp_fb_packet(skb)) ; // forward and then drop + else if (g->target.rtcp_fw) + is_rtcp = RTCP_FORWARD; // forward, mark, and pass to userspace else goto out; // just pass to userspace @@ -5423,7 +5429,7 @@ static unsigned int rtpengine46(struct sk_buff *skb, struct rtpengine_table *t, rtp.payload[12], rtp.payload[13], rtp.payload[14], rtp.payload[15], rtp.payload[16], rtp.payload[17], rtp.payload[18], rtp.payload[19]); } - else if (is_rtcp && rtp.rtcp) { + else if (is_rtcp != NOT_RTCP && rtp.rtcp) { pkt_idx = 0; err = srtcp_auth_validate(&g->decrypt_rtcp, &g->target.decrypt, &rtp, &pkt_idx); errstr = "SRTCP authentication tag mismatch"; @@ -5436,6 +5442,11 @@ static unsigned int rtpengine46(struct sk_buff *skb, struct rtpengine_table *t, goto out_error; } skb_trim(skb, rtp.header_len + rtp.payload_len); + if (is_rtcp == RTCP_FORWARD) { + // mark packet as "handled" with negative timestamp + oskb->tstamp = -oskb->tstamp; + nf_action = XT_CONTINUE; + } } if (g->target.do_intercept) { @@ -5455,8 +5466,8 @@ static unsigned int rtpengine46(struct sk_buff *skb, struct rtpengine_table *t, } // output - start_idx = 0; - end_idx = g->num_rtp_destinations; + start_idx = (is_rtcp != NOT_RTCP) ? g->num_rtp_destinations : 0; + end_idx = (is_rtcp != NOT_RTCP) ? g->target.num_destinations : g->num_rtp_destinations; if (start_idx == end_idx) goto out; // pass to userspace @@ -5545,7 +5556,7 @@ do_stats: if (skb) kfree_skb(skb); - return NF_DROP; + return nf_action; out_error: log_err("x_tables action failed: %s", errstr); @@ -5591,7 +5602,7 @@ static unsigned int rtpengine4(struct sk_buff *oskb, const struct xt_action_para dst.family = AF_INET; dst.u.ipv4 = ih->daddr; - return rtpengine46(skb, t, &src, &dst, (uint8_t)ih->tos, par); + return rtpengine46(skb, oskb, t, &src, &dst, (uint8_t)ih->tos, par); skip2: kfree_skb(skb); @@ -5633,7 +5644,7 @@ static unsigned int rtpengine6(struct sk_buff *oskb, const struct xt_action_para dst.family = AF_INET6; memcpy(&dst.u.ipv6, &ih->daddr, sizeof(dst.u.ipv6)); - return rtpengine46(skb, t, &src, &dst, ipv6_get_dsfield(ih), par); + return rtpengine46(skb, oskb, t, &src, &dst, ipv6_get_dsfield(ih), par); skip2: kfree_skb(skb); diff --git a/kernel-module/xt_RTPENGINE.h b/kernel-module/xt_RTPENGINE.h index 2decbcc5b..04f4299d3 100644 --- a/kernel-module/xt_RTPENGINE.h +++ b/kernel-module/xt_RTPENGINE.h @@ -125,6 +125,7 @@ struct rtpengine_target_info { rtp_only:1, track_ssrc:1, rtcp:1, + rtcp_fw:1, rtcp_fb_fw:1, do_intercept:1, pt_filter:1,