Tailcat Connection Establishment Flow: From Compact Address to WireGuard Tunnel

Tailcat establishes encrypted connections through a three-phase process—address generation, DERP-assisted path discovery, and WireGuard handshake—that converts a compact Base64-URL address into a peer-to-peer WireGuard tunnel without external coordination.

Tailcat is a standalone secure networking library in the tailscale/tailcat repository that creates WireGuard tunnels without requiring a Tailscale account or centralized control plane. The connection establishment flow in Tailcat transforms a concise, shareable address string into an end-to-end encrypted tunnel through a carefully orchestrated sequence of key exchange, NAT traversal, and protocol upgrade.

Phase 1: Address Generation and ConnInfo Encoding

The server initiates the connection establishment flow by generating a compact, self-contained address that encodes all necessary cryptographic material. In tailcat.go, the type ConnInfo struct (lines 51-88) aggregates the server's WireGuard node public key, a separate disco public key for path discovery, an optional pre-shared key, and the target DERP region ID.

This structure is CBOR-encoded and then Base64-URL-encoded into a type Addr string (lines 46-50), producing a compact string like tcomFwWC… that can be distributed to clients via any out-of-band channel. The address contains everything required to locate and authenticate the server, eliminating the need for external coordination.

Phase 2: DERP Discovery and Path Discovery

When the client receives the address, it parses the string back into a ConnInfo via ConnInfo.Expand (lines 103-110), which fetches the DERP map if the address does not contain the full region list. The client then connects to the specified DERP relay using the tailscale.com/disco package.

Through this relay, the client and server exchange disco packets that convey the server's ServerDiscoPublic key and UDP endpoints. The server registers its dialer with tsdial.NewDialer, while the client listens on the DERP connection. This phase, implemented around lines 660-682 in tailcat.go, establishes a fallback relay path and gathers the network intelligence needed for NAT traversal.

Phase 3: WireGuard Handshake and Direct Path Upgrade

With cryptographic material exchanged, both sides instantiate a WireGuard engine using wgengine.NewEngine (lines 520-560). The WireGuard handshake completes over the established DERP channel, creating the first encrypted tunnel immediately.

Once the handshake succeeds, the magicsock layer attempts to upgrade the connection from relayed DERP to a direct peer-to-peer UDP path. The function ns.GetUDPHandlerForFlow (lines 663-682) manages this transition, testing direct connectivity between the discovered UDP endpoints. If NAT traversal succeeds, traffic shifts to the direct path for lower latency; if it fails, the connection continues using the DERP relay as a fallback, maintaining the encrypted WireGuard tunnel throughout.

Key Source Files and Functions

The connection establishment flow spans several critical files in the tailscale/tailcat repository:

  • tailcat.go: Core implementation containing ConnInfo address parsing (ParseAddr), server initialization (NewServer), client creation (NewClient), and the magicsock upgrade logic.
  • wire.go: CBOR wire format definitions that determine how ConnInfo structures serialize into the compact Addr format.
  • disco.go: Path-discovery packet definitions used during the DERP exchange phase.
  • cmd/tailcat/tailcat.go: Command-line interface that demonstrates the complete flow from address generation to tunneled connection.

Server and Client Implementation Example

The following example demonstrates the complete connection establishment flow using the Tailcat API:

// Server side: generate an address containing all connection parameters
srv, _ := tailcat.NewServer(tailcat.ServerOptions{
    // optionally set RegionID to let the client pick a DERP region
})
addr := srv.Addr() // produces a string like "tcomFwWC…"
fmt.Println("Give this address to your client:", addr)

// Client side: parse address and establish secure tunnel
ci, err := tailcat.ParseAddr(addr) // decodes CBOR back into ConnInfo
if err != nil { log.Fatal(err) }
client, err := tailcat.NewClient(ci) // expands DERP map, performs discovery
if err != nil { log.Fatal(err) }
conn, err := client.Dial(context.Background(), "example.com:22") // encrypted WireGuard tunnel
if err != nil { log.Fatal(err) }
fmt.Println("Connected to server over WireGuard!")

Summary

  • Tailcat uses a three-phase connection establishment that encodes connection parameters into a compact address, discovers paths via DERP relays, and upgrades to direct WireGuard connections.
  • The ConnInfo struct in tailcat.go encapsulates all cryptographic identity and network location data, serialized via CBOR into a portable Addr string.
  • DERP relays provide the initial bootstrap path for NAT traversal and key exchange, with the tailscale.com/disco package handling endpoint discovery.
  • Magicsock upgrades connections from relayed to direct UDP paths automatically, falling back to DERP if direct connectivity fails, ensuring resilient encrypted tunnels without external coordination.

Frequently Asked Questions

What information is encoded in a Tailcat address?

A Tailcat address is a Base64-URL-encoded CBOR payload containing the ConnInfo struct. This includes the server's WireGuard public key (ServerPublic), a separate disco public key (ServerDiscoPublic) for path discovery, an optional pre-shared key, and the DERP region ID. This self-contained design allows clients to establish connections using only the address string, without querying external directories.

How does Tailcat achieve NAT traversal without a control plane?

Tailcat leverages DERP (Designated Encrypted Relay for Packets) relays and the tailscale.com/disco protocol for NAT traversal. The client and server use the DERP relay to exchange UDP endpoint information through encrypted disco packets. After learning each other's public endpoints, the magicsock layer attempts direct UDP hole punching; if successful, the connection migrates from the relay to the direct path transparently.

Is the connection encrypted during the initial DERP relay phase?

Yes. While DERP provides the transport for initial packets, the actual WireGuard handshake establishes an encrypted tunnel immediately. The DERP relay only forwards opaque WireGuard packets and cannot decrypt the payload. Once the handshake completes in phase 3, all application traffic flows through the WireGuard tunnel, regardless of whether it traverses the DERP relay or a direct UDP path.

What happens if direct peer-to-peer connection fails?

If NAT traversal fails and no direct UDP path can be established, Tailcat maintains the connection through the DERP relay. The magicsock layer, specifically via ns.GetUDPHandlerForFlow in tailcat.go, gracefully handles this fallback, keeping the encrypted WireGuard tunnel active over the relay indefinitely. This ensures connectivity even in restrictive network environments that block direct UDP communication.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →