> your AI agent picks dependencies from memory; give it dated facts — try starlog.dev ↗ vet your agent's deps ↗ vibe-coding is fine. vibe-importing isn’t. — try starlog.dev ↗ vibe-importing isn’t fine ↗ your agent has never seen your private packages — try starlog.dev ↗ facts for private packages ↗ a linter for the dependencies your AI agent picks — try starlog.dev ↗ a linter for agent deps ↗ whois is redacted, cdns mask the rest — get the real operator — try whoisgeni.us ↗ who really runs that domain ↗ domain attribution that shows its work — full evidence chain — try whoisgeni.us ↗ domain intel w/ evidence ↗

← Back to Articles

Tailcat: Extracting Tailscale's WireGuard Stack Into a Token-Based Netcat

[ View on GitHub ]

Tailcat: Extracting Tailscale's WireGuard Stack Into a Token-Based Netcat

Hook

You can build encrypted peer-to-peer tunnels with automatic NAT traversal without a single line of server coordination code—just a base64 token passed through a Slack message.

Context

Traditional netcat works beautifully when both peers have public IPs or live on the same network. But in 2024, most devices sit behind NAT, CGNAT, or corporate firewalls. UDP hole-punching tools exist, but they're fragile and require manual STUN server coordination. Full VPN solutions like Tailscale solve NAT traversal elegantly, but they introduce control plane dependencies—you need accounts, authentication servers, and coordination infrastructure just to connect two machines.

Tailcat proves that Tailscale's core networking magic—the WireGuard encryption, UDP hole-punching via the 'disco' protocol, and DERP relay fallback—can work as a standalone library without any SaaS backend. It's a reference implementation showing how to extract Tailscale's data plane components into developer-friendly primitives. The result is netcat semantics with WireGuard security and automatic NAT traversal, coordinated through nothing more than a copyable token string.

Technical Insight

Tailcat's architecture reveals how Tailscale's networking stack operates independently of its control plane. At the core are three components: WireGuard-Go for encryption, magicsock for transport multiplexing, and gVisor's netstack for userspace TCP/IP termination.

The server bootstraps by generating a WireGuard keypair and connecting to a DERP relay—Tailscale's encrypted relay servers that act as rendezvous points when direct connections fail. The server then encodes its public key and DERP coordinates into a compact token:

package main

import (
    "fmt"
    "github.com/tailscale/tailcat"
)

func main() {
    server := &tailcat.Server{}
    token, err := server.Start()
    if err != nil {
        panic(err)
    }
    fmt.Printf("Connection token: %s\n", token)
    
    // Token format: tc<region><base64-cbor-data>
    // Example: tcnyc3LJHMKx9zR2vNpQ8aW...
    
    // Accept connections on localhost:8080
    server.Forward(":8080")
}

The token encoding is deliberately clever. Short tokens (starting with a region code like 'nyc' or 'sfo') assume both peers know about Tailscale's public DERP map—a hardcoded list of relay servers. Long tokens embed the full DERP metadata, making them self-contained but verbose. This two-tier approach balances convenience for common cases against reliability for air-gapped or custom DERP deployments.

When a client receives this token, it parses the CBOR payload to extract the server's public key and DERP coordinates. The client generates its own ephemeral WireGuard keypair, connects to the same DERP relay, and sends a 'Meow' message containing its public key. This handshake is minimal but sufficient: the server dynamically reconfigures its WireGuard peer list with the client's key and responds with 'Meowed'. Both sides now have each other's WireGuard public keys and can complete the Noise protocol handshake over the DERP relay:

client := &tailcat.Client{
    Token: "tcnyc3LJHMKx9zR2vNpQ8aW...",
}

conn, err := client.Dial()
if err != nil {
    panic(err)
}
defer conn.Close()

// At this point, conn is an encrypted tunnel
conn.Write([]byte("Hello over WireGuard\n"))

While this DERP-relayed connection establishes, magicsock runs parallel endpoint discovery. It performs STUN binding requests to discover the client's external IP and port, then sends 'disco' protocol messages—Tailscale's custom UDP hole-punching mechanism—to attempt direct peer-to-peer connectivity. If NAT types permit (anything except symmetric NAT on both sides), the connection upgrades from DERP relay to direct UDP. If hole-punching fails, DERP continues transparently as an encrypted relay with approximately 50-150ms added latency depending on relay proximity.

The TCP handling is where things get architecturally interesting. Unlike traditional VPN tools that create TUN devices and manipulate kernel routing tables, tailcat uses gVisor's netstack to terminate TCP connections entirely in userspace. When you forward a port, netstack creates a virtual network interface inside the process, handles TCP state machines, congestion control, and retransmissions without kernel involvement. This means no root privileges, no iptables rules, no sysctls—just a Go process accepting connections and shuttling bytes through the WireGuard tunnel.

For saved client keys, the workflow changes slightly. Instead of ephemeral keypairs, you can persist a client's public key and use it for access control:

# Server allows specific client keys
tailcat --allow client1.key --allow client2.key :8080

# Client saves its key for reuse
tailcat --save-key myclient.key <token>

This creates a crude but effective ACL system at the WireGuard layer. Unauthorized handshakes are rejected before reaching the application, and each saved key acts like a cryptographic credential—no passwords, no certificates, just WireGuard public key whitelisting.

Gotcha

The WASM build is fundamentally limited. GitHub issue #4 tracks WebRTC peer connection support, but currently browser clients are permanently DERP-relayed with no hole-punching capability. This makes sense given browser security constraints—you can't do raw UDP socket operations from JavaScript—but it means web demos have relay latency and bandwidth limits that native builds avoid. If you're building a browser-based tool, expect all traffic to route through DERP servers indefinitely.

Multi-client support is non-existent by design. The server accepts exactly one peer at a time with ephemeral keys, and even with saved keys, there's no session management or connection multiplexing. This is fundamentally point-to-point netcat, not a tunnel server. If you need to accept multiple simultaneous clients, you'll need to run multiple server instances or switch to full Tailscale with its control plane managing mesh connectivity. The DERP relay dependency also means you need reachable infrastructure for initial handshaking. Self-hosted DERP requires TLS certificates and publicly routable domains, which raises operational complexity compared to pure UDP hole-punching solutions that work with just port forwards.

Verdict

Use if: you need encrypted NAT-busting tunnels for ephemeral point-to-point connections without installing full VPN infrastructure, you're prototyping mesh networking tools and want to extract Tailscale's stack as a library, or you're building developer tooling where users coordinate via out-of-band token exchange (imagine pastebin-based file transfers or temporary SSH access). Skip if: you need persistent multi-peer networks (use Tailscale proper with its control plane), you require low-latency browser-to-browser links without relay servers (use pure WebRTC with custom signaling), or you want simpler UDP hole-punching without WireGuard overhead (consider pwnat or manual STUN). This is reference-quality code for learning how Tailscale's data plane works, but operationally it's niche—most production use cases are better served by full Tailscale or dedicated P2P libraries like libp2p.