Core Components of Tailcat's Architecture: How the P2P Tunneling Tool Works
Tailcat is a control-plane-free, peer-to-peer TCP tunneling utility that leverages Tailscale's data plane—including WireGuard encryption, DERP relays, and magicsock NAT traversal—to establish direct connections without accounts, persistent daemons, or centralized coordination.
Tailcat is a lightweight "netcat-like" tool developed by Tailscale that creates encrypted TCP tunnels between peers using only the data plane. Unlike standard Tailscale deployments that require a control server for network management, Tailcat's architecture operates autonomously through compact connection tokens and pre-configured DERP maps. This minimal design enables instant, ephemeral networking suitable for debugging, file transfers, or ad-hoc remote access scenarios.
Components of Tailcat's Architecture
Tailcat's implementation is deliberately minimal, consisting of tightly coupled components that fit within a single process. The architecture eliminates the need for background services by embedding the entire networking stack—including WireGuard, NAT traversal, and TCP handling—directly into the application binary.
Server Component
The Server acts as the listening endpoint in tailcat.go (lines 69–78). It initializes a WireGuard tunnel bootstrapped through a DERP relay and exposes TCP handlers via callback functions.
OnTCP— Registers a handler function that accepts inbound TCP connections on specific ports. When a client connects, the server invokes this callback with a standardnet.Conn.OnTCPForward— Optional callback that enables the server to act as an exit node, forwarding traffic to alternate destinations rather than terminating it locally.
The server generates a ConnBlob token upon startup, which encodes its public key and DERP region details required for client connection.
Client Component
The Client (tailcat.go, lines 99–108) initiates connections using a parsed ConnBlob token. It implements a lazy initialization pattern where the WireGuard engine starts only upon the first dial attempt.
Key APIs include:
DialandDialTCP— Establish TCP connections to the remote server through the encrypted tunnel.Ping— Verifies connectivity and latency to the server before initiating data transfer.
The client executes a "meow" handshake protocol over DERP to authenticate itself to the server before upgrading to a direct WireGuard connection.
locoBackend: The Local Backend
locoBackend (tailcat.go, lines 105–120) replaces Tailscale's standard LocalBackend to provide a control-plane-free experience. This component owns all per-process state, including:
- WireGuard private keys and peer configurations
- DERP map and region selection
- Network map and endpoint discovery state
It drives the underlying WireGuard engine, magicsock for UDP NAT traversal, and netstack for TCP handling. The backend processes "meow" handshake packets via locoBackend.onMeow, adding authenticated clients as WireGuard peers without external coordination.
WireGuard Engine and Netstack
wgengine is the userspace WireGuard implementation created via createEngine (tailcat.go, lines 57–67). It handles encryption, decryption, and NAT traversal at the UDP layer.
Netstack (tailcat.go, lines 46–55) embeds gVisor's lightweight userspace IP stack within the same process. This allows Tailcat to accept TCP listeners and route traffic without requiring kernel-level WireGuard interfaces or root privileges. The netstack bridges between the WireGuard tunnel and standard Go net.Conn interfaces.
DERP Map and ConnBlob Tokens
The DERP Map describes available relay regions for bootstrap connectivity. Rather than querying a control server, Tailcat embeds this information directly into ConnBlob tokens.
A ConnBlob is a compact, base64url-encoded CBOR token generated in tailcat.go (lines 33–43) and parsed in lines 52–66. It contains:
- The server's public WireGuard key
- Region ID for DERP relay selection
- Optional embedded DERP region details for offline operation
This design allows clients to connect using only a short string token, eliminating the need for DNS, mDNS, or external discovery services.
Discovery and MagicSock
MagicSock and the Discovery (disco) protocol handle NAT hole punching. When the initial DERP connection establishes, both sides exchange "call-me-maybe" packets advertising their UDP endpoints (tailcat.go, lines 111–119).
This endpoint advertisement enables the underlying WireGuard engine to upgrade from the relayed DERP connection to a direct peer-to-peer UDP path, minimizing latency and relay bandwidth once the tunnel stabilizes.
Command-Line Interface and Web Assembly
The CLI (cmd/tailcat/tailcat.go) provides a thin wrapper around the library, parsing flags to instantiate either a Server or Client and forwarding traffic accordingly.
A Web Demo (webdemo/webdemo.go) compiles the same core library to WebAssembly, demonstrating that the architecture functions within browser sandboxes using the identical Go networking code.
Connection Establishment Workflow
Tailcat establishes connections through a five-phase handshake that requires no control server:
-
Bootstrap — The server initializes via
Server.Start(), creating thelocoBackend, WireGuard engine, and netstack. It publishes a ConnBlob encoding its public key and DERP region. -
Discovery — The client receives the ConnBlob and calls
c.ensureStarted()→c.initLocked()→c.ci.Expand()to parse the token and expand the DERP map if necessary. -
Handshake — Both sides exchange "meow" and "meowed" packets over the DERP relay. The server invokes
locoBackend.onMeowto add the client as a validated WireGuard peer. -
Direct Path — MagicSock advertises UDP endpoints through "call-me-maybe" disco packets, allowing WireGuard to establish a direct peer-to-peer tunnel bypassing the relay.
-
Traffic — The netstack forwards TCP traffic through the WireGuard tunnel. The server invokes
OnTCPhandlers for incoming connections orOnTCPForwardfor exit-node functionality.
Implementation Examples
Running a Tailcat Server
The following minimal implementation starts a server and handles SSH connections on port 22:
package main
import (
"log"
"net"
"tailscale.com/tailcat"
)
func main() {
var s tailcat.Server
if err := s.Start(); err != nil {
log.Fatalf("Server.Start: %v", err)
}
defer s.Close()
// Display the connection token for clients
log.Printf("ConnBlob: %s", s.ConnBlob())
// Handle TCP connections on port 22
s.OnTCP = func(port uint16) func(net.Conn) {
if port == 22 {
return func(c net.Conn) {
// Handle SSH traffic here
defer c.Close()
}
}
return nil // Returns RST for other ports
}
select {} // Block forever
}
Key calls: s.Start() initializes the networking stack, while s.ConnBlob() produces the base64url-encoded connection token. Source: tailcat.go lines 52–58.
Connecting a Tailcat Client
Clients use the ConnBlob token to dial specific ports on the server:
package main
import (
"context"
"log"
"tailscale.com/tailcat"
)
func main() {
// Token obtained from the server
blob := tailcat.ConnBlob("tc...") // Insert actual token
c := tailcat.NewClient(blob)
// Dial port 22 (SSH) through the encrypted tunnel
conn, err := c.DialTCPPort(context.Background(), "127.0.0.1:22")
if err != nil {
log.Fatalf("DialTCPPort: %v", err)
}
defer conn.Close()
// Use conn as standard net.Conn
}
Key calls: c.DialTCPPort triggers lazy initialization via c.ensureStarted, which invokes c.initLocked and c.ci.Expand to bootstrap the WireGuard engine. Source: Client.ensureStarted in tailcat.go lines 94–102.
Using the Command-Line Interface
# Server mode: listen on port 22 and print connection token
tailcat -l -port 22
# Client mode: connect using server token and forward local port
tailcat -connect tcABcd... -dial 127.0.0.1:22
The CLI implementation in cmd/tailcat/tailcat.go maps these flags directly to the Server and Client structs described above.
Key Source Files
Understanding Tailcat's architecture requires familiarity with these specific files in the tailscale/tailcat repository:
tailcat.go— Core library containingServer,Client, andlocoBackendimplementations. Defines the ConnBlob generation/parsing logic and high-level orchestration.wire.go— Minimal CBOR wire format definitions (lines 25–60) for serializing ConnBlob data structures containing server public keys and DERP regions.cmd/tailcat/tailcat.go— Command-line interface that translates flags into library calls for server and client modes.webdemo/webdemo.go— WebAssembly target demonstrating browser-based operation of the same networking stack.disco.go— Wrapper around Tailscale's discovery protocol for endpoint advertisement and NAT traversal coordination.
Summary
- Tailcat's architecture eliminates the control plane by embedding DERP maps and public keys directly into ConnBlob tokens, enabling connection without accounts or background daemons.
- The
locoBackendreplaces Tailscale's LocalBackend to manage WireGuard keys, peer state, and network maps entirely within the process. - Connection bootstrap uses CBOR-encoded tokens (base64url) rather than DNS or mDNS, allowing offline-capable peer discovery.
- MagicSock and D relays enable NAT traversal, automatically upgrading from relayed connections to direct peer-to-peer WireGuard tunnels after the "meow" handshake completes.
- Netstack integration provides userspace TCP handling without requiring kernel modules or root privileges, making the tool portable across operating systems and WASM environments.
Frequently Asked Questions
Does Tailcat require a Tailscale account or control server?
No. Tailcat operates entirely without a control plane. The locoBackend implementation manages keys and peer state locally, while ConnBlob tokens (generated in tailcat.go lines 33–43) embed all necessary connection information. This allows two peers to establish encrypted tunnels without authentication servers, persistent daemons, or network infrastructure beyond the DERP relay required for initial NAT traversal.
What is contained within a ConnBlob token?
A ConnBlob is a compact, base64url-encoded CBOR structure defined in wire.go (lines 25–60). It minimally contains the server's public WireGuard key and DERP region identifier. Optionally, it may embed complete DERP region details, allowing clients to connect without fetching external DERP maps. Clients parse these tokens via ConnInfo.Expand to reconstruct the network parameters needed for dialing.
How does Tailcat differ from standard netcat or SSH port forwarding?
Unlike traditional netcat, Tailcat encrypts all traffic using WireGuard and automatically handles NAT traversal. Unlike SSH, it requires no installed daemon, no authentication keys beyond the ephemeral WireGuard keypairs, and no listening ports on the public internet. The "meow" handshake and magicsock layer in tailcat.go (lines 111–119) coordinate direct P2P connections that bypass intermediate servers once established, whereas SSH tunnels typically route through intermediaries.
Can Tailcat run in a web browser?
Yes. The webdemo/webdemo.go file compiles the complete Tailcat library—including WireGuard, netstack, and DERP client—to WebAssembly. This demonstrates that the architecture's userspace networking approach (gVisor netstack rather than kernel interfaces) functions within browser security sandboxes, enabling P2P TCP tunnels directly from web applications without plugins or native code installation.
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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →