UDP NAT traversal is surprisingly difficult because UDP is a connectionless protocol, and NAT devices, by their nature, need to track connection state to translate addresses and ports.

Let’s see this in action. Imagine two peers, Alice and Bob, both behind NATs, trying to establish a direct UDP connection.

Alice’s machine: 192.168.1.100:5000 Alice’s NAT: 203.0.113.10:12345 (external IP and port) Bob’s machine: 192.168.1.200:6000 Bob’s NAT: 198.51.100.20:67890 (external IP and port)

If Alice wants to send a UDP packet to Bob, she doesn’t know Bob’s external IP and port directly. She might know Bob’s internal IP and port (192.168.1.200:6000), but her packet will never reach Bob’s machine because it will be dropped by Bob’s NAT. Similarly, if Bob sends a packet to Alice’s internal IP, it will never reach her.

The core problem is that NAT devices, especially stateful ones, expect incoming packets to correspond to an established outgoing connection. For UDP, which doesn’t have explicit connection establishment like TCP, this is a problem. When a packet arrives at a NAT from an external IP and port, the NAT checks its translation table. If there’s no entry for that specific external IP/port pair (meaning no outgoing UDP packet from the internal host established this mapping), the NAT will typically drop the packet.

Here are the common techniques to overcome this:

1. UDP Hole Punching

This is the most fundamental technique. The idea is to get both peers to send UDP packets to each other simultaneously.

  • How it works:

    1. Rendezvous Server: Alice and Bob both connect to a publicly accessible rendezvous server. This server knows their external IP addresses and the ports their NATs assigned for outgoing UDP traffic.
    2. Information Exchange: The rendezvous server tells Alice Bob’s external IP (198.51.100.20:67890) and tells Bob Alice’s external IP (203.0.113.10:12345).
    3. Simultaneous Send: Alice sends a UDP packet to 198.51.100.20:67890, and Bob sends a UDP packet to 203.0.113.10:12345 around the same time.
    4. NAT Translation: When Alice’s packet hits Bob’s NAT, Bob’s NAT sees an outgoing UDP packet from 192.168.1.200:6000 to 203.0.113.10:12345. It creates a translation entry: external_ip:port -> internal_ip:port. Now, when Alice’s packet arrives from 203.0.113.10:12345, Bob’s NAT knows to forward it to 192.168.1.200:6000. The same happens in reverse for Bob’s packet hitting Alice’s NAT.
    5. Direct Connection: After this, Alice and Bob can send UDP packets directly to each other’s external IP addresses and ports.
  • Why it works: The outgoing UDP packets create temporary entries in the NAT’s state table. When the "other" peer’s packet arrives from the external IP/port pair that was just used for the outgoing packet, the NAT sees it as a valid response and allows it through.

2. STUN (Session Traversal Utilities for NAT)

STUN is a protocol designed to discover the public IP address and port mapping assigned by a NAT. It’s often used in conjunction with UDP hole punching.

  • How it works:

    1. Client Request: A client behind a NAT sends a STUN "Binding Request" to a public STUN server.
    2. Server Response: The STUN server receives the request and sends back a STUN "Binding Success Response." This response contains the client’s external IP address and port as seen by the server.
    3. Mapping Discovery: The client receives this response and now knows its public IP and port. This information can then be shared with other peers (e.g., via a signaling server) to facilitate hole punching.
  • Why it works: STUN relies on the same NAT behavior as hole punching: an outgoing packet creates a mapping. The STUN server simply reports back what it sees the source IP/port to be.

3. TURN (Traversal Using Relays around NAT)

TURN is a fallback mechanism when direct P2P connections (even with hole punching) fail. It acts as a relay.

  • How it works:

    1. Relay Allocation: A client behind a NAT connects to a TURN server and requests to allocate a relay address. The TURN server reserves a port on its public IP for this client.
    2. Data Relaying: When Alice wants to send data to Bob, she sends it to the TURN server. The TURN server then forwards this data to Bob’s known external IP/port. Similarly, when Bob sends data, it goes to the TURN server, which forwards it to Alice.
    3. P2P Attempt: TURN servers can also facilitate P2P connections. If a client can successfully punch a hole, TURN can be used to send the initial "allow" packet to the other peer, helping to establish the P2P link.
  • Why it works: It bypasses NAT entirely by acting as a middleman. All traffic goes through the TURN server, which is on the public internet and can reach any peer. This is more robust but incurs higher latency and bandwidth costs.

4. ICE (Interactive Connectivity Establishment)

ICE is a framework that combines STUN and TURN to provide the most reliable P2P connection. It systematically tries various methods.

  • How it works:

    1. Candidate Gathering: Each peer gathers a list of "candidates" for connecting. These include:
      • Host Candidates: Direct IP addresses on the local network.
      • Server Reflexive Candidates: IP/port pairs discovered via STUN (their public IP/port).
      • Relayed Candidates: IP/port pairs on a TURN server.
    2. Connectivity Check: Peers exchange their candidate lists (via a signaling server). Then, they systematically try to establish connections between all possible pairs of candidates (e.g., Alice’s host candidate to Bob’s server reflexive candidate, Alice’s server reflexive to Bob’s server reflexive, etc.). STUN is used extensively during these checks to verify reachability.
    3. Best Path Selection: ICE prioritizes the fastest and most direct connection path that works. If a direct P2P path (host-to-host, host-to-server-reflexive, server-reflexive-to-server-reflexive) is established, it’s preferred. If not, it falls back to using a TURN relay.
  • Why it works: ICE is a comprehensive strategy that exhaustively tries all known methods for establishing connectivity, using STUN to verify and TURN as a last resort, ensuring the highest probability of a successful P2P connection.

5. UDP Fragmentation and Reassembly

This isn’t strictly NAT traversal, but it’s a crucial related problem. When UDP packets traverse networks, they can be fragmented if they exceed the Maximum Transmission Unit (MTU) of any link. NAT devices, especially those performing Network Address Port Translation (NAPT) which modifies packet headers, can interfere with this process.

  • Problem: If a UDP packet is fragmented, and the NAT needs to translate the source IP/port, it can only do so for the first fragment which contains the UDP header. Subsequent fragments, which do not contain the UDP header, will not have their source address translated, and the receiving NAT will likely drop them because they don’t match any outgoing connection state.
  • Solution: The most common solution is Path MTU Discovery (PMTUD) or, more reliably for UDP, simply ensuring that applications do not send UDP packets larger than a common MTU (e.g., 1500 bytes, or even smaller like 1200 bytes to be safe across various network types) and that they handle fragmentation themselves if necessary. Some applications might use techniques like "packet coalescing" or "segmentation" at the application layer to avoid fragmentation altogether.

The underlying challenge for all these techniques is the inherent statefulness of NAT devices, which are designed to manage TCP connections but struggle with the stateless nature of UDP.

The next hurdle you’ll likely encounter is dealing with symmetric NATs, which are particularly challenging for hole punching.

Want structured learning?

Take the full Udp course →