Documentation
¶
Index ¶
- Constants
- Variables
- func ApplyDNSResolver(c DNSResolverConfig)
- func CheckCapability() (bool, string)
- func CheckHostNetwork() bool
- func CheckIKEv2Capability() bool
- func CheckL2TPCapability() (bool, string)
- func DetectPlatform() string
- func DetectRuntimeMode()
- func GenerateWireGuardClientConfig(serverCfg WireGuardConfig, peer WireGuardPeer, endpoint, dns string) string
- func GenerateWireGuardKey() (string, string)
- func IsBondStream(addr string) bool
- func IsCompatMode() bool
- func PublicKeyFromPrivate(privB64 string) (string, error)
- func PurgeDNSCache()
- func RuleEngineAvailable() bool
- func SanitizeExitMode(exitPaths []string, exitMode string) (string, error)
- func StopWireGuard()
- func TunCaptureActive() bool
- func TunModeActive() bool
- func WGAddPeer(peer WireGuardPeer) error
- func WGRemovePeer(publicKey string) error
- func WGUpdatePeer(peer WireGuardPeer) error
- func WireGuardConnectedCount() int
- func WireGuardRunning() bool
- type App
- func (a *App) ActivePath(exitVia string) string
- func (a *App) AddClient(cl ClientEntry) error
- func (a *App) AddProxy(pc ProxyConfig) error
- func (a *App) AddRule(r RoutingRule)
- func (a *App) AddUser(u UserConfig) error
- func (a *App) AllActivePaths() map[string]string
- func (a *App) ApplyRule(r RoutingRule)
- func (a *App) DataDir() string
- func (a *App) DeleteRule(id string)
- func (a *App) FlushTraffic()
- func (a *App) GetConfig() Config
- func (a *App) GetPasswordConflicts() map[string]map[string][]string
- func (a *App) IsExitCompat(exitVia string) bool
- func (a *App) IsPasswordConflicted(username, proxy string) bool
- func (a *App) LookupUser(username, password, proxy string) (*UserConfig, error)
- func (a *App) Node() *relay.Node
- func (a *App) PersistNodeID(id string)
- func (a *App) ReconnectAll()
- func (a *App) RecordTraffic(username string, bytes int64)
- func (a *App) RemoveClient(name string) error
- func (a *App) RemoveProxy(id string) error
- func (a *App) RemoveRule(id string)
- func (a *App) RemoveUser(id string) error
- func (a *App) ResetUserTraffic(id string) error
- func (a *App) ResolveViaExit(ctx context.Context, name, exitVia string) ([]string, error)
- func (a *App) RestartIKEv2() error
- func (a *App) RestartL2TP() error
- func (a *App) RestartSS()
- func (a *App) RestartServer()
- func (a *App) RuleUsesTun(r RoutingRule) bool
- func (a *App) Run(ctx context.Context) error
- func (a *App) SetClientDisabled(name string, disabled bool) error
- func (a *App) SetGraphLayout(pos map[string]GraphLayoutPos) error
- func (a *App) SetNested(peer string, enabled bool) error
- func (a *App) SetPeerDisabled(peer string, disabled bool) error
- func (a *App) StartClient(cl ClientEntry)
- func (a *App) StartIKEv2(cfg IKEv2Config) error
- func (a *App) StartIPForwarding(targets []ipfwdTarget) error
- func (a *App) StartL2TP(cfg L2TPConfig) error
- func (a *App) StartProxy(pc ProxyConfig)
- func (a *App) StartRuleEngine()
- func (a *App) StartRuleReconciler(ctx context.Context)
- func (a *App) StartSS(cfg SSConfig)
- func (a *App) StartTrafficFlusher(ctx context.Context)
- func (a *App) StartWireGuard(cfg WireGuardConfig) error
- func (a *App) StopClient(name string)
- func (a *App) StopIKEv2()
- func (a *App) StopIPForwarding()
- func (a *App) StopL2TP()
- func (a *App) StopProxy(id string)
- func (a *App) StopRuleEngine()
- func (a *App) Store() *ConfigStore
- func (a *App) TLS() *TLSStore
- func (a *App) ToggleRule(id string, enabled bool)
- func (a *App) ToggleUser(id string, enabled bool) error
- func (a *App) UpdateClient(cl ClientEntry) error
- func (a *App) UpdateClientByAddr(oldName string, cl ClientEntry) error
- func (a *App) UpdateProxy(pc ProxyConfig) error
- func (a *App) UpdateRule(id string, r RoutingRule)
- func (a *App) UpdateUser(id string, u UserConfig) error
- func (a *App) UpdateWebCredentials(username, passHash string)
- type CertInfo
- type ClientEntry
- type Config
- type ConfigStore
- type DNSResolverConfig
- type Device
- type DeviceJSON
- type GraphLayoutPos
- type IKEv2Config
- type L2TPConfig
- type PeerConfig
- type PortConflict
- type ProxyConfig
- type RelayAuthConn
- type RoutingRule
- type SOCKS5Config
- type SSConfig
- type ServerConfig
- type SessionManager
- func (m *SessionManager) Connect(username, remoteIP, protocol string, cancel func()) string
- func (m *SessionManager) Count() int
- func (m *SessionManager) Disconnect(sessionID string, txBytes, rxBytes int64)
- func (m *SessionManager) IsBlocked(username, remoteIP, protocol string) bool
- func (m *SessionManager) Kick(key string) bool
- func (m *SessionManager) KickUser(username string) int
- func (m *SessionManager) List() []DeviceJSON
- type TLSStore
- func (s *TLSStore) CAParent(id string) string
- func (s *TLSStore) CertPath(id string) string
- func (s *TLSStore) Delete(id string) error
- func (s *TLSStore) Generate(id, name string, domains []string, days int) error
- func (s *TLSStore) Get(id string) (CertInfo, error)
- func (s *TLSStore) GetPEM(id string) (string, error)
- func (s *TLSStore) Import(id, name, certPEM, keyPEM string) error
- func (s *TLSStore) KeyPath(id string) string
- func (s *TLSStore) List() ([]CertInfo, error)
- func (s *TLSStore) SignWithCA(caID, newID, name, cn string, days int) error
- func (s *TLSStore) TLSConfig(id string) (*tls.Config, error)
- type TunModeConfig
- type UserConfig
- type WireGuardConfig
- type WireGuardPeer
Constants ¶
const ( PlatformLinux = "linux" PlatformIKuai = "ikuai" PlatformOpenWrt = "openwrt" )
Platform identifiers
Variables ¶
var AppVersion = "dev"
AppVersion is set by the api package at init time.
var PasswordOnlyProxies = []string{"hy2", "ss"}
PasswordOnlyProxies lists proxy types that authenticate by password alone (no username). These need per-proxy password support and conflict detection. To add a new proxy: add its key here AND in web/app/src/config/proxyRegistry.ts
Functions ¶
func ApplyDNSResolver ¶ added in v1.3.4
func ApplyDNSResolver(c DNSResolverConfig)
ApplyDNSResolver hot-reloads the runtime snapshot and purges the cache. Called from updateUISettings so the operator's edits land without a process restart.
func CheckCapability ¶ added in v1.0.4
func CheckHostNetwork ¶
func CheckHostNetwork() bool
CheckHostNetwork returns true if the container appears to be running with --network host.
func CheckIKEv2Capability ¶ added in v1.3.0
func CheckIKEv2Capability() bool
CheckIKEv2Capability tests if strongSwan/xfrm can run. Docker Desktop LinuxKit VM supports xfrm → IKEv2 works. Bare WSL2 without Docker Desktop may lack xfrm support.
func CheckL2TPCapability ¶
CheckL2TPCapability tests if the runtime can actually run L2TP/IPsec. Checks NET_ADMIN, /dev/ppp, and kernel l2tp_ppp module. Docker Desktop LinuxKit VM has PPP but lacks l2tp_ppp → L2TP rejected, IKEv2 still works.
func DetectPlatform ¶ added in v1.3.0
func DetectPlatform() string
DetectPlatform returns the detected platform identifier.
func DetectRuntimeMode ¶ added in v1.2.2
func DetectRuntimeMode()
DetectRuntimeMode runs early detection and logs the result.
func GenerateWireGuardClientConfig ¶ added in v1.1.0
func GenerateWireGuardClientConfig(serverCfg WireGuardConfig, peer WireGuardPeer, endpoint, dns string) string
GenerateWireGuardClientConfig generates a .conf file for a WireGuard peer.
func GenerateWireGuardKey ¶ added in v1.1.0
GenerateWireGuardKey returns (privateKey, publicKey) base64.
func IsBondStream ¶ added in v1.2.0
IsBondStream returns true if the address is a bond stream.
func IsCompatMode ¶ added in v1.2.2
func IsCompatMode() bool
IsCompatMode returns true when the node has NET_ADMIN but no working iptables. This is now a last-resort fallback — iKuai with bundled host iptables runs normal mode.
func PublicKeyFromPrivate ¶ added in v1.1.0
PublicKeyFromPrivate derives public key from base64 private key.
func PurgeDNSCache ¶ added in v1.3.4
func PurgeDNSCache()
PurgeDNSCache wipes every entry. Wired into updateUISettings so switching upstream takes effect on the next call rather than after the existing TTLs naturally expire.
func RuleEngineAvailable ¶ added in v1.1.3
func RuleEngineAvailable() bool
RuleEngineAvailable returns true if the rule engine can operate.
func SanitizeExitMode ¶ added in v1.3.0
dialExit routes traffic through an exit path, stripping the local node name prefix. dialExitWithMode routes traffic with the specified exit mode. mode: "" = direct, "quality" = adaptive failover, "aggregate" = load balance SanitizeExitMode checks and sanitizes exit_mode. - Clears mode if no meaningful exit paths exist - Aggregate mode requires all paths to reach the same final exit node Returns the (possibly corrected) mode and any validation error.
func StopWireGuard ¶ added in v1.1.0
func StopWireGuard()
StopWireGuard stops the running WireGuard instance.
func TunCaptureActive ¶ added in v1.1.2
func TunCaptureActive() bool
TunCaptureActive returns true if TUN capture mode is in use.
func TunModeActive ¶ added in v1.2.2
func TunModeActive() bool
TunModeActive returns whether the TUN IP forwarding engine is running.
func WGAddPeer ¶ added in v1.1.1
func WGAddPeer(peer WireGuardPeer) error
WGAddPeer adds a peer to the running WireGuard device without restarting.
func WGRemovePeer ¶ added in v1.1.1
WGRemovePeer removes a peer from the running WireGuard device without restarting.
func WGUpdatePeer ¶ added in v1.1.1
func WGUpdatePeer(peer WireGuardPeer) error
WGUpdatePeer updates a peer's WG-level config without restarting the device.
func WireGuardConnectedCount ¶ added in v1.1.0
func WireGuardConnectedCount() int
WireGuardConnectedCount returns the number of WG peers with active connections.
func WireGuardRunning ¶ added in v1.1.0
func WireGuardRunning() bool
WireGuardRunning returns true if WireGuard is active.
Types ¶
type App ¶
type App struct {
Sessions *SessionManager
// contains filtered or unexported fields
}
func (*App) ActivePath ¶ added in v1.2.2
ActivePath returns the last successful exit path for a given primary exit_via.
func (*App) AddClient ¶
func (a *App) AddClient(cl ClientEntry) error
func (*App) AddProxy ¶
func (a *App) AddProxy(pc ProxyConfig) error
func (*App) AddRule ¶ added in v1.1.3
func (a *App) AddRule(r RoutingRule)
func (*App) AddUser ¶
func (a *App) AddUser(u UserConfig) error
func (*App) AllActivePaths ¶ added in v1.2.2
AllActivePaths returns all tracked active paths.
func (*App) ApplyRule ¶ added in v1.1.3
func (a *App) ApplyRule(r RoutingRule)
ApplyRule enables a routing rule (adds iptables + proxy mapping).
func (*App) DeleteRule ¶ added in v1.1.3
func (*App) FlushTraffic ¶
func (a *App) FlushTraffic()
FlushTraffic persists dirty traffic counters to config.
func (*App) GetPasswordConflicts ¶ added in v1.3.0
GetPasswordConflicts returns a map of username → proxy → []conflicting usernames. Only users with actual conflicts are included.
func (*App) IsExitCompat ¶ added in v1.3.0
IsExitCompat returns true if the given exit peer cannot perform full TUN forwarding (i.e. is "limited" — no NET_ADMIN/no /dev/net/tun on its side). This indicates traffic to that exit must use L7 proxy semantics rather than raw IP forwarding, regardless of whether THIS node is running TUN locally.
func (*App) IsPasswordConflicted ¶ added in v1.3.0
IsPasswordConflicted returns true if the user has a password collision on the given proxy.
func (*App) LookupUser ¶
func (a *App) LookupUser(username, password, proxy string) (*UserConfig, error)
LookupUser authenticates a username/password pair for a specific proxy (socks5/http/l2tp/ikev2/...). The `proxy` argument is consulted against the per-user ProxyDisabled list so an admin can revoke access to a single protocol without deleting the user. Pass an empty proxy string to skip the per-proxy check (for legacy/internal callers that don't represent a specific listening protocol). VPN callers (l2tp/ikev2) commonly pass an empty password — they validated the secret elsewhere — but they still pay the ProxyDisabled check.
func (*App) PersistNodeID ¶
PersistNodeID writes the node ID to the persistent file.
func (*App) ReconnectAll ¶
func (a *App) ReconnectAll()
ReconnectAll stops and restarts all connections (outbound + hy2 server) after ID change. Restarting the server disconnects all inbound peers, forcing them to reconnect and see the new ID.
func (*App) RecordTraffic ¶
func (*App) RemoveClient ¶
func (*App) RemoveProxy ¶
func (*App) RemoveRule ¶ added in v1.1.3
RemoveRule disables a routing rule (removes iptables + proxy mapping).
func (*App) RemoveUser ¶
func (*App) ResetUserTraffic ¶
func (*App) ResolveViaExit ¶ added in v1.3.4
ResolveViaExit is the public entry point. Returns IPs the way net.LookupHost does. Behaviour:
- if DNSResolver.Enabled == false, fall straight through to net.LookupHost on this node (legacy / off-by-default path).
- else, dial the configured upstream resolver THROUGH the rule's own `exitVia` and speak DNS-over-TCP. Each rule's DNS naturally rides the same exit chain as its data plane — a rule with exit_via=us resolves through us, a rule with exit_via=jp resolves through jp. No global "DNS exit pin"; the per-rule exit is the only routing dimension.
- the relay-layer plumbing is just plain TCP forwarding to upstream:53, so this works against ANY hy2-compatible peer (vanilla hy2 server, older hy2scale, etc.). No new wire protocol is added — the "DNS via exit" semantic falls out naturally from the upstream seeing the query coming from the exit's clean IP rather than from the polluted entry.
Cache key is `<exit>/<name>` so the same domain queried through different exits is cached independently — geo-DNS / CDN region answers stay distinct per route.
Falls back to net.LookupHost if the relay query fails AND no fresh cache entry exists (stale-while-revalidate; an upstream blip won't abruptly flip a rule back to the polluted host resolver).
func (*App) RestartIKEv2 ¶ added in v1.1.3
RestartIKEv2 stops and restarts the IKEv2 service with current config.
func (*App) RestartL2TP ¶ added in v1.1.3
RestartL2TP stops and restarts L2TP with current config.
func (*App) RestartSS ¶
func (a *App) RestartSS()
RestartSS stops and restarts the SS server with current config.
func (*App) RestartServer ¶ added in v1.1.2
func (a *App) RestartServer()
RestartServer is the public wrapper for restartServer.
func (*App) RuleUsesTun ¶ added in v1.3.0
func (a *App) RuleUsesTun(r RoutingRule) bool
RuleUsesTun reports whether an enabled rule is actually running through the TUN path right now (as opposed to the relay proxy fallback). A rule with UseTun=true only takes the TUN path when the exit peer is TUN-capable and the target is locally routable.
func (*App) SetGraphLayout ¶ added in v1.3.0
func (a *App) SetGraphLayout(pos map[string]GraphLayoutPos) error
SetGraphLayout replaces the persisted graph-layout map with the supplied one. A nil or empty map clears the layout (returns the UI to auto-layout).
func (*App) SetPeerDisabled ¶ added in v1.3.0
SetPeerDisabled marks a peer (or qualified peer path) as disabled, preventing it from being used as an exit hop without dropping the connection.
func (*App) StartClient ¶
func (a *App) StartClient(cl ClientEntry)
func (*App) StartIKEv2 ¶
func (a *App) StartIKEv2(cfg IKEv2Config) error
StartIKEv2 configures and starts IKEv2/IPsec VPN.
func (*App) StartIPForwarding ¶ added in v1.2.2
StartIPForwarding sets up TUN device and policy routing for IP packet forwarding.
func (*App) StartL2TP ¶
func (a *App) StartL2TP(cfg L2TPConfig) error
StartL2TP sets up xl2tpd, strongswan, iptables, and the transparent proxy.
func (*App) StartProxy ¶
func (a *App) StartProxy(pc ProxyConfig)
func (*App) StartRuleEngine ¶ added in v1.1.3
func (a *App) StartRuleEngine()
StartRuleEngine initializes the rule engine if in host network mode. Each rule decides independently whether to use TUN (via r.UseTun) or normal relay proxy; the TUN engine starts lazily when the first TUN rule is applied and stops automatically when the last one is removed.
func (*App) StartRuleReconciler ¶ added in v1.3.0
StartRuleReconciler periodically re-evaluates rule modes (TUN vs proxy).
func (*App) StartTrafficFlusher ¶
StartTrafficFlusher runs a background goroutine to periodically flush traffic.
func (*App) StartWireGuard ¶ added in v1.1.0
func (a *App) StartWireGuard(cfg WireGuardConfig) error
StartWireGuard starts userspace WireGuard with full traffic forwarding.
func (*App) StopClient ¶
func (*App) StopIKEv2 ¶ added in v1.1.3
func (a *App) StopIKEv2()
StopIKEv2 stops the IKEv2 service (kills strongswan connections, removes configs).
func (*App) StopIPForwarding ¶ added in v1.2.2
func (a *App) StopIPForwarding()
StopIPForwarding tears down TUN device and routing.
func (*App) StopRuleEngine ¶ added in v1.1.3
func (a *App) StopRuleEngine()
StopRuleEngine removes all rules and stops the proxy.
func (*App) Store ¶
func (a *App) Store() *ConfigStore
func (*App) ToggleRule ¶ added in v1.1.3
func (*App) UpdateClient ¶
func (a *App) UpdateClient(cl ClientEntry) error
func (*App) UpdateClientByAddr ¶
func (a *App) UpdateClientByAddr(oldName string, cl ClientEntry) error
UpdateClientByAddr finds a client by oldName (name or addr) and replaces it.
func (*App) UpdateProxy ¶
func (a *App) UpdateProxy(pc ProxyConfig) error
func (*App) UpdateRule ¶ added in v1.1.3
func (a *App) UpdateRule(id string, r RoutingRule)
func (*App) UpdateUser ¶
func (a *App) UpdateUser(id string, u UserConfig) error
func (*App) UpdateWebCredentials ¶ added in v1.0.3
type CertInfo ¶
type CertInfo struct {
ID string `json:"id"`
Name string `json:"name"`
Subject string `json:"subject"`
Issuer string `json:"issuer"`
NotAfter string `json:"not_after"`
IsCA bool `json:"is_ca"`
KeyFile string `json:"key_file,omitempty"`
CertFile string `json:"cert_file,omitempty"`
CAParentID string `json:"ca_parent_id,omitempty"`
}
CertInfo describes a stored certificate.
type ClientEntry ¶
type ClientEntry struct {
Name string `yaml:"name" json:"name"`
Addr string `yaml:"addr" json:"addr"` // primary address (backward compat)
Addrs []string `yaml:"addrs,omitempty" json:"addrs,omitempty"` // all addresses (including primary)
Password string `yaml:"password" json:"password"`
// TLS
SNI string `yaml:"sni,omitempty" json:"sni"`
Insecure bool `yaml:"insecure" json:"insecure"`
CA string `yaml:"ca,omitempty" json:"ca"` // PEM content or path
// Bandwidth (bytes/sec)
MaxTx int `yaml:"max_tx,omitempty" json:"max_tx"`
MaxRx int `yaml:"max_rx,omitempty" json:"max_rx"`
// QUIC
InitStreamWindow int `yaml:"init_stream_window,omitempty" json:"init_stream_window"`
MaxStreamWindow int `yaml:"max_stream_window,omitempty" json:"max_stream_window"`
InitConnWindow int `yaml:"init_conn_window,omitempty" json:"init_conn_window"`
MaxConnWindow int `yaml:"max_conn_window,omitempty" json:"max_conn_window"`
// Misc
FastOpen bool `yaml:"fast_open,omitempty" json:"fast_open"`
BBRProfile string `yaml:"bbr_profile,omitempty" json:"bbr_profile,omitempty"` // "", "standard", "conservative", "aggressive"
Disabled bool `yaml:"disabled,omitempty" json:"disabled"`
}
func (ClientEntry) AllAddrs ¶ added in v1.2.0
func (c ClientEntry) AllAddrs() []string
AllAddrs returns the effective address list. If Addrs is populated, returns it. Otherwise falls back to the single Addr field for backward compatibility.
func (ClientEntry) PrimaryAddr ¶ added in v1.2.0
func (c ClientEntry) PrimaryAddr() string
PrimaryAddr returns the first address (used as stable key and default connection).
type Config ¶
type Config struct {
NodeID string `yaml:"node_id" json:"node_id"`
Name string `yaml:"name" json:"name"`
ExitNode bool `yaml:"exit_node" json:"exit_node"`
Hy2UserAuth bool `yaml:"hy2_user_auth,omitempty" json:"hy2_user_auth"`
Server *ServerConfig `yaml:"server" json:"server"`
Clients []ClientEntry `yaml:"clients" json:"clients"`
Peers map[string]PeerConfig `yaml:"peers" json:"peers"`
SOCKS5 *SOCKS5Config `yaml:"socks5,omitempty" json:"-"`
Users []UserConfig `yaml:"users" json:"users"`
Proxies []ProxyConfig `yaml:"proxies" json:"proxies"`
SS *SSConfig `yaml:"ss,omitempty" json:"ss,omitempty"`
L2TP *L2TPConfig `yaml:"l2tp,omitempty" json:"l2tp,omitempty"`
IKEv2 *IKEv2Config `yaml:"ikev2,omitempty" json:"ikev2,omitempty"`
WireGuard *WireGuardConfig `yaml:"wireguard,omitempty" json:"wireguard,omitempty"`
Rules []RoutingRule `yaml:"rules,omitempty" json:"rules,omitempty"`
TunMode *TunModeConfig `yaml:"tun_mode,omitempty" json:"tun_mode,omitempty"`
UIListen string `yaml:"ui_listen,omitempty" json:"ui_listen,omitempty"`
UIBasePath string `yaml:"ui_base_path,omitempty" json:"ui_base_path,omitempty"`
WebUsername string `yaml:"web_username,omitempty" json:"web_username,omitempty"`
WebPassword string `yaml:"web_password,omitempty" json:"web_password,omitempty"`
DNS string `yaml:"dns,omitempty" json:"dns,omitempty"`
ForceHTTPS bool `yaml:"force_https,omitempty" json:"force_https,omitempty"`
HTTPSCertID string `yaml:"https_cert_id,omitempty" json:"https_cert_id,omitempty"`
SessionTimeoutH int `yaml:"session_timeout_h,omitempty" json:"session_timeout_h,omitempty"` // hours, default 12
// Persisted topology-graph layout: node key → SVG coordinates. Stored
// server-side so the layout follows the user across browsers/devices
// and multiple concurrent sessions converge on a single source of truth.
GraphLayout map[string]GraphLayoutPos `yaml:"graph_layout,omitempty" json:"graph_layout,omitempty"`
// Nested-discovery hard limits. Defensive backstops on the deep-cache
// machinery (see internal/api/server.go walkAndCache /
// assembleDeepTree). Under a sane config rule 1 cycle drop + rule 2
// gating already structurally bound the tree shape; these caps only
// fire under pathological mis-config or hostile peers. Hot-reloadable:
// updateUISettings refreshes the runtime atomic-pointer so changes
// take effect within the next SubPeersUpdater tick (≤7 s) without a
// restart. Zero / missing means "use built-in default".
MaxNestedDepth int `yaml:"max_nested_depth,omitempty" json:"max_nested_depth,omitempty"` // default 5, hard cap 10
MaxResponseNodes int `yaml:"max_response_nodes,omitempty" json:"max_response_nodes,omitempty"` // default 1024, hard cap 65536
MaxCacheEntries int `yaml:"max_cache_entries,omitempty" json:"max_cache_entries,omitempty"` // default 5000, hard cap 100000
MaxResponseBytes int `yaml:"max_response_bytes,omitempty" json:"max_response_bytes,omitempty"` // default 1048576, hard cap 16<<20
MaxFetchFanOut int `yaml:"max_fetch_fan_out,omitempty" json:"max_fetch_fan_out,omitempty"` // default 8, hard cap 64
// RelayAdminPassthrough lets web/API requests delivered through the
// authenticated peer-to-peer relay bridge (apiBridge in
// internal/api/server.go) skip the local session/Bearer-token check.
// Off by default — backwards compatible with every prior release where
// every API route required login regardless of transport. When on, the
// trust boundary becomes the relay handshake itself: a peer that has
// already authenticated as a known node is allowed to administer this
// node's web UI without a separate admin password.
RelayAdminPassthrough bool `yaml:"relay_admin_passthrough,omitempty" json:"relay_admin_passthrough,omitempty"`
// DNSResolver routes hy2scale's own internal name lookups (rules-engine
// `applyDomainRule`, future call sites) through a clean upstream DNS
// reachable via the relay/exit, so a polluted local resolv.conf does
// not contaminate which IPs the rule installs in iptables. Disabled by
// default: hy2scale falls back to net.LookupHost (host's resolv.conf).
DNSResolver DNSResolverConfig `yaml:"dns_resolver,omitempty" json:"dns_resolver,omitempty"`
}
func LoadOrInitConfig ¶
LoadOrInitConfig loads persisted config from dataDir/config.yaml. If it doesn't exist, creates a fresh default config.
type ConfigStore ¶
type ConfigStore struct {
// contains filtered or unexported fields
}
ConfigStore manages dynamic configuration with persistence.
func NewConfigStore ¶
func NewConfigStore(cfg Config, persistPath string) *ConfigStore
func (*ConfigStore) Get ¶
func (s *ConfigStore) Get() Config
func (*ConfigStore) Update ¶
func (s *ConfigStore) Update(fn func(*Config)) error
type DNSResolverConfig ¶ added in v1.3.4
type DNSResolverConfig struct {
// Enabled turns the resolver on. *bool so we can distinguish three
// states: nil (config field absent → default ENABLED), explicit
// true, explicit false. Defaulting nil to enabled means upgrades
// from 1.3.3 (which had no `dns_resolver` section) and fresh
// installs both get the safer relay-routed path; only operators
// who explicitly turned it off keep their off state.
Enabled *bool `yaml:"enabled,omitempty" json:"enabled,omitempty"`
// CacheTTL is how long an answer stays cached (seconds). Default
// 300. Fixed window — Go's stdlib resolver path doesn't surface
// the upstream's per-record TTL, so we use one operator-tunable
// value rather than honouring per-record TTL with min/max clamps.
CacheTTL int `yaml:"cache_ttl,omitempty" json:"cache_ttl,omitempty"`
// NegativeTTL is how long failures stay cached (seconds). Default
// 30. Avoids hammering upstream on an obviously-broken name.
NegativeTTL int `yaml:"negative_ttl,omitempty" json:"negative_ttl,omitempty"`
// CacheSize is the maximum number of cached entries (LRU evicted).
// Default 1024.
CacheSize int `yaml:"cache_size,omitempty" json:"cache_size,omitempty"`
// QueryTimeoutMs bounds a single upstream query (milliseconds).
// Default 3000.
QueryTimeoutMs int `yaml:"query_timeout_ms,omitempty" json:"query_timeout_ms,omitempty"`
}
DNSResolverConfig controls hy2scale's internal name-resolution behaviour. Hot-reloadable via updateUISettings — ApplyDNSResolver swaps the runtime atomic pointer so the next ResolveViaExit call picks up new values without a process restart.
Routing model: there is NO "DNS exit pin". Each rule's DNS naturally rides the same exit as its data — `exit_via=us` rules resolve through us, `exit_via=jp` rules resolve through jp. The wire-level mechanism is just a TCP/53 connection forwarded by the relay to the upstream resolver, so this works against any hy2-compatible peer including vanilla hy2 server. No new protocol added.
Upstream resolver list is NOT a field here — it reuses the top-level `cfg.DNS` (also used for VPN-client DNS push). Same comma-separated list, port :53 implied. One config knob serves both VPN clients and hy2scale's own lookups.
func (DNSResolverConfig) IsEnabled ¶ added in v1.3.4
func (c DNSResolverConfig) IsEnabled() bool
IsEnabled returns the effective Enabled value: nil pointer = default true (resolver is on out of the box). Use this everywhere instead of dereferencing c.Enabled directly so the default-on semantic stays in one place.
type Device ¶ added in v1.1.0
type Device struct {
Key string // username|ip|protocol
Username string
RemoteIP string
Protocol string // "socks5", "ss", "hy2", "l2tp", "ikev2"
ConnectAt time.Time
ConnCount atomic.Int32 // number of active TCP connections
TxBytes atomic.Int64
RxBytes atomic.Int64
// contains filtered or unexported fields
}
Device represents an active client device, aggregated by (username, IP, protocol). Multiple TCP connections from the same device are counted, not listed separately.
type DeviceJSON ¶ added in v1.1.0
type DeviceJSON struct {
Key string `json:"key"`
Username string `json:"username"`
RemoteIP string `json:"remote_ip"`
Protocol string `json:"protocol"`
ConnectAt int64 `json:"connect_at"`
Duration int `json:"duration"`
ConnCount int `json:"conn_count"`
TxBytes int64 `json:"tx_bytes"`
RxBytes int64 `json:"rx_bytes"`
}
type GraphLayoutPos ¶ added in v1.3.0
GraphLayoutPos stores a single node's coordinates in the topology graph.
type IKEv2Config ¶
type IKEv2Config struct {
Enabled bool `yaml:"enabled" json:"enabled"`
Mode string `yaml:"mode" json:"mode"` // "mschapv2" or "psk"
Pool string `yaml:"pool" json:"pool"` // e.g. "10.10.10.1/24"
CertID string `yaml:"cert_id" json:"cert_id"` // TLS cert ID (for mschapv2)
PSK string `yaml:"psk" json:"psk"` // pre-shared key (for psk mode)
LocalID string `yaml:"local_id" json:"local_id"` // server identity (leftid), default = node ID
RemoteID string `yaml:"remote_id" json:"remote_id"` // client identity (rightid), default = %any
PSKUserMode bool `yaml:"psk_user_mode" json:"psk_user_mode"` // PSK: require user auth
DefaultExit string `yaml:"default_exit" json:"default_exit"` // exit_via when user mode off
DefaultExitMode string `yaml:"default_exit_mode,omitempty" json:"default_exit_mode,omitempty"` // ""|"quality"|"aggregate"
DNS string `yaml:"dns" json:"dns"` // DNS servers, default "8.8.8.8 8.8.4.4"
ProxyPort int `yaml:"proxy_port" json:"proxy_port"` // transparent proxy port, default 12350
MTU int `yaml:"mtu" json:"mtu"` // tunnel MTU, default 1400
}
IKEv2Config holds IKEv2/IPsec VPN configuration.
type L2TPConfig ¶
type L2TPConfig struct {
Listen string `yaml:"listen" json:"listen"` // UDP port, e.g. "1701"
Enabled bool `yaml:"enabled" json:"enabled"`
Pool string `yaml:"pool" json:"pool"` // e.g. "192.168.25.1/24"
PSK string `yaml:"psk" json:"psk"` // IPsec pre-shared key
ProxyPort int `yaml:"proxy_port" json:"proxy_port"` // transparent proxy port, default 12345
MTU int `yaml:"mtu" json:"mtu"` // PPP MTU, default 1280
}
L2TPConfig holds L2TP/IPsec server configuration.
type PeerConfig ¶
type PortConflict ¶ added in v1.1.1
type PortConflict struct {
Port int `json:"port"`
Proto string `json:"proto"` // "tcp" or "udp"
Desc string `json:"desc"` // what's using it
}
PortConflict describes a port that is already in use.
func CheckPorts ¶ added in v1.1.1
func CheckPorts(ports []PortConflict) []PortConflict
CheckPorts tests if the given ports are available. Returns a list of conflicts (empty if all available).
type ProxyConfig ¶
type ProxyConfig struct {
ID string `yaml:"id" json:"id"`
Protocol string `yaml:"protocol" json:"protocol"` // "socks5", "http"
Listen string `yaml:"listen" json:"listen"`
Enabled bool `yaml:"enabled" json:"enabled"`
TLSCert string `yaml:"tls_cert,omitempty" json:"tls_cert,omitempty"` // TLS cert ID (enables TLS wrapping)
ExitVia string `yaml:"exit_via,omitempty" json:"exit_via,omitempty"`
ExitPaths []string `yaml:"exit_paths,omitempty" json:"exit_paths,omitempty"`
ExitMode string `yaml:"exit_mode,omitempty" json:"exit_mode,omitempty"`
}
ProxyConfig defines a protocol listener.
type RelayAuthConn ¶ added in v1.3.2
RelayAuthConn wraps the hub-side end of the net.Pipe used to deliver a `_relay_api_:0` stream to the local API server, carrying the hyserver authID that authenticated the originating QUIC connection. The api package's relaySrv ConnContext type-asserts this on Accept and threads the authID into the request context, so authMiddleware can apply RelayAdminPassthrough only when authID == "system".
func (*RelayAuthConn) RelayAuthID ¶ added in v1.3.2
func (c *RelayAuthConn) RelayAuthID() string
RelayAuthID exposes the carried authID without requiring callers to import this package's concrete type — they can use the small interface `interface{ RelayAuthID() string }` instead.
type RoutingRule ¶ added in v1.1.3
type RoutingRule struct {
ID string `yaml:"id" json:"id"`
Name string `yaml:"name" json:"name"`
Type string `yaml:"type" json:"type"` // "ip" or "domain"
Targets []string `yaml:"targets" json:"targets"` // IPs/CIDRs/ranges or domains
ExitVia string `yaml:"exit_via" json:"exit_via"`
ExitPaths []string `yaml:"exit_paths,omitempty" json:"exit_paths,omitempty"`
ExitMode string `yaml:"exit_mode,omitempty" json:"exit_mode,omitempty"` // ""|"quality"|"aggregate"
Enabled bool `yaml:"enabled" json:"enabled"`
// Priority resolves overlaps between rules. Higher priority wins for the
// same IP/CIDR. At equal priority, use_tun=true wins (TUN naturally
// preempts proxy at the routing layer anyway). Default 0.
Priority int `yaml:"priority,omitempty" json:"priority,omitempty"`
// UseTun requests full TUN forwarding for this rule. When the exit peer is
// TUN-capable (has NET_ADMIN + /dev/net/tun) and the target is routable,
// packets go through a raw IP tunnel (source IP preserved, ICMP supported).
// Otherwise silently falls back to normal relay proxy. When UseTun is set
// ExitPaths and ExitMode are ignored — only a single exit_via is honored.
UseTun bool `yaml:"use_tun,omitempty" json:"use_tun,omitempty"`
}
RoutingRule defines a traffic routing rule (IP or domain based).
type SOCKS5Config ¶
type SSConfig ¶
type SSConfig struct {
Listen string `yaml:"listen" json:"listen"`
Enabled bool `yaml:"enabled" json:"enabled"`
Method string `yaml:"method" json:"method"` // aes-128-gcm, aes-256-gcm, chacha20-ietf-poly1305
}
SSConfig holds Shadowsocks server configuration.
type ServerConfig ¶
type SessionManager ¶ added in v1.1.0
type SessionManager struct {
// contains filtered or unexported fields
}
SessionManager tracks active devices across proxy protocols. WireGuard is excluded — it has its own peer management.
func NewSessionManager ¶ added in v1.1.0
func NewSessionManager() *SessionManager
func (*SessionManager) Connect ¶ added in v1.1.0
func (m *SessionManager) Connect(username, remoteIP, protocol string, cancel func()) string
Connect registers a new connection from a device. Returns a connID for Disconnect. Returns empty string if blocked.
func (*SessionManager) Count ¶ added in v1.1.0
func (m *SessionManager) Count() int
Count returns total active devices.
func (*SessionManager) Disconnect ¶ added in v1.1.0
func (m *SessionManager) Disconnect(sessionID string, txBytes, rxBytes int64)
Disconnect removes a connection. If the device has no more connections, it's removed.
func (*SessionManager) IsBlocked ¶ added in v1.1.0
func (m *SessionManager) IsBlocked(username, remoteIP, protocol string) bool
IsBlocked checks if a device is temporarily blocked (kicked).
func (*SessionManager) Kick ¶ added in v1.1.0
func (m *SessionManager) Kick(key string) bool
Kick disconnects all connections for a device and blocks reconnection for 60s.
func (*SessionManager) KickUser ¶ added in v1.3.0
func (m *SessionManager) KickUser(username string) int
KickUser disconnects all active sessions for a given username.
func (*SessionManager) List ¶ added in v1.1.0
func (m *SessionManager) List() []DeviceJSON
List returns all active devices.
type TLSStore ¶
type TLSStore struct {
// contains filtered or unexported fields
}
TLSStore manages certificates in the data directory.
func NewTLSStore ¶
func (*TLSStore) CAParent ¶ added in v1.1.3
CAParent returns the CA ID that signed this cert, or empty string.
func (*TLSStore) SignWithCA ¶ added in v1.1.3
SignWithCA uses a CA certificate to sign a new server certificate.
type TunModeConfig ¶ added in v1.2.2
type TunModeConfig struct {
Enabled bool `yaml:"enabled" json:"enabled"`
Mode string `yaml:"mode" json:"mode"` // "mixed" (routable=TUN, others=proxy) or "full" (all TUN)
}
TunModeConfig controls TUN-based IP packet forwarding for the rules engine. When enabled, raw IP packets are forwarded through the relay instead of TCP/UDP proxy, preserving end-to-end connections (required for protocols like Moonlight ENC-RTSP that bind encryption to TCP sessions).
type UserConfig ¶
type UserConfig struct {
ID string `yaml:"id" json:"id"`
Username string `yaml:"username" json:"username"`
Password string `yaml:"password" json:"password"`
ProxyPasswords map[string]string `yaml:"proxy_passwords,omitempty" json:"proxy_passwords,omitempty"` // proxy-specific overrides (e.g. "hy2", "ss")
// ProxyDisabled lists proxy keys (hy2/ss/socks5/http/l2tp/ikev2) that
// MUST refuse to authenticate this user. Empty/missing list = the user
// is allowed on every proxy. Used by the per-proxy auth toggle in the
// admin UI; the auth path consults IsProxyEnabled() before issuing a
// successful auth on each protocol.
ProxyDisabled []string `yaml:"proxy_disabled,omitempty" json:"proxy_disabled,omitempty"`
ExitVia string `yaml:"exit_via" json:"exit_via"`
ExitPaths []string `yaml:"exit_paths,omitempty" json:"exit_paths,omitempty"`
ExitMode string `yaml:"exit_mode,omitempty" json:"exit_mode,omitempty"` // ""|"quality"|"aggregate"
TrafficLimit int64 `yaml:"traffic_limit" json:"traffic_limit"` // bytes, 0=unlimited
TrafficUsed int64 `yaml:"traffic_used" json:"traffic_used"`
ExpiryDate string `yaml:"expiry_date,omitempty" json:"expiry_date"`
Enabled bool `yaml:"enabled" json:"enabled"`
}
UserConfig defines a client user with auth and exit routing.
func (*UserConfig) EffectivePassword ¶ added in v1.3.0
func (u *UserConfig) EffectivePassword(proxy string) string
EffectivePassword returns the proxy-specific password if set, else the main password.
func (*UserConfig) IsProxyEnabled ¶ added in v1.3.2
func (u *UserConfig) IsProxyEnabled(proxy string) bool
IsProxyEnabled reports whether this user is allowed to authenticate on the given proxy key. Default (empty list) is "allowed everywhere".
type WireGuardConfig ¶ added in v1.1.0
type WireGuardConfig struct {
Enabled bool `yaml:"enabled" json:"enabled"`
ListenPort int `yaml:"listen_port" json:"listen_port"`
PrivateKey string `yaml:"private_key" json:"private_key"`
Address string `yaml:"address" json:"address"`
DNS string `yaml:"dns,omitempty" json:"dns,omitempty"`
MTU int `yaml:"mtu,omitempty" json:"mtu,omitempty"`
Peers []WireGuardPeer `yaml:"peers" json:"peers"`
}
WireGuardConfig stored in config.yaml.
type WireGuardPeer ¶ added in v1.1.0
type WireGuardPeer struct {
Name string `yaml:"name" json:"name"`
PublicKey string `yaml:"public_key" json:"public_key"`
PrivateKey string `yaml:"private_key" json:"private_key"`
AllowedIPs string `yaml:"allowed_ips" json:"allowed_ips"`
Keepalive int `yaml:"keepalive" json:"keepalive"`
ExitVia string `yaml:"exit_via,omitempty" json:"exit_via"`
ExitPaths []string `yaml:"exit_paths,omitempty" json:"exit_paths,omitempty"`
ExitMode string `yaml:"exit_mode,omitempty" json:"exit_mode,omitempty"`
}
WireGuardPeer is a peer entry.
Source Files
¶
- adaptive.go
- app.go
- bond.go
- bond_receiver.go
- config.go
- debug.go
- dns_resolver.go
- forward_accept_linux.go
- hy2_eventlog.go
- idle_timeout.go
- ikev2.go
- l2tp.go
- platform_linux.go
- portcheck.go
- rules.go
- rules_udp_linux.go
- sessions.go
- ss.go
- tls.go
- tun_capture.go
- tun_capture_linux.go
- tun_device_linux.go
- tun_ipfwd_linux.go
- wg_tun.go
- wireguard.go
- xfrm_bridge_linux.go