Why NAT complicates peer-to-peer media
Network Address Translation (NAT) rewrites source IP addresses and ports so many internal hosts can share a public IPv4 address. A stateful implementation keeps a session table: for each outbound flow it records the inside tuple (private IP, private port), the post-NAT outside tuple (public IP, public port), and the far-end tuple the internal host first contacted. Return traffic that matches that far-end tuple is rewritten back; packets sourced from a different remote host:port generally hit no row and are discarded unless filtering is unusually loose.
That asymmetry is why two hosts that only know each other’s private RFC 1918 addresses cannot complete UDP or TCP directly: neither NAT has a row yet for the other peer’s tuple, and neither side can “open” the mapping without an outbound stimulus toward the correct remote.
NAT traversal is the set of techniques that establish a working media path anyway: learning the public side of a mapping (STUN), probing pairs of addresses (ICE), and relaying when no direct path exists (TURN).
Binding and filtering vocabulary (RFC 4787)
NAT behavior is usually discussed along two axes that determine whether reflexive candidates can be predicted. Mapping controls how the external port is chosen when the same internal socket talks to different remotes: with endpoint-independent mapping (EIM), many destinations often share one public port; with address- or address-and-port-dependent mapping, the NAT may allocate a different public port per remote 5-tuple—what operators colloquially call a symmetric NAT. Filtering controls which remote endpoints may send packets inbound through an existing mapping: endpoint-independent filtering is permissive; address-dependent filtering only accepts sources you already contacted, which is common and interacts with ICE retransmission timers.
Hairpinning (loopback translation) matters when two hosts behind the same public IPv4 use their reflexive candidates toward each other: without hairpin support at the NAT, those packets never reach the internal peer even though both sides appear to be on the same public address.
STUN: Binding transactions and reflexive candidates
STUN (Session Traversal Utilities for NAT, RFC 5389) frames are TLV records on UDP or TCP. A classic discovery exchange is a Binding Request / Binding Response carrying a 96-bit TRANSACTION-ID (combined with the leading magic cookie in the XOR routine), optional USERNAME and MESSAGE-INTEGRITY when short-term credentials are negotiated, and often FINGERPRINT (CRC-32 over the message) to distinguish STUN from random UDP payloads. The server copies the packet’s source IP and UDP port into XOR-MAPPED-ADDRESS so on-path observers cannot trivially scrape addresses without knowing the transaction id.
For ICE, those reflexive tuples become srflx candidates. STUN also carries Binding Indications on the media path for consent and keep-alive once a candidate pair is selected—distinct from the initial discovery transaction.
ICE: foundations, priorities, and connectivity checks
ICE (RFC 8445) structures work into gathering (host, srflx, relay), connectivity checks, and nomination. Each candidate has a foundation string, component-id (RTP vs RTCP when not muxed), priority, and transport. Checks are STUN Binding requests sent from a local candidate toward a remote candidate; successful responses create a valid pair. A prflx (peer-reflexive) candidate may appear when the remote’s view of your reflexive address differs from what your own STUN server reported—common with multiple NAT tiers.
Roles (controlling vs controlled) decide which side nominates the single pair that will carry media once both agree. WebRTC multiplexes ICE STUN with DTLS on the same UDP port for RTP when using ICE mux; RTCP can ride on the same socket (BUNDLE) or a second component depending on SDP.
After a pair works, endpoints must continue to pass ICE consent freshness checks (RFC 7675): without periodic consent, implementations should stop forwarding—this is why “silent” middleboxes that drop STUN can look like mid-call drops rather than immediate setup failures.
TURN: allocations, permissions, and channels
TURN (RFC 5766, transport updates in RFC 8656) is not only UDP relay. A client performs an Allocate transaction to obtain a relayed transport address on the TURN server, then explicitly installs CreatePermission for each peer IP (and optionally uses ChannelBind to reduce per-packet overhead with a 16-bit channel number). Only permitted peers may send into the allocation; the server rewrites source addresses so the remote sees traffic from the relay, not the original client.
Long-lived UDP mappings require refresh before the allocation lifetime expires. Enterprise deployments often terminate TURN over TLS on TCP 443 when UDP is blocked, accepting higher head-of-line blocking latency versus native UDP TURN.
DTLS-SRTP after ICE
Once ICE selects a UDP 5-tuple, WebRTC runs DTLS on that socket to derive keys for SRTP (RFC 5764 profile, updated by later DTLS-SRTP specifications). Signaling carries fingerprints (a=fingerprint) so peers can authenticate certificates out-of-band. A failure here surfaces as ICE connected but no audio—distinct from ICE failed which never reaches a valid pair.
ICE-lite vs full ICE
ICE-lite endpoints skip active connectivity checks and only answer checks. SFUs and public PSTN gateways often advertise ICE-lite to reduce CPU while browsers remain full ICE with aggressive nomination—useful when reading SDP from mixed vendors.
Failure modes practitioners recognize
- Symmetric NAT plus wrong TURN topology: Both sides learn srflx ports that never match what the remote observes; TURN becomes mandatory.
- UDP ALG or SIP helper interference: Rewriting addresses inside signaling without updating ICE candidates leaves one-way RTP.
- MTU and IP fragmentation on VPN paths: TURN with
DONT-FRAGMENTprobes can fail when DTLS records exceed path MTU—watch for black holes after connect. - Missing consent or NAT UDP timer expiry: Long silence may drop mappings; applications send keep-alives on the selected pair.
WebRTC-specific considerations
Browsers expose candidate APIs to JavaScript; signaling still crosses HTTPS/WebSocket origins. Host candidates reveal private LAN ranges to remote peers during negotiation unless policy suppresses them—review WebRTC IP exposure and disabling WebRTC where host leakage is unacceptable.
| Mechanism | Role | Carries media? |
|---|---|---|
| STUN | Discovers reflexive addresses; keeps-alive bindings | No (signaling/control only) |
| ICE | Orders candidates, runs connectivity checks, selects a pair | Coordinates where DTLS/SRTP will run |
| TURN | Relays packets when direct paths fail | Yes (by design) |
ICE candidate types (SDP naming)
| Type | How it is obtained | Typical use |
|---|---|---|
host | Local socket bind to an interface address | Same-LAN or hairpin-capable paths; exposes RFC 1918 to remote SDP |
srflx | STUN Binding Response XOR-MAPPED-ADDRESS | Internet path when NAT exposes a stable reflexive port |
prflx | Discovered during ICE checks (remote sees a different reflexive tuple) | Double-NAT, CGNAT, or timing skew between STUN and first packet |
relay | TURN Allocate success with relayed address | Guaranteed path when UDP filters or symmetric NAT block direct pairs |
Operational checklist
- Publish STUN/TURN URIs in signaling; rotate TURN shared secrets frequently.
- Monitor relay bitrate; unexpected spikes may indicate abuse or misconfigured clients.
- Test from guest Wi‑Fi that mimics UDP restrictions before relying on P2P savings versus an SFU.
- Log ICE end states (
failedvsdisconnected) to distinguish NAT issues from certificate errors.
For DNS dependencies in signaling channels, see how DNS works. To verify what the Internet sees from your network after changes, use your public IP context.