server

package
v0.6.0 Latest Latest
Warning

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

Go to latest
Published: Apr 15, 2026 License: Apache-2.0 Imports: 34 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type AdminAPI

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

AdminAPI provides the RESTful management API.

func NewAdminAPI

func NewAdminAPI(server *Server) *AdminAPI

NewAdminAPI creates a new admin API handler.

func (*AdminAPI) Handler

func (a *AdminAPI) Handler() http.Handler

Handler returns the http.Handler for the admin API.

type ClientInfo

type ClientInfo struct {
	ID         string       `json:"id"`
	Subdomain  string       `json:"subdomain"`
	RemoteAddr string       `json:"remote_addr"`
	CreatedAt  time.Time    `json:"created_at"`
	LastSeen   time.Time    `json:"last_seen"`
	BytesIn    uint64       `json:"bytes_in"`
	BytesOut   uint64       `json:"bytes_out"`
	Tunnels    []TunnelJSON `json:"tunnels"`
}

ClientInfo is the per-client info returned by the API.

type ClientSession

type ClientSession struct {
	ID        string
	Subdomain string
	Mux       *tunnel.Mux
	Tunnels   []*TunnelInfo
	CreatedAt time.Time
	LastSeen  time.Time
	BytesIn   uint64
	BytesOut  uint64

	// Authentication info.
	TeamName string
	Role     auth.Role

	// P2P info.
	P2PPublicAddr string
	P2PNATType    string
	P2PLocalAddr  string
	P2PPublicKey  string // ECDH public key (base64-encoded) for E2E encryption.
	P2PTunnelID   string // Tunnel ID from the latest P2P offer.
	// contains filtered or unexported fields
}

ClientSession represents a connected client.

type Config

