How NAT Traversal Works: STUN, TURN, and ICE Explained

NAT traversal is the set of techniques that allow two devices, both behind NAT, to establish direct communication with each other. This is one of the hardest practical problems in networking. NAT was designed to let internal devices reach external servers, not to let two internal devices on different networks reach each other. Every voice call, video chat, multiplayer game, and peer-to-peer file transfer between devices behind NAT must solve this problem, and the solutions — STUN, TURN, and ICE — form the backbone of real-time communication on the modern internet.

The fundamental challenge is simple to state: two devices behind separate NATs have no way to send packets to each other. Device A at 192.168.1.10 behind NAT A does not know the public IP or port mapping of Device B at 10.0.0.5 behind NAT B, and even if it did, NAT B would drop the unsolicited incoming packet because it has no matching entry in its translation table. Both sides face the same problem. Neither can go first. NAT traversal techniques exist to break this deadlock.

NAT Types and Their Traversal Implications

Not all NATs behave the same way. The behavior of a NAT device — specifically, how it allocates external ports and how it filters incoming packets — determines which traversal techniques will work. RFC 4787 defines the behavioral classifications that matter for traversal, but the older classification from RFC 3489 remains widely used in practice.

Full Cone NAT (Endpoint-Independent Mapping and Filtering)

A full cone NAT creates a mapping from an internal address:port to an external address:port, and then allows any external host to send packets to that external address:port. Once device 192.168.1.10:5000 sends a packet outbound and gets mapped to 203.0.113.5:40000, any host on the internet can send a packet to 203.0.113.5:40000 and it will be forwarded to 192.168.1.10:5000.

Full cone NAT is the easiest to traverse. A device only needs to discover its external mapping (via STUN) and share that address with its peer. The peer can then send directly to the mapped address. Full cone NATs are rare in modern networks because they offer minimal security — they are effectively a static port mapping created on demand.

Address-Restricted Cone NAT

An address-restricted cone NAT uses the same mapping as full cone (the same internal address:port always maps to the same external address:port regardless of destination), but it only forwards incoming packets from an IP address that the internal device has previously sent a packet to. If 192.168.1.10:5000 has sent packets to 198.51.100.20, then only packets from 198.51.100.20 (any port) will be forwarded through the mapping. Packets from 198.51.100.30 are dropped unless the internal device has also sent to that address.

Traversal is straightforward: both peers send packets to each other's discovered external address. Once both sides have sent a packet, the NAT on each side has "seen" the other's IP, and return traffic is allowed through.

Port-Restricted Cone NAT

A port-restricted cone NAT tightens the filtering further. It only forwards incoming packets from the exact IP:port combination that the internal device previously sent to. If 192.168.1.10:5000 sent to 198.51.100.20:3478, only packets from 198.51.100.20:3478 are forwarded. Packets from 198.51.100.20:9000 are dropped.

This is the most common NAT type in consumer routers. Traversal via hole punching still works because the mapping is consistent — the same internal address:port always maps to the same external address:port. Both peers discover their external mappings via STUN, exchange them, and simultaneously send packets to each other's mapped address:port. Both NATs then have entries allowing the other's traffic through.

Symmetric NAT

Symmetric NAT is the most restrictive and the hardest to traverse. It creates a different external mapping for each unique destination. When 192.168.1.10:5000 sends to 198.51.100.20:3478, it gets mapped to 203.0.113.5:40000. When the same internal address:port sends to 198.51.100.30:5000, it gets a different external mapping: 203.0.113.5:40001. The external port varies per destination.

This breaks standard hole punching. The port mapping that STUN discovers (the one created when talking to the STUN server) is different from the mapping that will be created when the device tries to send to its actual peer. The peer cannot predict what port the NAT will assign. If both sides are behind symmetric NATs, direct connection is generally impossible without a relay.

Symmetric NAT is commonly found in enterprise firewalls, carrier-grade NAT (CGNAT), and mobile carrier networks. These environments prioritize security and port conservation over peer-to-peer connectivity.

