NAT Types Explained
View SourceUnderstanding NAT (Network Address Translation) types is essential for building P2P applications that work across different network environments. This guide explains the NAT classification model used in Macula based on the NATCracker methodology.
Why NAT Matters for P2P
When two peers behind NAT want to communicate directly:
Peer A (192.168.1.10) Peer B (192.168.2.20)
| |
[NAT A] [NAT B]
| |
203.0.113.5:40000 198.51.100.8:50000
| |
+------------ Internet ----------------+The challenge: Neither peer can initiate a connection to the other because NATs block unsolicited incoming traffic.
NAT Policy Classification
Macula uses the NATCracker 3-policy classification model to characterize NAT behavior. Each NAT is described by three policies:
1. Mapping Policy (How NAT assigns external addresses)
| Policy | Code | Behavior | Prevalence |
|---|---|---|---|
| Endpoint-Independent | EI | Same external addr for all destinations | ~52% |
| Host-Dependent | HD | Different external addr per destination host | ~12% |
| Port-Dependent | PD | Different external addr per destination host:port | ~36% |
Example - Endpoint-Independent (EI):
Local: 192.168.1.10:5000
-> Destination A: 8.8.8.8:53 => NAT maps to 203.0.113.5:40000
-> Destination B: 1.1.1.1:53 => NAT maps to 203.0.113.5:40000 (same!)Example - Port-Dependent (PD):
Local: 192.168.1.10:5000
-> Destination A: 8.8.8.8:53 => NAT maps to 203.0.113.5:40000
-> Destination B: 1.1.1.1:53 => NAT maps to 203.0.113.5:40001 (different!)2. Filtering Policy (What incoming traffic NAT accepts)
| Policy | Code | Behavior | Security |
|---|---|---|---|
| Endpoint-Independent | EI | Accepts from any source | Low |
| Host-Dependent | HD | Accepts from hosts we've contacted | Medium |
| Port-Dependent | PD | Accepts from host:port we've contacted | High |
Example - Port-Dependent filtering:
Local 192.168.1.10:5000 sends to 8.8.8.8:53
NAT now accepts incoming on 203.0.113.5:40000 ONLY from 8.8.8.8:53
-> 8.8.8.8:53 => ALLOWED
-> 8.8.8.8:80 => BLOCKED (wrong port)
-> 1.1.1.1:53 => BLOCKED (wrong host)3. Allocation Policy (How NAT chooses external ports)
| Policy | Code | Behavior | Predictability |
|---|---|---|---|
| Port-Preservation | PP | external_port = local_port | High |
| Port-Contiguity | PC | external_port = last_port + delta | Medium |
| Random | RD | No predictable pattern | None |
Example - Port-Preservation (PP):
Local: 192.168.1.10:5000 => NAT: 203.0.113.5:5000 (same port!)Example - Port-Contiguity (PC):
Local: 192.168.1.10:5000 => NAT: 203.0.113.5:40000
Local: 192.168.1.10:5001 => NAT: 203.0.113.5:40001 (delta = 1)Common NAT Type Combinations
Based on NATCracker research across millions of NATs:
| Type | Mapping | Filtering | Allocation | Prevalence | Direct P2P |
|---|---|---|---|---|---|
| Full Cone | EI | EI | PP | 15% | Yes |
| Restricted Cone | EI | HD | PP | 37% | With punch |
| Port Restricted | EI | PD | PP | 20% | With punch |
| Symmetric | PD | PD | RD | 12% | No (relay) |
| CGNAT | varies | PD | varies | 16% | Usually relay |
Full Cone NAT (EI, EI, PP) - Best Case
Internet
|
[Full Cone NAT]
|
203.0.113.5:5000
|
Any external host can send to this address
after ANY outbound packet from local peer
Direct P2P: YES - Any peer can connect directlyRestricted Cone NAT (EI, HD, PP) - Good
Local sends to Host A
-> External: 203.0.113.5:5000
Now Host A (any port) can send back
Host B cannot send (never contacted)
Direct P2P: YES with hole punchingSymmetric NAT (PD, PD, RD) - Worst Case
Local sends to Host A:Port1 -> NAT: 203.0.113.5:40000
Local sends to Host B:Port2 -> NAT: 203.0.113.5:40001 (different!)
Each destination gets different external address
External port is random and unpredictable
Direct P2P: NO - must use relayNAT Detection in Macula
Macula detects NAT type automatically using macula_nat_detector:
%% Get local NAT profile
{ok, Profile} = macula_nat_detector:get_local_profile().
%% Profile contains:
#{
mapping => ei, % Endpoint-Independent
filtering => pd, % Port-Dependent
allocation => pp, % Port-Preservation
public_ip => {203,0,113,5},
public_port => 5000,
detected_at => 1700000000
}Detection Algorithm
Send NAT_PROBE to primary observer (gateway/public peer)
- Receive reflexive address (your public IP:port as seen from outside)
Send NAT_PROBE to secondary observer (different public peer)
- Compare reflexive addresses
Classification:
- Same address for both observers -> EI mapping
- Same IP, different port -> HD mapping
- Different IP -> PD mapping (or multiple NATs)
Connection Strategy Decision Tree
Macula's macula_nat_coordinator uses this decision tree:
Start: Want to connect Peer A <-> Peer B
|
v
Either has public IP?
|-- YES -> Direct connection to public peer
|-- NO -> Check NAT profiles
|
v
Both have EI mapping?
|-- YES -> Hole punching possible
| |
| v
| Any has EI filtering?
| |-- YES -> Simple hole punch
| |-- NO -> Coordinated hole punch
|
|-- NO -> Either has PD+PD+RD (symmetric)?
|-- YES -> Must use relay
|-- NO -> Try hole punch with predictionHole Punching Explained
Hole punching creates NAT mappings that allow peers to communicate:
Time T0: Peer A and B have no mappings to each other
Time T1: Coordinator tells both peers to send packet
Peer A sends to Peer B's predicted external addr
Peer B sends to Peer A's predicted external addr
Time T2: Packets arrive at NATs
NAT A: Creates mapping for B's address (outbound packet)
NAT B: Creates mapping for A's address (outbound packet)
Time T3: Subsequent packets pass through created mappings
Direct communication established!Requirements for successful hole punch:
- Both NATs have EI or HD mapping (predictable external address)
- At least one has PP or PC allocation (predictable port)
- Timing coordination within ~100ms
CGNAT (Carrier-Grade NAT)
ISPs increasingly use CGNAT, adding another NAT layer:
Your Device (192.168.1.10)
|
[Home Router NAT]
|
10.0.0.50 (ISP private)
|
[CGNAT]
|
203.0.113.5 (public)
|
InternetCGNAT complications:
- Multiple customers share same public IP
- Often uses PD filtering (restrictive)
- Hole punching success rate drops to ~40%
- Relay fallback frequently needed
Best Practices
For Application Developers
- Always have relay fallback - Some NATs cannot be traversed
- Detect NAT type early - Cache profile at peer startup
- Prefer EI-mapping peers as coordinators - Better success rate
For Network Operators
- Use Full Cone or Restricted Cone NAT - Best P2P compatibility
- Enable UPnP/NAT-PMP - Allows applications to request mappings
- Avoid Symmetric NAT - Breaks most P2P protocols
Further Reading
- RFC 5780 - NAT Behavior Discovery
- NATCracker Paper - 27 NAT type classification
See Also:
- NAT Traversal Developer Guide - API usage and code examples