NAT Types & Behavior
How different NATs affect connectivity — RFC 4787 classification
RFC 4787: The Modern Classification
The old "cone NAT" terminology is imprecise and frequently misused. RFC 4787 (2007) replaced it with two orthogonal axes: mapping behavior (how the NAT creates outbound bindings) and filtering behavior (which inbound packets the NAT lets through). Every NAT is described as a combination of one mapping behavior and one filtering behavior.
Note
Why this matters: When you're debugging why two nodes behind NAT can't connect directly, the mapping behavior determines whether STUN can even give you a useful external address, and the filtering behavior determines whether the remote peer's packets will be accepted.
Mapping Behavior
When an internal host 192.168.1.5:12345 sends a UDP packet outbound, the NAT assigns an external IP:port. The question is: does sending to a different destination reuse the same external mapping?
Endpoint-Independent Mapping (EIM)
EIM: Same source always gets the same external mapping
Once the NAT maps 192.168.1.5:12345 to 203.0.113.1:54321, that mapping is reused for all destinations. Sending to 8.8.8.8:53 or 1.1.1.1:443 both use 203.0.113.1:54321.
192.168.1.5:12345203.0.113.1:54321Tip
Key insight: Because the external mapping is stable regardless of destination, a STUN server can tell you your public IP:port and that address will be valid for communicating with any peer. This is what makes hole-punching possible.
Address-Dependent Mapping (ADM)
ADM: Mapping depends on the destination IP
The NAT reuses the same external mapping only when sending to the same destination IP. A new destination IP gets a new external port.
192.168.1.5:12345Address & Port-Dependent Mapping (APDM)
APDM: Mapping depends on destination IP AND port
Each unique destination IP:port pair gets its own external mapping. This is the most restrictive mapping behavior.
192.168.1.5:12345Warning
Why APDM is devastating for traversal: When you ask a STUN server "what's my public IP:port?", the answer is only valid for talking back to that specific STUN server. A different peer will see a different external port, making the STUN-learned address useless.
Filtering Behavior
Once a mapping exists, which inbound packets does the NAT allow through to the internal host?
Endpoint-Independent Filtering (EIF)
EIF: Accept inbound from anyone
Once a mapping exists for 203.0.113.1:54321, any external host can send packets to that address and they'll be forwarded to the internal host. Essentially an open door.
Address-Dependent Filtering (ADF)
ADF: Only accept from IPs we've sent to
Inbound packets to 203.0.113.1:54321 are only accepted if the internal host previously sent a packet to that source IP (any port on that IP is fine).
Address & Port-Dependent Filtering (APDF)
APDF: Only accept from the exact IP:port we've sent to
The most restrictive. Inbound packets are only forwarded if the internal host previously sent a packet to that exact source IP:port combination.
- Any external host can send inbound
- Mapping just needs to exist
- Hole-punching trivial: one side sends, other can reach it
- Must have sent to exact
IP:port - Both sides must send to each other simultaneously
- Requires precise coordination or relay
Legacy Terminology Mapping
The original RFC 3489 (2003) defined four NAT types using "cone" terminology. While outdated and imprecise, these terms are everywhere — in documentation, forums, and even some modern tools. Here's how they map to RFC 4787:
| Legacy Term | Mapping Behavior | Filtering Behavior | Traversability |
|---|---|---|---|
| Full Cone NAT | Endpoint-Independent (EIM) | Endpoint-Independent (EIF) | Easiest |
| Restricted Cone NAT | Endpoint-Independent (EIM) | Address-Dependent (ADF) | Moderate |
| Port-Restricted Cone NAT | Endpoint-Independent (EIM) | Addr+Port-Dependent (APDF) | Moderate |
| Symmetric NAT | Addr+Port-Dependent (APDM) | Addr+Port-Dependent (APDF) | Hardest |
Note
Observation: All three "cone" types share EIM mapping. The crucial distinction is that Symmetric NAT is the only one with dependent mapping. This is why Symmetric NAT is in a class of its own for traversal difficulty — STUN simply cannot provide a useful address.
How NAT Type Affects Traversability
Hole-punching relies on two things: (1) knowing your peer's external IP:port (requires predictable mapping) and (2) the peer's NAT allowing your packets through (depends on filtering). Here's which combinations allow direct connectivity:
| Peer A \ Peer B | Full Cone | Restricted Cone | Port-Restricted | Symmetric |
|---|---|---|---|---|
| Full Cone | Direct | Direct | Direct | Direct |
| Restricted Cone | Direct | Direct | Direct | Port prediction needed |
| Port-Restricted | Direct | Direct | Direct | Relay required |
| Symmetric | Direct | Port prediction needed | Relay required | Relay required |
Why Symmetric + Port-Restricted (or worse) Requires Relay
- Symmetric NAT peer A sends to STUN and gets
:54321— but when A sends to peer B, the NAT assigns a different port, say:54399 - Peer B was told A's address is
:54321— B sends to:54321, which the NAT drops (wrong mapping) - Even if B guesses the right port, Port-Restricted filtering on B's NAT will drop A's packets because B hasn't sent to A's real (unknown) port
- Result: neither side's packets reach the other. Only a relay (TURN/DERP) can bridge this.
Symmetric NAT: The Traversal Killer
Symmetric NAT (APDM + APDF) is the most common type in enterprise networks, carrier-grade NATs, and many mobile carriers. It's specifically designed to be hard to traverse — each new destination gets a completely independent mapping.
- Host sends to STUN server at
198.51.100.1:3478. NAT creates mapping:192.168.1.5:12345 → 203.0.113.1:54321(for this destination only). - STUN replies: "Your public address is
203.0.113.1:54321." Host shares this with peer B via signaling. - Host sends to Peer B at
198.51.200.5:9999. NAT creates a new mapping:192.168.1.5:12345 → 203.0.113.1:54399(different port!). - Peer B sends to
203.0.113.1:54321(what STUN reported). NAT drops it — that mapping is only for the STUN server, not for Peer B. - Connection fails. Peer B has no way to know the real mapping (
:54399) was assigned for it.
Warning
Port prediction attacks: Some implementations try to predict the next port the Symmetric NAT will allocate (e.g., sequential allocation: 54321, 54322, 54323...). This works with some NATs but is unreliable — randomized port allocation defeats it entirely.
CGNAT: Double NAT Trouble
Carrier-Grade NAT (CGNAT, RFC 6598) is your ISP running NAT before your home/office NAT. Your traffic traverses two NAT layers, and both must be punched through for direct connectivity.
CGNAT Indicators
- Your WAN IP is in
100.64.0.0/10(RFC 6598 shared address space) — this is the dead giveaway tracerouteshows extra hops before reaching public internet- Port forwarding on your router doesn't work (the ISP NAT doesn't know about it)
tailscale netcheckwill report if it detects CGNAT
- One translation layer
- Port forwarding works
- STUN reveals your actual public IP
- Hole-punching success: high (if EIM)
- Two translation layers to traverse
- Port forwarding useless (ISP layer blocks it)
- STUN still works (reveals ISP's public IP)
- Hole-punching: depends on ISP NAT type
Tip
Silver lining: STUN/hole-punching can still work through CGNAT if the ISP's NAT uses EIM. STUN discovers the final public IP (the CGNAT's external address), and hole-punching proceeds as normal. The problem is when the CGNAT is Symmetric — then you're stuck with a relay.
Testing Your NAT Type
STUN-Based Testing
Classic STUN-based NAT type detection (RFC 3489 algorithm) works by sending requests to a STUN server from the same local port but to different server IPs/ports, then comparing the resulting mapped addresses:
Send to Server IP1:Port1
Get mapped address A
Send to Server IP2:Port1
Get mapped address B
Compare A and B
Same = EIM, Different = APDM
Test filtering
Ask server to send from different port
Using tailscale netcheck
$ tailscale netcheck
Report:
* UDP: true
* IPv4: yes, 203.0.113.50:29876
* IPv6: yes, [2001:db8::1]:54321
* MappingVariesByDestIP: false
* HairPinning: true
* PortMapping: UPnP, PMP, PCP
* CaptivePortal: false
* Nearest DERP: San Francisco
* DERP latency:
- sf: 2.1ms
- lax: 5.3ms
- sea: 12.1ms
Key Fields in tailscale netcheck
| Field | What It Means |
|---|---|
MappingVariesByDestIP |
false = EIM (good), true = APDM/Symmetric (bad for direct connections) |
HairPinning |
Can two hosts behind the same NAT talk via their public addresses? Needed for some topologies. |
PortMapping |
UPnP/NAT-PMP/PCP availability — these let the client request specific port mappings from the NAT. |
UDP |
Whether UDP works at all. If false, everything must go over DERP (HTTPS relay). |
Nearest DERP |
The closest relay server — used as fallback when direct fails. |
Tip
In practice: Tailscale reports that roughly 92% of connections succeed as direct (no relay), despite the prevalence of NAT. This is because most consumer NATs use EIM, and Tailscale's connection engine tries multiple strategies (STUN, UPnP, NAT-PMP, PCP, birthday attacks on port prediction) before falling back to DERP relay.
Quick Reference
Full Cone
Restricted Cone
Port-Restricted
Symmetric
Easiest to traverse ←→ Hardest to traverse