NAT Types: Mapping and Filtering Behavior Full Cone NAT Same mapping for all destinations Any external host can send to mapped port 10.0.0.5:5000 → :40000 ANY host → :40000 OK Address-Restricted Cone Same mapping for all destinations Only previously-contacted IPs allowed 10.0.0.5:5000 → :40000 Known IP only OK Port-Restricted Cone Same mapping for all destinations Only previously-contacted IP:port allowed 10.0.0.5:5000 → :40000 Known IP:port only Symmetric NAT Different mapping per destination Only exact destination IP:port allowed :5000→A = :40000 :5000→B = :40001 Unpredictable port NAT Traversal Difficulty Easy Moderate Harder Usually impossible Direct Connection Success (Hole Punching) Peer A NAT Peer B NAT Result Full/Restricted Cone Full/Restricted Cone Direct connection Port-Restricted Port-Restricted Direct connection Symmetric Port-Restricted Port prediction (unreliable) Symmetric Symmetric Requires TURN relay Symmetric-to-symmetric is the worst case: ~8% of real-world NAT pairs

STUN: Discovering Your Public Address

STUN (Session Traversal Utilities for NAT, RFC 8489) is the simplest NAT traversal protocol. Its primary purpose is to let a device behind NAT discover its public IP address and port mapping — the address:port that the NAT assigned on the external side. STUN does not relay traffic. It only provides information.

The protocol works by sending a UDP packet to a STUN server on the public internet. The STUN server reads the source IP and port from the incoming packet (which is the NAT's external mapping, not the client's private address) and echoes it back to the client in the response payload. The client now knows its public address:port as seen from outside the NAT.

The STUN Binding Request

A STUN Binding Request is a 20-byte UDP message (just the header, with no attributes). The STUN server responds with a Binding Response containing a XOR-MAPPED-ADDRESS attribute — the client's public IP and port, XOR'd with the STUN transaction ID. The XOR is not for security; it prevents NAT ALGs (Application Layer Gateways) from rewriting the IP address inside the STUN payload, which some broken ALGs are known to do with plaintext IP addresses.

The STUN message format is simple: a 20-byte header with message type, message length, a magic cookie (0x2112A442), and a 96-bit transaction ID. Attributes follow in TLV (type-length-value) format. The entire exchange is typically a single request-response pair, completing in one round trip.

STUN Binding Request (20 bytes)
  Type:           0x0001 (Binding Request)
  Length:         0x0000 (no attributes)
  Magic Cookie:   0x2112A442
  Transaction ID: [96-bit random]

STUN Binding Response
  Type:           0x0101 (Binding Success Response)
  XOR-MAPPED-ADDRESS:
    Family:  IPv4
    Port:    external_port XOR 0x2112
    Address: external_ip XOR 0x2112A442

STUN for NAT Type Detection

STUN can also determine the NAT type by performing multiple tests. The client sends Binding Requests to different STUN server addresses and ports and compares the external mappings. If the same internal address:port always maps to the same external address:port regardless of destination, the NAT uses endpoint-independent mapping (cone NAT). If different destinations produce different mappings, the NAT is symmetric. RFC 5780 defines these additional tests.

In practice, most modern NAT traversal implementations do not bother with formal NAT type detection. ICE (described below) simply tries all candidate pairs and uses whichever works, making the NAT type classification largely academic for connection establishment. However, knowing the NAT type remains useful for predicting traversal success rates and diagnosing connectivity issues.

STUN Server Infrastructure

Running a STUN server is cheap. The server is stateless — it processes each request independently, requires no session tracking, and sends a single response per request. The bandwidth is negligible (a few dozen bytes per query). Google operates free public STUN servers at stun.l.google.com:19302, and many other providers do the same. STUN is so lightweight that a single server can handle millions of queries per day.

UDP Hole Punching

The core traversal technique for UDP is hole punching. It exploits the fact that most NATs (all types except the most restrictive symmetric NATs) create a port mapping when an outbound packet is sent, and then allow return traffic through that mapping. The trick is to get both sides to send a packet at roughly the same time, so both NATs create mappings, and then each side's subsequent packets arrive at a mapping the other side's NAT already has.

