node

package
v0.2.4 Latest Latest
Warning

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

Go to latest
Published: Apr 9, 2026 License: MIT Imports: 41 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func BridgeDirectCounted added in v0.1.6

func BridgeDirectCounted(a, b net.Conn, tc *TrafficCounters)

BridgeDirectCounted copies between two net.Conn bidirectionally using pooled buffers, tracking bytes through traffic counters.

func ClientTLSConfig

func ClientTLSConfig(nodeCert tls.Certificate, caPool *x509.CertPool) *tls.Config

ClientTLSConfig returns a TLS config that presents the node cert and verifies peers against the CA.

Overlay networks don't use hostname-based certificate verification — peer addresses are determined by the gossip table, not DNS. We skip Go's built-in hostname check and instead verify the cert chain manually against the CA pool. This is the same approach used by WireGuard, Tailscale, and other mesh VPNs.

func Debugf

func Debugf(format string, args ...any)

func Errorf

func Errorf(format string, args ...any)

func ExportFECFrameWrite added in v0.2.1

func ExportFECFrameWrite(w io.Writer, frameType byte, groupID uint16, index byte, payload []byte) error

ExportFECFrameWrite is an exported alias for fecFrameWrite, used by tests.

func FECFrameRead

func FECFrameRead(r io.Reader) (frameType byte, groupID uint16, index byte, payload []byte, err error)

fecFrameRead reads one FEC-framed packet.

func FECGroupSizeForLoss added in v0.2.1

func FECGroupSizeForLoss(lossRate float64) int

FECGroupSizeForLoss returns the optimal FEC group size for a given packet loss rate. Returns 0 to disable FEC when loss is negligible.

func FormatPortRanges

func FormatPortRanges(ports []PortRange) string

FormatPortRanges formats port ranges as a human-readable string.

func HandleRelayStream

func HandleRelayStream(stream net.Conn, reader *bufio.Reader, req TunnelRequest, selfID string, callerNodeID string, router *Router, acls *ACLTable, metaLookup MetaLookup, tc *TrafficCounters)

HandleRelayStream is called by the dispatcher when a tunnel stream arrives. callerNodeID is the verified identity of the peer that opened the stream (from TLS CN).

func Infof

func Infof(format string, args ...any)

func LinkScore

func LinkScore(e PeerEntry) float64

LinkScore computes a composite routing score for a peer entry. Lower score = better path. Uses latency, loss rate, and hop count.

func LoadCAPool

func LoadCAPool(caCertPEM []byte) (*x509.CertPool, error)

LoadCAPool loads only the CA cert for client nodes (no private key needed).

func LoadNodePubKey

func LoadNodePubKey(path string) (ed25519.PublicKey, error)

LoadNodePubKey loads an Ed25519 public key from a PEM file. Useful for the operator authorize flow.

func MatchesNode

func MatchesNode(pattern, nodeID string, meta NodeMeta) bool

matchesNode checks if pattern matches nodeID, considering tags and names. Pattern formats:

  • "*" or glob: matched against nodeID
  • "tag:<name>": true if the node has that tag
  • plain string that isn't a glob: matched as name first, then as nodeID glob

func MeshIPFromNodeID

func MeshIPFromNodeID(nodeID string) net.IP

MeshIPFromNodeID derives a deterministic mesh IP from a node ID string within the configured mesh CIDR. The host part is derived from the first 4 hex chars of the nodeID (2 bytes), combined with the network prefix.

func MeshIPFromNodeIDWithCIDR added in v0.2.0

func MeshIPFromNodeIDWithCIDR(nodeID, cidr string) net.IP

MeshIPFromNodeIDWithCIDR derives a mesh IP within the given CIDR. It uses FNV-1a hash of the full nodeID for good distribution and avoids both the network address (host 0) and broadcast address (max host).

func NewFECDecoder

func NewFECDecoder() *fecDecoder

func NewFECEncoder

func NewFECEncoder(groupSize int) *fecEncoder

NewFECEncoder creates an encoder with the given group size. Use groupSize=0 to get the default (10).

func RegisterService

func RegisterService(table *Table, selfID, addr string, pubKey []byte, isCA bool, svc ServiceRecord)

RegisterService adds a service to the node's self-entry in the gossip table. Other nodes learn about it on the next gossip push.

func SaveNodeState added in v0.2.0

func SaveNodeState(dataDir string, snc SignedNodeConfig) error

SaveNodeState atomically writes a signed node config to state.dat.

func SavePeers

func SavePeers(dataDir string, entries []PeerEntry) error

SavePeers atomically writes entries to peers.json in dataDir.

func ServeTCP

func ServeTCP(listenAddr string, router *Router, selfID string, isRevoked func(string) bool, tc *TrafficCounters) error

ServeTCP listens for inbound TCP client connections and relays them. Uses SO_REUSEPORT so the kernel can load-balance across multiple goroutines.

func SetLogLevel

func SetLogLevel(l LogLevel)

SetLogLevel sets the global log level.

func SetupLogFile added in v0.2.0

func SetupLogFile(path string) error

SetupLogFile configures the global logger to write to a rotating file.

func StoreJoinResult

func StoreJoinResult(dir string, resp JoinResponse) error

StoreJoinResult persists the CA cert and CA-signed node cert returned by the join flow.

func VerifyNetConfig

func VerifyNetConfig(snc SignedNetConfig, pub ed25519.PublicKey) error

VerifyNetConfig checks the signature on a SignedNetConfig against pub.

func VerifyNodeConfig added in v0.2.0

func VerifyNodeConfig(snc SignedNodeConfig, pub ed25519.PublicKey) error

VerifyNodeConfig checks the signature on a SignedNodeConfig.

func Warnf

func Warnf(format string, args ...any)

Types

type ACLRule

type ACLRule struct {
	Action     string      `json:"action"`            // "allow" or "deny" (default "allow")
	SrcPattern string      `json:"src_pat,omitempty"` // source node pattern (glob, tag:xxx, or name)
	DstPattern string      `json:"dst_pat"`           // destination node pattern
	Ports      []PortRange `json:"ports,omitempty"`   // empty = all ports
}

ACLRule defines a traffic policy. Rules are evaluated top-to-bottom; first match wins.

type ACLTable

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

ACLTable is a concurrent-safe store of node ACL policies.

func NewACLTable

func NewACLTable() *ACLTable

func (*ACLTable) Check

func (t *ACLTable) Check(callerID, destNodeID string, port uint16, lookup MetaLookup) error

Check is a convenience method on the table.

func (*ACLTable) Get

func (t *ACLTable) Get(nodeID string) NodeACL

Get returns the ACL for a node. If no explicit ACL exists, returns a default allow-all policy so nodes without ACLs are unrestricted.

func (*ACLTable) MergeFrom

func (t *ACLTable) MergeFrom(acls []NodeACL)

MergeFrom merges a slice of ACLs received via gossip.

func (*ACLTable) Snapshot

func (t *ACLTable) Snapshot() []NodeACL

Snapshot returns a copy of all ACL entries.

func (*ACLTable) Upsert

func (t *ACLTable) Upsert(a NodeACL)

Upsert adds or replaces an entry (keeps the higher Version).

type CA

type CA struct {
	PrivKey   ed25519.PrivateKey
	Cert      *x509.Certificate
	CertPEM   []byte
	Pool      *x509.CertPool
	JoinToken string    // legacy master token (fallback)
	Events    *EventLog // event log for CA operations (set by node)

	OnTokenUsed func(string) // callback when a token is used (wired to scribe)
	// contains filtered or unexported fields
}

CA is the certificate authority for the pulse network. Only one node runs as CA; all others get their certs signed by it.

func InitCA

func InitCA(dir string, joinToken string) (*CA, error)

InitCA generates a new CA keypair and writes it to dir.

func LoadCA

func LoadCA(dir string, joinToken string) (*CA, error)

LoadCA loads an existing CA from disk.

func (*CA) HandleJoin

func (ca *CA) HandleJoin(req JoinRequest) JoinResponse

HandleJoin validates a join request and returns the signed certificate. Authentication is token-based only.

func (*CA) IsRevoked

func (ca *CA) IsRevoked(nodeID string) bool

IsRevoked reports whether nodeID has been revoked.

func (*CA) RevokeNode

func (ca *CA) RevokeNode(nodeID string)

RevokeNode marks nodeID as revoked in the CA's local revocation set and audits it. The scribe is responsible for distributing the revocation via NetworkConfig.

func (*CA) ServerTLSConfig

func (ca *CA) ServerTLSConfig(nodeCert tls.Certificate) *tls.Config

ServerTLSConfig returns a TLS config that enforces mTLS using the CA as trust root.

func (*CA) SignIdentity

func (ca *CA) SignIdentity(pub ed25519.PublicKey, nodeID string) (JoinResponse, error)

SignIdentity issues a CA-signed certificate for the given node identity. Used by the CA node to sign its own cert during first-time initialization, so peers can verify it via mTLS using the CA pool.

func (*CA) SyncRevokedIDs

func (ca *CA) SyncRevokedIDs(ids []string)

SyncRevokedIDs updates the CA's local revocation set from a scribe NetworkConfig.

func (*CA) SyncTokens

func (ca *CA) SyncTokens(tokens []JoinToken)

SyncTokens updates the CA's local token list from a scribe NetworkConfig.

type CIDRRoute

type CIDRRoute struct {
	CIDR      string `json:"cidr"`
	NodeID    string `json:"node_id"`
	AutoLearn bool   `json:"auto,omitempty"` // true if learned from gossip, false if manually added
	// contains filtered or unexported fields
}

CIDRRoute maps a network prefix to an exit relay node. Traffic destined for IPs in CIDR is tunnelled through NodeID.

type ControlServer

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

ControlServer exposes the node's runtime over a Unix domain socket.

func NewControlServer

func NewControlServer(socketPath string, n *Node) *ControlServer

func (*ControlServer) ListenAndServe

func (s *ControlServer) ListenAndServe(ctx context.Context) error

type CumulativeStats added in v0.1.8

type CumulativeStats struct {
	BytesIn  int64 `json:"bytes_in"`
	BytesOut int64 `json:"bytes_out"`
}

CumulativeStats is the persisted summary for a peer (survives restarts).

type DNSServer

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

DNSServer resolves .pulse hostnames for the local mesh.

func NewDNSServer

func NewDNSServer(addr string, table *Table, extraZones func() []DNSZone) *DNSServer

func (*DNSServer) ListenAndServe

func (d *DNSServer) ListenAndServe(ctx context.Context) error

func (*DNSServer) ServeDNS

func (d *DNSServer) ServeDNS(w dns.ResponseWriter, r *dns.Msg)

ServeDNS handles all queries for *.pulse.

type DNSZone

type DNSZone struct {
	Name  string `json:"name"`  // fully-qualified record name, e.g. "svc.internal.example.com."
	Type  string `json:"type"`  // A, AAAA, CNAME, TXT, SRV
	Value string `json:"value"` // record value
	TTL   uint32 `json:"ttl"`
}

DNSZone is a DNS record pushed by the scribe to all node DNS servers.

type EventEntry added in v0.1.8

type EventEntry struct {
	Timestamp time.Time `json:"ts"`
	Type      EventType `json:"type"`
	NodeID    string    `json:"node_id,omitempty"`
	Detail    string    `json:"detail,omitempty"`
	Error     string    `json:"error,omitempty"`
}

EventEntry is one line in the event log.

func ReadFiltered added in v0.1.8

func ReadFiltered(path string, opts FilterOpts) ([]EventEntry, error)

ReadFiltered reads the log file and returns matching events.

type EventLog added in v0.1.8

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

EventLog is a buffered, append-only JSONL event log with rotation. Writes are buffered and flushed periodically (not fsynced per write) for minimal impact on the data path.

func OpenEventLog added in v0.1.8

func OpenEventLog(path string) (*EventLog, error)

OpenEventLog opens (or creates) the event log at path.

func (*EventLog) Close added in v0.1.8

func (l *EventLog) Close() error

Close flushes and closes the log file.

func (*EventLog) Emit added in v0.1.8

func (l *EventLog) Emit(e EventEntry)

Emit appends one event to the log. Buffered, not fsynced.

func (*EventLog) Flush added in v0.1.8

func (l *EventLog) Flush()

Flush writes buffered data to disk.

func (*EventLog) Subscribe added in v0.1.8

func (l *EventLog) Subscribe() chan EventEntry

Subscribe returns a channel that receives new events as they are emitted. Call Unsubscribe to stop receiving and free resources.

func (*EventLog) Unsubscribe added in v0.1.8

func (l *EventLog) Unsubscribe(ch chan EventEntry)

Unsubscribe removes a subscriber channel.

type EventType added in v0.1.8

type EventType string

EventType identifies the kind of event being logged.

const (
	// Node lifecycle.
	EventStartup  EventType = "startup"
	EventShutdown EventType = "shutdown"

	// Link events.
	EventLinkUp   EventType = "link_up"
	EventLinkDown EventType = "link_down"

	// NAT punch.
	EventNATPunchSuccess EventType = "nat_punch_success"
	EventNATPunchFail    EventType = "nat_punch_fail"

	// Certificate lifecycle.
	EventCertRenew         EventType = "cert_renew"
	EventCertExpiryWarning EventType = "cert_expiry_warning"

	// CA operations.
	EventJoinAttempted EventType = "join_attempted"
	EventCertIssued    EventType = "cert_issued"
	EventJoinFailed    EventType = "join_failed"
	EventCertRevoked   EventType = "cert_revoked"

	// Scribe operations.
	EventNetconfigBroadcast EventType = "netconfig_broadcast"
	EventACLChanged         EventType = "acl_changed"
	EventDNSChanged         EventType = "dns_changed"
	EventTagChanged         EventType = "tag_changed"
	EventNodeRevoked        EventType = "node_revoked"
)

type ExitRouteTable

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

ExitRouteTable is the client-side CIDR → exit node mapping. Persisted as JSON to disk so it survives restarts.

func NewExitRouteTable

func NewExitRouteTable(path string) *ExitRouteTable

func (*ExitRouteTable) Add

func (t *ExitRouteTable) Add(cidr, nodeID string) error

Add inserts a CIDR → nodeID mapping (or updates existing).

func (*ExitRouteTable) Load

func (t *ExitRouteTable) Load() error

Load reads routes from disk. No-op if the file doesn't exist yet.

func (*ExitRouteTable) Lookup

func (t *ExitRouteTable) Lookup(ip net.IP) string

Lookup returns the exit node ID for ip using longest-prefix match. Returns empty string if no route matches.

func (*ExitRouteTable) Remove

func (t *ExitRouteTable) Remove(cidr string)

Remove deletes the route for cidr.

func (*ExitRouteTable) Save

func (t *ExitRouteTable) Save() error

Save persists the current route table to disk atomically.

func (*ExitRouteTable) Snapshot

func (t *ExitRouteTable) Snapshot() []CIDRRoute

Snapshot returns a copy of the current route table for display.

func (*ExitRouteTable) SyncFromGossip

func (t *ExitRouteTable) SyncFromGossip(exitNodes []PeerEntry)

SyncFromGossip updates auto-learned routes from exit nodes in the gossip table. Manual routes are never touched. Auto-learned routes for nodes no longer advertising a CIDR are removed.

type FilterOpts added in v0.1.8

type FilterOpts struct {
	Type  EventType
	Node  string
	Since time.Time
}

FilterOpts controls which events are returned by ReadFiltered.

type Identity

type Identity struct {
	NodeID     string
	PublicKey  ed25519.PublicKey
	PrivateKey ed25519.PrivateKey
	TLSCert    tls.Certificate
	CAPool     *x509.CertPool // nil until joined; then used for mTLS peer verification
	Joined     bool           // true once the node has a CA-signed cert
}

func LoadOrCreateIdentity

func LoadOrCreateIdentity(dir string) (*Identity, error)

type JoinRequest

type JoinRequest struct {
	PublicKey []byte `json:"public_key"` // raw ed25519 public key of the joining node
	Token     string `json:"token"`      // shared join token
}

JoinRequest is sent by a new node to request a signed certificate.

type JoinResponse

type JoinResponse struct {
	CACert     string `json:"ca_cert"`     // PEM of the CA certificate
	SignedCert string `json:"signed_cert"` // PEM of the node's CA-signed certificate
	NodeID     string `json:"node_id"`
	Error      string `json:"error,omitempty"`
}

JoinResponse is returned by the CA (or proxied back through the mesh).

func Join

func Join(ctx context.Context, relayAddr string, req JoinRequest) (*JoinResponse, error)

Join connects to a relay's /join endpoint for first-time bootstrapping.

func SignIdentityFromKeyFile

func SignIdentityFromKeyFile(keyPath string, ca *CA) (JoinResponse, string, error)

SignIdentityFromKeyFile loads a node's identity.key and signs a cert using the given CA. Returns the JoinResponse (containing signed cert + CA cert PEM) and the node ID. Used for offline signing when the CA is behind NAT and unreachable by the new node.

type JoinToken

type JoinToken struct {
	Value     string    `json:"value"`
	CreatedAt time.Time `json:"created_at"`
	ExpiresAt time.Time `json:"expires_at,omitempty"` // zero = no expiry
	MaxUses   int       `json:"max_uses,omitempty"`   // 0 = unlimited
	UseCount  int       `json:"use_count"`
}

JoinToken is a scribe-managed token that authorizes nodes to join the mesh.

func GenerateToken

func GenerateToken(ttl time.Duration, maxUses int) JoinToken

GenerateToken creates a new random join token.

func (*JoinToken) IsExhausted

func (t *JoinToken) IsExhausted() bool

IsExhausted reports whether the token has reached its max use count.

func (*JoinToken) IsExpired

func (t *JoinToken) IsExpired() bool

IsExpired reports whether the token has passed its expiry time.

func (*JoinToken) IsValid

func (t *JoinToken) IsValid() bool

IsValid reports whether the token can still be used.

type LinkRegistry

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

LinkRegistry manages active peer sessions.

func NewLinkRegistry

func NewLinkRegistry() *LinkRegistry

func (*LinkRegistry) Add

func (r *LinkRegistry) Add(link *PeerLink)

func (*LinkRegistry) All

func (r *LinkRegistry) All() []*PeerLink

func (*LinkRegistry) Get

func (r *LinkRegistry) Get(nodeID string) (*PeerLink, bool)

func (*LinkRegistry) Has

func (r *LinkRegistry) Has(nodeID string) bool

func (*LinkRegistry) Remove

func (r *LinkRegistry) Remove(nodeID string)

func (*LinkRegistry) SessionOwner

func (r *LinkRegistry) SessionOwner(s Session) string

SessionOwner returns the NodeID of the peer that owns the given session.

type LinkStats

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

LinkStats holds measured quality metrics for a single peer link.

func (*LinkStats) LatencyMS

func (s *LinkStats) LatencyMS() float64

LatencyMS returns the exponentially-weighted moving average RTT in milliseconds. Returns math.MaxFloat64 if no successful probes yet.

func (*LinkStats) LossRate

func (s *LinkStats) LossRate() float64

LossRate returns the fraction of failed probes in the rolling window (0.0–1.0).

type LogLevel

type LogLevel int32

LogLevel controls the verbosity of pulse's logging.

const (
	LevelDebug LogLevel = iota
	LevelInfo
	LevelWarn
	LevelError
)

func ParseLogLevel

func ParseLogLevel(s string) LogLevel

ParseLogLevel maps a string to a LogLevel.

type MetaLookup

type MetaLookup func(nodeID string) NodeMeta

MetaLookup resolves a nodeID to its operator-assigned metadata.

type MultipathSession

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

MultipathSession wraps multiple Sessions to the same logical destination and provides weighted load balancing across them.

Open() uses inverse-score weighted random selection — better paths get proportionally more traffic. A 5ms path gets ~10x more streams than a 50ms path instead of an equal split.

Accept() fans in from all underlying sessions via background goroutines.

func NewMultipathSession

func NewMultipathSession(sessions []Session, scores []float64) *MultipathSession

func (*MultipathSession) Accept

func (m *MultipathSession) Accept() (net.Conn, error)

func (*MultipathSession) Close

func (m *MultipathSession) Close() error

func (*MultipathSession) IsClosed

func (m *MultipathSession) IsClosed() bool

func (*MultipathSession) Open

func (m *MultipathSession) Open() (net.Conn, error)

Open picks a session using weighted random selection (better paths get more traffic).

func (*MultipathSession) Transport

func (m *MultipathSession) Transport() string

type NATManager

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

NATManager discovers the local public address and orchestrates hole punching to build direct links between peers.

func NewNATManager

func NewNATManager(selfID string, table *Table, registry *LinkRegistry, router *Router, tlsCfg *tls.Config, onSession func(context.Context, Session, string, string)) *NATManager

func (*NATManager) HandlePunchStart added in v0.1.6

func (m *NATManager) HandlePunchStart(ctx context.Context, conn interface{ Write([]byte) (int, error) }, peerNodeID, peerPublicAddr, token string)

