mesh

package
v0.1.0-alpha.8 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 18, 2026 License: Apache-2.0 Imports: 29 Imported by: 0

Documentation

Overview

Package mesh owns the WireGuard overlay (ADR-0003). The Manager interface is consumed by the daemon wiring and the agent; implementations:

  • device manager with wireguard-go / kernel WG (tasks T-18..T-21, T-57/58)
  • Disabled (single-node mode, returned by NewDisabled)
  • testutil fake (simcluster)

Index

Constants

View Source
const (
	// GossipPort is the memberlist bind port. It is bound to the mesh IP only —
	// never a public interface.
	GossipPort = 7946
)

Gossip is a memberlist-based failure detector (T-56). Control nodes run it over the mesh: SWIM-style probing spots a dead node within a few seconds — far faster than the 30s heartbeat deadline — and feeds the same durable SetNodeStatus path as the heartbeat monitor (T-21). The two detectors are combined by Decide so neither can flap a node's status on its own.

Variables

This section is empty.

Functions

func DiscoKey

func DiscoKey(pub wgtypes.Key, caHash []byte) []byte

DiscoKey derives the shared disco HMAC key for a node.

func EnsureNodeKey

func EnsureNodeKey(path string) (string, error)

EnsureNodeKey loads or creates the WG private key at path and returns its public key (base64). A joining node calls this to advertise its public key in the join request before the device is brought up; Up reuses the same path so the advertised key matches the running device.

func RunPeerSync

func RunPeerSync(ctx context.Context, cfg PeerSyncConfig) error

RunPeerSync keeps a WatchPeers stream open and applies every pushed PeerSet to the mesh device, reconnecting with backoff. Blocks until ctx is canceled.

Types

type DeviceManager

type DeviceManager struct {
	// contains filtered or unexported fields
}

DeviceManager implements mesh.Manager over a real WireGuard device.

func NewDeviceManager

func NewDeviceManager(log *slog.Logger) *DeviceManager

NewDeviceManager builds a mesh manager backed by a real WG device. The kernel-vs-userspace choice is made at Up time (kernel preferred on Linux).

func (*DeviceManager) ApplyPeers

func (dm *DeviceManager) ApplyPeers(_ context.Context, peers *clusterv1.PeerSet) error

ApplyPeers reconciles the device's peer set to exactly `peers`.

func (*DeviceManager) Down

func (dm *DeviceManager) Down(_ context.Context) error

Down tears the device down.

func (*DeviceManager) InjectRelayed

func (dm *DeviceManager) InjectRelayed(srcNodeID string, payload []byte)

InjectRelayed queues a relay-received WG packet for WireGuard — called by the relay client's read loop. No-op without meshsock.

func (*DeviceManager) LastHandshakes

func (dm *DeviceManager) LastHandshakes() (map[string]int64, error)

LastHandshakes returns the last-handshake time (unix seconds, 0 = never) per peer, keyed by hex public key. Useful for path diagnostics and integration tests.

func (*DeviceManager) PublicKey

func (dm *DeviceManager) PublicKey() (string, error)

PublicKey returns the node's WG public key, generating the keypair on first use. Valid before Up (the key path is taken from the last Up config or, if Up has not run, this returns an error asking for a path).

func (*DeviceManager) PunchNow

func (dm *DeviceManager) PunchNow(peerID string, endpoints []netip.AddrPort, at time.Time)

PunchNow schedules a probe burst toward peerID at `at` — called when control pushes a PunchCommand over the node's PunchStream. No-op without meshsock.

func (*DeviceManager) Status

func (dm *DeviceManager) Status() Status

Status reports the current device state.

func (*DeviceManager) Up

func (dm *DeviceManager) Up(_ context.Context, cfg NodeConfig) error

Up creates and configures the WG device (idempotent). It requires root/CAP_NET_ADMIN.

type Disabled

type Disabled struct{}

Disabled is the single-node no-mesh implementation: everything is a no-op and Status reports Enabled=false. The daemon then binds all internal services to 127.0.0.1.

func NewDisabled

func NewDisabled() Disabled

func (Disabled) ApplyPeers

func (Disabled) Down

func (Disabled) Down(context.Context) error

func (Disabled) PublicKey

func (Disabled) PublicKey() (string, error)

func (Disabled) Status

func (Disabled) Status() Status

func (Disabled) Up

type DiscoPinger

type DiscoPinger struct {
	NodeID   string
	Key      []byte
	Controls []string // control disco endpoints "ip:port"
	Interval time.Duration
	Clock    clock.Clock
	Report   func(observedEndpoint string)
	Logger   *slog.Logger
	// contains filtered or unexported fields
}

DiscoPinger is the node-side prober. It pings each control's disco endpoint and reports the reflexive address the control observed.

func (*DiscoPinger) Run

func (p *DiscoPinger) Run(ctx context.Context)

Run probes every Interval until ctx is canceled.

type DiscoResponder

type DiscoResponder struct {
	// contains filtered or unexported fields
}

DiscoResponder is the control-side echo server. For each valid ping it returns a pong carrying the observed UDP source address.

func NewDiscoResponder

func NewDiscoResponder(addr string, keyForNode func(string) ([]byte, bool), log *slog.Logger) (*DiscoResponder, error)

NewDiscoResponder binds a UDP listener on addr ("ip:port").

func (*DiscoResponder) Addr

func (r *DiscoResponder) Addr() string

Addr is the bound listen address.

