NAT Traversal Patterns
AdvancedNAT (Network Address Translation) hides private IP addresses behind a single public IP, breaking peer-to-peer connectivity. NAT traversal techniques — STUN, TURN, and ICE — are how WebRTC and VoIP establish direct connections between clients behind NAT.
Overview
Most devices on the internet are behind NAT — home routers, mobile carrier NAT (CGNAT), and cloud instance private VPCs. While NAT works seamlessly for client-server connections (client initiates, NAT creates a mapping), it breaks peer-to-peer — neither peer can initiate a connection to the other's private IP. Applications like video calls (WebRTC), gaming, and VoIP need direct peer connections for low latency. STUN discovers your public IP:port. TURN relays traffic when direct connection fails. ICE tries all candidate pairs and picks the best working path. Understanding NAT traversal is increasingly important as P2P, WebRTC, and edge computing grow.
Why NAT Breaks Peer-to-Peer
NAT translates private (RFC 1918) addresses to the router's public IP. The NAT table maps (private IP, private port) ↔ (public IP, public port). A packet from the internet only reaches a device if a NAT mapping already exists — created by an outbound packet from that device. Two peers behind different NATs cannot initiate connections to each other.
// NAT mapping example:
// Home network: 192.168.1.0/24, public IP: 203.0.113.5
//
// Device A (192.168.1.10) opens connection to Google (142.250.80.36:443):
// → NAT creates mapping: 192.168.1.10:54321 ↔ 203.0.113.5:45001
// → Packet arrives at Google with src=203.0.113.5:45001
// ← Google replies to 203.0.113.5:45001 → NAT translates → 192.168.1.10:54321 ✓
// Peer-to-Peer problem:
// Peer A: 192.168.1.10 (behind NAT: 203.0.113.5)
// Peer B: 10.0.0.20 (behind NAT: 198.51.100.7)
//
// A tries to connect to B directly:
// A knows B's private IP (10.0.0.20) → not reachable from internet
// A knows B's public IP (198.51.100.7) → but which port? NAT table unknown
// B's NAT drops inbound packets from A — no matching outbound mapping exists
//
// Neither peer can initiate → connection impossible without traversalSTUN: Discover Your Public Address
STUN (Session Traversal Utilities for NAT) is a simple request-response protocol. A client sends a request to a STUN server on the public internet. The STUN server replies with the client's observed public IP and port (the NAT-translated address). The client learns its own "reflexive candidate" — the public address that represents it to the outside world.
// STUN request/response:
// Client (192.168.1.10:54321) → STUN server (stun.l.google.com:19302)
// STUN Binding Request (UDP)
// "What is my public IP:port as you see it?"
// STUN Response:
// XOR-MAPPED-ADDRESS: 203.0.113.5:45001
// ← This is what the internet sees when A sends from 192.168.1.10:54321
// After STUN:
// Peer A knows: public=203.0.113.5:45001, private=192.168.1.10:54321
// Peer B knows: public=198.51.100.7:62345, private=10.0.0.20:54321
// A and B exchange this info via signalling server (WebSocket/HTTP)
// UDP Hole Punching (works for full-cone and address-restricted NATs):
// Both A and B send UDP packets to each other's public IP:port simultaneously
// A → 198.51.100.7:62345 (creates NAT mapping on A's NAT)
// B → 203.0.113.5:45001 (creates NAT mapping on B's NAT)
// Second packet from each side passes through the now-open NAT mapping
// Direct UDP connection established!TURN: Relay Fallback
STUN and hole punching fail for symmetric NATs (common on corporate networks) — where the NAT assigns a different external port for each destination. TURN (Traversal Using Relays around NAT) provides a relay server that both peers connect to. All traffic flows through the relay. This always works but adds latency and bandwidth cost.
// TURN — when hole punching fails (symmetric NAT):
// Both peers connect to TURN server, relay traffic through it:
//
// Peer A (behind symmetric NAT)
// └──▶ TURN server (turn.aicancode.org:3478)
// └──▶ Peer B (behind symmetric NAT)
//
// TURN allocate flow:
// 1. A sends Allocate Request to TURN server (with credentials)
// 2. TURN creates a relay address: 203.0.113.100:49152
// 3. A sends relay address to B via signalling
// 4. B connects to TURN relay address
// 5. All A↔B traffic relayed through TURN
// Cost: TURN relay uses bandwidth on your server — expensive at scale
// Mitigation: only use TURN when direct/STUN path fails (ICE selects best path)
// Self-hosted TURN server (coturn):
// turnserver --listening-port 3478 --realm aicancode.org
// --user username:password --lt-cred-mechICE: Putting It All Together
ICE (Interactive Connectivity Establishment) is the framework that orchestrates STUN and TURN. It gathers all candidate addresses (host, server-reflexive via STUN, relayed via TURN), exchanges them with the peer via signalling, then systematically tries all candidate pairs and selects the best working path — direct connection preferred, TURN relay as last resort.
// ICE candidate types (gathered by WebRTC):
// host candidate: 192.168.1.10:54321 ← direct (LAN only)
// srflx candidate: 203.0.113.5:45001 ← server-reflexive (STUN)
// relay candidate: 203.0.113.100:49152 ← TURN relay
// ICE connectivity checks — try all pairs simultaneously:
// (A host ↔ B host) → fails (different NATs)
// (A srflx ↔ B srflx) → try UDP hole punch simultaneously
// A → B public: creates A's NAT mapping
// B → A public: creates B's NAT mapping → SUCCESS → direct path!
// (A relay ↔ B relay) → always works but slowest → used if above fail
// WebRTC ICE (JavaScript):
const pc = new RTCPeerConnection({
iceServers: [
{ urls: 'stun:stun.l.google.com:19302' }, // STUN
{ urls: 'turn:turn.aicancode.org:3478', // TURN
username: 'user', credential: 'pass' }
]
})
pc.onicecandidate = e => {
if (e.candidate) signalingServer.send(e.candidate) // exchange via signalling
}
// WebRTC handles hole punching, candidate pairing, and path selection automaticallyKey Points to Remember
- 1NAT breaks P2P because neither peer's private IP is routable from the internet, and NAT tables have no mapping until outbound traffic creates one.
- 2STUN discovers your public (NAT-translated) IP:port by asking an external server to echo back what it sees.
- 3UDP hole punching works when both peers send simultaneously — each outbound packet creates a NAT mapping that allows the other's inbound packet.
- 4TURN provides a relay server that always works — even through symmetric NAT — but adds latency and bandwidth cost.
- 5ICE orchestrates all of this: gather candidates (host, STUN, TURN), exchange via signalling, try all pairs, pick the best working path.
Interview Questions
Sign in to ask AriaWhy can't two clients behind different NATs connect directly?
What is STUN and what problem does it solve?
When does UDP hole punching fail and what is the fallback?
What is the role of ICE in WebRTC connection establishment?
How would you design the signalling and NAT traversal infrastructure for a video calling app?
Ask Aria about NAT Traversal Patterns
Your personal AI tutor — ask anything about this concept
Revision Status
Personal Notes
Sign in to save personal notes for this topic.
Discussion
Sign in to join the discussion.