[PR #5805] [client] Fix ICE reconnection loop and buffer candidates before agent initialization #26813

Open
opened 2026-08-05 07:07:50 -04:00 by saavagebueno · 0 comments
Owner

Original Pull Request: https://github.com/netbirdio/netbird/pull/5805

State: closed
Merged: No


Summary

  • Guard Loop Fix: When both peers are behind the same NAT (same public IP), their connectivity guards fire simultaneously every ~12s, each sending a new offer with a new session ID. This cancels the other side's ICE agent before it can finish negotiating, creating an infinite reconnection loop. Fix: skip new offers while agentConnecting == true to let the current ICE attempt complete.
  • Candidate Buffering: Remote ICE candidates that arrive before the local ICE agent is created were silently dropped. Add a pendingCandidates buffer that collects early candidates and flushes them once the agent is ready.

Both fixes are tightly coupled — without the buffer, the guard loop fix alone would still miss early candidates.

Checklist

  • Bug fix
  • Create tests that fail without the change: ICE connections between peers behind the same NAT consistently failed before this fix
  • Documentation not needed — internal ICE behavior change, no user-facing API change

By submitting this pull request, I confirm that I have read and agree to the terms of the Contributor License Agreement.

Fixes #3669 — Unable to connect to netbird peer on different LAN with the same public IP
Fixes #5672 — ICE Agent is not initialized yet on android app
Related #2703 — Multiple peers behind NAT getting relayed
Related #3339 — Same LAN cannot successfully P2P
Related #4031 — No P2P/direct connection, only relayed
Related #4225 — Netbird Self-Hosted P2P not working
Related #5670 — macOS ICE agent never initializes (arm64)

Summary by CodeRabbit

  • Bug Fixes
    • Buffer early remote connection candidates with a bounded cap to avoid lost candidates and limit memory use.
    • Expand and queue applicable server-reflexive candidates for later delivery instead of dropping them.
    • Prevent rapid reconnection churn by skipping replacement of a recently-started agent while it’s still connecting (adds a short protection window).
    • Flush buffered candidates into a newly created connection and clear the buffer on close to prevent stale data.
**Original Pull Request:** https://github.com/netbirdio/netbird/pull/5805 **State:** closed **Merged:** No --- ## Summary - **Guard Loop Fix**: When both peers are behind the same NAT (same public IP), their connectivity guards fire simultaneously every ~12s, each sending a new offer with a new session ID. This cancels the other side's ICE agent before it can finish negotiating, creating an infinite reconnection loop. Fix: skip new offers while `agentConnecting == true` to let the current ICE attempt complete. - **Candidate Buffering**: Remote ICE candidates that arrive before the local ICE agent is created were silently dropped. Add a `pendingCandidates` buffer that collects early candidates and flushes them once the agent is ready. Both fixes are tightly coupled — without the buffer, the guard loop fix alone would still miss early candidates. ## Checklist - [x] Bug fix - [x] Create tests that fail without the change: ICE connections between peers behind the same NAT consistently failed before this fix - [x] Documentation not needed — internal ICE behavior change, no user-facing API change By submitting this pull request, I confirm that I have read and agree to the terms of the [Contributor License Agreement](https://github.com/netbirdio/netbird/blob/main/CONTRIBUTOR_LICENSE_AGREEMENT.md). ## Related Issues Fixes #3669 — Unable to connect to netbird peer on different LAN with the same public IP Fixes #5672 — ICE Agent is not initialized yet on android app Related #2703 — Multiple peers behind NAT getting relayed Related #3339 — Same LAN cannot successfully P2P Related #4031 — No P2P/direct connection, only relayed Related #4225 — Netbird Self-Hosted P2P not working Related #5670 — macOS ICE agent never initializes (arm64) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Bug Fixes** * Buffer early remote connection candidates with a bounded cap to avoid lost candidates and limit memory use. * Expand and queue applicable server-reflexive candidates for later delivery instead of dropping them. * Prevent rapid reconnection churn by skipping replacement of a recently-started agent while it’s still connecting (adds a short protection window). * Flush buffered candidates into a newly created connection and clear the buffer on close to prevent stale data. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
saavagebueno added the pull-request label 2026-08-05 07:07:50 -04:00
Sign in to join this conversation.
No Label pull-request
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: DYNR/netbird#26813