NAT Traversal

The hardest problem in peer-to-peer networking: getting two devices behind firewalls to talk directly.

Success Rates

ScenarioDirect Connection
Home to home>90% (UDP hole-punch)
Home to mobile carrier (CGNAT)~80%
Mobile to mobile (both CGNAT)~50-60%
Worst case (symmetric NAT both sides)Falls back to relay

When direct connection fails, traffic relays through the group’s lighthouse. The lighthouse cannot decrypt the traffic — it is just forwarding encrypted packets.

Connection Priority

PRIORITY 1: IPv6 Direct         (~20ms, no NAT needed)
PRIORITY 2: IPv6 via Lighthouse (~50ms)
PRIORITY 3: IPv4 + NAT Punch    (~80ms, Nebula punchy)
PRIORITY 4: IPv4 Relay           (~100ms, always works)

Why CGNAT Breaks Things

Carrier-Grade NAT (CGNAT) is what mobile carriers use to share one public IP among thousands of subscribers. It creates problems for peer-to-peer connections:

  • Symmetric NAT assigns different external ports per destination — STUN learns port A, but your peer gets port B
  • Short timeouts (30-120 seconds) break established connections
  • Double NAT (phone NAT + carrier CGNAT) adds two translation layers

The IPv6 Escape

IPv6 eliminates NAT entirely. When both peers have IPv6, direct peer-to-peer always works. Global IPv6 adoption is around 40% and growing. This is the long-term solution, but FreedomMesh cannot depend on it today.

The configuration listens on dual-stack ([::]), preferring IPv6 when available and falling back to IPv4 with NAT traversal when necessary.

The Browser Gateway

For zero-install guest access, the lighthouse bridges between WebRTC (browser-native) and Nebula (mesh-native):

  1. Guest opens an invite link in their browser
  2. WebRTC data channel established over HTTPS (port 443 — penetrates all firewalls)
  3. Lighthouse bridges WebRTC traffic into the Nebula mesh
  4. Guest can chat, video call, share screens
  5. Close the browser tab to disconnect — no residue on the device

No competitor offers zero-install browser access to a mesh network. This is FreedomCore’s “try before you install” moment.