# How Tailcat Handles NAT Traversal Without Port Forwarding

> Tailcat bypasses NAT and firewalls for direct P2P connections. Learn how WireGuard ICE, DERP relays, and DiscoPing achieve NAT traversal without port forwarding.

- Repository: [Tailscale/tailcat](https://github.com/tailscale/tailcat)
- Tags: deep-dive
- Published: 2026-09-08

---

**Tailcat eliminates the need for manual port forwarding by combining WireGuard's built-in ICE-style NAT hole punching, automatic DERP relay fallback, and continuous DiscoPing discovery to establish direct peer-to-peer connections through NATs and firewalls.**

The tailscale/tailcat repository provides a lightweight WireGuard tunneling solution that automatically traverses Network Address Translation (NAT) boundaries without requiring firewall rules or static public endpoints. Unlike traditional VPN configurations that demand port forwarding on gateways, Tailcat implements a multi-layered connectivity strategy that adapts to network constraints in real-time.

## WireGuard Data Plane with Built-In Hole Punching

Tailcat leverages the WireGuard protocol's cryptographic handshake to embed an ICE-style NAT hole punching process directly into the connection establishment phase. When initiating a tunnel, the client and server exchange UDP packets through their respective NAT gateways, creating transient port mappings that allow return traffic to flow without explicit forwarding rules.

According to the package comment in [`tailcat.go`](https://github.com/tailscale/tailcat/blob/main/tailcat.go) at line 5, Tailcat runs "WireGuard®...and NAT traversal," indicating that these capabilities are intrinsic to the implementation rather than bolted-on afterthoughts. This integration ensures that the encrypted data plane and NAT traversal mechanism share the same UDP sockets, eliminating the need for separate signaling channels.

### DiscoPing for Direct Path Discovery

The `Client.DiscoPing` method drives continuous network path optimization. As noted in lines 65-66 of [`tailcat.go`](https://github.com/tailscale/tailcat/blob/main/tailcat.go), "pinging repeatedly upgrades the connection when NAT traversal is possible." These discovery pings serve a dual purpose: measuring latency between peers and triggering the upgrade from relayed connections to direct peer-to-peer paths when firewall conditions permit.

## DERP Fallback for Restrictive Network Environments

When symmetric NATs or strict firewall rules block direct UDP connectivity, Tailcat automatically falls back to Tailscale's Distributed Endpoints Relay Protocol (DERP). DERP carries encrypted WireGuard packets over HTTPS and WebSockets, providing a reliable transport mechanism that operates on standard ports 443 and 80.

The package comment in [`tailcat.go`](https://github.com/tailscale/tailcat/blob/main/tailcat.go) at line 24 references "WireGuard encryption + NAT traversal," emphasizing that DERP operates as an encrypted relay rather than a decryption endpoint. This architecture ensures that even when relayed through Tailscale's DERP infrastructure, packets remain end-to-end encrypted with WireGuard's cryptographic guarantees.

## NAT64 Translation for IPv4 Compatibility

Tailcat operates an IPv6-only WireGuard tunnel internally, requiring a translation mechanism for reaching IPv4-only services. The implementation maps IPv4 addresses into the NAT64 prefix `64:ff9b::/96` before transmission through the tunnel.

In [`tailcat.go`](https://github.com/tailscale/tailcat/blob/main/tailcat.go) lines 46-51, the `nat64Prefix` constant and the `DialTCP` conversion logic handle this translation transparently. When a client calls `DialTCPPort` to reach an IPv4 address, Tailcat automatically converts the destination to the corresponding IPv6 representation within the NAT64 prefix, allowing seamless connectivity to legacy IPv4 services without requiring dual-stack configuration or port forwarding on IPv4 gateways.

## Practical Implementation Examples

The following examples demonstrate how Tailcat's NAT traversal operates in practice without requiring manual firewall configuration.

Serving a local HTTP server through NAT:

```go
package main

import (
	"context"
	"log"

	"tailscale.com/tailcat"
)

func main() {
	// Connect to a remote Tailcat server (identified by its public key)
	c, err := tailcat.NewClient(context.Background(),
		tailcat.ServerPublicKey("SERVER_PUBLIC_KEY"),
		tailcat.DERPMapURL("https://my-derp.example.com/derpmap.json"))
	if err != nil {
		log.Fatalf("client init: %v", err)
	}
	// Serve local port 8080 over the WireGuard tunnel
	if err := c.ServeTCPPort(context.Background(), 8080); err != nil {
		log.Fatalf("serve: %v", err)
	}
}

```

Piping a TCP connection through restrictive NAT:

```go
package main

import (
	"context"
	"log"

	"tailscale.com/tailcat"
)

func main() {
	c, err := tailcat.NewClient(context.Background(),
		tailcat.ServerPublicKey("SERVER_PUBLIC_KEY"))
	if err != nil {
		log.Fatalf("client init: %v", err)
	}
	// Open a TCP connection to the remote server's port 22 (SSH)
	conn, err := c.DialTCPPort(context.Background(), 22)
	if err != nil {
		log.Fatalf("dial: %v", err)
	}
	// Use conn as a normal net.Conn (e.g., feed it to an ssh client)
	_ = conn
}

```

## Key Source Files and Architecture

Understanding Tailcat's NAT traversal requires familiarity with several core files in the tailscale/tailcat repository:

- **[`tailcat.go`](https://github.com/tailscale/tailcat/blob/main/tailcat.go)**: The primary client implementation containing `Client.DiscoPing`, `ServeTCPPort`, and `DialTCPPort` methods, along with NAT64 translation logic in lines 46-51 and the DiscoPing upgrade logic in lines 65-66.
- **[`wire.go`](https://github.com/tailscale/tailcat/blob/main/wire.go)**: Defines the minimal wire format for DERP region information, enabling the client to select optimal relay servers when direct connectivity fails.
- **[`cmd/tailcat/tailcat.go`](https://github.com/tailscale/tailcat/blob/main/cmd/tailcat/tailcat.go)**: The CLI entry point that exposes the library functionality through `serve`, `pipe`, and `forward` commands, handling public key authentication and DERP map configuration.

## Summary

- **WireGuard Integration**: Tailcat embeds ICE-style NAT hole punching directly into WireGuard's cryptographic handshake, eliminating the need for separate signaling servers or manual port forwarding rules.
- **Automatic DERP Fallback**: When direct UDP paths are blocked by symmetric NATs or corporate firewalls, Tailcat transparently falls back to encrypted HTTPS/WebSocket relays without user intervention.
- **Continuous Path Optimization**: The `DiscoPing` mechanism actively probes for direct connectivity upgrades, ensuring connections migrate from relayed to peer-to-peer paths as network conditions change.
- **IPv4 Compatibility**: NAT64 prefix translation in `DialTCP` allows the IPv6-only WireGuard tunnel to reach IPv4 services without requiring dual-stack configuration or gateway modifications.

## Frequently Asked Questions

### What is DERP and why does Tailcat need it?

DERP (Distributed Endpoints Relay Protocol) serves as a fallback transport when direct NAT traversal fails. When both peers reside behind symmetric NATs or restrictive firewalls that block UDP hole punching, DERP relays encrypted WireGuard packets over standard HTTPS connections on ports 443 and 80. Because DERP operates as a blind relay that cannot decrypt traffic, it maintains the end-to-end security guarantees of WireGuard while ensuring connectivity in challenging network environments.

### How does Tailcat differ from standard WireGuard for NAT traversal?

Standard WireGuard requires at least one peer to have a publicly accessible endpoint or pre-configured port forwarding. Tailcat extends WireGuard with active NAT discovery mechanisms including `DiscoPing` and automatic DERP fallback. While standard WireGuard establishes static endpoints, Tailcat continuously probes for direct paths and falls back to relays dynamically, removing the administrative burden of manual firewall configuration.

### Does Tailcat require IPv6 support to function?

Yes, Tailcat implements an IPv6-only WireGuard tunnel internally. However, IPv4 connectivity is maintained through NAT64 translation using the `64:ff9b::/96` prefix as implemented in [`tailcat.go`](https://github.com/tailscale/tailcat/blob/main/tailcat.go) lines 46-51. When connecting to IPv4 addresses, the `DialTCP` method automatically maps them to the corresponding IPv6 representation, allowing seamless access to IPv4 services without requiring native IPv4 support on the tunnel interface itself.

### Can Tailcat traverse symmetric NATs?

Tailcat can establish connectivity through symmetric NATs by falling back to DERP relays. While symmetric NATs prevent direct UDP hole punching because they allocate different external ports for each destination, the encrypted DERP relay provides a reliable alternative path. Once connected via DERP, Tailcat continues to send `DiscoPing` probes; if the symmetric NAT configuration allows, the connection may upgrade to a direct path, though this depends on specific firewall behavior.