# How Tailcat Handles NAT Traversal: A Deep Dive into DERP Bootstrapping and UDP Hole-Punching

> Tailcat handles NAT traversal with DERP bootstrapping and UDP hole-punching. Discover how Tailcat ensures reliable connections, even behind firewalls.

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

---

**Tailcat performs NAT traversal by combining DERP relay bootstrapping, magicsock endpoint discovery, a custom "meow" handshake protocol, and seamless fallback to relay servers when direct paths fail.**

Tailcat is an open-source peer-to-peer networking tool from Tailscale that establishes direct UDP connections between nodes behind NATs without requiring a control plane or user accounts. This article examines the complete NAT traversal implementation in the `tailscale/tailcat` repository, from initial bootstrap to direct path establishment.

## DERP Bootstrap: The Foundation of NAT Traversal

Every Tailcat connection begins with **DERP (Designated Encrypted Relay for Packets)**, a publicly reachable UDP relay infrastructure. When a server or client starts, it contacts a DERP relay to obtain peer public keys and exchange initial packets.

According to the package documentation in [`tailcat.go`](https://github.com/tailscale/tailcat/blob/main/tailcat.go), "Tailscale's magicsock layer upgrades to a direct peer-to-peer UDP path whenever possible." This bootstrap phase is essential because both peers may reside behind restrictive NATs with no initially known public endpoints.

In [`tailcat.go`](https://github.com/tailscale/tailcat/blob/main/tailcat.go), the server initializes its DERP connection during startup, with the region ID accessible via `srv.lb.derpRegionID()`. The `-1` value enables automatic region selection based on latency.

## Endpoint Discovery via magicsock

Once bootstrapped, **magicsock**—Tailscale's transport layer—discovers each peer's UDP endpoints using **STUN (Session Traversal Utilities for NAT)** and local network interface enumeration. The discovered endpoints are stored in `lb.eps` and updated dynamically whenever network conditions change.

```go
// From tailcat.go - endpoint storage and updates
lb.eps        // stores discovered endpoints
// Lines 1409-1413: endpoint update logic when network changes occur

```

This continuous discovery enables Tailcat to respond to roaming clients, IP address changes, and network topology shifts without manual reconfiguration.

## The "Meow" Handshake: Custom Key Exchange Protocol

Tailcat introduces a lightweight custom protocol called the **"meow" handshake** to exchange cryptographic identities. This handshake uses specialized DERP packets defined in [`disco.go`](https://github.com/tailscale/tailcat/blob/main/disco.go).

The handshake flow operates as follows:

- **Meow ping**: Client sends a packet containing its WireGuard node public key and magicsock *disco* public key
- **Meowed acknowledgment**: Server replies, confirming readiness for direct communication

```go
// disco.go defines the handshake packet structure
// Lines 11-27: meow packet types and serialization

```

The meow handshake eliminates dependency on Tailscale's centralized coordination server, enabling fully decentralized peer discovery.

## Advertising Endpoints with CallMeMaybe

After successful handshake completion, the server advertises its current UDP endpoints to all known peers. This advertisement uses a **`disco.CallMeMaybe`** message wrapped in a DERP packet.

In [`tailcat.go`](https://github.com/tailscale/tailcat/blob/main/tailcat.go) (lines 1435-1467), the endpoint advertisement logic broadcasts the node's reachable addresses. Remote magicsock instances receive these messages, ping the advertised endpoints, and validate direct path viability.

```go
// Endpoint advertisement in tailcat.go
// Lines 1435-1467: disco.CallMeMaybe transmission to peers

```

## Establishing Direct UDP Paths

With endpoints discovered and advertised, both peers attempt **UDP hole-punching** to establish a direct connection. The process works symmetrically:

1. Each peer sends UDP probe packets to the other's advertised endpoints
2. Successful bidirectional communication confirms the direct path
3. magicsock migrates traffic from DERP relay to the direct UDP tunnel

This direct path provides lower latency and higher throughput than relayed traffic. The entire upgrade occurs transparently without application-level awareness.

## Fallback and Resilience

Tailcat's NAT traversal includes robust **fallback mechanisms**. If direct path establishment fails—due to symmetric NAT, firewall rules, or other obstacles—the connection silently falls back to the DERP relay.

Key resilience characteristics:

- **Zero external dependencies**: No Tailscale control-plane or account required
- **Automatic retry**: Continuous endpoint discovery attempts direct path re-establishment
- **Seamless upgrade**: Direct paths are established opportunistically without disrupting active connections

The DERP relay serves as a "last-resort" fallback, guaranteeing connectivity even when NAT traversal cannot be completed.

## Practical Implementation: Starting a Tailcat Server

The following example demonstrates starting a Tailcat server with automatic NAT traversal:

```go
import (
    "log"
    "tailscale.com/tailcat"
)

func main() {
    var srv tailcat.Server
    // Optional: specify a DERP region or let Tailcat auto-pick the nearest one.
    // srv.RegionID = -1 // auto-detect based on latency
    if err := srv.Start(); err != nil {
        log.Fatalf("server start: %v", err)
    }
    defer srv.Close()
    log.Printf("Server listening at %v (DERP region %d)", srv.Addr(), srv.lb.derpRegionID())
    select {} // block forever
}

```

The `Server.Start` method internally invokes the complete magicsock-based NAT traversal flow, including DERP bootstrap and endpoint discovery.

## Client Connection with Automatic NAT Traversal

Clients connect using the server address obtained via `srv.TailcatAddr()`:

```go
import (
    "context"
    "log"
    "tailscale.com/tailcat"
)

func main() {
    // Assume the server address was obtained via srv.TailcatAddr()
    serverAddr := tailcat.Addr("tc...")
    client, err := tailcat.NewClient(serverAddr)
    if err != nil {
        log.Fatalf("client init: %v", err)
    }
    if err := client.Start(context.Background()); err != nil {
        log.Fatalf("client start: %v", err)
    }
    defer client.Close()
    // Use client.DialTCP or client.DialUDP to communicate directly.
}

```

The `Client.Start` method performs the meow handshake and NAT traversal automatically. Once complete, `client.DialTCP` or `client.DialUDP` communicate over the established direct path.

## Key Source Files for NAT Traversal

| File | Role |
|------|------|
| [`tailcat.go`](https://github.com/tailscale/tailcat/blob/main/tailcat.go) | Core server/client implementation, DERP bootstrap, endpoint advertising, and magicsock integration |
| [`disco.go`](https://github.com/tailscale/tailcat/blob/main/disco.go) | Custom "meow" handshake packets for key exchange |
| [`README.md`](https://github.com/tailscale/tailcat/blob/main/README.md) | High-level description of magicsock NAT-traversal behavior |
| [`tailcat_test.go`](https://github.com/tailscale/tailcat/blob/main/tailcat_test.go) | Verification tests including `--until-direct` flag for NAT traversal validation |
| [`wire.go`](https://github.com/tailscale/tailcat/blob/main/wire.go) | CBOR wire format for Tailcat addresses including DERP region metadata |

## Summary

- **DERP bootstrap** provides initial connectivity when no direct path exists
- **magicsock endpoint discovery** uses STUN and local interfaces to find reachable addresses
- **"Meow" handshake** enables decentralized key exchange without central coordination
- **CallMeMaybe advertisements** broadcast endpoints to establish direct paths
- **Seamless DERP fallback** ensures connectivity when NAT traversal fails
- **Zero external dependencies** allow operation without Tailscale accounts or control plane

## Frequently Asked Questions

### What is DERP in Tailcat's NAT traversal?

DERP (Designated Encrypted Relay for Packets) is a publicly reachable UDP relay that provides initial connectivity between peers when direct paths are unknown. It serves as both a bootstrap mechanism and fallback path, encrypting all traffic end-to-end so the relay cannot read packet contents.

### How does the meow handshake differ from standard WireGuard handshake?

The meow handshake exchanges WireGuard node keys and magicsock disco keys over DERP before any direct UDP communication occurs. Standard WireGuard performs its handshake directly via UDP, which fails when both peers are behind uncooperative NATs. The meow handshake solves this chicken-and-egg problem by using the already-established DERP connection.

### Can Tailcat traverse symmetric NATs?

Symmetric NATs present the most challenging case for UDP hole-punching because they map each outbound destination to a unique external address-port pair. Tailcat attempts direct path establishment but falls back seamlessly to DERP relay when symmetric NAT prevents hole-punching success. The connection remains functional with slightly higher latency.

### Does Tailcat require any centralized servers?

Tailcat operates without Tailscale's control plane or user accounts. The only external dependency is the DERP relay infrastructure, which knows nothing about the encrypted traffic it relays. The meow handshake and endpoint advertisement occur directly between peers without centralized coordination.