HandlePunchStart is called when we receive a "punch_start" stream from a peer. We reply with "punch_ready" on the same stream, then begin probing.

func (*NATManager) Run

func (m *NATManager) Run(ctx context.Context)

Run starts the periodic hole-punch loop.

type NetworkConfig

type NetworkConfig struct {
	Version    int64               `json:"version"`               // monotonically increasing (unix milliseconds)
	MeshCIDR   string              `json:"mesh_cidr,omitempty"`   // network-wide mesh IP range (e.g. "10.100.0.0/16")
	RevokedIDs []string            `json:"revoked_ids"`           // node IDs whose certificates have been revoked
	DNSZones   []DNSZone           `json:"dns_zones"`             // additional DNS records served by all nodes
	GlobalACLs []NodeACL           `json:"global_acls"`           // network-wide ACL additions
	NodeMeta   map[string]NodeMeta `json:"node_meta,omitempty"`   // operator-assigned node names and tags
	JoinTokens []JoinToken         `json:"join_tokens,omitempty"` // scribe-managed join tokens
}

NetworkConfig is the authoritative network-wide configuration distributed by the scribe node. Nodes merge by keeping the entry with the highest Version.

type Node

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

Node is a running relay instance.

func New

func New(cfg *config.Config, ca *CA, version string) (*Node, error)

func (*Node) ReloadIdentity

func (n *Node) ReloadIdentity() error

ReloadIdentity reloads the identity from disk (after a successful join).

func (*Node) Run

func (n *Node) Run(ctx context.Context) error

func (*Node) SendRemoteCmd added in v0.2.0

func (n *Node) SendRemoteCmd(targetNodeID string, cmd string, config map[string]string) error

SendRemoteCmd sends a remote command to a target node via the mesh.

func (*Node) Stop

func (n *Node) Stop()

Stop triggers a graceful shutdown of the node.

type NodeACL

type NodeACL struct {
	NodeID  string    `json:"node_id"`
	Allow   []ACLRule `json:"allow"` // kept as "allow" in JSON for backward compat, but rules can be deny
	Version int64     `json:"version"`
}

NodeACL is the policy for one node. Rules are evaluated in order; first match wins.

func (NodeACL) Check

func (a NodeACL) Check(srcNodeID, destNodeID string, port uint16, lookup MetaLookup) error

Check returns nil if srcNodeID may connect to destNodeID:port. Uses first-match evaluation. No rules = allow-all (open by default). Any rules present + no match = implicit deny.

type NodeConfig added in v0.2.0

type NodeConfig struct {
	Version      int64    `json:"version"`
	TunEnabled   bool     `json:"tun_enabled"`
	SocksEnabled bool     `json:"socks_enabled"`
	DNSEnabled   bool     `json:"dns_enabled"`
	ExitEnabled  bool     `json:"exit_enabled"`
	ExitCIDRs    []string `json:"exit_cidrs,omitempty"`
	FECEnabled   bool     `json:"fec_enabled"`
	TunQueues    int      `json:"tun_queues,omitempty"` // multi-queue TUN readers
	MeshIP       string   `json:"mesh_ip,omitempty"`
	MeshCIDR     string   `json:"mesh_cidr,omitempty"`
	LogLevel     string   `json:"log_level,omitempty"`
}

NodeConfig is the per-node configuration managed by the scribe. Nodes receive this via mesh from the scribe and persist it to state.dat.

type NodeMeta

type NodeMeta struct {
	Name      string   `json:"name,omitempty"`
	Tags      []string `json:"tags,omitempty"`
	MeshIP    string   `json:"mesh_ip,omitempty"`    // operator-assigned mesh IP override
	PinnedVia string   `json:"pinned_via,omitempty"` // force traffic through this relay nodeID
}

NodeMeta holds operator-assigned metadata for a node (name, tags). Managed by the scribe and distributed via NetworkConfig.

type NodeStats

type NodeStats struct {
	NodeID      string    `json:"node_id"`
	ActiveConns int       `json:"active_conns"`
	BytesIn     int64     `json:"bytes_in"`
	BytesOut    int64     `json:"bytes_out"`
	ReportedAt  time.Time `json:"reported_at"`
}

NodeStats is a stats report pushed by a node to the scribe.

type PeerEntry