The procedure requires a rendezvous server (sometimes called a signaling server) that both clients can reach. This server does not relay traffic — it only exchanges the clients' discovered public addresses. The steps are:

  1. Both Client A and Client B send STUN Binding Requests to a STUN server and discover their external address:port mappings.
  2. Both clients register their external address:port with the rendezvous server (via a regular client-server connection).
  3. The rendezvous server tells Client A about Client B's external address:port, and vice versa.
  4. Client A sends a UDP packet to Client B's external address:port. This packet will likely be dropped by Client B's NAT (no matching entry yet), but it creates a mapping in Client A's NAT for traffic from Client B's external address.
  5. Client B sends a UDP packet to Client A's external address:port. Client A's NAT now has a matching entry, so this packet is delivered to Client A. The same packet creates a mapping in Client B's NAT.
  6. Client A sends another packet to Client B. Now Client B's NAT has a matching entry, and the packet is delivered. The hole is punched in both directions.

The timing does not need to be precise. As long as both sides send packets within the NAT's mapping timeout window (typically 30-120 seconds for UDP), the hole punch will succeed. In practice, both sides send packets as soon as they receive the peer's address from the rendezvous server, and the hole usually opens within a few hundred milliseconds.

Hole punching works reliably with full cone, address-restricted cone, and port-restricted cone NATs. It fails with symmetric NATs because the port mapping used to talk to the STUN server differs from the mapping that would be created for the peer — the peer has the wrong port number.

TURN: When Direct Connection Fails

TURN (Traversal Using Relays around NAT, RFC 8656) is the fallback when direct connection is impossible. A TURN server acts as an intermediary, relaying all traffic between the two peers. Both clients establish an authenticated connection to the TURN server, and the server allocates a public address:port for each client. Traffic from one client is received by the TURN server and forwarded to the other.

TURN is architecturally simple but operationally expensive. Every byte of data traverses the TURN server, which means the server must have enough bandwidth, processing power, and network capacity to handle all relayed traffic. For a video call at 2 Mbps in each direction, a single TURN-relayed session consumes 4 Mbps of the server's bandwidth. At scale, this adds up fast.

TURN Allocation

A client begins by sending an Allocate request to the TURN server over UDP (or TCP, or TLS-over-TCP). The server authenticates the client (TURN always requires authentication, unlike STUN), and if authorized, allocates a relay transport address — a public IP:port on the server that will accept and forward traffic on the client's behalf.

The server responds with the allocated relay address. The client then tells its peer (via the signaling channel) to send traffic to this relay address. When the TURN server receives packets at the relay address, it forwards them to the client via the established TURN connection. The reverse path works similarly: the client sends data to the TURN server, which forwards it to the peer's address.

TURN allocations have a default lifetime of 10 minutes and must be refreshed with periodic Refresh requests. If the client disappears, the allocation expires and the relay address is freed.

TURN Channels

For efficiency, TURN supports channel binding. Instead of wrapping every packet in a full TURN header (36+ bytes of overhead), the client can bind a peer address to a 4-byte channel number. Subsequent packets use the compact ChannelData format with just the 4-byte channel header, reducing overhead from 36 bytes to 4 bytes per packet. This matters for real-time media where packet rates are high (50 packets per second for audio).

TURN Transport Options

TURN supports multiple transport protocols between the client and the server:

The relay leg (TURN server to remote peer) is always UDP. Only the client-to-TURN-server leg varies. This means the remote peer receives standard UDP packets from the TURN server's relay address, unaware that TURN is involved.

STUN vs TURN: Cost

The cost difference between STUN and TURN is orders of magnitude. STUN is a single request-response exchange of a few dozen bytes, and the server is stateless. TURN relays every byte of actual application data, maintaining allocation state and consuming bandwidth proportional to the media stream. A STUN server can be run for essentially free. A TURN server serving a large user base requires significant infrastructure investment. This is why every NAT traversal implementation tries STUN-based hole punching first and falls back to TURN only when necessary. In practice, TURN is needed for roughly 8-15% of connections, depending on the user population.

ICE: The Complete Traversal Framework

ICE (Interactive Connectivity Establishment, RFC 8445) is the framework that ties STUN and TURN together into a systematic process for establishing connectivity. ICE does not introduce new traversal techniques — it orchestrates existing ones. It is the standard used by WebRTC, SIP telephony, and most modern real-time communication protocols.

