Documentation
¶
Index ¶
- func BridgeDirectCounted(a, b net.Conn, tc *TrafficCounters)
- func ClientTLSConfig(nodeCert tls.Certificate, caPool *x509.CertPool) *tls.Config
- func Debugf(format string, args ...any)
- func Errorf(format string, args ...any)
- func ExportFECFrameWrite(w io.Writer, frameType byte, groupID uint16, index byte, payload []byte) error
- func FECFrameRead(r io.Reader) (frameType byte, groupID uint16, index byte, payload []byte, err error)
- func FECGroupSizeForLoss(lossRate float64) int
- func FormatPortRanges(ports []PortRange) string
- func HandleRelayStream(stream net.Conn, reader *bufio.Reader, req TunnelRequest, selfID string, ...)
- func Infof(format string, args ...any)
- func LinkScore(e PeerEntry) float64
- func LoadCAPool(caCertPEM []byte) (*x509.CertPool, error)
- func LoadNodePubKey(path string) (ed25519.PublicKey, error)
- func MatchesNode(pattern, nodeID string, meta NodeMeta) bool
- func MeshIPFromNodeID(nodeID string) net.IP
- func MeshIPFromNodeIDWithCIDR(nodeID, cidr string) net.IP
- func NewFECDecoder() *fecDecoder
- func NewFECEncoder(groupSize int) *fecEncoder
- func RegisterService(table *Table, selfID, addr string, pubKey []byte, isCA bool, svc ServiceRecord)
- func SaveNodeState(dataDir string, snc SignedNodeConfig) error
- func SavePeers(dataDir string, entries []PeerEntry) error
- func ServeTCP(listenAddr string, router *Router, selfID string, isRevoked func(string) bool, ...) error
- func SetLogLevel(l LogLevel)
- func SetupLogFile(path string) error
- func StoreJoinResult(dir string, resp JoinResponse) error
- func VerifyNetConfig(snc SignedNetConfig, pub ed25519.PublicKey) error
- func VerifyNodeConfig(snc SignedNodeConfig, pub ed25519.PublicKey) error
- func Warnf(format string, args ...any)
- type ACLRule
- type ACLTable
- type CA
- func (ca *CA) HandleJoin(req JoinRequest) JoinResponse
- func (ca *CA) IsRevoked(nodeID string) bool
- func (ca *CA) RevokeNode(nodeID string)
- func (ca *CA) ServerTLSConfig(nodeCert tls.Certificate) *tls.Config
- func (ca *CA) SignIdentity(pub ed25519.PublicKey, nodeID string) (JoinResponse, error)
- func (ca *CA) SyncRevokedIDs(ids []string)
- func (ca *CA) SyncTokens(tokens []JoinToken)
- type CIDRRoute
- type ControlServer
- type CumulativeStats
- type DNSServer
- type DNSZone
- type EventEntry
- type EventLog
- type EventType
- type ExitRouteTable
- func (t *ExitRouteTable) Add(cidr, nodeID string) error
- func (t *ExitRouteTable) Load() error
- func (t *ExitRouteTable) Lookup(ip net.IP) string
- func (t *ExitRouteTable) Remove(cidr string)
- func (t *ExitRouteTable) Save() error
- func (t *ExitRouteTable) Snapshot() []CIDRRoute
- func (t *ExitRouteTable) SyncFromGossip(exitNodes []PeerEntry)
- type FilterOpts
- type Identity
- type JoinRequest
- type JoinResponse
- type JoinToken
- type LinkRegistry
- type LinkStats
- type LogLevel
- type MetaLookup
- type MultipathSession
- type NATManager
- type NetworkConfig
- type Node
- type NodeACL
- type NodeConfig
- type NodeMeta
- type NodeStats
- type PeerEntry
- type PeerLink
- type PortRange
- type Prober
- type RotatingWriter
- type Router
- type SOCKSServer
- type Scribe
- func (s *Scribe) AcceptStats(stats NodeStats)
- func (s *Scribe) AddACLRule(rule ACLRule)
- func (s *Scribe) AddDNSZone(zone DNSZone) error
- func (s *Scribe) BuildNodeConfigForPeer(nodeID string) NodeConfig
- func (s *Scribe) CreateToken(ttl time.Duration, maxUses int) JoinToken
- func (s *Scribe) DeleteTemplate(pattern string)
- func (s *Scribe) GetTemplates() map[string]NodeConfig
- func (s *Scribe) GlobalACLRules() []ACLRule
- func (s *Scribe) Groups() map[string]int
- func (s *Scribe) IncrementTokenUse(tokenValue string)
- func (s *Scribe) ListTokens() []JoinToken
- func (s *Scribe) NodesByTagPattern(pattern string) []string
- func (s *Scribe) PinRoute(nodeID, viaNodeID string)
- func (s *Scribe) PushNodeConfig(nodeID string, cfg NodeConfig)
- func (s *Scribe) PushTo(session Session)
- func (s *Scribe) RemoveACLRule(index int) error
- func (s *Scribe) RemoveDNSZone(name, recType string) error
- func (s *Scribe) RemoveTag(nodeID, tag string)
- func (s *Scribe) Revoke(nodeID string)
- func (s *Scribe) RevokeToken(prefix string) error
- func (s *Scribe) Run(ctx context.Context)
- func (s *Scribe) SetMeshIP(nodeID, meshIP string)
- func (s *Scribe) SetName(nodeID, name string)
- func (s *Scribe) SetTag(nodeID, tag string)
- func (s *Scribe) SetTemplate(pattern string, cfg NodeConfig)
- func (s *Scribe) Stats() map[string]NodeStats
- func (s *Scribe) UnpinRoute(nodeID string)
- type ServiceRecord
- type Session
- type SignedNetConfig
- type SignedNodeConfig
- type StatsRing
- type StatsSnapshot
- type Table
- func (t *Table) ExitNodes() []PeerEntry
- func (t *Table) FindCA() (PeerEntry, bool)
- func (t *Table) FindScribe() (PeerEntry, bool)
- func (t *Table) Get(nodeID string) (PeerEntry, bool)
- func (t *Table) MergeFrom(entries []PeerEntry, selfID string)
- func (t *Table) PruneStale(selfID string)
- func (t *Table) RunPruner(ctx context.Context, selfID string)
- func (t *Table) Snapshot() []PeerEntry
- func (t *Table) SnapshotSince(minVersion uint64) []PeerEntry
- func (t *Table) Upsert(e PeerEntry)
- func (t *Table) UpsertForce(e PeerEntry)
- func (t *Table) Version() uint64
- type TrafficCounters
- type TunDevice
- type TunnelRequest
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 ¶
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 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
FECGroupSizeForLoss returns the optimal FEC group size for a given packet loss rate. Returns 0 to disable FEC when loss is negligible.
func FormatPortRanges ¶
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 LinkScore ¶
LinkScore computes a composite routing score for a peer entry. Lower score = better path. Uses latency, loss rate, and hop count.
func LoadCAPool ¶
LoadCAPool loads only the CA cert for client nodes (no private key needed).
func LoadNodePubKey ¶
LoadNodePubKey loads an Ed25519 public key from a PEM file. Useful for the operator authorize flow.
func MatchesNode ¶
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 ¶
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
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 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 SetupLogFile ¶ added in v0.2.0
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.
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 ¶
Get returns the ACL for a node. If no explicit ACL exists, returns a default allow-all policy so nodes without ACLs are unrestricted.
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 (*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) RevokeNode ¶
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 ¶
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 ¶
SyncRevokedIDs updates the CA's local revocation set from a scribe NetworkConfig.
func (*CA) SyncTokens ¶
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
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 ¶
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
OpenEventLog opens (or creates) the event log at path.
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
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 ¶
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 ¶
GenerateToken creates a new random join token.
func (*JoinToken) IsExhausted ¶
IsExhausted reports whether the token has reached its max use count.
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) 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.
type LogLevel ¶
type LogLevel int32
LogLevel controls the verbosity of pulse's logging.
func ParseLogLevel ¶
ParseLogLevel maps a string to a LogLevel.
type MetaLookup ¶
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) 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 (*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 (*Node) ReloadIdentity ¶
ReloadIdentity reloads the identity from disk (after a successful join).
func (*Node) SendRemoteCmd ¶ added in v0.2.0
SendRemoteCmd sends a remote command to a target node via the mesh.
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.
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.
type PeerLink ¶
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.
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 ¶
ParsePortRanges parses a comma-separated list like "22,80,443,8000-9000".
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
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.
type Router ¶
type Router struct {
// contains filtered or unexported fields
}
func NewRouter ¶
func NewRouter(table *Table, registry *LinkRegistry) *Router
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 (*Scribe) AcceptStats ¶
AcceptStats stores a stats report from a peer node.
func (*Scribe) AddACLRule ¶
AddACLRule appends a global ACL rule and broadcasts the updated config.
func (*Scribe) AddDNSZone ¶
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 ¶
CreateToken generates a new join token and broadcasts it to the CA.
func (*Scribe) DeleteTemplate ¶ added in v0.2.0
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 ¶
GlobalACLRules returns a copy of the current global ACL rules.
func (*Scribe) Groups ¶ added in v0.2.0
Groups returns a map of tag prefixes to node counts for fleet overview.
func (*Scribe) IncrementTokenUse ¶
IncrementTokenUse marks a token as used once.
func (*Scribe) ListTokens ¶
ListTokens returns all tokens (including expired, for display).
func (*Scribe) NodesByTagPattern ¶ added in v0.2.0
NodesByTagPattern returns nodeIDs of all nodes whose tags match the pattern.
func (*Scribe) PinRoute ¶ added in v0.2.0
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 ¶
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 ¶
RemoveACLRule removes a global ACL rule by index and broadcasts.
func (*Scribe) RemoveDNSZone ¶
RemoveDNSZone removes DNS zone records matching name (and optionally type).
func (*Scribe) Revoke ¶
Revoke adds nodeID to the revocation list and broadcasts an updated NetworkConfig.
func (*Scribe) RevokeToken ¶
RevokeToken removes a token by value prefix.
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
Stats returns a copy of the per-node traffic stats collected from peers.
func (*Scribe) UnpinRoute ¶ added in v0.2.0
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
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
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 (*Table) FindScribe ¶
FindScribe returns the routing entry of the Scribe node, if known.
func (*Table) PruneStale ¶
PruneStale removes entries whose LastSeen is older than peerStaleTTL. selfID is never pruned — the self-entry is refreshed continuously.
func (*Table) RunPruner ¶
RunPruner starts a background goroutine that periodically evicts stale peers. It stops when ctx is cancelled.
func (*Table) SnapshotSince ¶
SnapshotSince returns entries that changed after minVersion (for delta-gossip).
func (*Table) Upsert ¶
Upsert adds or updates an entry, keeping the freshest LastSeen and lowest HopCount.
func (*Table) UpsertForce ¶
UpsertForce unconditionally replaces an entry, bypassing staleness checks. Use only for the local self-entry where we always want the current state to win.
type TrafficCounters ¶ added in v0.1.6
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.
type TunnelRequest ¶
type TunnelRequest struct {
DestNodeID string `json:"dest_node"`
DestAddr string `json:"dest_addr"`
}
TunnelRequest describes where to route a stream.
Source Files
¶
- acl.go
- ca.go
- control.go
- copy.go
- dns.go
- eventlog.go
- exit.go
- fec.go
- gossip.go
- handshake.go
- identity.go
- join.go
- log.go
- metrics.go
- multipath.go
- nat.go
- netconfig.go
- netlink_linux.go
- node.go
- persist.go
- pool.go
- probe.go
- quic_transport.go
- router.go
- scribe.go
- scribe_api.go
- session.go
- sockopt_linux.go
- socks.go
- stats.go
- tls.go
- token.go
- traffic.go
- transport.go
- tun.go
- tun_linux.go
- tunnel.go