type PeerEntry struct {
	NodeID    string    `json:"node_id"`
	Addr      string    `json:"addr"`
	PublicKey []byte    `json:"public_key"`
	LastSeen  time.Time `json:"last_seen"`
	HopCount  int       `json:"hop_count"`
	IsCA      bool      `json:"is_ca,omitempty"`

	// Measured link quality — populated by the Prober, not gossipped.
	LatencyMS float64 `json:"latency_ms,omitempty"`
	LossRate  float64 `json:"loss_rate,omitempty"`

	// Link type — populated locally from LinkRegistry, not gossipped.
	// Values: "direct_quic" (direct P2P via NAT hole punch), "quic" (direct QUIC),
	// "websocket" (relay via websocket+yamux), "" (no active session).
	LinkType string `json:"link_type,omitempty"`

	// NAT hole punching.
	PublicAddr string `json:"public_addr,omitempty"`

	// Exit node routing.
	IsExit    bool     `json:"is_exit,omitempty"`
	ExitCIDRs []string `json:"exit_cidrs,omitempty"`

	// Service discovery (DNS SRV records).
	Services []ServiceRecord `json:"services,omitempty"`

	// ACL policy for this node, distributed by the CA via gossip.
	ACL *NodeACL `json:"acl,omitempty"`

	// Scribe role — collects stats and distributes NetworkConfig.
	IsScribe      bool   `json:"is_scribe,omitempty"`
	ScribeAPIAddr string `json:"scribe_api_addr,omitempty"` // HTTP API address of scribe

	// Tun device — mesh IP assigned to this node.
	MeshIP string `json:"mesh_ip,omitempty"`

	// Binary version reported by the node in its handshake.
	Version string `json:"version,omitempty"`

	// Operator-assigned metadata (populated from NetworkConfig, not gossipped).
	Name string   `json:"name,omitempty"`
	Tags []string `json:"tags,omitempty"`

	// MetaVersion is a monotonic counter incremented when self-metadata
	// (MeshIP, Name, Tags) changes. It allows metadata updates to flow
	// through gossip even past hop-0 protection.
	MetaVersion uint64 `json:"meta_version,omitempty"`
	// contains filtered or unexported fields
}

PeerEntry is a routing table record that is gossipped between nodes.

func LoadPeers

func LoadPeers(dataDir string) ([]PeerEntry, error)

LoadPeers reads peers.json from dataDir. Returns nil, nil if the file doesn't exist yet.

type PeerLink struct {
	NodeID string

	ViaNAT bool // true if established via NAT hole punch
	// contains filtered or unexported fields
}

PeerLink is an active session to a peer node.

func (*PeerLink) Close

func (p *PeerLink) Close() error

func (*PeerLink) IsClosed

func (p *PeerLink) IsClosed() bool

func (*PeerLink) Open

func (p *PeerLink) Open() (net.Conn, error)

func (*PeerLink) Transport

func (p *PeerLink) Transport() string

type PortRange

type PortRange struct {
	Low  uint16 `json:"low"`
	High uint16 `json:"high"` // 0 means same as Low (single port)
}

PortRange is an inclusive range of TCP ports.

func ParsePortRanges

func ParsePortRanges(s string) ([]PortRange, error)

ParsePortRanges parses a comma-separated list like "22,80,443,8000-9000".

func (PortRange) Contains

func (r PortRange) Contains(port uint16) bool

type Prober

type Prober struct {
	OnLinkDead func(nodeID string) // called when a dead link is detected and removed
	// contains filtered or unexported fields
}

Prober continuously measures link quality to all directly-connected peers.

func NewProber

func NewProber(registry *LinkRegistry, table *Table) *Prober

func (*Prober) Run

func (p *Prober) Run(ctx interface{ Done() <-chan struct{} })

Run starts the probe loop. Call in a goroutine.

type RotatingWriter added in v0.2.0

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

RotatingWriter wraps a file with automatic rotation at logMaxBytes.

func NewRotatingWriter added in v0.2.0

func NewRotatingWriter(path string) (*RotatingWriter, error)

NewRotatingWriter opens a log file with rotation support.

func (*RotatingWriter) Write added in v0.2.0

func (w *RotatingWriter) Write(p []byte) (int, error)

type Router

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

func NewRouter

func NewRouter(table *Table, registry *LinkRegistry) *Router

func (*Router) Resolve

func (r *Router) Resolve(destNodeID string) (Session, error)

Resolve returns the best Session for reaching destNodeID. When multiple viable paths exist, a MultipathSession is returned so streams are load-balanced across all of them (Cloudflare Argo-style multipath).

type SOCKSServer

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

SOCKSServer is a SOCKS5 proxy that routes .pulse domains through the mesh and other traffic through exit nodes or directly.

func NewSOCKSServer

func NewSOCKSServer(addr string, router *Router, table *Table, exitRoutes *ExitRouteTable, selfID string, dnsZones func() []DNSZone, tc *TrafficCounters) *SOCKSServer

func (*SOCKSServer) ListenAndServe

func (s *SOCKSServer) ListenAndServe(ctx context.Context) error

type Scribe

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

Scribe collects network-wide statistics, distributes NetworkConfig (DNS zones, revocation lists, global ACLs), and exposes an HTTP management API.

A scribe is a regular node that does not forward TCP streams — it acts as the control plane of the mesh, while relay nodes are the data plane.

func NewScribe

func NewScribe(n *Node) *Scribe

func (*Scribe) AcceptStats

func (s *Scribe) AcceptStats(stats NodeStats)

AcceptStats stores a stats report from a peer node.

func (*Scribe) AddACLRule

func (s *Scribe) AddACLRule(rule ACLRule)

AddACLRule appends a global ACL rule and broadcasts the updated config.

func (*Scribe) AddDNSZone

func (s *Scribe) AddDNSZone(zone DNSZone) error

AddDNSZone upserts a DNS zone record and broadcasts updated NetworkConfig.

func (*Scribe) BuildNodeConfigForPeer added in v0.2.0

func (s *Scribe) BuildNodeConfigForPeer(nodeID string) NodeConfig

BuildNodeConfigForPeer constructs a NodeConfig for a node based on its metadata and templates.

func (*Scribe) CreateToken

func (s *Scribe) CreateToken(ttl time.Duration, maxUses int) JoinToken

CreateToken generates a new join token and broadcasts it to the CA.

func (*Scribe) DeleteTemplate added in v0.2.0

func (s *Scribe) DeleteTemplate(pattern string)

DeleteTemplate removes a config template.

func (*Scribe) GetTemplates added in v0.2.0

func (s *Scribe) GetTemplates() map[string]NodeConfig

GetTemplates returns a copy of all config templates.

func (*Scribe) GlobalACLRules

func (s *Scribe) GlobalACLRules() []ACLRule

GlobalACLRules returns a copy of the current global ACL rules.

func (*Scribe) Groups added in v0.2.0

func (s *Scribe) Groups() map[string]int

Groups returns a map of tag prefixes to node counts for fleet overview.

func (*Scribe) IncrementTokenUse

func (s *Scribe) IncrementTokenUse(tokenValue string)

IncrementTokenUse marks a token as used once.

func (*Scribe) ListTokens

func (s *Scribe) ListTokens() []JoinToken

ListTokens returns all tokens (including expired, for display).

func (*Scribe) NodesByTagPattern added in v0.2.0

func (s *Scribe) NodesByTagPattern(pattern string) []string

NodesByTagPattern returns nodeIDs of all nodes whose tags match the pattern.

func (*Scribe) PinRoute added in v0.2.0

func (s *Scribe) PinRoute(nodeID, viaNodeID string)

PinRoute forces traffic to a node through a specific relay.

func (*Scribe) PushNodeConfig added in v0.2.0

func (s *Scribe) PushNodeConfig(nodeID string, cfg NodeConfig)

PushNodeConfig generates a signed NodeConfig for a target node and sends it via mesh.

func (*Scribe) PushTo

func (s *Scribe) PushTo(session Session)

PushTo sends the current signed NetworkConfig to a single session. Called when a new peer connects so it gets config immediately without waiting for the next broadcast tick.

func (*Scribe) RemoveACLRule

func (s *Scribe) RemoveACLRule(index int) error

RemoveACLRule removes a global ACL rule by index and broadcasts.

func (*Scribe) RemoveDNSZone

func (s *Scribe) RemoveDNSZone(name, recType string) error

RemoveDNSZone removes DNS zone records matching name (and optionally type).

func (*Scribe) RemoveTag

func (s *Scribe) RemoveTag(nodeID, tag string)

RemoveTag removes a tag from a node.

func (*Scribe) Revoke

func (s *Scribe) Revoke(nodeID string)

Revoke adds nodeID to the revocation list and broadcasts an updated NetworkConfig.

func (*Scribe) RevokeToken

func (s *Scribe) RevokeToken(prefix string) error

RevokeToken removes a token by value prefix.

func (*Scribe) Run

func (s *Scribe) Run(ctx context.Context)

Run starts the scribe's HTTP API and the periodic NetworkConfig broadcast.

func (*Scribe) SetMeshIP added in v0.2.0

func (s *Scribe) SetMeshIP(nodeID, meshIP string)

SetMeshIP assigns a manual mesh IP override to a node.

func (*Scribe) SetName

func (s *Scribe) SetName(nodeID, name string)

SetName assigns a friendly name to a node.

func (*Scribe) SetTag

func (s *Scribe) SetTag(nodeID, tag string)

SetTag adds a tag to a node.

func (*Scribe) SetTemplate added in v0.2.0

func (s *Scribe) SetTemplate(pattern string, cfg NodeConfig)

SetTemplate adds or updates a config template for a tag pattern.

func (*Scribe) Stats added in v0.1.6

func (s *Scribe) Stats() map[string]NodeStats

Stats returns a copy of the per-node traffic stats collected from peers.

func (*Scribe) UnpinRoute added in v0.2.0

func (s *Scribe) UnpinRoute(nodeID string)

UnpinRoute removes a route pin from a node.

type ServiceRecord

type ServiceRecord struct {
	Name     string `json:"name"`
	Port     uint16 `json:"port"`
	Priority uint16 `json:"priority,omitempty"`
}

ServiceRecord is a service advertised by a node in the gossip table.

type Session

type Session interface {
	// Open creates a new outbound stream to the peer.
	Open() (net.Conn, error)
	// Accept waits for the peer to open an inbound stream.
	Accept() (net.Conn, error)
	// Close terminates the session and all its streams.
	Close() error
	// IsClosed reports whether the session has been terminated.
	IsClosed() bool
	// Transport returns a human-readable transport name for logging.
	Transport() string
}

Session is an abstract multiplexed connection to a peer. Implemented by both yamuxSession (WebSocket) and quicSession (QUIC).

type SignedNetConfig

type SignedNetConfig struct {
	Config    NetworkConfig `json:"config"`
	Signature []byte        `json:"sig"`
	ScribeID  string        `json:"scribe_id"`
}

SignedNetConfig wraps a NetworkConfig with an ed25519 signature from the scribe. Nodes verify the signature against the scribe's public key from the gossip table before accepting a new config.

func SignNetConfig

func SignNetConfig(cfg NetworkConfig, priv ed25519.PrivateKey, scribeID string) (SignedNetConfig, error)

SignNetConfig signs cfg with the scribe's private key.

type SignedNodeConfig added in v0.2.0

type SignedNodeConfig struct {
	Config    NodeConfig `json:"config"`
	Signature []byte     `json:"sig"`
	ScribeID  string     `json:"scribe_id"`
}

SignedNodeConfig wraps a NodeConfig with a scribe signature.