ICE's approach is exhaustive: gather every possible address a peer might be reachable at, pair them up, test them systematically, and use the best working pair. This brute-force strategy is what makes ICE reliable across the wildly diverse NAT and firewall configurations found in the real world.

Candidate Gathering

The first phase of ICE is candidate gathering. Each peer collects a list of addresses (called candidates) where it might be reachable. There are three types:

Candidates are gathered in parallel for efficiency. The ICE agent sends STUN Binding Requests to STUN servers and TURN Allocate requests to TURN servers simultaneously. As candidates are discovered, they are trickled to the remote peer via the signaling channel (this is called Trickle ICE, defined in RFC 8838). The alternative — waiting for all candidates before sending any — is called Full ICE and adds unnecessary latency.

Candidate Pairing and Prioritization

Once both peers have exchanged candidates, each side forms a checklist of candidate pairs — every combination of a local candidate with a remote candidate. If Peer A has 3 candidates and Peer B has 4 candidates, there are 12 candidate pairs to test.

Each pair is assigned a priority based on the candidate types. The priority formula in RFC 8445 favors direct connections over relayed ones:

  1. Host-to-host — Highest priority. Both peers on the same LAN.
  2. Host-to-server-reflexive — Direct connection through one NAT.
  3. Server-reflexive-to-server-reflexive — Both peers behind NAT, hole punching.
  4. Relay candidates — Lowest priority. Used only if nothing else works.

The pairs are sorted by priority and tested in order. This ensures that the cheapest, lowest-latency connection is used whenever possible, with TURN relay as the guaranteed fallback.

Connectivity Checks

For each candidate pair, the ICE agent sends a STUN Binding Request from the local candidate to the remote candidate. If the remote peer receives the request and responds, the pair is marked as succeeded. Both sides perform checks (ICE is symmetric — both the controlling agent and the controlled agent send checks), and a pair is only fully valid when both directions succeed.

Connectivity checks happen in parallel across multiple pairs, with pacing to avoid flooding the network. RFC 8445 recommends a default interval of 50ms between checks (called Ta). A typical ICE connectivity check phase completes in 100-500ms for cases where hole punching works, and may take a few seconds when falling back to relay candidates.

During connectivity checks, ICE may discover new candidates. If a STUN Binding Request arrives from an address not previously seen (a peer-reflexive candidate), ICE adds it to the candidate list and creates new pairs. This handles cases where the NAT behavior differs from what STUN initially reported.

Nomination and Completion

Once a candidate pair passes connectivity checks, the controlling agent (one side is designated controlling, the other controlled) nominates a pair for use. In regular nomination, the controlling agent may wait to test multiple pairs before nominating the best one. In aggressive nomination, every connectivity check includes a nomination flag, and the first pair that works is used immediately.

After nomination, both peers begin sending application data over the nominated pair. ICE continues monitoring the connection and can switch to a different pair if the nominated one fails (called ICE restart).

ICE Connection Establishment Peer A STUN/TURN Signaling Peer B 1. CANDIDATE GATHERING STUN Binding Request XOR-MAPPED-ADDRESS (srflx) TURN Allocate Relay address (relay candidate) 2. CANDIDATE EXCHANGE (Trickle ICE) SDP offer + ICE candidates SDP answer + candidates 3. CONNECTIVITY CHECKS (parallel, prioritized) STUN Binding Request (host → host) STUN Binding Response STUN Binding Request (srflx → srflx) [hole punch] 4. NOMINATION & DATA FLOW STUN Binding Request (USE-CANDIDATE flag) Application data flows (media, etc.)

TCP NAT Traversal Challenges

Everything described so far assumes UDP. TCP NAT traversal is significantly harder, and in many cases impossible without a relay.

The fundamental problem is TCP's connection model. A TCP connection begins with a three-way handshake (SYN, SYN-ACK, ACK), and NAT devices track connection state. When a device behind NAT sends a TCP SYN to an external server, the NAT creates a mapping and expects a SYN-ACK from that specific server. An unsolicited SYN from a different host is not a "return packet" — it is a new incoming connection attempt, and most NATs drop it.

Simultaneous TCP Open

TCP does have a rarely-used feature called simultaneous open. If both peers send SYN packets to each other at the same time, both sides transition from SYN-SENT to SYN-RECEIVED, and the connection completes without the normal client-server distinction. This is the TCP equivalent of UDP hole punching — both sides send SYNs simultaneously, creating NAT mappings on both sides.

In theory, this works. In practice, it fails far more often than UDP hole punching because:

For these reasons, TCP-based real-time communication almost always uses a relay (TURN over TCP or TLS) rather than attempting direct TCP hole punching. WebRTC prioritizes UDP and only falls back to TCP relay when UDP is completely blocked.

TCP Candidates in ICE

RFC 6544 extends ICE to support TCP candidates. It defines three TCP candidate types: active (will initiate the connection), passive (will listen), and simultaneous-open (will attempt simultaneous open). In practice, active-passive pairs only work when the passive side has a public address or port forwarding configured, and simultaneous-open pairs rarely succeed due to the problems described above. ICE-TCP exists as a specification but is infrequently relied upon for real-world traversal.

UPnP, NAT-PMP, and PCP

An alternative approach to NAT traversal is to ask the NAT device itself to create a mapping. Several protocols allow software on the internal network to request port forwarding rules programmatically:

UPnP IGD (Universal Plug and Play Internet Gateway Device)

UPnP IGD is the oldest and most widely supported protocol for automatic port mapping. A client on the internal network discovers the NAT gateway via SSDP (Simple Service Discovery Protocol) multicast, then sends SOAP (XML-over-HTTP) requests to add port mappings. The NAT device, if it supports UPnP and has it enabled, creates the mapping and returns the external address:port.

UPnP has significant drawbacks. It has no authentication — any device on the local network can create arbitrary port mappings, making it a security risk. Many enterprise networks disable UPnP entirely. The protocol is complex (XML/SOAP over HTTP over multicast discovery), and implementations across different router vendors are notoriously inconsistent. Some routers advertise UPnP support but fail silently when mappings are requested. Despite these issues, UPnP remains widely used by gaming consoles, BitTorrent clients, and other peer-to-peer applications.

NAT-PMP (NAT Port Mapping Protocol)

NAT-PMP (RFC 6886) was designed by Apple as a simpler alternative to UPnP. It uses lightweight UDP packets instead of XML/SOAP, has a smaller attack surface, and is more reliable. The client sends a 12-byte UDP request to the gateway's internal address on port 5351, and receives a response with the mapped external address:port.

NAT-PMP also lacks authentication, but its simpler design means fewer implementation bugs. It was primarily implemented in Apple routers (AirPort) and some third-party devices.

PCP (Port Control Protocol)

PCP (RFC 6887) is the successor to NAT-PMP. It adds support for IPv6, CGNAT traversal, third-party mappings, and flow-level control. PCP can request mappings not just on the immediate NAT gateway but potentially through multiple layers of NAT — critical for carrier-grade NAT deployments where the user's router is behind another NAT at the ISP.

PCP is increasingly supported in ISP-grade equipment, but adoption is uneven. WireGuard-based VPN solutions and tools like Tailscale can use PCP when available, but never rely on it — they always fall back to STUN/TURN-based traversal.

NAT Traversal in Practice: Real-World Protocols

Understanding how major protocols handle NAT traversal reveals the practical tradeoffs between the techniques described above.

WebRTC

WebRTC uses the full ICE stack. Every WebRTC peer connection gathers host, server-reflexive, and relay candidates, exchanges them via the application's signaling channel, and runs connectivity checks. WebRTC implementations typically configure both STUN and TURN servers. Google Chrome uses Google's STUN servers by default but requires the application to provide its own TURN servers. Approximately 86% of WebRTC connections succeed with direct (non-relayed) connectivity; the remaining 14% use TURN.

Tailscale and WireGuard

Tailscale implements its own NAT traversal layer on top of WireGuard. The coordination server acts as the signaling channel, exchanging STUN-discovered endpoints between peers. Tailscale uses hard NAT detection and aggressive port prediction for symmetric NATs, achieving direct connectivity rates above 90% even in challenging network environments. When direct connection fails, traffic is relayed through Tailscale's DERP (Designated Encrypted Relay for Packets) servers — a custom relay protocol optimized for WireGuard traffic that serves the same role as TURN.

