Documentation
¶
Index ¶
- Variables
- func GenerateSessionID() (uint64, error)
- func NewIceDialer(cfg *ICEDialerConfig) infra.Dialer
- func NewRelayDialer(cfg *RelayDialerConfig) infra.Dialer
- func NewWGConfigurator(peerOps PeerOps, routeOps RouteOps) *wgConfigurator
- type ConnectionConfigurator
- type ConnectionState
- type ICEDialerConfig
- type ICETransport
- type PeerOps
- type PeerState
- type PeerStats
- type Probe
- func (p *Probe) Close()
- func (p *Probe) Handle(ctx context.Context, remoteId infra.PeerIdentity, packet *signal.SignalPacket) error
- func (p *Probe) OnConnectionStateChange(state ice.ConnectionState)
- func (p *Probe) Ping(ctx context.Context) error
- func (p *Probe) RTT() time.Duration
- func (p *Probe) RemoteAppID() string
- func (p *Probe) SetRTT(d time.Duration)
- func (p *Probe) Start(ctx context.Context, remoteId infra.PeerIdentity) error
- func (p *Probe) State() PeerState
- func (p *Probe) SyncAllowedIPs(allowedIPs string) error
- type ProbeFactory
- func (p *ProbeFactory) Allows(remoteId string) bool
- func (f *ProbeFactory) Get(remoteId infra.PeerIdentity) (*Probe, error)
- func (p *ProbeFactory) Handle(ctx context.Context, remoteId infra.PeerID, packet *signal.SignalPacket) error
- func (p *ProbeFactory) NewProbe(remoteId infra.PeerIdentity) (*Probe, error)
- func (p *ProbeFactory) OnReceive(sessionId [28]byte, data []byte) error
- func (p *ProbeFactory) PeerConnectionStates() map[string]string
- func (p *ProbeFactory) PeerRTTs() map[string]int64
- func (f *ProbeFactory) Register(remoteId infra.PeerIdentity, probe *Probe)
- func (f *ProbeFactory) Remove(appId string)
- func (f *ProbeFactory) StartReconciler(ctx context.Context, interval time.Duration)
- type ProbeFactoryConfig
- type RelayDialerConfig
- type RelayTransport
- type RouteOps
- type SessionManager
- type StateMachine
Constants ¶
This section is empty.
Variables ¶
var ErrDialerClosed = errors.New("iceDialer explicitly closed")
ErrDialerClosed is returned by Dial when the iceDialer is explicitly closed (e.g. ICE reached Failed state or a SYN arrived on an active agent). It signals that onClose already triggered probe.restart(), so onFailure should NOT schedule a second restart.
var UpgradeDisabled = false
UpgradeDisabled turns the periodic relay→direct upgrade retry off entirely. The retry is break-before-make (ADR-0007): every attempt tears down a working relayed session. While the direct path is unusable anyway (e.g. the macOS NE self-capture problem), the retries only buy outage windows.
Functions ¶
func GenerateSessionID ¶
func NewIceDialer ¶
func NewIceDialer(cfg *ICEDialerConfig) infra.Dialer
func NewRelayDialer ¶
func NewRelayDialer(cfg *RelayDialerConfig) infra.Dialer
func NewWGConfigurator ¶
NewWGConfigurator creates a configurator. peerOps and routeOps may be nil (operations become no-ops, useful for testing).
Types ¶
type ConnectionConfigurator ¶
type ConnectionConfigurator interface {
// RegisterPeer adds a peer entry to WireGuard (called on first SYN/ACK).
RegisterPeer(publicKey, allowedIPs string) error
// SetEndpoint updates the WireGuard peer endpoint (called on every connect).
SetEndpoint(publicKey, endpoint string, persistentKeepalive int) error
// RemovePeer removes a peer entry from WireGuard (called on Failed/Closed).
RemovePeer(publicKey string) error
// ApplyRoute adds or removes a kernel route for the peer's VPN address.
ApplyRoute(address, iface string) error
// SetupNAT configures NAT rules for the WireGuard interface.
SetupNAT(iface string) error
}
ConnectionConfigurator defines the WireGuard configuration actions triggered by connection state transitions.
type ConnectionState ¶
type ConnectionState int
ConnectionState is an enum showing the state of a ICE Connection
const ( ConnectionStateUnknown ConnectionState = iota // ConnectionStateNew probe the remote peer. ConnectionStateNew ConnectionStateChecking ConnectionStateConnected ConnectionStateCompleted ConnectionStateFailed ConnectionStateDisconnected ConnectionStateClosed )
List of supported States
func (ConnectionState) String ¶
func (c ConnectionState) String() string
type ICEDialerConfig ¶
type ICEDialerConfig struct {
Sender func(ctx context.Context, peerId infra.PeerID, data []byte) error
LocalId infra.PeerIdentity
RemoteId infra.PeerIdentity
FilteringMux *infra.FilteringUDPMux
FilteringMux6 *infra.FilteringUDPMux // nil when IPv6 unavailable
Configurer provision.Provisioner
// GetLocalPeer is called at send time so late-arriving ApplyFullConfig
// updates (Address, AllowedIPs) are always reflected in SYN/ACK peer info.
GetLocalPeer func() *infra.Peer
OnPeerReceived func(peer infra.Peer)
ShowLog bool
// OnRestart is called when a SYN arrives on an already-closed dialer,
// indicating the remote peer restarted. Mirrors the Relay dialer pattern.
OnRestart func()
}
type ICETransport ¶
type ICETransport struct {
// contains filtered or unexported fields
}
func (*ICETransport) Close ¶
func (i *ICETransport) Close() error
func (*ICETransport) Priority ¶
func (i *ICETransport) Priority() uint8
func (*ICETransport) RemoteAddr ¶
func (i *ICETransport) RemoteAddr() string
func (*ICETransport) Type ¶
func (i *ICETransport) Type() infra.TransportType
func (*ICETransport) Write ¶
func (i *ICETransport) Write(data []byte) error
type PeerOps ¶
type PeerOps interface {
AddPeer(publicKey, allowedIPs string) error
SetEndpoint(publicKey, endpoint string, persistentKeepalive int) error
RemovePeer(publicKey string) error
}
PeerOps is the minimal interface for WireGuard peer management.
type PeerState ¶
type PeerState string
PeerState represents the lifecycle stage of a peer connection.
type PeerStats ¶
type PeerStats struct {
LastHandshake time.Time
RxBytes uint64
// Endpoint is where WireGuard currently sends this peer's packets. It
// follows the source of the last authenticated packet received, so it can
// differ from the transport the probe chose.
Endpoint *net.UDPAddr
}
PeerStats is the WireGuard-side view of a peer used for liveness checks.
type Probe ¶
type Probe struct {
// contains filtered or unexported fields
}
Probe manages the connection lifecycle to a single remote peer.
func (*Probe) Handle ¶
func (p *Probe) Handle(ctx context.Context, remoteId infra.PeerIdentity, packet *signal.SignalPacket) error
func (*Probe) OnConnectionStateChange ¶
func (p *Probe) OnConnectionStateChange(state ice.ConnectionState)
func (*Probe) RemoteAppID ¶
RemoteAppID returns the remote peer's AppID.
func (*Probe) State ¶
State returns the peer's current connection lifecycle state (probing / ice-ready / relay-ready / failed / closed).
func (*Probe) SyncAllowedIPs ¶
SyncAllowedIPs re-applies this peer's WireGuard AllowedIPs from a locally computed value — e.g. the server-side netmap widened it to 0.0.0.0/0 after this node selected the peer as an exit-node route provider. This is independent of P2P signaling: the signaling handshake only ever carries the remote peer's self-description, which has no notion of "who selected me as their exit route" (that's a consumer-side, per-viewer decision), so it can never carry this value. The configurator is idempotent per (publicKey, allowedIPs), so calling this with an unchanged value is a cheap no-op — safe to call on every netmap application.
type ProbeFactory ¶
type ProbeFactory struct {
FilteringMux *infra.FilteringUDPMux
FilteringMux6 *infra.FilteringUDPMux
// contains filtered or unexported fields
}
func NewProbeFactory ¶
func NewProbeFactory(cfg *ProbeFactoryConfig) *ProbeFactory
func (*ProbeFactory) Get ¶
func (f *ProbeFactory) Get(remoteId infra.PeerIdentity) (*Probe, error)
func (*ProbeFactory) Handle ¶
func (p *ProbeFactory) Handle(ctx context.Context, remoteId infra.PeerID, packet *signal.SignalPacket) error
Handle is the NATS SignalHandler boundary: remoteId is PeerID from packet.SenderId. It resolves to a full PeerIdentity via PeerManager before passing down.
func (*ProbeFactory) NewProbe ¶
func (p *ProbeFactory) NewProbe(remoteId infra.PeerIdentity) (*Probe, error)
func (*ProbeFactory) OnReceive ¶
func (p *ProbeFactory) OnReceive(sessionId [28]byte, data []byte) error
func (*ProbeFactory) PeerConnectionStates ¶
func (p *ProbeFactory) PeerConnectionStates() map[string]string
PeerConnectionStates snapshots each tracked peer's connection lifecycle state (probing / ice-ready / relay-ready / failed / closed), keyed by remote AppID. Embedded-engine clients (Apple Network Extension) surface this as connection quality: ice-ready = direct, relay-ready = relayed.
func (*ProbeFactory) PeerRTTs ¶
func (p *ProbeFactory) PeerRTTs() map[string]int64
PeerRTTs snapshots each tracked peer's latest direct-path echo RTT in milliseconds, keyed by remote AppID. 0 = not measured (older agent, relayed path, or no echo yet).
func (*ProbeFactory) Register ¶
func (f *ProbeFactory) Register(remoteId infra.PeerIdentity, probe *Probe)
func (*ProbeFactory) Remove ¶
func (f *ProbeFactory) Remove(appId string)
func (*ProbeFactory) StartReconciler ¶
func (f *ProbeFactory) StartReconciler(ctx context.Context, interval time.Duration)
StartReconciler periodically revives probes that reached StateClosed.
Probes close permanently after 60 s of failed discovery (Probe.onFailure), and the netmap pipeline cannot be relied on to recreate them: the poll loop skips re-applying an unchanged ConfigVersion, so a node whose first probe window overlapped a peer outage or a control-plane incident stayed dark until process restart even though every dependency had recovered (observed live: Mac initiator probes closed during the STUN outage and never restarted, 2026-09-19). This reconciler replaces every closed probe with a fresh one (Get swaps StateClosed entries) and starts it, restoring the initiate/answer role it had before.
type ProbeFactoryConfig ¶
type ProbeFactoryConfig struct {
LocalId infra.PeerIdentity
Signal infra.SignalService
GetOnMessage func() func(context.Context, *infra.Message) error
PeerManager *infra.PeerManager
GetRelay func() infra.RelayChannel
FilteringMux *infra.FilteringUDPMux
FilteringMux6 *infra.FilteringUDPMux
GetProvisioner func() provision.Provisioner
// GetPeerStats returns the WireGuard handshake time and received-byte
// counter for the given peer public key. Used by the liveness ticker to
// detect silent peer failures. May be nil (liveness monitoring is disabled).
GetPeerStats func(pubKey string) (PeerStats, error)
ShowLog bool
}
type RelayDialerConfig ¶
type RelayDialerConfig struct {
LocalId infra.PeerIdentity
RemoteId infra.PeerIdentity
Relay infra.RelayChannel
SM *SessionManager
SessionId uint64
// GetLocalPeer is called at send time so late-arriving ApplyFullConfig
// updates (Address, AllowedIPs) are always reflected in SYN/ACK peer info.
GetLocalPeer func() *infra.Peer
OnPeerReceived func(peer infra.Peer)
Sender func(ctx context.Context, peerId infra.PeerID, data []byte) error
// OnRestart is called when a HANDSHAKE_SYN arrives while the session is
// already active, signalling that the remote peer restarted. The callback
// should trigger probe.restart() to re-run discovery with fresh dialers.
OnRestart func()
}
type RelayTransport ¶
type RelayTransport struct {
// contains filtered or unexported fields
}
func (RelayTransport) Close ¶
func (w RelayTransport) Close() error
func (RelayTransport) Priority ¶
func (w RelayTransport) Priority() uint8
func (RelayTransport) RemoteAddr ¶
func (w RelayTransport) RemoteAddr() string
func (RelayTransport) Type ¶
func (w RelayTransport) Type() infra.TransportType
func (RelayTransport) Write ¶
func (w RelayTransport) Write(data []byte) error
type SessionManager ¶
type SessionManager struct {
// contains filtered or unexported fields
}
func (*SessionManager) Add ¶
func (m *SessionManager) Add(pubKey [32]byte, sid uint64)
Add registers a new session (typically called after NATS negotiation completes)
func (*SessionManager) Remove ¶
func (m *SessionManager) Remove(pubKey [32]byte, sid uint64)
Remove deletes a session
type StateMachine ¶
type StateMachine struct {
// contains filtered or unexported fields
}
StateMachine guards connection lifecycle transitions. It does NOT handle side effects — callers register callbacks via OnTransition.
func NewStateMachine ¶
func NewStateMachine(initial PeerState) *StateMachine
NewStateMachine creates a state machine in the given initial state.
func (*StateMachine) Current ¶
func (sm *StateMachine) Current() PeerState
Current returns the current state (thread-safe).
func (*StateMachine) OnTransition ¶
func (sm *StateMachine) OnTransition(cb func(from, to PeerState))
OnTransition registers a callback that fires on every successful transition.
func (*StateMachine) Transition ¶
func (sm *StateMachine) Transition(target PeerState) error
Transition attempts to move from the current state to target. Returns an error if the transition is not allowed. On success, fires all registered OnTransition callbacks.