Ports and NAT Traversal

On this page

A sends a request to the STUN server from the same UDP socket and obtains the external address 203.0.113.10:62000, which it tells B. However, packets sent by B do not reach A: this may be because A used a different mapping when communicating with B, or because the mapping is the same but inbound filtering does not allow B. NAT traversal requires handling both issues simultaneously and confirming candidate paths through actual connectivity checks.

MechanismProvidesDoes Not Guarantee
Local Port AllocationDistinguishes sockets/transport endpointsEvery connection globally exclusively uses one port number
NAT MappingState correspondence between internal/external addresses and portsAny external source can enter inbound
STUNObserve mappings and build connectivity checksAutomatically open paths to all peers
TURNAllocate and maintain relay carriersRelay is always reachable, without resource or authentication failures
ICECollect candidates, check candidate pairs, and nominateDirectly measure and select the globally lowest RTT path

Port Capacity: Clarify Which Fields Are Fixed

TCP connections are typically distinguished by source/destination addresses and ports within the corresponding network context. The same local port may be used to connect to different remote endpoints, so the statement "with 28,232 ephemeral ports, you can only establish a total of 28,232 TCP connections" is incorrect. Explicit binds, different socket usage, target concentration, and NAT allocation policies alter multiplexing conditions. Cloudflare: Ephemeral Ports and Connection Quadruplet Experiments

If the ephemeral range is 32768–60999, there are 28,232 numbers including both ends. For a fixed source IP and fixed destination IP:port, temporarily ignoring reserved ports, concurrent survival, and secure multiplexing, if each short connection occupies the quadruplet for about 60 seconds, the magnitude estimate is 28,232/60 ≈ 470 new connections per second. This is a capacity budget under restricted conditions, not the global performance upper limit of the machine.

Expanding source addresses, multiplexing connections, and reducing invalid short connections may change the budget; increasing the port range does not fix limitations on file descriptors, memory, conntrack, or upstream NAT port quotas. Identify the failure point first, then explain errors like EADDRNOTAVAIL; do not unconditionally modify TIME_WAIT parameters just because an error occurs.

# Read-only verification of local configuration and connection status; this article does not modify these parameters.
cat /proc/sys/net/ipv4/ip_local_port_range
cat /proc/sys/net/ipv4/ip_local_reserved_ports
ss -s
ss -tan state time-wait

UDP does not have the TCP TIME_WAIT state, but the mapping and filtering states reserved by NAT/conntrack for UDP may still occupy resources, time out, or be reclaimed; the two cannot be treated as a single timer.

Mapping and Filtering: Two Independent Classification Axes

Mapping and filtering answer two separate questions Mapping: Which external endpoint to use when going out Same local socket → different destinations Filtering: Which external sources are allowed in External endpoint already exists → is it admitted? EIM: Can reuse the same mapping Still can only receive from contacted IP:port Endpoint-Independent Mapping does not mean anyone can enter; do not simply equate Full Cone with EIM.

Assume the internal endpoint is fixed at I=192.168.1.10:50000, visiting S1=198.51.100.1:3478, S2=198.51.100.2:3478, and S3=198.51.100.2:9999 in sequence.

Mapping BehaviorDoes it include destination in mapping reuse conditions?Understanding in this example
Endpoint-Independent Mapping (EIM)Does not depend on external destination endpointI can reuse the same mapping for all three
Address-Dependent Mapping (ADM)Depends on external destination IPS2/S3 can reuse, S1 is not in the same group
Address and Port-Dependent Mapping (APDM)Depends on destination IP and portThree destinations are handled separately

Classifications describe the dependencies of mappings; they do not require that a never-before-seen external port be allocated every time, nor do they imply that APDM ports are necessarily random and unpredictable. Port reservation, conflict handling, and mapping classification are different dimensions. RFC 4787: UDP NAT Mappings

Filtering BehaviorWhich external sources are allowed when a mapping already exists?
Endpoint-Independent FilteringDoes not restrict sources based on previously contacted external endpoints
Address-Dependent FilteringSource IP must meet conditions established by previous outbound communication
Address and Port-Dependent FilteringBoth source IP and port must meet corresponding conditions

EIM can coexist with strict filtering; legacy Cone/Symmetric labels compress multiple behaviors into one name, which is unsuitable for precise diagnosis. You cannot assert behavior and success rates solely based on labels like "home" or "mobile network". RFC 4787: Filtering

Same Public Port, Why Are Return Packets Still Blocked?

First, contact only A:3478, then switch the filtering axis to observe the admission of the other two sources. Then contact B:3478, and switch the mapping axis to observe whether a new external endpoint is created. The allowed list for each row corresponds only to that row's mapping; you cannot use communication history from another mapping to allow it through.

Preparing the visual
Same Public Port, Why Are Return Packets Still Blocked?

Mapping answers how external endpoints are reused; filtering answers which sources can enter an existing mapping. They are not on the same axis; observing a mapping via STUN does not prove that any peer can enter.

STUN: The Server Tells You the Source It Sees

After the Binding Request passes through the NAT, the STUN server sees the translated source endpoint and returns it in the XOR-MAPPED-ADDRESS of the response. The STUN fixed header is 20 bytes, containing message type, attribute length, magic cookie, and transaction ID; subsequent attributes have type, length, and alignment rules. XOR is an encoding method, not encryption for address confidentiality. RFC 8489: STUN

For IPv4 XOR-MAPPED-ADDRESS, the port is XORed with the high 16 bits of the cookie, and the address is XORed with the full 32-bit cookie; IPv6 masks also incorporate the transaction ID. The code at the end verifies the round-trip encoding/decoding of the example 203.0.113.10:62000.

What you get is the address seen by the server during this transaction. If the mapping depends on the destination, the external endpoint for B may be different; if the state times out, the old address may also become invalid. Tests must use the sockets and context required for actual communication; do not randomly open another port to probe and use the result to replace the original socket.

Why Do UDP Hole Punching Require Both Parties to Cooperate?

A and B exchange candidate endpoints via their own application signaling channels and send check packets to each other's candidates respectively. Outbound packets may establish the corresponding mapping and filtering permissions, allowing subsequent packets from the peer to pass through. Discarding the first check does not necessarily mean failure; retries, timing, and state lifespan are all factors.

STUN is not responsible for implementing this signaling channel for the application. Hole punching is not "the STUN server forwards all subsequent data"; once a direct connection is established, application data can flow directly between the two ends. Multiple layers of NAT, different mapping behaviors, hairpin support, and outbound UDP restrictions all affect the result.

TURN: Clearly Distinguish Protocols on Both Sides of the Relay

The client first obtains a relay address and maintains an allocation via Allocate, then establishes corresponding permissions for the peer. Sending can use Send Indication; after establishing channel binding, more compact ChannelData can also be used; these are not application payloads forwarded by the server to ordinary peers as-is. RFC 8656: TURN

TURN: Client side is TURN encapsulation, peer side is relay UDP Client A Allocation established TURN Server R Relay address R:60000 Peer B Ordinary UDP peer Send Indication / ChannelData UDP: Source R:60000, Destination B UDP: Source B, Destination R:60000 Data Indication / ChannelData Requires corresponding permission; ChannelData also requires channel binding. TURN does not guarantee that the target, authentication, and network are always available.

B sends ordinary UDP to the relay address; the server receives it according to permissions and other conditions, then forwards it to A via Data Indication or ChannelData. Data Indication belongs to the TURN server-to-client side and cannot be placed on the ordinary UDP peer side. The client-to-TURN connection can choose supported carriers such as UDP, TCP, or TLS, but this does not mean that ordinary relay peers automatically switch to the same protocol.

Allocations, permissions, and channel bindings have their own lifespans and refresh rules. Credentials, quotas, server resources, and network policies can all cause relay failures; therefore, TURN provides a backup carrier rather than a "always working" solution. TLS to the relay only protects the corresponding link; for end-to-end confidentiality, business logic still relies on corresponding end-to-end encryption.

How to Budget for Latency and Bandwidth

Assume one-way A→R is 15 ms and R→B is 20 ms; ignoring queuing and processing, the relay path for this direction is about 35 ms; if the reverse is exactly symmetric, the RTT is about 70 ms. Do not add two RTTs and multiply by an unknown N as a universal formula, nor guarantee that the relay is always slower than all direct connections.

If A→B application payload is 2 Mbit/s and B→A is 1 Mbit/s, the relay needs to receive 3 Mbit/s and send 3 Mbit/s, totaling 6 Mbit/s for RX+TX, plus encapsulation and protocol overhead. Network cards, service provider billing, and capacity limits have different metrics; clarify whether the measurement is for ingress, egress, or both.

ICE: Candidate Pairs Must Be Checked and Nominated

Candidates include host (local endpoint), server-reflexive (observed from STUN), and relayed (allocated by TURN); peer-reflexive candidates may also be discovered during checks. Both parties exchange candidates and ICE credentials via signaling, forming comparable candidate pairs and arranging STUN connectivity checks. RFC 8445: ICE

Candidate priority is often constructed as 2²⁴×type_pref + 2⁸×local_pref + (256−component_id). Type preference is a policy preference, not a measured RTT. Successful checks produce usable candidate pairs; the controlling role determines the pair to use via nomination, the controlled role cooperates, and there are rules for handling role conflicts.

Candidate pairs do not only exist in the neat combinations of host↔host, srflx↔srflx, and relay↔relay. Sorting, check scheduling, triggered checks, and nomination form a complete process; do not draw it as a fixed serial ladder where "any relay is considered only after all direct connections completely fail." Applications can also restrict candidate types for privacy or network policy reasons.

Trickle ICE allows incremental delivery of candidates, allowing collection and checking to overlap; it does not exempt authentication, checks, or nomination. When the network changes, corresponding restart or persistence mechanisms are still needed; initial success does not guarantee permanent availability of candidates. RFC 8838: Trickle ICE

Tailscale as an Implementation Case

Tailscale has direct and relay paths; official documentation also distinguishes between DERP and peer relay. The system can first use available relays to maintain connections while attempting more suitable direct connections; relay communication and direct discovery can overlap.

DERP is not another name for TURN; specific path establishment, WireGuard encrypted carriers, and relay services should be understood according to product documentation. Random port allocation increases the difficulty of probing, but "random means it is mathematically impossible to hit" is also incorrect; do not rely on infinite port probing to replace reliable relay design. Tailscale Connection Types

Diagnostic Order: Locate Where State is Lost

Known PhenomenonPriority Check
Local socket establishment failurePorts, binding method, FD/memory, and error codes
STUN no responseServer reachability, transaction matching, protocol, and filtering
Has srflx but direct connection failsSame socket, destination-dependent mapping, bidirectional filtering, state lifespan
TURN allocation successful but no dataPermission, channel, relay address, and peer path
ICE checks successful but no application dataNomination result, application mapping, encryption state, and subsequent path changes

IPv6 can reduce the need for IPv4 address translation, but having a global address does not mean the firewall allows inbound traffic; ICE can still be used to select and verify paths. Port mapping tools explicitly request mappings on manageable gateways, which is a different approach from observing NAT behavior with STUN.

Local Example: XOR Address and Capacity

from ipaddress import IPv4Address
import struct

cookie = 0x2112A442
port = 62000
address = int(IPv4Address('203.0.113.10'))
value = struct.pack('!BBHI',0,1,port^(cookie>>16),address^cookie)
reserved,family,xport,xaddress = struct.unpack('!BBHI',value)
assert reserved == 0 and family == 1
assert xport^(cookie>>16) == port
assert str(IPv4Address(xaddress^cookie)) == '203.0.113.10'
assert value.hex() == '0001d322ea12d548'
assert 60999-32768+1 == 28232
assert 470 < 28232/60 < 471

def priority(type_pref,local_pref,component):
    return (1<<24)*type_pref+(1<<8)*local_pref+256-component
assert priority(126,65535,1) == 2130706431
assert priority(126,65535,1)>priority(100,65535,1)>priority(0,65535,1)
assert 2*(2+1) == 6
print('STUN IPv4 XOR attribute, port budget, ICE priority, and relay traffic check passed')

The example does not include complete STUN transactions, authentication, or ICE state machines; no hole punching, port scanning, relay allocation, or gateway configuration is initiated.

Continue Reading

  • TCP: Quadruplets, TIME_WAIT, and connection lifecycle.
  • UDP and QUIC: Datagrams, migration, and path verification.
  • WebRTC: Combination of ICE and media negotiation.
  • Tailscale Architecture: Division of labor among control, direct connection, and relay.