type Config struct {
	// ListenAddr is the address to listen on for client connections.
	ListenAddr string

	// HTTPAddr is the address to listen on for HTTP traffic.
	HTTPAddr string

	// AdminAddr is the address to listen on for the admin API.
	AdminAddr string

	// Domain is the base domain for tunnel URLs.
	Domain string

	// TLSEnabled enables TLS for client connections.
	TLSEnabled bool

	// TLSCertFile is the path to the TLS certificate.
	TLSCertFile string

	// TLSKeyFile is the path to the TLS private key.
	TLSKeyFile string

	// AutoTLS enables automatic TLS certificate via Let's Encrypt.
	AutoTLS bool

	// AutoTLSEmail is the email for Let's Encrypt registration.
	AutoTLSEmail string

	// TunnelTLSEnabled enables TLS for the tunnel control listener.
	// When true, the tunnel listener is also wrapped with TLS.
	// Defaults to the value of TLSEnabled if not explicitly set.
	TunnelTLSEnabled bool

	// TCPPortRange is the range of ports for TCP tunnels.
	TCPPortRangeStart int
	TCPPortRangeEnd   int

	// MuxConfig is the multiplexer configuration.
	MuxConfig tunnel.MuxConfig

	// ReadTimeout is the read timeout for connections.
	ReadTimeout time.Duration

	// WriteTimeout is the write timeout for connections.
	WriteTimeout time.Duration

	// IdleTimeout is the idle timeout for connections.
	IdleTimeout time.Duration

	// MaxClients is the maximum number of concurrent clients.
	// 0 means unlimited.
	MaxClients int

	// MaxTunnelsPerClient is the maximum number of tunnels a single client can register.
	// 0 means unlimited.
	MaxTunnelsPerClient int

	// RequireAuth requires authentication for connections.
	RequireAuth bool

	// AuthTokens is a list of valid authentication tokens (simple mode).
	AuthTokens []string

	// AuthSecret is the HMAC secret for signed token mode.
	// Must be at least 16 bytes. If empty, only simple token mode is available.
	AuthSecret string

	// AuthTimeout is the timeout for the authentication handshake.
	AuthTimeout time.Duration

	// AdminToken is the token required to access the admin API.
	// If empty, the admin API requires no authentication.
	AdminToken string

	// RateLimitEnabled enables authentication failure rate limiting.
	RateLimitEnabled bool

	// RateLimitMaxFailures is the max failures before blocking an IP.
	RateLimitMaxFailures int

	// RateLimitWindow is the time window for counting failures.
	RateLimitWindow time.Duration

	// RateLimitBlockDuration is how long to block after exceeding failures.
	RateLimitBlockDuration time.Duration

	// Persistence configures the storage backend for auth data.
	// Options: "memory" (default), "sqlite"
	Persistence PersistenceType

	// PersistencePath is the path to the SQLite database file.
	// Only used when Persistence is "sqlite".
	// If empty, defaults to ~/.wormhole/wormhole.db
	PersistencePath string

	// EnableMetrics enables Prometheus metrics collection and the /metrics endpoint.
	EnableMetrics bool

	// OIDCIssuer enables OIDC JWT token validation.
	// When set, JWT tokens signed by the given issuer are accepted in addition to
	// the HMAC tokens.  Example: "https://accounts.google.com"
	OIDCIssuer string

	// OIDCClientID is the OAuth2 client ID to validate the audience claim.
	OIDCClientID string

	// OIDCTeamClaim is the JWT claim used as the Wormhole team name (default: "email").
	OIDCTeamClaim string

	// OIDCRoleClaim is an optional JWT claim for the Wormhole role.
	OIDCRoleClaim string

	// AuditEnabled enables structured audit logging.
	// When false, no audit events are recorded.
	AuditEnabled bool

	// AuditPersistence controls the storage backend for audit logs.
	// Options: "memory" (default ring buffer) or "sqlite".
	AuditPersistence PersistenceType

	// AuditPath is the path to the SQLite audit database file.
	// Only used when AuditPersistence is "sqlite".
	// If empty, defaults to ~/.wormhole/audit.db.
	AuditPath string

	// AuditBufferSize is the number of events to keep in memory.
	// Only used when AuditPersistence is "memory". Defaults to 10 000.
	AuditBufferSize int

	// ClusterNodeID is a unique identifier for this node in the cluster.
	// Defaults to the hostname when empty and clustering is enabled.
	ClusterNodeID string

	// ClusterNodeAddr is the address (host:port) other nodes use to reach this
	// node's HTTP listener for cross-node tunnel proxying.
	// Example: "10.0.0.1:7002"
	ClusterNodeAddr string

	// ClusterStateBackend selects the shared-state backend.
	// Options: "memory" (default, single-node) or "redis".
	ClusterStateBackend string

	// ClusterRedisAddr is the Redis server address for the Redis state backend.
	// Required when ClusterStateBackend is "redis".
	ClusterRedisAddr string

	// ClusterRedisPassword is the optional Redis AUTH password.
	ClusterRedisPassword string

	// ClusterRedisDB is the Redis database number (default 0).
	ClusterRedisDB int
}

Config holds the server configuration.

func DefaultConfig

func DefaultConfig() Config

DefaultConfig returns the default server configuration.

type CreateTeamRequest

type CreateTeamRequest struct {
	Name string `json:"name"`
}

CreateTeamRequest is the request body for creating a team.

type ErrorResponse

type ErrorResponse struct {
	Error string `json:"error"`
}

ErrorResponse is the standard error response for the admin API.

type GenerateTokenRequest

type GenerateTokenRequest struct {
	Team string `json:"team"`
	Role string `json:"role"`
}

GenerateTokenRequest is the request body for token generation.

type GenerateTokenResponse

type GenerateTokenResponse struct {
	Token   string `json:"token"`
	Team    string `json:"team"`
	Role    string `json:"role"`
	Expires string `json:"expires,omitempty"`
}

GenerateTokenResponse is the response for token generation.

type HTTPHandler

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

HTTPHandler handles incoming HTTP requests and routes them through tunnels.

func NewHTTPHandler

