The NAT barrier to direct connections
Network Address Translation (NAT) rewrites packet headers so devices behind a router can share a public IP. The router tracks outgoing connections and forwards responses back to the originator. Incoming connections are a problem: if a device inside NAT tries to accept a connection from the outside, the router has no rule for forwarding it, so the connection dies. This isolates peer-to-peer applications like file sharing or voice calls.
Hole punching through a rendezvous server
Hole punching (also called UDP hole punching) works around NAT using a public rendezvous server. Peer A contacts the server and says 'I am at 192.168.1.10:5000 internally, port 54321 externally'. Peer B does the same. The server tells each peer the other's external address. Both peers then send UDP packets to each other's external addresses. The outgoing packet from each peer punches a hole in its NAT (creating a mapping), and the packets pass through. Subsequent packets use this hole and connect directly.
When hole punching fails
Some NATs are symmetric: they assign a different external port for each destination, making the hole from A to B useless for A talking to C. Others are cone-shaped: one external port for all destinations. STUN (Session Traversal Utilities for NAT) detects the NAT type, and applications choose the right strategy. If hole punching fails (symmetric NAT, overly restrictive firewall), applications fall back to a relay server: both peers send traffic through the server, defeating peer-to-peer but ensuring connectivity.