# How Tailcat Achieves UDP Hole-Punching for NAT Traversal: Inside the Disco Protocol

> Discover how Tailcat achieves UDP hole-punching for NAT traversal using its disco protocol. Enable direct UDP connectivity between peers with seamless DERP fallback.

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

---

**Tailcat leverages Tailscale's lightweight "disco" protocol to exchange "meow" packets and STUN probes, enabling direct UDP connectivity between NAT-bound peers with seamless DERP fallback.**

NAT traversal remains a critical hurdle for peer-to-peer networking tools. The `tailscale/tailcat` repository solves this through a sophisticated UDP hole-punching implementation that combines cryptographic endpoint verification with intelligent fallback strategies, all orchestrated through the Tailscale control plane.

## The Disco Protocol Architecture

The foundation of Tailcat's NAT traversal lies in the **disco** package, a lightweight discovery protocol derived from netcode. This protocol handles endpoint discovery without requiring manual port configuration.

At connection initiation, peers exchange their **node public key** and **disco public key** through the Tailscale control server. This cryptographic handshake establishes identity before any UDP packets flow, ensuring that hole-punching attempts target the correct endpoints.

## The "Meow" Packet Handshake

Central to the discovery process are **"meow" packets**—special DERP frames marked by the magic ASCII prefix `m e o w` that signal NAT-traversal intent. When a Tailcat client initiates a connection, it constructs these packets containing its public keys and transmits them toward the peer.

In [`disco.go`](https://github.com/tailscale/tailcat/blob/main/disco.go), the `IsMeowPacket` function identifies these frames by scanning for the meow magic prefix, distinguishing them from standard DERP relay traffic. This allows the receiver to parse the embedded cryptographic credentials and prepare for direct UDP communication.

## STUN Probing and Address Mapping

Before attempting direct connection, Tailcat must learn its external network topology. The client issues a **STUN-only probe** configured with `STUNOnly: true` in the wire protocol to determine its public-facing UDP address as seen by the server.

This external address mapping propagates back through the meow ping/pong exchange, giving both peers the necessary endpoint information to attempt direct communication. The STUN probe logic resides in [`disco.go`](https://github.com/tailscale/tailcat/blob/main/disco.go), where it handles the binding request/response cycle required for NAT mapping discovery.

## Executing UDP Hole-Punching

Armed with reciprocal external addresses, both peers simultaneously transmit UDP datagrams to each other's publicly mapped ports. This synchronized transmission exploits the behavior of most NAT devices, which temporarily open return-path holes upon observing outbound traffic.

The implementation sends these datagrams through the raw UDP socket managed by the wire layer, attempting to establish a full-duplex channel that bypasses the DERP relay entirely. Success depends on NAT behavior—cone NATs typically allow this direct path, while symmetric NATs may block it.

## DERP Fallback Mechanism

When direct UDP connectivity fails—common with symmetric NATs or aggressive firewall rules—Tailcat seamlessly transitions to **DERP relay** mode. The [`wire.go`](https://github.com/tailscale/tailcat/blob/main/wire.go) file manages this fallback, handling low-level packet framing and relay selection without interrupting the application-layer connection.

This ensures that even when hole-punching fails, SSH or other tunneled traffic continues flowing through the relay infrastructure, providing reliability without user intervention.

## Practical Usage Examples

Deploying Tailcat automatically engages these NAT traversal mechanisms. No manual configuration is required to enable hole-punching.

Start a server that listens for inbound connections and automatically attempts UDP hole-punching with each client:

```bash
sudo tailcat -listen :22 -ssh

```

Connect a client to the server. The client executes the full NAT-traversal handshake, including meow packet exchange and STUN probing, transparently to the user:

```bash
tailcat -connect user@my-server.example.com -ssh

```

Both commands work even when both endpoints reside behind NAT devices. Tailcat will either establish a direct UDP tunnel or fall back to DERP relay automatically.

## Summary

- Tailcat uses the **disco protocol** from Tailscale to coordinate NAT traversal between peers.
- **"Meow" packets** with the magic prefix `m e o w` initiate the handshake and exchange cryptographic identities via [`disco.go`](https://github.com/tailscale/tailcat/blob/main/disco.go).
- **STUN probing** with the `STUNOnly` flag determines external UDP addresses required for direct connection attempts.
- Synchronized UDP transmission performs the actual **hole-punching** through NAT devices.
- If direct connection fails, the system automatically falls back to **DERP relay** via [`wire.go`](https://github.com/tailscale/tailcat/blob/main/wire.go).

## Frequently Asked Questions

### How does Tailcat differ from standard STUN-based hole-punching tools?

Tailcat integrates STUN probing with a cryptographic identity layer (disco keys) and a reliable fallback to DERP relays. Unlike standalone STUN tools that only provide address discovery, Tailcat handles the complete connection lifecycle including encrypted tunnel establishment and automatic relay failover as implemented in `tailscale/tailcat`.

### What happens if both peers are behind symmetric NATs?

Symmetric NATs assign unique external ports for each destination, preventing standard hole-punching. In this scenario, Tailcat's direct UDP attempts fail, and the connection immediately transitions to the DERP relay mode managed by [`wire.go`](https://github.com/tailscale/tailcat/blob/main/wire.go), maintaining connectivity without user action.

### Are the "meow" packets encrypted?

The meow packets themselves carry disco public keys for endpoint verification but are not the primary encryption layer. Once the direct UDP path or DERP tunnel establishes, all application traffic flows through the Tailscale WireGuard tunnel, ensuring data confidentiality regardless of the discovery method used.

### Can I disable hole-punching and force DERP-only mode?

The current implementation in [`tailcat.go`](https://github.com/tailscale/tailcat/blob/main/tailcat.go) automatically attempts hole-punching for optimal performance. While there is no command-line flag to disable direct UDP attempts in the provided interface, the system automatically prioritizes DERP fallback when direct paths prove unreachable.