func NewHTTPHandler(router *Router, server *Server) *HTTPHandler

NewHTTPHandler creates a new HTTP handler.

func (*HTTPHandler) ServeHTTP

func (h *HTTPHandler) ServeHTTP(w http.ResponseWriter, r *http.Request)

ServeHTTP implements http.Handler.

type HealthResponse

type HealthResponse struct {
	Status  string `json:"status"`
	Version string `json:"version,omitempty"`
	Uptime  string `json:"uptime"`
}

HealthResponse is the response for the health endpoint.

type MemoryStateStore added in v0.6.0

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

MemoryStateStore is a single-node in-memory implementation of StateStore. It provides no cross-node coordination; all state is local to the process. This is the default backend for single-node deployments.

func NewMemoryStateStore added in v0.6.0

func NewMemoryStateStore() *MemoryStateStore

NewMemoryStateStore creates a new in-memory state store.

func (*MemoryStateStore) Close added in v0.6.0

func (m *MemoryStateStore) Close() error

func (*MemoryStateStore) EvictDeadNodes added in v0.6.0

func (m *MemoryStateStore) EvictDeadNodes(olderThan time.Duration) error

func (*MemoryStateStore) GetNodes added in v0.6.0

func (m *MemoryStateStore) GetNodes() ([]NodeInfo, error)

func (*MemoryStateStore) ListRoutes added in v0.6.0

func (m *MemoryStateStore) ListRoutes() ([]RouteEntry, error)

func (*MemoryStateStore) LookupBySubdomain added in v0.6.0

func (m *MemoryStateStore) LookupBySubdomain(subdomain string) (*RouteEntry, error)

func (*MemoryStateStore) NodeHeartbeat added in v0.6.0

func (m *MemoryStateStore) NodeHeartbeat(info NodeInfo) error

func (*MemoryStateStore) RegisterRoute added in v0.6.0

func (m *MemoryStateStore) RegisterRoute(entry RouteEntry) error

func (*MemoryStateStore) UnregisterRoute added in v0.6.0

func (m *MemoryStateStore) UnregisterRoute(clientID string) error

type Metrics added in v0.4.3

type Metrics struct {
	// ActiveClients is the number of currently connected clients.
	ActiveClients prometheus.Gauge

	// ActiveTunnels is the number of currently active tunnels.
	ActiveTunnels prometheus.Gauge

	// ConnectionsTotal is the total number of client connections accepted.
	ConnectionsTotal prometheus.Counter

	// BytesTransferredTotal is the total bytes transferred, labeled by direction (in/out).
	BytesTransferredTotal *prometheus.CounterVec

	// RequestsTotal is the total number of requests, labeled by protocol and status.
	RequestsTotal *prometheus.CounterVec

	// RequestDurationSeconds is the histogram of request durations in seconds.
	RequestDurationSeconds prometheus.Histogram

	// AuthAttemptsTotal is the total number of authentication attempts, labeled by result (success/failure).
	AuthAttemptsTotal *prometheus.CounterVec

	// P2PConnectionsTotal is the total number of P2P connection attempts, labeled by result (success/fallback).
	P2PConnectionsTotal *prometheus.CounterVec

	// TunnelDurationSeconds is the histogram of tunnel lifetimes in seconds.
	TunnelDurationSeconds prometheus.Histogram
	// contains filtered or unexported fields
}

Metrics holds all Prometheus metrics for the wormhole server.

func NewMetrics added in v0.4.3

func NewMetrics() *Metrics

NewMetrics creates and registers all Prometheus metrics. It uses a custom registry to avoid polluting the global default.

func (*Metrics) Registry added in v0.4.3

func (m *Metrics) Registry() *prometheus.Registry

Registry returns the Prometheus registry used by these metrics.

type NodeInfo added in v0.6.0