func (*DiscoResponder) Close

func (r *DiscoResponder) Close() error

Close stops the responder.

func (*DiscoResponder) Serve

func (r *DiscoResponder) Serve(ctx context.Context)

Serve reads and answers pings until ctx is canceled.

type Gossip

type Gossip struct {
	// contains filtered or unexported fields
}

Gossip owns the running memberlist and its liveness tracker.

func NewGossip

func NewGossip(cfg GossipConfig) (*Gossip, error)

NewGossip starts memberlist bound to the mesh IP and joins the given peers (best-effort — a node that cannot reach any peer yet still runs and will be discovered when a peer probes it).

func (*Gossip) Leave

func (g *Gossip) Leave(timeout time.Duration) error

Leave broadcasts a graceful departure, then Shutdown stops the listener.

func (*Gossip) Shutdown

func (g *Gossip) Shutdown() error

Shutdown stops the retry-join loop and the memberlist listener.

func (*Gossip) Snapshot

func (g *Gossip) Snapshot() map[string]nodehealth.GossipLiveness

Snapshot returns the current gossip liveness view keyed by node id.

type GossipConfig

type GossipConfig struct {
	// NodeID is this node's zattera id — used as the memberlist node name so
	// events map straight back to nodes.
	NodeID string
	// BindAddr is the mesh IP to bind (e.g. 10.90.0.1). Never a public IP.
	BindAddr string
	// Peers are other control nodes' mesh IPs to join (host or host:port).
	Peers []string
	// CAHash is the cluster CA hash; the gossip encryption key derives from it,
	// so only cluster members can join or read the gossip.
	CAHash []byte
	Clock  clock.Clock
	Logger *slog.Logger
}

GossipConfig configures the gossip failure detector.

type Manager

type Manager interface {
	// Up creates/configures the WG device. Idempotent.
	Up(ctx context.Context, cfg NodeConfig) error
	// ApplyPeers reconciles the device's peer set to exactly `peers`
	// (declarative full set — implementations diff internally).
	ApplyPeers(ctx context.Context, peers *clusterv1.PeerSet) error
	// Down tears the device down.
	Down(ctx context.Context) error
	Status() Status
	// PublicKey returns the node's WG public key (generating a keypair on
	// first use), valid before Up.
	PublicKey() (string, error)
}

Manager is the per-node mesh controller.

type MeshsockConfig

type MeshsockConfig struct {
	NodeID string
	CAHash []byte
	// Punch coordinates hole punching via control (nil disables punching).
	Punch meshsock.PunchRequester
	// Relay sends WG packets via the control TCP relay (nil disables the relay).
	Relay meshsock.RelaySender
}

MeshsockConfig parameterizes the meshsock datapath (T-57/T-58).

type NodeConfig

type NodeConfig struct {
	// PrivateKeyPath stores the WG private key (0600). Generated when absent.
	PrivateKeyPath string
	MeshIP         netip.Addr
	// ListenPort for WireGuard UDP (default 51820).
	ListenPort uint16
	// InterfaceName defaults to "zt0" (utunN chosen automatically on darwin).
	InterfaceName string
	// Meshsock, when set, brings the device up on the userspace meshsock bind
	// (UDP hole punching + relay, phases C/D). Kernel WG cannot use a custom
	// bind, so this forces userspace.
	Meshsock *MeshsockConfig
}

NodeConfig is what a node needs to bring its mesh interface up.

type PeerSyncConfig

type PeerSyncConfig struct {
	NodeID  string
	Manager Manager
	Clock   clock.Clock
	Logger  *slog.Logger
	// Dial opens a connection to a control node's MeshService. Called on every
	// (re)connect; the returned closer is invoked when the stream ends.
	Dial func(ctx context.Context) (grpc.ClientConnInterface, func() error, error)
	// OnPeers, when set, is called with every PeerSet received (before it is
	// applied). A worker uses it to keep its control-node failover set current.
	OnPeers func(*clusterv1.PeerSet)
}

PeerSyncConfig configures the node-side peer synchronizer.

type Status

type Status struct {
	Enabled   bool
	Up        bool
	MeshIP    netip.Addr
	PublicKey string
	// PeerPaths maps node id → path in use: "direct" | "punched" | "relay" | "hub".
	PeerPaths map[string]string
}

Status describes the current mesh device state.

Directories

Path Synopsis
Package meshsock is the custom wireguard-go conn.Bind (ADR-0003 Phase C/D): one UDP socket multiplexes WireGuard transport packets and disco probe frames, a per-peer path state machine upgrades hub-routed peers to direct or hole-punched UDP paths, and (Phase D) falls back to a TCP relay when no UDP path works.
Package meshsock is the custom wireguard-go conn.Bind (ADR-0003 Phase C/D): one UDP socket multiplexes WireGuard transport packets and disco probe frames, a per-peer path state machine upgrades hub-routed peers to direct or hole-punched UDP paths, and (Phase D) falls back to a TCP relay when no UDP path works.
Package relay is the Phase D DERP-lite fallback (ADR-0003): every control node runs an mTLS TCP relay; a meshsock node with no working UDP path frames its already-encrypted WireGuard packets as (dst node, payload) and the relay forwards them to the destination's connection.
Package relay is the Phase D DERP-lite fallback (ADR-0003): every control node runs an mTLS TCP relay; a meshsock node with no working UDP path frames its already-encrypted WireGuard packets as (dst node, payload) and the relay forwards them to the destination's connection.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL