From dd347cf5b497a286d37189b011af875f013c1ea5 Mon Sep 17 00:00:00 2001 From: Richard Fuchs Date: Thu, 9 Jul 2026 11:08:19 -0400 Subject: [PATCH] MT#55283 altered endpoint learning with ICE ICE drops packets early in media_demux_protocols() (via ice_peer_address_known()), which means in media_packet_address_check() we can immediately set any socket as confirmed that has received anything. Take receiving socket into account to determine whether the endpoint is a match. Disable endpoint learning with ICE. ICE is in charge of determining endpoint address and local socket. `media-handover` and `strict-source` handling remains in place. With `media-handover` set, we allow changing endpoint and local socket based on what is actually received, overriding the nomination from ICE. Change-Id: Ieac2893355df6ee560b497867181e6f47d646f2e (cherry picked from commit d3af01349462afc31f1001bf7e30aef484c6c2b3) --- daemon/ice.c | 1 + daemon/media_socket.c | 52 +++++++++++++++++++++++++++---------------- 2 files changed, 34 insertions(+), 19 deletions(-) diff --git a/daemon/ice.c b/daemon/ice.c index f76756c13..84ec0ea50 100644 --- a/daemon/ice.c +++ b/daemon/ice.c @@ -1202,6 +1202,7 @@ static int __check_valid(struct ice_agent *ag) { if (sfd->local_intf != pair->local_intf) continue; ps->selected_sfd = sfd; + PS_SET(ps, CONFIRMED); if (ps->component == 1) ilogs(ice, LOG_INFO, "ICE negotiated: local interface %s", sockaddr_print_buf(&pair->local_intf->spec->local_address.addr)); diff --git a/daemon/media_socket.c b/daemon/media_socket.c index 606e4a5ca..ddd7bfa3c 100644 --- a/daemon/media_socket.c +++ b/daemon/media_socket.c @@ -1582,12 +1582,14 @@ static const char *kernelize_target(kernelize_state *s, struct packet_stream *st // fill input __auto_type reti = &s->reti; - if (PS_ISSET2(stream, STRICT_SOURCE, MEDIA_HANDOVER)) { + reti->stun = MEDIA_ISSET(media, ICE) && media->ice_agent ? 1 : 0; + + if (PS_ISSET2(stream, STRICT_SOURCE, MEDIA_HANDOVER) || reti->stun) { __re_address_translate_ep(&reti->expected_src, MEDIA_ISSET(media, ASYMMETRIC) ? &stream->learned_endpoint : &stream->endpoint); - if (PS_ISSET(stream, STRICT_SOURCE)) - reti->src_mismatch = MSM_DROP; - else if (PS_ISSET(stream, MEDIA_HANDOVER)) + if (PS_ISSET(stream, MEDIA_HANDOVER) || reti->stun) reti->src_mismatch = MSM_PROPAGATE; + else if (PS_ISSET(stream, STRICT_SOURCE)) + reti->src_mismatch = MSM_DROP; } __re_address_translate_ep(&reti->local, &sfd->socket.local); @@ -1595,7 +1597,6 @@ static const char *kernelize_target(kernelize_state *s, struct packet_stream *st reti->stats = stream->stats_in; reti->rtcp = PS_ISSET(stream, RTCP); reti->dtls = MEDIA_ISSET(media, DTLS); - reti->stun = media->ice_agent ? 1 : 0; reti->non_forwarding = s->non_forwarding ? 1 : 0; reti->blackhole = s->blackhole ? 1 : 0; reti->rtp_stats = (rtpe_config.measure_rtp @@ -2502,6 +2503,8 @@ static bool media_packet_address_check(struct packet_handler_ctx *phc) return false; } + bool has_ice = MEDIA_ISSET(phc->mp.media, ICE) && phc->mp.media->ice_agent; + // GH #697 - apparent Asterisk bug where it sends stray RTCP to the RTP port. // work around this by detecting this situation and ignoring the packet for // confirmation purposes when needed. This is regardless of whether rtcp-mux @@ -2522,7 +2525,7 @@ static bool media_packet_address_check(struct packet_handler_ctx *phc) if (MEDIA_ISSET(phc->mp.media, ASYMMETRIC)) update_endpoint = &phc->mp.stream->learned_endpoint; - if (phc->mp.stream->el_flags == EL_OFF) + if (phc->mp.stream->el_flags == EL_OFF || has_ice) PS_SET(phc->mp.stream, CONFIRMED); /* confirm sinks for unidirectional streams in order to kernelize */ @@ -2533,14 +2536,29 @@ static bool media_packet_address_check(struct packet_handler_ctx *phc) } } + /* wait at least 3 seconds after last signal before committing to a particular + * endpoint address */ + bool wait_time = false; + if (!phc->mp.call->last_signal_us || rtpe_now <= phc->mp.call->last_signal_us + 3000000LL) + wait_time = true; + /* if we have already updated the endpoint in the past ... */ if (PS_ISSET(phc->mp.stream, CONFIRMED)) { /* see if we need to compare the source address with the known endpoint */ - if (PS_ISSET2(phc->mp.stream, STRICT_SOURCE, MEDIA_HANDOVER)) { + if (PS_ISSET2(phc->mp.stream, STRICT_SOURCE, MEDIA_HANDOVER) || has_ice) { endpoint_t endpoint = phc->mp.fsin; - int tmp = memcmp(&endpoint, update_endpoint, sizeof(endpoint)); - if (tmp && PS_ISSET(phc->mp.stream, MEDIA_HANDOVER)) { + int tmp = memcmp(&endpoint, update_endpoint, sizeof(endpoint)) + || phc->mp.sfd != phc->mp.stream->selected_sfd; + if (tmp && has_ice) { + // rate-limit for ICE to avoid rapid flip-flop + if (wait_time) + tmp = 0; + else + phc->mp.call->last_signal_us = rtpe_now; + } + + if (tmp && (PS_ISSET(phc->mp.stream, MEDIA_HANDOVER) || has_ice)) { /* out_lock remains locked */ ilog(LOG_INFO | LOG_FLAG_LIMIT, "Peer address changed to %s%s%s", FMT_M(endpoint_print_buf(&phc->mp.fsin))); @@ -2553,10 +2571,12 @@ static bool media_packet_address_check(struct packet_handler_ctx *phc) if (tmp && PS_ISSET(phc->mp.stream, STRICT_SOURCE)) { ilog(LOG_INFO | LOG_FLAG_LIMIT, "Drop due to strict-source attribute; " - "got %s%s%s, " - "expected %s%s%s", + "got %s%s%s -> %s, " + "expected %s%s%s -> %s", FMT_M(endpoint_print_buf(&endpoint)), - FMT_M(endpoint_print_buf(update_endpoint))); + endpoint_print_buf(&phc->mp.sfd->socket.local), + FMT_M(endpoint_print_buf(update_endpoint)), + endpoint_print_buf(&phc->mp.stream->selected_sfd->socket.local)); atomic64_inc_na(&phc->mp.stream->stats_in->errors); atomic64_inc_na(&phc->mp.sfd->local_intf->stats->in.errors); ret = true; @@ -2566,15 +2586,9 @@ static bool media_packet_address_check(struct packet_handler_ctx *phc) return ret; } - /* wait at least 3 seconds after last signal before committing to a particular - * endpoint address */ - bool wait_time = false; - if (!phc->mp.call->last_signal_us || rtpe_now <= phc->mp.call->last_signal_us + 3000000LL) - wait_time = true; - const struct endpoint *use_endpoint_confirm = &phc->mp.fsin; - if (phc->mp.stream->el_flags == EL_IMMEDIATE) + if (phc->mp.stream->el_flags == EL_IMMEDIATE || has_ice) goto confirm_now; if (phc->mp.stream->el_flags == EL_HEURISTIC