# What Is the Meow Protocol in Tailcat? Complete Technical Guide

> Discover the Meow protocol in Tailcat. Learn how this bootstrap mechanism establishes WireGuard peer relationships over DERP connections using a unique magic prefix and ping-pong messages.

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

---

**The Meow protocol is a lightweight, custom bootstrap mechanism implemented in the Tailcat repository that establishes WireGuard peer relationships over DERP connections, distinguished by a four-byte magic prefix `[m e o w]` and simple ping-pong message exchange to register clients and confirm peer establishment.**

The Meow protocol provides the foundational discovery layer for Tailcat, enabling clients to announce their public keys to the server and receive acknowledgment before initiating standard WireGuard handshakes. Unlike traditional discovery mechanisms, this protocol operates directly on Tailscale's DERP relay infrastructure, allowing peer registration even when both endpoints lack direct UDP connectivity.

## Meow Protocol Packet Structure

The Meow protocol defines a minimal binary format optimized for embedding within DERP datagrams. As implemented in [`main/disco.go`](https://github.com/tailscale/tailcat/blob/main/main/disco.go), each packet begins with a distinctive signature that distinguishes it from other discovery traffic.

### Magic Prefix and Message Types

Every Meow packet starts with a four-byte magic prefix defined in [`main/disco.go`](https://github.com/tailscale/tailcat/blob/main/main/disco.go) lines 15-18 as the byte sequence `[m e o w]`. Immediately following this prefix, a single byte identifies the message type:

- **`meowTypePing` (0x01)**: Sent from client to server to initiate registration
- **`meowTypePong` (0x02)**: Sent from server to client as acknowledgment

These constants are defined in [`main/disco.go`](https://github.com/tailscale/tailcat/blob/main/main/disco.go) lines 20-23.

### Payload Format

For **MeowPing** messages (client-to-server), the payload consists of two consecutive 32-byte raw key values:

1. The client's **NodePublic** key
2. The client's **DiscoPublic** key

The `EncodeMeowPing` function in [`main/disco.go`](https://github.com/tailscale/tailcat/blob/main/main/disco.go) (lines 30-38) serializes these keys directly into the packet buffer following the magic prefix and type byte. The server responds with a **Meowed** packet, which contains only the magic prefix and the `meowTypePong` byte (see `EncodeMeowed` in lines 41-46), providing a deterministic acknowledgment that the peer registration succeeded.

## Server-Side Peer Registration

The server processes incoming Meow packets through the `(*locoBackend).onMeow` method defined in [`main/tailcat.go`](https://github.com/tailscale/tailcat/blob/main/main/tailcat.go) (lines 56-60). This handler implements the full lifecycle of peer admission and network configuration.

### Validation and Client Filtering

Upon receiving a valid MeowPing, the server first validates the source against an `allowedClients` authorization list. If the client passes authorization checks, the server constructs a new `tailcfg.Node` entry containing the parsed public keys and stores it in the internal `b.clients` map (lines 71-84).

### Network Map Distribution

After peer registration, the server immediately constructs a fresh `netmap.NetworkMap` containing both the server node and all registered peers. This network map is distributed to two critical subsystems:

1. **MagicSock**: Updated via `mc.SetNetworkMap` to establish DERP routing paths
2. **Netstack**: Updated via `b.sys.Netstack.Get().UpdateNetstackIPs` to configure internal IP addressing

This dual update ensures the new peer becomes reachable through both the DERP relay and the virtual network interface.

### Sending the Meowed Acknowledgment

Once the peer is fully registered in the network map, the server transmits the Meowed acknowledgment back to the client. As shown around line 429 in [`main/tailcat.go`](https://github.com/tailscale/tailcat/blob/main/main/tailcat.go), the server calls `mc.SendDERPPacketTo(src, regionID, EncodeMeowed())` to deliver the pong response through the same DERP region where the ping arrived.

## Client-Side Implementation

Clients initiate the WireGuard bootstrap sequence by constructing and transmitting a MeowPing packet, then monitoring the DERP connection for the server's response.

### Encoding and Sending MeowPing

The client creates the bootstrap packet using `EncodeMeowPing(nodeKey, discoKey)` from [`main/disco.go`](https://github.com/tailscale/tailcat/blob/main/main/disco.go) (lines 30-38). This function serializes the client's node and disco public keys into the standard Meow format. The resulting byte slice is transmitted as a raw DERP packet through the MagicSock layer:

```go
// Build the ping
ping := tailcat.EncodeMeowPing(myNodePublic, myDiscoPublic)

// Send as raw DERP packet
magicSock.SendDERPPacket(remoteAddr, ping)

```

### Receiving the Meowed Response

After transmission, the client blocks on the DERP connection until it receives a valid Meowed packet. The `IsMeowedPacket` helper function in [`main/disco.go`](https://github.com/tailscale/tailcat/blob/main/main/disco.go) (lines 64-67) validates the four-byte magic prefix and message type:

```go
// Block until we see a Meowed packet
buf := make([]byte, 1500)
n, _, _ := conn.ReadFrom(buf)
if tailcat.IsMeowedPacket(buf[:n]) {
    // Meowed received – safe to start WireGuard handshake
}

```

Receipt of this acknowledgment confirms that the server has registered the peer and populated the network map, allowing the client to proceed with standard WireGuard key exchange.

## Protocol Detection Helpers

Tailcat provides utility functions to distinguish Meow traffic from other DERP-bound packets without full parsing. The `IsMeowPacket` function in [`main/disco.go`](https://github.com/tailscale/tailcat/blob/main/main/disco.go) (lines 25-28) performs a fast four-byte prefix check against the `meowMagic` constant. Similarly, `IsMeowedPacket` validates server responses (lines 64-67). These predicates enable efficient packet filtering in the DERP handling pipeline defined in [`main/wire.go`](https://github.com/tailscale/tailcat/blob/main/main/wire.go), ensuring Meow packets route to the specialized `onMeow` handler while other traffic proceeds to standard WireGuard processing.

## Summary

- The **Meow protocol** uses a four-byte magic prefix `[m e o w]` to identify bootstrap packets within DERP streams.
- **MeowPing** messages carry 32-byte NodePublic and DiscoPublic keys from client to server, initiating peer registration.
- The server validates clients against `allowedClients`, registers them in the internal node map, and broadcasts updated network configurations to MagicSock and Netstack.
- **Meowed** packets (type 0x02) provide deterministic acknowledgment that peer registration succeeded and WireGuard initialization can proceed.
- Helper functions `IsMeowPacket` and `IsMeowedPacket` in [`main/disco.go`](https://github.com/tailscale/tailcat/blob/main/main/disco.go) enable zero-copy packet classification before full parsing.

## Frequently Asked Questions

### How does the Meow protocol differ from standard WireGuard handshake?

The Meow protocol operates at the **discovery layer** rather than the cryptographic layer. While WireGuard handles key exchange and session establishment, Meow solves the prerequisite problem of how a client announces its existence and public keys to the server when direct UDP connectivity may not exist. According to the Tailcat source code, Meow packets travel over DERP relays (defined in [`main/wire.go`](https://github.com/tailscale/tailcat/blob/main/main/wire.go)), allowing bootstrap registration through NATs and firewalls that would block standard WireGuard UDP packets.

### What security checks does the server perform when processing a MeowPing?

The server implements authorization through the `allowedClients` check within `(*locoBackend).onMeow` ([`main/tailcat.go`](https://github.com/tailscale/tailcat/blob/main/main/tailcat.go), lines 56-60). Before creating a `tailcfg.Node` entry or updating the network map, the server validates that the connecting public key appears in the authorized client list. This prevents unauthorized nodes from injecting themselves into the mesh network during the bootstrap phase.

### Can the Meow protocol handle multiple concurrent registration requests?

Yes. The implementation in [`main/tailcat.go`](https://github.com/tailscale/tailcat/blob/main/main/tailcat.go) uses the `b.clients` map (lines 71-84) to store peer state, and the `onMeow` handler acquires appropriate locks (implied by the backend structure) before modifying shared state. The server constructs a complete `netmap.NetworkMap` for each successful registration, ensuring all connected peers receive updated routing information through `mc.SetNetworkMap` calls, supporting dynamic mesh growth without requiring restarts.

### What happens if a client never receives the Meowed acknowledgment?

Without receiving a valid Meowed packet validated by `IsMeowedPacket` ([`main/disco.go`](https://github.com/tailscale/tailcat/blob/main/main/disco.go), lines 64-67), the client cannot confirm that the server has registered its peer entry. The client would typically retry the MeowPing transmission or fail to establish the WireGuard tunnel, as the server's network map would not include the necessary peer configuration for routing packets back to the client.