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
pull/2138/head
Richard Fuchs 3 weeks ago
parent 9cb902319c
commit d3af013494

@ -1239,6 +1239,7 @@ static int __check_valid(struct ice_agent *ag) {
if (sfd->local_intf != pair->local_intf)
continue;
ps->selected_sfd = sfd;
sfd->confirmed = true;
if (ps->component == 1)
ilogs(ice, LOG_INFO, "ICE negotiated: local interface %s",
sockaddr_print_buf(&pair->local_intf->spec->local_address.addr));

@ -1584,12 +1584,14 @@ static const char *kernelize_target(kernelize_state *s, struct packet_stream *st
// fill input
__auto_type reti = &s->reti.target;
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);
@ -1597,7 +1599,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
@ -3146,6 +3147,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
@ -3164,7 +3167,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)
phc->mp.sfd->confirmed = true;
/* confirm sinks for unidirectional streams in order to kernelize */
@ -3176,13 +3179,28 @@ 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 (phc->mp.sfd->confirmed) {
/* see if we need to compare the source address with the known endpoint */
if (PS_ISSET2(phc->mp.stream, STRICT_SOURCE, MEDIA_HANDOVER)) {
bool matched = memcmp(&phc->mp.fsin, update_endpoint, sizeof(phc->mp.fsin)) == 0;
if (PS_ISSET2(phc->mp.stream, STRICT_SOURCE, MEDIA_HANDOVER) || has_ice) {
bool matched = memcmp(&phc->mp.fsin, update_endpoint, sizeof(phc->mp.fsin)) == 0
&& phc->mp.sfd == phc->mp.stream->selected_sfd;
if (!matched && has_ice) {
// rate-limit for ICE to avoid rapid flip-flop
if (wait_time)
matched = true;
else
phc->mp.call->last_signal_us = rtpe_now;
}
if (!matched && PS_ISSET(phc->mp.stream, MEDIA_HANDOVER)) {
if (!matched && (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)));
@ -3196,17 +3214,21 @@ static bool media_packet_address_check(struct packet_handler_ctx *phc)
// try some other options before dropping
if (!matched && !MEDIA_ISSET(phc->mp.media, ASYMMETRIC))
matched = memcmp(&phc->mp.fsin, &phc->orig_stream->endpoint,
sizeof(phc->mp.fsin)) == 0;
sizeof(phc->mp.fsin)) == 0
&& phc->mp.sfd == phc->mp.stream->selected_sfd;
if (!matched)
matched = memcmp(&phc->mp.fsin, &phc->orig_stream->learned_endpoint,
sizeof(phc->mp.fsin)) == 0;
sizeof(phc->mp.fsin)) == 0
&& phc->mp.sfd == phc->mp.stream->selected_sfd;
if (!matched && 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(&phc->mp.fsin)),
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;
@ -3216,15 +3238,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

Loading…
Cancel
Save