func LoadNodeState added in v0.2.0

func LoadNodeState(dataDir string) (*SignedNodeConfig, error)

LoadNodeState reads state.dat from dataDir. Returns nil, nil if the file doesn't exist.

func SignNodeConfig added in v0.2.0

func SignNodeConfig(cfg NodeConfig, priv ed25519.PrivateKey, scribeID string) (SignedNodeConfig, error)

SignNodeConfig signs a per-node config with the scribe's private key.

type StatsRing added in v0.1.8

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

StatsRing holds per-peer ring buffers for time-series metrics.

func NewStatsRing added in v0.1.8

func NewStatsRing() *StatsRing

NewStatsRing creates an empty stats ring.

func (*StatsRing) AllLatest added in v0.1.8

func (s *StatsRing) AllLatest() map[string]StatsSnapshot

AllLatest returns the most recent snapshot per peer.

func (*StatsRing) Get added in v0.1.8

func (s *StatsRing) Get(nodeID string) []StatsSnapshot

Get returns the time-series for a peer in chronological order.

func (*StatsRing) LoadCumulative added in v0.1.8

func (s *StatsRing) LoadCumulative(path string) error

LoadCumulative restores cumulative totals from a JSON file.

func (*StatsRing) Record added in v0.1.8

func (s *StatsRing) Record(nodeID string, snap StatsSnapshot)

Record adds a snapshot for a peer.

func (*StatsRing) SaveCumulative added in v0.1.8

func (s *StatsRing) SaveCumulative(path string) error

SaveCumulative writes per-peer cumulative totals to a JSON file.

type StatsSnapshot added in v0.1.8

type StatsSnapshot struct {
	Timestamp   time.Time `json:"ts"`
	LatencyMS   float64   `json:"latency_ms"`
	LossRate    float64   `json:"loss_rate"`
	BytesIn     int64     `json:"bytes_in"`
	BytesOut    int64     `json:"bytes_out"`
	ActiveConns int       `json:"active_conns"`
}

StatsSnapshot is one sample of per-peer metrics.

type Table

type Table struct {
	OnPrune func(nodeID string) // called when a stale peer is evicted
	// contains filtered or unexported fields
}

Table is a thread-safe routing table.

func NewTable

func NewTable() *Table

func (*Table) ExitNodes

func (t *Table) ExitNodes() []PeerEntry

ExitNodes returns all entries advertising themselves as exit nodes.

func (*Table) FindCA

func (t *Table) FindCA() (PeerEntry, bool)

FindCA returns the routing entry of the CA node, if known.

func (*Table) FindScribe

func (t *Table) FindScribe() (PeerEntry, bool)

FindScribe returns the routing entry of the Scribe node, if known.

func (*Table) Get

func (t *Table) Get(nodeID string) (PeerEntry, bool)

Get returns a single entry by NodeID.

func (*Table) MergeFrom

func (t *Table) MergeFrom(entries []PeerEntry, selfID string)

MergeFrom merges received entries, incrementing HopCount by 1.

func (*Table) PruneStale

func (t *Table) PruneStale(selfID string)

PruneStale removes entries whose LastSeen is older than peerStaleTTL. selfID is never pruned — the self-entry is refreshed continuously.

func (*Table) RunPruner

func (t *Table) RunPruner(ctx context.Context, selfID string)

RunPruner starts a background goroutine that periodically evicts stale peers. It stops when ctx is cancelled.

func (*Table) Snapshot

func (t *Table) Snapshot() []PeerEntry

Snapshot returns a copy of all entries.

func (*Table) SnapshotSince

func (t *Table) SnapshotSince(minVersion uint64) []PeerEntry

SnapshotSince returns entries that changed after minVersion (for delta-gossip).

func (*Table) Upsert

func (t *Table) Upsert(e PeerEntry)

Upsert adds or updates an entry, keeping the freshest LastSeen and lowest HopCount.

func (*Table) UpsertForce

func (t *Table) UpsertForce(e PeerEntry)

UpsertForce unconditionally replaces an entry, bypassing staleness checks. Use only for the local self-entry where we always want the current state to win.

func (*Table) Version

func (t *Table) Version() uint64

Version returns the current table version (monotonic counter).

type TrafficCounters added in v0.1.6

type TrafficCounters struct {
	BytesIn     atomic.Int64
	BytesOut    atomic.Int64
	ActiveConns atomic.Int64
}

TrafficCounters tracks bytes transferred and active connections across all tunnels and SOCKS proxied streams on this node.

type TunDevice

type TunDevice interface {
	Run(ctx context.Context)
	HandleInbound(conn net.Conn) // legacy one-shot stream (pre-pipe fallback)
	RunPipe(nodeID string, conn net.Conn)
	RefreshMeshIPs()
	UpdateMeshCIDR(newCIDR string) bool // reconfigure TUN IP+route when mesh CIDR changes; returns true if changed
}

TunDevice is the interface for the optional layer-3 mesh VPN. Implemented by tunManager on Linux and tunStub elsewhere.

func NewTunDevice

func NewTunDevice(n *Node, devName, meshCIDR string) (TunDevice, error)

type TunnelRequest

type TunnelRequest struct {
	DestNodeID string `json:"dest_node"`
	DestAddr   string `json:"dest_addr"`
}

TunnelRequest describes where to route a stream.

Jump to

Keyboard shortcuts

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