Skip to content

Hole punching

Hole punching is a way for two devices behind NAT to connect directly without either one opening an inbound port. A NAT only lets in packets that look like replies to something a device sent out. In UDP hole punching, both devices send packets to each other. Each outgoing packet makes the sender’s own NAT open a mapping, the “hole”, so when the other side’s packets arrive they look like replies and are let through. For this to work, each side needs to know the public address and port to aim at, and something has to tell them.

In Managed Nebula, lighthouses do the telling:

  1. Every host reports to its lighthouses on a timer. The lighthouse records the public address and port the report arrived from, which is how the host looks from outside its NAT.
  2. When host A wants to reach host B, it asks a lighthouse for B’s addresses and starts sending handshake packets to them. Those packets open a hole in A’s NAT.
  3. The lighthouse tells B that A is trying to reach it, and B sends a packet toward A’s addresses, which opens a hole in B’s NAT.
  4. A’s handshake packets now get through B’s NAT as replies, the handshake completes, and traffic flows directly between the two hosts.

Managed Nebula turns on two punchy settings on every host except lighthouses. punchy.punch sends small keepalive packets so holes don’t close while a tunnel is idle, and punchy.respond has B start a handshake back toward A, which can rescue a connection when only one side’s NAT is difficult. The timing settings punchy.delay and punchy.respond_delay are available as config overrides.

Hole punching relies on a NAT using the same public port no matter where a host’s traffic goes. A symmetric NAT picks a new port for every destination, so the address the lighthouse saw only works for reaching the lighthouse. When both hosts are behind symmetric NAT, they can’t punch through to each other. Networks that block outbound UDP stop it too, since Nebula has no TCP fallback. In those cases traffic goes through a relay, and every lighthouse is a relay by default.

NAT traversal covers the rest of how hosts get through NAT, and Nebula’s NAT traversal and firewalls guide goes through each NAT type in detail.