type NodeInfo struct {
	// NodeID is the unique identifier for this node.
	NodeID string

	// NodeAddr is the HTTP address other nodes should proxy to for tunnels
	// owned by this node (e.g. "10.0.0.1:7000").
	NodeAddr string

	// LastHeartbeat is when the node last reported it was alive.
	LastHeartbeat time.Time
}

NodeInfo describes a member of the cluster.

type PersistenceType

type PersistenceType string

PersistenceType represents the storage backend type.

const (
	// PersistenceMemory uses in-memory storage (no persistence).
	PersistenceMemory PersistenceType = "memory"
	// PersistenceSQLite uses SQLite for persistent storage.
	PersistenceSQLite PersistenceType = "sqlite"
)

type RateLimitResponse

type RateLimitResponse struct {
	Enabled    bool     `json:"enabled"`
	TrackedIPs int      `json:"tracked_ips"`
	BlockedIPs []string `json:"blocked_ips"`
}

RateLimitResponse is the response for the rate limit status endpoint.

type RedisStateStore added in v0.6.0

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

RedisStateStore implements StateStore using Redis for multi-node coordination.

Key layout:

wormhole:route:<clientID>  — JSON RouteEntry, TTL = defaultRouteTTL
wormhole:sub:<subdomain>   — clientID string, TTL = defaultRouteTTL
wormhole:node:<nodeID>     — JSON NodeInfo, TTL = defaultNodeTTL

func NewRedisStateStore added in v0.6.0

func NewRedisStateStore(cfg RedisStateStoreConfig) (*RedisStateStore, error)

NewRedisStateStore creates a Redis-backed state store.

func (*RedisStateStore) Close added in v0.6.0

func (r *RedisStateStore) Close() error

func (*RedisStateStore) EvictDeadNodes added in v0.6.0

func (r *RedisStateStore) EvictDeadNodes(_ time.Duration) error

EvictDeadNodes is a no-op for Redis because Redis TTL handles expiry automatically. The Redis TTL on node keys (defaultNodeTTL) ensures stale entries are cleaned up.

func (*RedisStateStore) GetNodes added in v0.6.0

func (r *RedisStateStore) GetNodes() ([]NodeInfo, error)

func (*RedisStateStore) ListRoutes added in v0.6.0

func (r *RedisStateStore) ListRoutes() ([]RouteEntry, error)

func (*RedisStateStore) LookupBySubdomain added in v0.6.0

func (r *RedisStateStore) LookupBySubdomain(subdomain string) (*RouteEntry, error)

func (*RedisStateStore) NodeHeartbeat added in v0.6.0

func (r *RedisStateStore) NodeHeartbeat(info NodeInfo) error

func (*RedisStateStore) RegisterRoute added in v0.6.0

func (r *RedisStateStore) RegisterRoute(entry RouteEntry) error

func (*RedisStateStore) UnregisterRoute added in v0.6.0

func (r *RedisStateStore) UnregisterRoute(clientID string) error

type RedisStateStoreConfig added in v0.6.0

type RedisStateStoreConfig struct {
	// Addr is the Redis server address (host:port).
	Addr string

	// Password is the Redis AUTH password (optional).
	Password string

	// DB is the Redis database number (default 0).
	DB int
}

RedisStateStoreConfig configures the Redis state store.

type RefreshTokenRequest

type RefreshTokenRequest struct {
	Token     string `json:"token"`
	RevokeOld bool   `json:"revoke_old"`
	ExtendBy  string `json:"extend_by,omitempty"`
}

type RevokeTeamTokensRequest added in v0.3.0

type RevokeTeamTokensRequest struct {
	Team string `json:"team"`
}

RevokeTeamTokensRequest is the request body for team-level token revocation.

type RevokeTokenRequest

type RevokeTokenRequest struct {
	Token   string `json:"token,omitempty"`
	TokenID string `json:"token_id,omitempty"`
}

RevokeTokenRequest is the request body for token revocation.

type RouteEntry added in v0.6.0

type RouteEntry struct {
	// ClientID is the unique identifier of the client session.
	ClientID string

	// Subdomain is the subdomain assigned to this client.
	Subdomain string

	// NodeID is the cluster node that owns this client connection.
	NodeID string

	// NodeAddr is the reachable HTTP address of the owning node
	// (used for cross-node proxying).
	NodeAddr string

	// RegisteredAt is when the route was registered.
	RegisteredAt time.Time
}

RouteEntry describes a tunnel route registered in the cluster state.

type Router

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

Router manages the mapping between hostnames/paths and client sessions. It supports both subdomain-based routing (e.g., myapp.tunnel.example.com) and path-based routing (e.g., tunnel.example.com/myapp/).

func NewRouter

func NewRouter(domain string) *Router

NewRouter creates a new router with the given base domain.

func (*Router) ActiveRoutes

func (r *Router) ActiveRoutes() int

ActiveRoutes returns the number of active routes.

func (*Router) RegisterHostname

func (r *Router) RegisterHostname(hostname string, client *ClientSession) error

RegisterHostname registers a custom hostname route for a client session.

func (*Router) RegisterPath

func (r *Router) RegisterPath(pathPrefix string, client *ClientSession) error

RegisterPath registers a path-based route for a client session.

func (*Router) RegisterSubdomain

func (r *Router) RegisterSubdomain(subdomain string, client *ClientSession) error

RegisterSubdomain registers a subdomain route for a client session.

func (*Router) Route

func (r *Router) Route(host, path string) *ClientSession

Route resolves a host and path to a client session. It checks in order: custom hostname, subdomain, path prefix.

func (*Router) SubdomainURL

func (r *Router) SubdomainURL(subdomain string, useTLS bool) string

SubdomainURL returns the public URL for a subdomain.

func (*Router) Unregister

func (r *Router) Unregister(client *ClientSession)

Unregister removes all routes for the given client session.

type Server

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

func NewServer

func NewServer(config Config) *Server

NewServer creates a new server instance.

func (*Server) FindPeerForP2P

func (s *Server) FindPeerForP2P(excludeClientID string) *ClientSession

FindPeerForP2P looks up the best peer client for P2P connection with the given initiator. Candidates are ranked by NAT traversal friendliness: Full Cone > Restricted Cone > Port Restricted > Symmetric. Returns nil if no suitable peer is found.

func (*Server) Shutdown

func (s *Server) Shutdown() error

Shutdown gracefully shuts down the server.

func (*Server) Start

func (s *Server) Start(ctx context.Context) error

Start starts the server.

type StateStore added in v0.6.0

type StateStore interface {
	// RegisterRoute stores a client's route entry on this node.
	RegisterRoute(entry RouteEntry) error

	// UnregisterRoute removes all routes for a given client.
	UnregisterRoute(clientID string) error

	// LookupBySubdomain returns the route entry for the given subdomain.
	// Returns (nil, nil) when no entry is found (not an error condition).
	LookupBySubdomain(subdomain string) (*RouteEntry, error)

	// ListRoutes returns all active route entries across the cluster.
	ListRoutes() ([]RouteEntry, error)

	// NodeHeartbeat records that a node is alive.
	NodeHeartbeat(info NodeInfo) error

	// GetNodes returns the list of known cluster nodes and their last heartbeat.
	GetNodes() ([]NodeInfo, error)

	// EvictDeadNodes removes nodes whose heartbeat is older than the given
	// threshold and cleans up their routes.
	EvictDeadNodes(olderThan time.Duration) error

	// Close releases any resources held by the store.
	Close() error
}

StateStore is the shared-state interface for cluster coordination. All methods must be safe for concurrent use.

Single-node deployments use MemoryStateStore (no external dependency). Multi-node deployments use RedisStateStore.

type Stats

type Stats struct {
	ActiveClients uint64
	TotalClients  uint64
	ActiveTunnels uint64
	BytesIn       uint64
	BytesOut      uint64
	Requests      uint64
	StartTime     time.Time
}

