ENGDESK-49495: Restrict ICE auto-change to negotiated candidates only - #513
ENGDESK-49495: Restrict ICE auto-change to negotiated candidates only#513baloeng wants to merge 1 commit into
Conversation
When receiving a STUN Binding Request from an IP not in the negotiated ICE candidates (from SDP or trickle ICE), skip the auto-change of RTP/DTLS destination while still sending the required STUN response. This prevents DTLS handshake failures caused by path mismatch when: 1. Client sends STUN from an unadvertised relay IP 2. b2bua-rtc auto-changes to that IP 3. Client responds to DTLS from its original/direct IP 4. DTLS fails due to source IP mismatch The fix checks if the STUN source matches any known candidate (cur_idx >= 0) before allowing the destination change. Unknown sources are logged as warnings. Root cause: Voice SDK sent STUN from TURN relay IP (64.16.248.199) that was not included in the SDP, then responded to DTLS from direct IP (102.218.8.246).
Additional Comments (1)
The earlier loop at lines 1565-1579 correctly checks both IP and port: if (!strcmp(...con_addr, from_host) && ...con_port == from_port)This needs the port check added: Prompt To Fix With AIThis is a comment left during a code review.
Path: src/switch_rtp.c
Line: 1669:1673
Comment:
This loop only checks IP address (`from_host`) but not port. If a client sends STUN from the same IP with a different port (which is exactly the scenario in the PR description where relay used `64.16.248.199:60158`), this will incorrectly match and set `cur_idx >= 0`, allowing the unwanted auto-change.
The earlier loop at lines 1565-1579 correctly checks both IP and port:
```c
if (!strcmp(...con_addr, from_host) && ...con_port == from_port)
```
This needs the port check added:
```suggestion
for (i = 0; i < ice->ice_params->cand_idx[ice->proto]; i++) {
if (!strcmp(ice->ice_params->cands[i][ice->proto].con_addr, from_host) && ice->ice_params->cands[i][ice->proto].con_port == from_port) {
cur_idx = i;
}
}
```
How can I resolve this? If you propose a fix, please make it concise. |
| /* ENGDESK-49495: Only allow auto-change if source IP matches a known ICE candidate. | ||
| * This prevents DTLS path mismatch when STUN arrives from an IP not in the negotiated SDP. | ||
| * The STUN response is still sent (required by ICE), but we don't change the RTP/DTLS destination. */ | ||
| if (cur_idx < 0) { |
There was a problem hiding this comment.
cur_idx is assigned only in the candidate-search loop inside the else if (!do_adj …) → elapsed_adj > 1000 block — i.e. only on HIT 3/4/5. When do_adj is set earlier by HIT 1 (adj_window) or HIT 2 (switch_cmp_addr same-IP/diff-port, or use_candidate && !is_relay nomination), that loop never runs and cur_idx stays -1, so this guard unconditionally skips auto-change on those paths regardless of whether the source is a known candidate. That's very likely the ENGDESK-48822 reconnection regression. Suggest hoisting the candidate search so cur_idx is computed before this check on every adjust path.
| rtp_type(rtp_session), is_rtcp ? "rtcp" : "rtp", | ||
| from_host, from_port, host2, port2); | ||
| } else { | ||
| ice->missed_count = 0; |
There was a problem hiding this comment.
missed_count, rready, and last_ok (further down) were previously set on every do_adj; moving them inside the cur_idx≥0 branch means a peer that keeps sending STUN from an unknown IP never refreshes liveness → can trip ICE timeout/teardown even though we're still answering its binding requests. Suggest keeping rready/last_ok outside this branch and gating only chosen[] + switch_rtp_change_ice_dest.
| * The STUN response is still sent (required by ICE), but we don't change the RTP/DTLS destination. */ | ||
| if (cur_idx < 0) { | ||
| switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(rtp_session->session), SWITCH_LOG_WARNING, | ||
| "Skipping auto-change for %s stun/%s/dtls - source %s:%u is not a negotiated ICE candidate (current: %s:%u)\n", |
There was a problem hiding this comment.
LOG_WARNING fires on every skipped binding request; STUN retransmits sub-second, so a sustained unknown-IP source will spam the logs. Suggest DEBUG, or log once per source.
Summary
Restricts ICE auto-change to only accept STUN Binding Requests from known ICE candidates (from SDP or trickle ICE). STUN from unknown IPs will still receive a response (required by ICE RFC), but will not trigger a change of RTP/DTLS destination.
Problem
A DTLS handshake failure occurred because:
64.16.248.199) not included in the SDP102.218.8.246)Root Cause Analysis
The client's SDP only contained:
10.4.248.248:52332(host - dropped by ACL)102.218.8.246:52332(srflx - chosen)No relay candidate was negotiated, yet the client sent STUN from
64.16.248.199:60158with valid ICE credentials.Fix
Before allowing auto-change, verify the STUN source IP matches a known candidate:
cur_idx >= 0(match found): proceed with auto-changecur_idx < 0(no match): log warning, skip auto-change, still send STUN responseTesting
Related