From 8f338b7cfe8900dd7dc36361d4c4cdbfa5e77edf Mon Sep 17 00:00:00 2001 From: Richard Fuchs Date: Wed, 6 Sep 2023 13:18:03 -0400 Subject: [PATCH] MT#57977 support short-packet blocking Change-Id: I132cfc24262b97a29a7887e717d15e0ac38f439b (cherry picked from commit 81151b3793fb2ca9dffa0e5773718ae977d63779) --- daemon/call.c | 3 +++ daemon/call_interfaces.c | 5 +++++ daemon/codec.c | 10 +++++++++ daemon/media_socket.c | 9 ++++++-- docs/ng_control_protocol.md | 8 +++++++ include/call.h | 1 + include/call_interfaces.h | 1 + include/codec.h | 2 ++ kernel-module/xt_RTPENGINE.c | 43 ++++++++++++++++++++++-------------- kernel-module/xt_RTPENGINE.h | 1 + lib/codeclib.c | 8 +++++++ lib/codeclib.h | 2 ++ utils/rtpengine-ng-client | 1 + 13 files changed, 76 insertions(+), 18 deletions(-) diff --git a/daemon/call.c b/daemon/call.c index ace6df2ce..cacb741f4 100644 --- a/daemon/call.c +++ b/daemon/call.c @@ -2516,6 +2516,9 @@ static void __update_init_subscribers(struct call_monologue *ml, GQueue *streams recording_setup_monologue(ml); + if (flags && flags->block_short) + ml->block_short = 1; + for (unsigned int j = 0; j < ml->medias->len; j++) { struct call_media *media = ml->medias->pdata[j]; if (!media) diff --git a/daemon/call_interfaces.c b/daemon/call_interfaces.c index c09e91893..6fc779a1e 100644 --- a/daemon/call_interfaces.c +++ b/daemon/call_interfaces.c @@ -1151,6 +1151,11 @@ static void call_ng_flags_flags(struct sdp_ng_flags *out, str *s, void *dummy) { case CSH_LOOKUP("mirror-rtcp"): out->rtcp_mirror = 1; break; + case CSH_LOOKUP("block-short"): + case CSH_LOOKUP("block-shorts"): + case CSH_LOOKUP("block-short-packets"): + out->block_short = 1; + break; default: // handle values aliases from other dictionaries if (call_ng_flags_prefix(out, s, "from-tags-", call_ng_flags_esc_str_list, diff --git a/daemon/codec.c b/daemon/codec.c index 63871fffd..dd5a3ee55 100644 --- a/daemon/codec.c +++ b/daemon/codec.c @@ -308,6 +308,7 @@ static void __handler_shutdown(struct codec_handler *handler) { handler->cn_payload_type = -1; handler->pcm_dtmf_detect = 0; handler->passthrough = 0; + handler->payload_len = 0; codec_handler_free(&handler->dtmf_injector); @@ -1655,6 +1656,15 @@ static int handler_func_passthrough(struct codec_handler *h, struct media_packet ts = ntohl(mp->rtp->timestamp); codec_calc_jitter(mp->ssrc_in, ts, h->source_pt.clock_rate, &mp->tv); codec_calc_lost(mp->ssrc_in, ntohs(mp->rtp->seq_num)); + + if (mp->media->monologue->block_short && h->source_pt.codec_def + && h->source_pt.codec_def->fixed_sizes) + { + if (!h->payload_len) + h->payload_len = mp->payload.len; + else if (mp->payload.len < h->payload_len) + return 0; + } } mp->media->monologue->dtmf_injection_active = 0; diff --git a/daemon/media_socket.c b/daemon/media_socket.c index cf704dbfe..38c39765e 100644 --- a/daemon/media_socket.c +++ b/daemon/media_socket.c @@ -1561,16 +1561,18 @@ output: redi->local = reti->local; redi->output.tos = call->tos; - // media silencing + // PT manipulations bool silenced = call->silence_media || media->monologue->silence_media || sink_handler->attrs.silence_media; - if (silenced) { + bool manipulate_pt = silenced || media->monologue->block_short; + if (manipulate_pt && payload_types) { int i = 0; for (GList *l = *payload_types; l; l = l->next) { struct rtp_stats *rs = l->data; struct rtpengine_pt_output *rpt = &redi->output.pt_output[i++]; struct codec_handler *ch = codec_handler_get(media, rs->payload_type, sink->media, sink_handler); + str replace_pattern = STR_NULL; if (silenced && ch->source_pt.codec_def) replace_pattern = ch->source_pt.codec_def->silence_pattern; @@ -1581,6 +1583,9 @@ output: rpt->replace_pattern_len = replace_pattern.len; memcpy(rpt->replace_pattern, replace_pattern.s, replace_pattern.len); } + + if (media->monologue->block_short && ch->payload_len) + rpt->min_payload_len = ch->payload_len; } } diff --git a/docs/ng_control_protocol.md b/docs/ng_control_protocol.md index 936ec0a80..fa7c18d74 100644 --- a/docs/ng_control_protocol.md +++ b/docs/ng_control_protocol.md @@ -807,6 +807,14 @@ Spaces in each string may be replaced by hyphens. Corresponds to the *rtpproxy* `a` flag. Advertises an RTP endpoint which uses asymmetric RTP, which disables learning of endpoint addresses (see below). +* `block short` or `block short packets` + + Enables blocking of short RTP packets for the applicable call participant. + Short RTP packets are packets shorter than the expected minimum length, + which is determined empirically based on what is observed on the wire. + Short packets are simply discarded. This is supported only for codecs for + which a fixed packet size is expected (e.g. G.711). + * `debug` or `debugging` Enabled full debug logging for this call, regardless of global log level settings. diff --git a/include/call.h b/include/call.h index 5a7c5b8fc..3a935c004 100644 --- a/include/call.h +++ b/include/call.h @@ -539,6 +539,7 @@ struct call_monologue { unsigned int detect_dtmf:1; unsigned int no_recording:1; unsigned int transcoding:1; + unsigned int block_short:1; }; struct call_iterator_list { diff --git a/include/call_interfaces.h b/include/call_interfaces.h index 9ffe2922a..47216c542 100644 --- a/include/call_interfaces.h +++ b/include/call_interfaces.h @@ -199,6 +199,7 @@ struct sdp_ng_flags { drop_traffic_stop:1, passthrough_on:1, passthrough_off:1, + block_short:1, disable_jb:1, nat_wait:1, pierce_nat:1; diff --git a/include/codec.h b/include/codec.h index 5de3b268a..4518ca78e 100644 --- a/include/codec.h +++ b/include/codec.h @@ -47,6 +47,8 @@ struct codec_handler { unsigned int transcoder:1; unsigned int pcm_dtmf_detect:1; + size_t payload_len; // for short-packet blocking + struct ssrc_hash *ssrc_hash; struct codec_handler *input_handler; // == main handler for supp codecs struct codec_handler *output_handler; // == self, or other PT handler diff --git a/kernel-module/xt_RTPENGINE.c b/kernel-module/xt_RTPENGINE.c index 1c57c41b9..ace8ad231 100644 --- a/kernel-module/xt_RTPENGINE.c +++ b/kernel-module/xt_RTPENGINE.c @@ -1789,11 +1789,12 @@ static int proc_list_show(struct seq_file *f, void *v) { seq_printf(f, "\n"); for (j = 0; j < g->target.num_payload_types; j++) { - if (o->output.pt_output[j].replace_pattern_len) + if (o->output.pt_output[j].replace_pattern_len || o->output.pt_output[j].min_payload_len) seq_printf(f, " RTP payload type %3u: " - "%u bytes replacement payload\n", + "%u bytes replacement payload, min payload len %u\n", g->target.pt_input[j].pt_num, - o->output.pt_output[j].replace_pattern_len); + o->output.pt_output[j].replace_pattern_len, + o->output.pt_output[j].min_payload_len); } proc_list_crypto_print(f, &o->encrypt_rtp, &o->output.encrypt, "encryption"); @@ -5134,7 +5135,7 @@ static void proxy_packet_output_rtcp(struct sk_buff *skb, struct rtpengine_outpu skb_put(skb, rtp->payload_len - pllen); } -static void proxy_packet_output_rtXp(struct sk_buff *skb, struct rtpengine_output *o, +static bool proxy_packet_output_rtXp(struct sk_buff *skb, struct rtpengine_output *o, int rtp_pt_idx, struct rtp_parsed *rtp, int ssrc_idx) { @@ -5144,20 +5145,26 @@ static void proxy_packet_output_rtXp(struct sk_buff *skb, struct rtpengine_outpu if (!rtp->ok) { proxy_packet_output_rtcp(skb, o, rtp, ssrc_idx); - return; + return true; } // pattern rewriting - if (rtp_pt_idx >= 0 && o->output.pt_output[rtp_pt_idx].replace_pattern_len) { - if (o->output.pt_output[rtp_pt_idx].replace_pattern_len == 1) - memset(rtp->payload, o->output.pt_output[rtp_pt_idx].replace_pattern[0], - rtp->payload_len); - else { - for (i = 0; i < rtp->payload_len; - i += o->output.pt_output[rtp_pt_idx].replace_pattern_len) - memcpy(&rtp->payload[i], - o->output.pt_output[rtp_pt_idx].replace_pattern, - o->output.pt_output[rtp_pt_idx].replace_pattern_len); + if (rtp_pt_idx >= 0) { + if (o->output.pt_output[rtp_pt_idx].min_payload_len + && rtp->payload_len < o->output.pt_output[rtp_pt_idx].min_payload_len) + return false; + + if (o->output.pt_output[rtp_pt_idx].replace_pattern_len) { + if (o->output.pt_output[rtp_pt_idx].replace_pattern_len == 1) + memset(rtp->payload, o->output.pt_output[rtp_pt_idx].replace_pattern[0], + rtp->payload_len); + else { + for (i = 0; i < rtp->payload_len; + i += o->output.pt_output[rtp_pt_idx].replace_pattern_len) + memcpy(&rtp->payload[i], + o->output.pt_output[rtp_pt_idx].replace_pattern, + o->output.pt_output[rtp_pt_idx].replace_pattern_len); + } } } @@ -5175,6 +5182,8 @@ static void proxy_packet_output_rtXp(struct sk_buff *skb, struct rtpengine_outpu srtp_encrypt(&o->encrypt_rtp, &o->output.encrypt, rtp, pkt_idx); srtp_authenticate(&o->encrypt_rtp, &o->output.encrypt, rtp, pkt_idx); skb_put(skb, rtp->payload_len - pllen); + + return true; } static int send_proxy_packet_output(struct sk_buff *skb, struct rtpengine_target *g, @@ -5182,7 +5191,9 @@ static int send_proxy_packet_output(struct sk_buff *skb, struct rtpengine_target struct rtpengine_output *o, struct rtp_parsed *rtp, int ssrc_idx, const struct xt_action_param *par) { - proxy_packet_output_rtXp(skb, o, rtp_pt_idx, rtp, ssrc_idx); + bool send_or_not = proxy_packet_output_rtXp(skb, o, rtp_pt_idx, rtp, ssrc_idx); + if (!send_or_not) + return 0; return send_proxy_packet(skb, &o->output.src_addr, &o->output.dst_addr, o->output.tos, par); } diff --git a/kernel-module/xt_RTPENGINE.h b/kernel-module/xt_RTPENGINE.h index fde130479..079dc6507 100644 --- a/kernel-module/xt_RTPENGINE.h +++ b/kernel-module/xt_RTPENGINE.h @@ -100,6 +100,7 @@ struct rtpengine_pt_input { uint32_t clock_rate; }; struct rtpengine_pt_output { + unsigned int min_payload_len; char replace_pattern[16]; unsigned char replace_pattern_len; }; diff --git a/lib/codeclib.c b/lib/codeclib.c index 0b332ce04..3154a545c 100644 --- a/lib/codeclib.c +++ b/lib/codeclib.c @@ -256,6 +256,7 @@ static struct codec_def_s __codec_defs[] = { [DTX_SILENCE] = &dtx_method_silence, [DTX_CN] = &dtx_method_cn, }, + .fixed_sizes = 1, }, { .rtpname = "PCMU", @@ -272,6 +273,7 @@ static struct codec_def_s __codec_defs[] = { [DTX_SILENCE] = &dtx_method_silence, [DTX_CN] = &dtx_method_cn, }, + .fixed_sizes = 1, }, { .rtpname = "G723", @@ -288,6 +290,7 @@ static struct codec_def_s __codec_defs[] = { [DTX_SILENCE] = &dtx_method_silence, [DTX_CN] = &dtx_method_cn, }, + .fixed_sizes = 1, }, { .rtpname = "G722", @@ -305,6 +308,7 @@ static struct codec_def_s __codec_defs[] = { [DTX_SILENCE] = &dtx_method_silence, [DTX_CN] = &dtx_method_cn, }, + .fixed_sizes = 1, }, { .rtpname = "QCELP", @@ -334,6 +338,7 @@ static struct codec_def_s __codec_defs[] = { [DTX_SILENCE] = &dtx_method_silence, [DTX_CN] = &dtx_method_cn, }, + .fixed_sizes = 1, }, { .rtpname = "G729a", @@ -349,6 +354,7 @@ static struct codec_def_s __codec_defs[] = { [DTX_SILENCE] = &dtx_method_silence, [DTX_CN] = &dtx_method_cn, }, + .fixed_sizes = 1, }, #else { @@ -367,6 +373,7 @@ static struct codec_def_s __codec_defs[] = { [DTX_SILENCE] = &dtx_method_silence, [DTX_CN] = &dtx_method_cn, }, + .fixed_sizes = 1, }, { .rtpname = "G729a", @@ -383,6 +390,7 @@ static struct codec_def_s __codec_defs[] = { [DTX_SILENCE] = &dtx_method_silence, [DTX_CN] = &dtx_method_cn, }, + .fixed_sizes = 1, }, #endif { diff --git a/lib/codeclib.h b/lib/codeclib.h index a3be3fb67..47a1bb8f8 100644 --- a/lib/codeclib.h +++ b/lib/codeclib.h @@ -213,6 +213,7 @@ struct codec_def_s { // flags unsigned int supplemental:1, dtmf:1, // special case + fixed_sizes:1, // hint for `block-short` feature amr:1; const codec_type_t *codec_type; @@ -465,6 +466,7 @@ INLINE int decoder_event(decoder_t *dec, enum codec_event event, void *ptr) { struct codec_def_s { int dtmf; int supplemental; + int fixed_sizes; format_cmp_f * const format_cmp; format_print_f * const format_print; const str silence_pattern; diff --git a/utils/rtpengine-ng-client b/utils/rtpengine-ng-client index 54a1a45dc..0fe3284a0 100755 --- a/utils/rtpengine-ng-client +++ b/utils/rtpengine-ng-client @@ -50,6 +50,7 @@ my @flags = qw( no-passthrough pause early-media + block-short ); my @string_opts = qw(