# Core Tailscale Components Reused by Tailcat: Architecture Guide

> Explore how Tailcat reuses core Tailscale components like wgengine, disco, netstack, and tailcfg for WireGuard encryption, NAT traversal, and DERP relays without an external control plane.

- Repository: [Tailscale/tailcat](https://github.com/tailscale/tailcat)
- Tags: architecture
- Published: 2026-08-30

---

**Tailcat composes production-grade Tailscale packages—including `wgengine`, `disco`, `netstack`, and `tailcfg`—to deliver WireGuard-encrypted networking, Magicsock-style NAT traversal, and DERP relay functionality without requiring an external control plane.**

Tailcat is an experimental networking tool within the `tailscale/tailcat` repository that demonstrates how to build a lightweight, encrypted data-plane by importing **core Tailscale components**. Instead of re-implementing cryptographic tunnels or NAT traversal logic, the project assembles existing high-performance packages from the Tailscale Go module to create a "control-plane-free" node that operates solely via compact connection tokens.

## WireGuard Engine and Cryptographic Foundation

At the heart of Tailcat’s encryption layer sits the same userspace WireGuard implementation that powers the standard Tailscale client.

### Userspace WireGuard Engine (`wgengine`)

The `tailscale.com/wgengine` package provides the packet encryption engine responsible for routing and WireGuard key management. In [`tailcat.go`](https://github.com/tailscale/tailcat/blob/main/tailcat.go) lines 82–86, the engine is initialized to handle all cryptographic operations. This package includes several critical sub-components:

- **`wgengine/netstack`** (lines 84–86): Supplies an in-process TCP/IP stack that creates a virtual network interface without requiring root privileges or kernel modules.
- **`wgengine/router`** (lines 85–86): Forwards traffic between the virtual netstack and the host network, managing route tables dynamically.
- **`wgengine/filter`** (lines 86–87): Implements a packet filter that restricts inbound ports as a defense-in-depth security measure.
- **`wgengine/wgcfg`** (lines 86–87): Defines configuration structures for WireGuard keys and network addresses.

### Cryptographic Identity and Logging

Tailcat uses strongly-typed key structures from `tailscale.com/types/key` (lines 76–77) to manage node and discovery (disco) public/private key pairs. For observability, it adopts the minimal `Logf` interface from `tailscale.com/types/logger` (lines 77–78), ensuring consistent logging across all subsystems.

## Magicsock-Style Discovery and NAT Traversal

To establish direct connections through firewalls and NATs, Tailcat reuses Tailscale’s proven endpoint discovery mechanisms.

### Discovery Protocol (`disco`)

The `tailscale.com/disco` package (lines 63–66) provides the "meow" handshake and endpoint advertising logic originally developed for Magicsock. This enables Tailcat to perform UDP hole punching and STUN-based endpoint discovery automatically.

### Network Monitoring (`netmon`)

Complementing the disco layer, `tailscale.com/net/netmon` (lines 69–70) tracks local UDP endpoints and reacts to interface changes. This component monitors STUN responses and network topology shifts, triggering endpoint re-advertisement when a host moves between networks.

## Virtual Network Stack and Traffic Control

Tailcat runs a complete TCP/IP stack entirely in userspace, eliminating the need for external network configuration.

### In-Process TCP/IP Implementation

The `netstack` package imported at lines 84–86 allows Tailcat to expose TCP listeners and SSH servers without binding to host ports directly. This virtual interface is bridged to the physical network via the `wgengine/router` component, which handles packet forwarding between the netstack and the host.

### Packet Filtering and Security

The `wgengine/filter` package (lines 86–87) enforces port-level access controls. By default, Tailcat uses this filter to limit which inbound ports a client may access, providing security-by-default even within the encrypted mesh.

## Control Plane Types and Network State

Despite operating without a traditional control plane, Tailcat relies on Tailscale’s standard type definitions to describe network topology and configuration.

### Network Map and DERP Configuration

The `tailscale.com/tailcfg` package (lines 73–75) defines types for DERP regions, node descriptions, and the overall network map. Tailcat uses `tailscale.com/types/netmap` (lines 78–79) to represent the local node and its peer relationships in memory, maintaining compatibility with Tailscale’s standard network map format.

### System Dependency Container (`tsd`)

All subsystems are coordinated through `tailscale.com/tsd` (lines 71–73), the Tailscale system-dependency container. This container holds references to the engine, netstack, DNS resolver, and health monitors, providing a unified lifecycle management layer for the application.

## Observability and System Integration

Tailcat mirrors the status reporting capabilities of the standard Tailscale client through shared interfaces.

### Health Tracking and Status Reporting

The `tailscale.com/health` package (lines 65–66) integrates with Tailscale’s diagnostic system, while `tailscale.com/ipn` and `ipn/ipnstate` (lines 66–68) provide the same status structures used by the regular client. The `tailscale.com/util/eventbus` (lines 80–81) propagates status updates between subsystems asynchronously.

### Dialing and DNS Resolution

For outbound connectivity, `tailscale.com/net/tsdial` (lines 48–49) provides a dialer that can route traffic either through the in-process netstack or directly over UDP. Name resolution inside the virtual network is handled by `tailscale.com/net/dns` (lines 70–71), which manages the DNS configuration for the netstack.

### Utilities and Feature Flags

Supporting functionality includes `tailscale.com/net/netns` (lines 71–72) for Linux-specific networking isolation, `tailscale.com/envknob` (lines 16–17) for runtime feature flags like `TS_DEBUG_CONNBLOB`, and `tailscale.com/util/mak` (lines 81–82) for efficient map and slice manipulations when building peer lists.

## Practical Implementation: Server and Client Examples

The following examples demonstrate how Tailcat assembles these components to create encrypted connections using only a connection token.

### Starting a Tailcat Server

This server uses the WireGuard engine, netstack, and disco components to accept encrypted connections and expose an SSH listener on port 22:

```go
package main

import (
	"log"
	"net"

	"github.com/tailscale/tailcat"
)

func main() {
	srv := &tailcat.Server{
		// Use an automatically generated key
		Key: tailcat.key.NodePrivate{},
		// Listen on the default DERP region (auto-detected)
		RegionID: -1,
		// Expose an SSH server (no authentication)
		OnTCP: func(port uint16) func(net.Conn) {
			if port == 22 {
				return func(c net.Conn) {
					// Tailcat provides a minimal SSH implementation
					// For brevity we just close the connection
					c.Close()
				}
			}
			return nil
		},
	}
	if err := srv.Start(); err != nil {
		log.Fatalf("server start: %v", err)
	}
	log.Printf("Tailcat server ready – token: %s", srv.ConnBlob())
	select {} // block forever
}

```

### Connecting a Tailcat Client

The client uses the `tsdial` package and WireGuard engine to connect via the token generated above:

```go
package main

import (
	"log"

	"github.com/tailscale/tailcat"
)

func main() {
	// Token obtained from the server’s ConnBlob() call
	const token = "tc..."

	client := tailcat.NewClient(tailcat.ConnBlob(token))

	// Optional: run a simple TCP echo test
	if err := client.DialTCPPort(8000).Write([]byte("hello")); err != nil {
		log.Fatalf("dial: %v", err)
	}
	log.Println("connected and sent data")
}

```

## Key Source Files

Understanding the file structure reveals how these components are glued together:

- **[`tailcat.go`](https://github.com/tailscale/tailcat/blob/main/tailcat.go)**: The central library (lines 16–87) that imports all Tailscale packages and exposes the `Server`, `Client`, and `ConnBlob` APIs.
- **[`pickregion.go`](https://github.com/tailscale/tailcat/blob/main/pickregion.go)**: Implements automatic DERP region selection using `tailscale.com/net/netcheck` to find the lowest-latency relay.
- **[`wire.go`](https://github.com/tailscale/tailcat/blob/main/wire.go)**: Handles CBOR encoding for the connection token, wrapping `tailcfg` types for compact wire representation.
- **[`disco.go`](https://github.com/tailscale/tailcat/blob/main/disco.go)**: A thin wrapper around the `tailscale.com/disco` package for endpoint advertising.

## Summary

Tailcat demonstrates the reusability of Tailscale’s networking stack by composing these essential components:

- **Encryption and Routing**: `wgengine`, `wgcfg`, and `types/key` provide WireGuard functionality without custom cryptography.
- **NAT Traversal**: `disco` and `netmon` enable Magicsock-style endpoint discovery and UDP hole punching.
- **Virtual Networking**: `netstack` and `router` create an isolated TCP/IP environment within the process.
- **Configuration**: `tailcfg`, `netmap`, and `tsd` standardize network state representation.
- **Observability**: `health`, `ipnstate`, and `eventbus` integrate with Tailscale’s monitoring ecosystem.

By leveraging these packages, Tailcat achieves the same security guarantees as the standard Tailscale client—WireGuard encryption, automatic NAT traversal, and DERP fallback—while remaining a compact, self-contained binary.

## Frequently Asked Questions

### What is the primary difference between Tailcat and the standard Tailscale client?

Tailcat operates without a centralized control plane or coordination server. While it reuses the same **core Tailscale components** for encryption and networking (such as `wgengine` and `disco`), it establishes connections using a pre-shared connection token (`ConnBlob`) rather than fetching a network map from Tailscale's control servers. This makes Tailcat suitable for ephemeral, token-based peer connections.

### How does Tailcat handle NAT traversal without a control plane?

Tailcat imports the `tailscale.com/disco` package to perform the standard Magicsock discovery handshake. The `disco` package (referenced in [`tailcat.go`](https://github.com/tailscale/tailcat/blob/main/tailcat.go) lines 63–66) advertises endpoints via STUN and attempts direct UDP paths between peers. If direct connection fails, Tailcat falls back to DERP relays, using the region selection logic in [`pickregion.go`](https://github.com/tailscale/tailcat/blob/main/pickregion.go) to choose the nearest relay automatically.

### Which Tailscale package provides the TCP/IP stack for Tailcat?

The **in-process TCP/IP stack** comes from `tailscale.com/wgengine/netstack`, imported at lines 84–86 of [`tailcat.go`](https://github.com/tailscale/tailcat/blob/main/tailcat.go). This package implements a full network stack in userspace, allowing Tailcat to accept TCP connections and handle DNS resolution internally without requiring root access or TUN device configuration on the host.

### Can Tailcat be used in production environments?

Tailcat is currently an experimental demonstration of how to compose Tailscale libraries. While it uses production-grade packages like `wgengine` and `netstack` that power millions of Tailscale connections, the specific orchestration in [`tailcat.go`](https://github.com/tailscale/tailcat/blob/main/tailcat.go) lacks the comprehensive testing, failover logic, and multi-platform support of the official client. It serves best as a reference architecture for building custom Tailscale-powered tools.