TCP Traversal Through NATs and Firewalls: How TCP Connections Cross Network Boundaries
Most devices on the internet today sit behind a NAT. Your laptop, your phone, your office router, all of them usually share one public IP address with dozens or hundreds of other devices. This works fine for normal browsing. But it creates real problems for TCP connections that need to start from outside your network, like video calls, file sharing apps, or remote access tools. This article explains how TCP behaves when NAT and firewalls get in the way, why some connections just refuse to work, and what techniques exist to fix that.
How TCP connections normally start
TCP connections begin with a three-way handshake. The client sends a SYN packet. The server replies with a SYN-ACK. The client sends back an ACK. After that, both sides can send data.
This handshake assumes something simple: the server has a fixed, reachable address, and the client can send a packet straight to it. That assumption breaks down once NAT is involved, because the "server" a device behind NAT would need is not directly reachable from outside.
What NAT actually does
Network Address Translation lets many private devices share one public IP address. When a device behind a NAT router sends a packet out, the router rewrites the source IP and port, then keeps track of that mapping in a table. When a reply comes back to that public IP and port, the router looks up the table and forwards the packet to the right internal device.
This works well for outbound connections. Your laptop opens a connection to a website, the NAT remembers it, and replies flow back correctly. The trouble starts when a connection needs to come from the outside in, because there is no existing mapping in the table for the NAT to match against. The incoming SYN packet has nowhere to go, so the router usually just drops it.
NAT types and mapping behavior
Not all NAT devices behave the same way, and this is the part that decides whether traversal techniques will even work. RFC 4787 and RFC 5382 describe this in terms of two separate behaviors: how a NAT assigns mappings, and how it filters incoming packets.
Mapping behavior determines whether the NAT reuses the same public port for a given internal address and port, no matter which external host it's talking to.
- Endpoint-Independent Mapping: the NAT keeps using the same external port for a given internal source, regardless of the destination. If your device opens two connections from the same internal port to two different servers, both get the same external port.
- Address-Dependent Mapping: the external port stays the same only if the destination IP address stays the same.
- Address and Port-Dependent Mapping: a new external port gets assigned for every distinct destination IP and port pair. This is what used to be called Symmetric NAT.
Filtering behavior determines which incoming packets the NAT will actually let through to a mapping that already exists.
- Endpoint-Independent Filtering: any external host can send a packet to the mapped port and it gets through.
- Address-Dependent Filtering: only packets from an IP address you've already sent to are allowed in.
- Address and Port-Dependent Filtering: only packets from the exact IP and port you've already sent to are allowed in.
Endpoint-Independent Mapping combined with Endpoint-Independent Filtering is the easiest case for traversal, since one outbound packet opens the door for anyone. Address and Port-Dependent behavior on both sides is the hardest, since the external port can't be predicted ahead of time and only the exact peer can get through.
Firewalls and TCP filtering
Firewalls add another layer on top of NAT, and they don't always follow the same rules. A stateful firewall tracks which connections were started from inside the network and only allows return traffic for those. Unlike NAT, a firewall can exist even when there's no address translation happening at all, such as on a network with public IPs assigned to every device.
Most firewalls block unsolicited inbound SYN packets by default. This is a security feature, not a bug, since it stops random hosts on the internet from probing devices on your network. But it's also exactly the behavior that breaks direct peer-to-peer TCP connections.
Why some TCP connections fail through NAT
A few specific things go wrong:
- No inbound path exists. If Device A is behind NAT and Device B tries to connect first, there's no mapping table entry for A yet, so the SYN never reaches it.
- Both devices are behind NAT. Neither side can accept an unsolicited inbound connection, so neither one can act as the "server."
- Symmetric NAT unpredictability. If a NAT uses Address and Port-Dependent Mapping, the external port assigned to a connection depends on who it's talking to. A peer can't guess this port in advance, which breaks most traversal tricks.
- Firewall policy blocks new inbound flows outright, regardless of what NAT is doing underneath.
- TCP simultaneous open isn't well supported. TCP does have a mechanism for two hosts to send SYNs to each other at the same moment and complete a handshake without a traditional client and server role, but many NAT implementations and some operating systems handle this poorly or block it.
TCP hole punching
TCP hole punching is a technique that lets two devices, each behind their own NAT, establish a direct connection without a relay server carrying all the traffic afterward.
The basic idea:
- Both devices connect to a third party, a rendezvous server, that both can reach normally. Through this server, they exchange their public IP addresses and ports as seen by the outside world.
- Each device then tries to open a TCP connection directly to the other device's public IP and port, at roughly the same time.
- Each outbound SYN attempt causes the local NAT to open a mapping, effectively punching a hole for return traffic.
- If timing and NAT behavior line up, the SYN from one side arrives just as the local NAT has already opened a matching hole, and the connection completes, often using TCP simultaneous open rather than a normal client and server handshake.
TCP hole punching is more likely to succeed when NAT behavior permits predictable mappings and accepts the resulting inbound traffic. Restrictive mapping or filtering can cause traversal to fail. When either side is behind a NAT with Address and Port-Dependent Mapping, the external port the rendezvous server observed may not be the port that will actually be used for the connection to the other peer, which is why success rates drop off sharply in that case. The measurement results later in this article put real numbers on how often each scenario actually works.
NAT traversal techniques in practice
STUN (Session Traversal Utilities for NAT), described in RFC 5389 and its successor RFC 8489, lets a device ask a public server what its own public IP and port look like from outside. This is the basic building block for hole punching, since a device needs to know its own external address before it can share it with a peer.
TURN (Traversal Using Relays around NAT), RFC 5766 and later RFC 8656, is the fallback when direct traversal fails. A public relay server forwards all traffic between the two peers. It always works, but it costs bandwidth and adds latency, since every packet takes a detour.
ICE (Interactive Connectivity Establishment), RFC 8445, ties STUN and TURN together. Both sides gather a list of possible addresses, called candidates, covering their local IP, their address as seen by STUN, and a relay address from TURN. They exchange these lists and test each combination, then use whichever pairing actually works. RFC 6544 extends ICE specifically for TCP candidates, which matters here because most ICE deployments were originally built around UDP for media streams.
UPnP IGD and NAT-PMP / PCP let a device directly ask its own router to open a specific port and forward it inward. This avoids hole punching entirely, but only works when the router supports the protocol and it's turned on, which isn't universal on consumer or enterprise hardware.
Application Level Gateways (ALGs) are a feature some routers include to specifically watch and rewrite certain protocols, like FTP, as they pass through NAT. They're protocol-specific and don't generalize to arbitrary TCP traffic, and they sometimes cause more problems than they solve when they misinterpret payload data.
Real examples
- Peer-to-peer file sharing tools often try a direct TCP connection first, fall back to hole punching using a tracker or rendezvous server for peer discovery, and fall back again to a relay if both fail.
- Remote desktop and remote access tools frequently rely on a broker service the client and host both dial out to, since dialing out is unaffected by NAT, then attempt to upgrade to a direct connection once both sides have exchanged address information.
- Online multiplayer games commonly use a mix of UDP hole punching for gameplay traffic and TCP for lobby or matchmaking servers, precisely because TCP hole punching is less reliable across the full range of NAT types found on home routers.
- VoIP and video calling apps typically default to using ICE, attempting a direct connection first and dropping to TURN relay only when both peers report Address and Port-Dependent NAT behavior.
Comparing the core research areas
TCP NAT and firewall traversal is really a handful of separate problems that get lumped together. Here's how they relate to each other.
| Research area | What it actually studies | Main challenge | Key source |
|---|---|---|---|
| TCP traversal through NATs | Whether a direct TCP connection can form between two hosts that each sit behind their own NAT | NAT hides both endpoints, so neither can accept an unsolicited inbound SYN | Guha and Francis, IMC 2005 |
| TCP traversal through firewalls | Whether a stateful firewall, with or without NAT, will let a new inbound flow through | Firewalls apply security policy on top of NAT and can block a flow NAT would otherwise allow | RFC 5128 |
| NAT mapping and filtering behavior | How a specific NAT box assigns external ports and decides which inbound packets to accept | Behavior varies by vendor, firmware, and even changes between product revisions | RFC 4787, RFC 5382 |
| TCP simultaneous open | Whether two hosts can complete a handshake by sending SYNs to each other at the same time, with neither acting as a traditional server | Many NAT boxes and older operating systems handle this sequence incorrectly or block it | RFC 793, Guha and Francis, IMC 2005 |
| TCP hole punching | The technique that combines port prediction, timing, and simultaneous open to actually establish the connection | Depends entirely on the mapping and filtering behavior of both NATs lining up | Ford, Srisuresh, and Kegel, USENIX 2005 |
| Experimental and measurement considerations | How researchers test real NAT boxes at scale to find out what they actually do, rather than what the spec says they should do | Lab tests cover a small number of devices, while field tests draw from a biased, self-selected sample of home routers | Guha and Francis, IMC 2005 |
The first two rows describe the obstacle. The middle two describe why the obstacle is hard to predict. The last two describe the fix and how anyone would go about proving the fix works.
How TCP NAT traversal is tested
Knowing that NAT breaks TCP is one thing. Proving which NAT you're dealing with, and whether a given traversal technique will work against it, takes actual measurement. The methodology below follows the approach used in the original Cornell study on this topic, and it still holds up as a practical way to test a NAT today.
Test setup. A proper test needs two components: a client on the host behind the NAT device under test, and a server that sits fully outside that NAT, on the open internet. The client and server exchange test traffic and compare notes on what each side actually sent and received, since the whole point is to catch the places where the NAT silently changes or drops something along the way.
NAT device under test. This is the router or firewall being characterized. It can be a single consumer router, a chain of several NATs in series (common in double-NAT home setups or behind a mobile carrier), or a software NAT running as part of an operating system or a tool like iptables. When multiple NATs sit in a row, the test only sees the combined behavior of the whole chain, not any one device in isolation.
External test server. The server needs at least two separate network interfaces or IP addresses so it can test whether the NAT's mapping changes when the destination address changes. It also needs to be able to originate connections back toward the client, since testing filtering behavior means checking whether inbound packets from various sources get through, not just outbound ones.
TCP SYN/SYN-ACK behavior. The core of the test is watching how the NAT handles the packets around the handshake. This includes whether an outbound SYN is forwarded as sent, whether a delayed SYN-ACK still gets through once it arrives, whether an inbound SYN following an outbound SYN is accepted (the sequence needed for TCP simultaneous open), and what happens when an ICMP error like TTL-exceeded shows up between the SYN and the expected reply. Some NATs treat that ICMP message as a fatal error and tear down the connection state early, which breaks traversal techniques that rely on low-TTL SYN packets.
Mapping and filtering observations. For each connection attempt, the test records the external address and port the NAT assigned, and compares it against what was assigned for previous connections from the same internal source. It also records which inbound packets were let through to an existing mapping and which were dropped or rejected, broken down by whether the source address, source port, both, or neither had to match a prior outbound packet.
Success and failure measurement. Every connection attempt gets logged as a success, a silent failure (packet dropped with no response), or an explicit failure (TCP RST or ICMP error). Timing is recorded too, since a connection that eventually succeeds after several seconds behaves very differently for an interactive application than one that fails immediately.
NAT traversal measurement results
Running this kind of test across a wide range of real devices produces a much more useful picture than reading the specification alone. The original Cornell study tested sixteen NAT products in a lab setting and ninety-three home routers in the field, and combined that with market-share data to estimate how common each behavior is in practice. A few of the headline findings:
Different NAT behaviors show up at meaningful rates. For mapping behavior, an estimated 70% of NATs in the field use endpoint-independent mapping, which is the easy case. The rest split across the address-dependent and address-and-port-dependent categories, meaning roughly three in ten home NATs assign a fresh external port for at least some connections, which breaks naive port prediction.
Connection success rates vary a lot by technique. Across the approaches tested, peer-to-peer TCP establishment succeeded anywhere from about 45% of the time for the simplest technique up to about 88% to 89% for the more refined ones that retry from both ends and don't depend on manipulating packet TTLs. A small number of NAT pairings reached 100% success because both sides happened to use the most permissive mapping and filtering behavior.
Mapping behavior has an outsized effect on success. When both NATs in a connection use endpoint-independent mapping, the external port can be learned once and reused reliably, and traversal techniques that depend on predicting that port work almost every time. When either NAT reassigns a new port per destination, prediction becomes unreliable and traversal success drops sharply for techniques that depend on it.
Filtering behavior matters separately from mapping. Around 82% of NATs in the field were found to require that an inbound packet's source address and port both match a previous outbound destination before letting it through. Only a small share allowed any external host to reach an existing mapping. This means that even when mapping is predictable, a peer usually still needs to send at least one outbound packet toward the exact expected source before an inbound connection from that peer will get through.
Results vary between NAT devices for a few concrete reasons. Vendors implement their translation and connection-tracking logic differently, firmware updates change behavior on the same hardware, and some devices behave differently in a busy home network with other traffic on the same NAT than they do in an isolated lab test. The study found that a NAT model that used one mapping behavior on an older firmware version switched to a different, more predictable behavior on a newer release, which is a reminder that any classification of a specific device is a snapshot, not a permanent fact.
Factors that affect TCP traversal success
Pulling the test results together, a handful of factors decide whether a given TCP connection attempt through NAT will actually succeed.
Endpoint-independent mapping. When a NAT keeps reusing the same external port for a given internal source regardless of destination, a peer can learn that port once and use it reliably. This is the single biggest factor in favor of successful traversal, and it's the behavior most traversal techniques are built around.
Address-dependent mapping. When the external port only stays fixed for a given destination address, prediction still works but only against the specific server used to learn the mapping in the first place. A peer trying to connect using a mapping learned against a different server will often fail.
Address-and-port-dependent mapping. When a new external port gets assigned for every distinct destination, prediction becomes a matter of guessing rather than knowing, and most straightforward traversal techniques fail outright against this behavior on either end of a connection.
Firewall filtering. Independent of what the NAT does, a firewall can still block a new inbound flow as a matter of policy. This matters because two hosts can have perfectly compatible, permissive NAT mapping and still fail to connect if a firewall in the path rejects unsolicited inbound SYNs regardless of the NAT state underneath it.
Simultaneous TCP open. Traversal techniques that rely on both hosts sending SYN packets to each other at close to the same moment depend on the operating system and the NAT both handling that sequence correctly. Some NATs and some older operating systems don't support an inbound SYN arriving right after an outbound SYN was just sent from the same port, which breaks this class of technique even when the mapping and filtering behavior would otherwise allow the connection through.
Research and standards background
The behavioral categories used throughout this article, endpoint-independent versus address-dependent versus address-and-port-dependent mapping and filtering, come from a combination of academic measurement work and IETF standards written to formalize what well-behaved NAT and firewall devices should do.
The foundational measurement work is Guha and Francis's 2005 study, presented at the ACM SIGCOMM Internet Measurement Conference, which tested a broad set of commercial NAT products in the lab and in the field and is the source of the mapping and filtering classifications and success-rate figures used in this article. RFC 5382 turns similar findings into concrete behavioral requirements specifically for TCP, describing how a NAT should handle connection establishment, simultaneous open, and connection teardown so that TCP traversal techniques have a fair chance of working. RFC 4787 does the same for UDP and is the specification that originally defined the endpoint-independent, address-dependent, and address-and-port-dependent terminology later adapted for TCP. RFC 5128 surveys the broader landscape of peer-to-peer NAT traversal across both UDP and TCP and documents the general techniques, including hole punching, that this article covers.
References
Foundational research paper
- Guha, S. and Francis, P. "Characterization and Measurement of TCP Traversal through NATs and Firewalls." Proceedings of the 5th ACM SIGCOMM Conference on Internet Measurement (IMC '05), Berkeley, CA, October 2005. Full text: usenix.org/legacy/events/imc05/tech/full_papers/guha/guha.pdf
Related research
- Ford, B., Srisuresh, P., and Kegel, D. "Peer-to-Peer Communication Across Network Address Translators." Proceedings of the 2005 USENIX Annual Technical Conference, Anaheim, CA, April 2005.
- Biggadike, A., Ferullo, D., Wilson, G., and Perrig, A. "NATBLASTER: Establishing TCP Connections Between Hosts Behind NATs." Proceedings of ACM SIGCOMM Asia Workshop, Beijing, China, April 2005.
RFCs
- RFC 793 — Transmission Control Protocol
- RFC 3489 — STUN, original specification (obsoleted by RFC 5389)
- RFC 5389 — Session Traversal Utilities for NAT (STUN)
- RFC 8489 — STUN, current specification
- RFC 5766 — Traversal Using Relays around NAT (TURN)
- RFC 8656 — TURN, current specification
- RFC 8445 — Interactive Connectivity Establishment (ICE)
- RFC 6544 — TCP Candidates with Interactive Connectivity Establishment
- RFC 4787 — Network Address Translation (NAT) Behavioral Requirements for Unicast UDP
- RFC 5382 — NAT Behavioral Requirements for TCP
- RFC 5128 — State of Peer-to-Peer (P2P) Communication Across NATs
Summary
TCP was designed for a world where servers had fixed, reachable addresses. NAT and firewalls broke that assumption for most devices on the internet today. Whether a given TCP connection can traverse NAT comes down to the mapping and filtering behavior of the NAT devices on both ends, not just whether NAT is present. Endpoint-independent behavior makes hole punching workable. Address and port-dependent behavior often forces a fallback to a relay. Understanding which case you're dealing with is the first step in diagnosing why a connection won't come through.