What Information Is Contained in a Tailcat ConnBlob?

A Tailcat ConnBlob is a compact, URL-safe string that encodes a CBOR-serialized ConnInfo structure containing the server's public key and DERP region information, enabling clients to locate and authenticate to a Tailcat server without additional network calls.

A ConnBlob serves as a self-contained connection credential within the tailscale/tailcat repository. This binary-to-text format packages everything a client needs to establish an authenticated connection while minimizing payload size and network round trips.

Internal Structure and Data Model

The ConnInfo Core Fields

At the heart of every ConnBlob lies a ConnInfo structure that carries two essential data categories:

  • ServerPublic: The server's public key (key.NodePublic), serialized with the CBOR field name p. This field is always present and forms the cryptographic basis for connection authentication.
  • Region Data: Either a full Region list or a lightweight RegionID. The Region field contains complete DERP region objects (serialized as r), while RegionID stores a numeric reference to a known Tailscale-provided region (serialized as i). Including region data allows clients to skip separate DERP map fetches.

Certain fields like RegionCode, RegionName, and redundant node names are intentionally omitted during encoding to reduce blob size. The ParseConnBlob function restores these implicit fields during decoding by cross-referencing the embedded region ID against the known DERP map.

Wire Format Definitions in wire.go

The CBOR wire types that define the binary layout are declared in wire.go:

  • wireConnInfo (lines 25-30): Maps to the top-level structure with fields p (public key), r (regions), and i (region ID).
  • wireRegion (lines 32-38): Represents DERP regions using compact field keys i (ID), c (code), m (name), and N (nodes).
  • wireNode (lines 40-58): Defines individual DERP nodes with single-character fields including n (name), h (hostname), 4 (IPv4), 6 (IPv6), s (port), d (cert name), and x (test flag).

These abbreviated field names minimize the final encoded payload size.

Encoding and Decoding Process

Creating a ConnBlob

The generation follows a strict pipeline to ensure compactness and URL safety:

  1. Struct Conversion: The high-level ConnInfo converts to wireConnInfo (and nested wireRegion/wireNode types), stripping redundant data.
  2. CBOR Encoding: The wire structure serializes using CBOR (Concise Binary Object Representation).
  3. Base64 Encoding: The CBOR bytes undergo base64-URL encoding without padding.
  4. Prefixing: The resulting string receives a "tc" prefix, producing the final ConnBlob format (e.g., tc...).

Parsing and Field Reconstruction

Decoding reverses this pipeline through the ParseConnBlob function implemented in tailcat.go (lines 744-747). The function:

  • Strips the "tc" prefix and base64-URL decodes the payload
  • CBOR-decodes the bytes into the wire types
  • Reconstructs the full ConnInfo, re-injecting omitted fields (such as region codes and names) when only a RegionID was provided

This ensures that clients receive a complete connection description regardless of which encoding optimization the server chose.

Working with ConnBlob in Go

Generating a ConnBlob

To create a ConnBlob with an embedded DERP region (larger payload):

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

func makeBlobWithRegion(pub tailcat.NodePublic, derp *tailcfg.DERPRegion) tailcat.ConnBlob {
	ci := tailcat.ConnInfo{
		ServerPublic: pub,
		Region:       []*tailcfg.DERPRegion{derp},
	}
	return ci.ConnBlob()
}

To generate a minimal ConnBlob using only a region ID:

func makeBlobWithRegionID(pub tailcat.NodePublic, id int) tailcat.ConnBlob {
	ci := tailcat.ConnInfo{
		ServerPublic: pub,
		RegionID:     id,
	}
	return ci.ConnBlob()
}

Parsing a ConnBlob

Extract connection details from a blob string:

func parseBlob(blob tailcat.ConnBlob) (tailcat.ConnInfo, error) {
	ci, err := tailcat.ParseConnBlob(blob)
	if err != nil {
		return tailcat.ConnInfo{}, err
	}
	// ci now holds ServerPublic + either Region or RegionID
	return ci, nil
}

Initializing a Client

Pass a ConnBlob directly to the client constructor:

func newClientFromBlob(blobStr string) *tailcat.Client {
	blob := tailcat.ConnBlob(blobStr)
	client := tailcat.NewClient(blob)
	return client
}

Summary

  • A Tailcat ConnBlob is a URL-safe string starting with "tc" that encodes connection parameters.
  • Internally, it contains CBOR-encoded data representing a ConnInfo structure with the server's public key (p) and either full DERP regions (r) or a region ID (i).
  • The wire format defined in wire.go uses single-character field names to minimize size.
  • ParseConnBlob in tailcat.go handles decoding and reconstructs omitted fields from the known DERP map.
  • Clients use this blob to authenticate and locate servers without fetching additional configuration.

Frequently Asked Questions

What does the "tc" prefix indicate in a ConnBlob?

The "tc" prefix identifies the string as a Tailcat ConnBlob and distinguishes it from other base64-encoded payloads. After removing this two-character prefix, the remaining string represents base64-URL-encoded CBOR data containing the connection information.

How does a ConnBlob minimize its size?

The encoding omits optional fields like region codes, region names, and duplicate node hostnames when they match the node name. The wire format in wire.go further reduces size by mapping struct fields to single-character CBOR keys (e.g., p for public key, i for region ID). When the client already knows the DERP map, the server can encode only a RegionID instead of full region objects.

What is the difference between Region and RegionID in a ConnBlob?

Region embeds a complete list of DERP region objects, making the blob self-contained but larger. RegionID stores only an integer reference to a Tailscale-hosted DERP region, producing a shorter blob that assumes the client possesses the corresponding DERP map. Both are serialized with distinct CBOR field keys (r vs i) in the wireConnInfo structure.

Where is the ConnBlob parsing logic implemented?

The ParseConnBlob function is implemented in tailcat.go (lines 744-747), which handles base64-URL decoding, CBOR deserialization into wireConnInfo, and reconstruction of any stripped fields. The ConnBlob() method that generates the string resides in the same file, while the underlying wire types are defined in wire.go (lines 25-58).

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 →