Tailscale's approach is notable because it continuously re-evaluates connectivity. Even after establishing a relayed connection through DERP, the client keeps attempting direct connections in the background. If a network change makes direct connectivity possible (for example, the user switches from a restrictive corporate network to their home Wi-Fi), Tailscale upgrades to a direct connection transparently.

SIP and VoIP

SIP (Session Initiation Protocol) predates ICE and historically struggled with NAT traversal. Early SIP deployments used ALGs (Application Layer Gateways) in NAT devices to rewrite SIP messages, which was fragile and unreliable. Modern SIP implementations use ICE, but many legacy systems rely on media proxies (functionally equivalent to TURN servers) or SRTP (Symmetric RTP) — a technique where the media gateway sends packets to the source address of received packets rather than the address specified in the SIP signaling.

Gaming

Online games face the same NAT traversal problems but often operate under tighter latency constraints than voice or video. Many games use UPnP as the first choice (because it creates a true port mapping with no relay overhead), fall back to UDP hole punching, and only use relays as a last resort. Console platforms (PlayStation Network, Xbox Live) operate STUN-like infrastructure to facilitate peer-to-peer game sessions. The common "NAT Type" indicator in console network settings (Type 1/Open, Type 2/Moderate, Type 3/Strict) maps roughly to the cone/symmetric classification described above.

Mapping Lifetime and Keepalives

NAT mappings are not permanent. UDP mappings in most consumer NATs expire after 30-120 seconds of inactivity. TCP mappings typically last longer (minutes to hours) because TCP has explicit connection teardown (FIN/RST). If a mapping expires while an application still needs it, the external address:port changes, and the peer can no longer reach the device.

Applications that need persistent NAT mappings must send keepalive packets at intervals shorter than the NAT's mapping timeout. STUN defines a keepalive mechanism: the client periodically sends STUN Binding Indications (a lightweight message that expects no response) to keep the mapping alive. WireGuard sends keepalive packets every 25 seconds by default. Tailscale tunes keepalive intervals based on the detected NAT timeout.

RFC 4787 recommends that NATs use a minimum UDP mapping timeout of 2 minutes, but compliance is inconsistent. Some mobile carrier NATs use timeouts as short as 15-30 seconds to conserve port resources in their CGNAT pool. Applications targeting mobile networks must use aggressive keepalive intervals to maintain connectivity.

IPv6 and the Future of NAT Traversal

IPv6 was designed to eliminate the need for NAT entirely. With 128-bit addresses providing 3.4 × 1038 unique addresses, every device can have its own globally routable address. In a pure IPv6 network, two devices can simply connect directly — no STUN, no TURN, no hole punching. The NAT traversal problem ceases to exist.

In reality, the transition is incomplete. As of 2026, roughly 45% of internet traffic uses IPv6. Many networks remain IPv4-only or dual-stack, and CGNAT deployments are increasing as IPv4 addresses become scarcer. NAT traversal will remain essential for the foreseeable future, though applications that support IPv6 natively benefit from simpler connectivity when both peers have IPv6 addresses.

Even in IPv6 networks, stateful firewalls (which block unsolicited inbound connections) create a similar traversal challenge. ICE works equally well with IPv6 — host candidates are simply IPv6 addresses, and connectivity checks proceed the same way. The difference is that server-reflexive candidates are unnecessary (there is no NAT to discover the mapping of) and relay candidates are only needed if a firewall blocks direct traffic.

Security Considerations

NAT traversal introduces security concerns because its core purpose is to circumvent network boundaries:

Look Up Your NAT-Translated Address

NAT traversal techniques exist because NAT hides your device's real address behind your router's public IP. That public IP — the one the rest of the internet sees — is the address announced in BGP by your ISP's autonomous system, reachable via the prefix your router's WAN address belongs to. Whether your traffic reaches its destination directly via hole punching or through a TURN relay, it ultimately traverses the same BGP paths. Use the god.ad BGP Looking Glass to look up your public IP and see how your traffic is routed across the global internet.

See BGP routing data in real time

Open Looking Glass
More Articles
What is DNS? The Internet's Phone Book
What is an IP Address?
IPv4 vs IPv6: What's the Difference?
What is a Network Prefix (CIDR)?
How Does Traceroute Work?
What is a CDN? Content Delivery Networks Explained