Stats contains server statistics.

type StatsResponse

type StatsResponse struct {
	ActiveClients       uint64 `json:"active_clients"`
	TotalClients        uint64 `json:"total_clients"`
	ActiveTunnels       uint64 `json:"active_tunnels"`
	ActiveRoutes        int    `json:"active_routes"`
	Requests            uint64 `json:"requests"`
	BytesIn             uint64 `json:"bytes_in"`
	BytesOut            uint64 `json:"bytes_out"`
	UptimeSeconds       int64  `json:"uptime_seconds"`
	AllocatedPorts      int    `json:"allocated_ports"`
	MaxClients          int    `json:"max_clients"`
	MaxTunnelsPerClient int    `json:"max_tunnels_per_client"`
}

StatsResponse is the response for the stats endpoint.

type TCPPortAllocator

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

TCPPortAllocator manages TCP port allocation for raw TCP tunnels.

func NewTCPPortAllocator

func NewTCPPortAllocator(start, end int) *TCPPortAllocator

NewTCPPortAllocator creates a new port allocator for the given range.

func (*TCPPortAllocator) Allocate

func (a *TCPPortAllocator) Allocate(ctx context.Context) (int, net.Listener, error)

Allocate allocates a TCP port and starts listening on it. Returns the port number and the listener.

func (*TCPPortAllocator) AllocatedPorts

func (a *TCPPortAllocator) AllocatedPorts() int

AllocatedPorts returns the count of currently allocated ports.

func (*TCPPortAllocator) CloseAll

func (a *TCPPortAllocator) CloseAll()

CloseAll closes all allocated port listeners.

func (*TCPPortAllocator) Release

func (a *TCPPortAllocator) Release(port int)

Release releases a previously allocated port.

type TLSManager

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

TLSManager manages TLS configuration and automatic certificate provisioning.

func NewTLSManager

func NewTLSManager(config Config) *TLSManager

NewTLSManager creates a new TLS manager from the server config.

func (*TLSManager) HTTPChallengeHandler

func (m *TLSManager) HTTPChallengeHandler() http.Handler

HTTPChallengeHandler returns an HTTP handler for ACME HTTP-01 challenges. This should be served on port 80 when using AutoTLS. Non-challenge requests are redirected to HTTPS.

func (*TLSManager) TLSConfig

func (m *TLSManager) TLSConfig() (*tls.Config, error)

TLSConfig returns a *tls.Config suitable for the HTTP server. It supports three modes:

  1. AutoTLS with Let's Encrypt (when AutoTLS=true and Domain is set).
  2. Manual TLS with provided cert/key files.
  3. No TLS (returns nil).

func (*TLSManager) WrapListener

func (m *TLSManager) WrapListener(ln net.Listener) net.Listener

WrapListener wraps a net.Listener with TLS if configured.

type TeamResponse

type TeamResponse struct {
	Name           string `json:"name"`
	CreatedAt      string `json:"created_at"`
	Tokens         int    `json:"tokens"`
	RevokedVersion int64  `json:"revoked_version"`
}

TeamResponse is the response for team endpoints.

type TunnelInfo

type TunnelInfo struct {
	ID        string
	LocalPort uint32
	Protocol  proto.Protocol
	PublicURL string
	TCPPort   uint32
	CreatedAt time.Time
}

TunnelInfo contains information about a tunnel.

type TunnelJSON

type TunnelJSON struct {
	ID        string `json:"id"`
	LocalPort uint32 `json:"local_port"`
	Protocol  string `json:"protocol"`
	PublicURL string `json:"public_url"`
	TCPPort   uint32 `json:"tcp_port,omitempty"`
	CreatedAt string `json:"created_at"`
}

TunnelJSON is the JSON representation of a tunnel.

type UnblockRequest

type UnblockRequest struct {
	IP string `json:"ip"`
}

UnblockRequest is the request body for unblocking an IP.

Jump to

Keyboard shortcuts

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