mirror of
https://github.com/fosrl/olm.git
synced 2026-10-01 18:29:08 +02:00
Add DisableRoutesAndAliases
This commit is contained in:
+19
-18
@@ -19,24 +19,25 @@ import (
|
||||
// non-empty, and is how olm later matches server-pushed gateway updates to the
|
||||
// resource the user actually connected through.
|
||||
type ConnectionRequest struct {
|
||||
ID string `json:"id"`
|
||||
Secret string `json:"secret"`
|
||||
Endpoint string `json:"endpoint"`
|
||||
UserToken string `json:"userToken,omitempty"`
|
||||
MTU int `json:"mtu,omitempty"`
|
||||
DNS string `json:"dns,omitempty"`
|
||||
DNSProxyIP string `json:"dnsProxyIP,omitempty"`
|
||||
UpstreamDNS []string `json:"upstreamDNS,omitempty"`
|
||||
InterfaceName string `json:"interfaceName,omitempty"`
|
||||
Holepunch bool `json:"holepunch,omitempty"`
|
||||
TlsClientCert string `json:"tlsClientCert,omitempty"`
|
||||
PingInterval string `json:"pingInterval,omitempty"`
|
||||
PingTimeout string `json:"pingTimeout,omitempty"`
|
||||
OrgID string `json:"orgId,omitempty"`
|
||||
MatchDomains []string `json:"matchDomains,omitempty"`
|
||||
SubnetRouter bool `json:"subnetRouter,omitempty"`
|
||||
GatewaySiteResourceId int `json:"gatewaySiteResourceId,omitempty"`
|
||||
GatewaySiteIds []int `json:"gatewaySiteIds,omitempty"`
|
||||
ID string `json:"id"`
|
||||
Secret string `json:"secret"`
|
||||
Endpoint string `json:"endpoint"`
|
||||
UserToken string `json:"userToken,omitempty"`
|
||||
MTU int `json:"mtu,omitempty"`
|
||||
DNS string `json:"dns,omitempty"`
|
||||
DNSProxyIP string `json:"dnsProxyIP,omitempty"`
|
||||
UpstreamDNS []string `json:"upstreamDNS,omitempty"`
|
||||
InterfaceName string `json:"interfaceName,omitempty"`
|
||||
Holepunch bool `json:"holepunch,omitempty"`
|
||||
TlsClientCert string `json:"tlsClientCert,omitempty"`
|
||||
PingInterval string `json:"pingInterval,omitempty"`
|
||||
PingTimeout string `json:"pingTimeout,omitempty"`
|
||||
OrgID string `json:"orgId,omitempty"`
|
||||
MatchDomains []string `json:"matchDomains,omitempty"`
|
||||
SubnetRouter bool `json:"subnetRouter,omitempty"`
|
||||
DisableRoutesAndAliases bool `json:"disableRoutesAndAliases,omitempty"`
|
||||
GatewaySiteResourceId int `json:"gatewaySiteResourceId,omitempty"`
|
||||
GatewaySiteIds []int `json:"gatewaySiteIds,omitempty"`
|
||||
}
|
||||
|
||||
// SwitchOrgRequest defines the structure for switching organizations
|
||||
|
||||
@@ -47,13 +47,14 @@ type OlmConfig struct {
|
||||
PingTimeout string `json:"pingTimeout"`
|
||||
|
||||
// Advanced
|
||||
DisableHolepunch bool `json:"disableHolepunch"`
|
||||
TlsClientCert string `json:"tlsClientCert"`
|
||||
OverrideDNS bool `json:"overrideDNS"`
|
||||
TunnelDNS bool `json:"tunnelDNS"`
|
||||
DisableRelay bool `json:"disableRelay"`
|
||||
PreferLocalRoutes bool `json:"preferLocalRoutes"`
|
||||
SubnetRouter bool `json:"subnetRouter"`
|
||||
DisableHolepunch bool `json:"disableHolepunch"`
|
||||
TlsClientCert string `json:"tlsClientCert"`
|
||||
OverrideDNS bool `json:"overrideDNS"`
|
||||
TunnelDNS bool `json:"tunnelDNS"`
|
||||
DisableRelay bool `json:"disableRelay"`
|
||||
PreferLocalRoutes bool `json:"preferLocalRoutes"`
|
||||
SubnetRouter bool `json:"subnetRouter"`
|
||||
DisableRoutesAndAliases bool `json:"disableRoutesAndAliases"`
|
||||
// DoNotCreateNewClient bool `json:"doNotCreateNewClient"`
|
||||
|
||||
// Parsed values (not in JSON)
|
||||
@@ -122,6 +123,7 @@ func DefaultConfig() *OlmConfig {
|
||||
config.sources["disableRelay"] = string(SourceDefault)
|
||||
config.sources["preferLocalRoutes"] = string(SourceDefault)
|
||||
config.sources["subnetRouter"] = string(SourceDefault)
|
||||
config.sources["disableRoutesAndAliases"] = string(SourceDefault)
|
||||
// config.sources["doNotCreateNewClient"] = string(SourceDefault)
|
||||
|
||||
return config
|
||||
@@ -297,6 +299,10 @@ func loadConfigFromEnv(config *OlmConfig) {
|
||||
config.SubnetRouter = true
|
||||
config.sources["subnetRouter"] = string(SourceEnv)
|
||||
}
|
||||
if val := os.Getenv("DISABLE_ROUTES_AND_ALIASES"); val == "true" {
|
||||
config.DisableRoutesAndAliases = true
|
||||
config.sources["disableRoutesAndAliases"] = string(SourceEnv)
|
||||
}
|
||||
// if val := os.Getenv("DO_NOT_CREATE_NEW_CLIENT"); val == "true" {
|
||||
// config.DoNotCreateNewClient = true
|
||||
// config.sources["doNotCreateNewClient"] = string(SourceEnv)
|
||||
@@ -309,28 +315,29 @@ func loadConfigFromCLI(config *OlmConfig, args []string) (bool, bool, error) {
|
||||
|
||||
// Store original values to detect changes
|
||||
origValues := map[string]interface{}{
|
||||
"endpoint": config.Endpoint,
|
||||
"id": config.ID,
|
||||
"secret": config.Secret,
|
||||
"org": config.OrgID,
|
||||
"userToken": config.UserToken,
|
||||
"mtu": config.MTU,
|
||||
"dns": config.DNS,
|
||||
"upstreamDNS": fmt.Sprintf("%v", config.UpstreamDNS),
|
||||
"matchDomains": fmt.Sprintf("%v", config.MatchDomains),
|
||||
"logLevel": config.LogLevel,
|
||||
"interface": config.InterfaceName,
|
||||
"httpAddr": config.HTTPAddr,
|
||||
"socketPath": config.SocketPath,
|
||||
"pingInterval": config.PingInterval,
|
||||
"pingTimeout": config.PingTimeout,
|
||||
"enableApi": config.EnableAPI,
|
||||
"disableHolepunch": config.DisableHolepunch,
|
||||
"overrideDNS": config.OverrideDNS,
|
||||
"disableRelay": config.DisableRelay,
|
||||
"preferLocalRoutes": config.PreferLocalRoutes,
|
||||
"tunnelDNS": config.TunnelDNS,
|
||||
"subnetRouter": config.SubnetRouter,
|
||||
"endpoint": config.Endpoint,
|
||||
"id": config.ID,
|
||||
"secret": config.Secret,
|
||||
"org": config.OrgID,
|
||||
"userToken": config.UserToken,
|
||||
"mtu": config.MTU,
|
||||
"dns": config.DNS,
|
||||
"upstreamDNS": fmt.Sprintf("%v", config.UpstreamDNS),
|
||||
"matchDomains": fmt.Sprintf("%v", config.MatchDomains),
|
||||
"logLevel": config.LogLevel,
|
||||
"interface": config.InterfaceName,
|
||||
"httpAddr": config.HTTPAddr,
|
||||
"socketPath": config.SocketPath,
|
||||
"pingInterval": config.PingInterval,
|
||||
"pingTimeout": config.PingTimeout,
|
||||
"enableApi": config.EnableAPI,
|
||||
"disableHolepunch": config.DisableHolepunch,
|
||||
"overrideDNS": config.OverrideDNS,
|
||||
"disableRelay": config.DisableRelay,
|
||||
"preferLocalRoutes": config.PreferLocalRoutes,
|
||||
"tunnelDNS": config.TunnelDNS,
|
||||
"subnetRouter": config.SubnetRouter,
|
||||
"disableRoutesAndAliases": config.DisableRoutesAndAliases,
|
||||
// "doNotCreateNewClient": config.DoNotCreateNewClient,
|
||||
}
|
||||
|
||||
@@ -359,6 +366,7 @@ func loadConfigFromCLI(config *OlmConfig, args []string) (bool, bool, error) {
|
||||
serviceFlags.BoolVar(&config.PreferLocalRoutes, "prefer-local-routes", config.PreferLocalRoutes, "Add tunnel routes with a high metric so overlapping local/connected routes take precedence (default false)")
|
||||
serviceFlags.BoolVar(&config.TunnelDNS, "tunnel-dns", config.TunnelDNS, "When enabled, DNS queries are routed through the tunnel for remote resolution. To ensure queries are tunneled correctly, you must define the DNS server as a Pangolin resource and enter its address as an Upstream DNS Server. (default false)")
|
||||
serviceFlags.BoolVar(&config.SubnetRouter, "subnet-router", config.SubnetRouter, "Enable this client to act as a subnet router: traffic forwarded from the local network is NATed to this client's own tunnel IP before going out over the tunnel. Linux only, requires CAP_NET_ADMIN. (default false)")
|
||||
serviceFlags.BoolVar(&config.DisableRoutesAndAliases, "disable-routes-and-aliases", config.DisableRoutesAndAliases, "Do not add routes to the system routing table and do not run the DNS proxy (aliases are not resolved). Gateway routes are still added. (default false)")
|
||||
// serviceFlags.BoolVar(&config.DoNotCreateNewClient, "do-not-create-new-client", config.DoNotCreateNewClient, "Do not create new client")
|
||||
|
||||
version := serviceFlags.Bool("version", false, "Print the version")
|
||||
@@ -451,6 +459,9 @@ func loadConfigFromCLI(config *OlmConfig, args []string) (bool, bool, error) {
|
||||
if config.SubnetRouter != origValues["subnetRouter"].(bool) {
|
||||
config.sources["subnetRouter"] = string(SourceCLI)
|
||||
}
|
||||
if config.DisableRoutesAndAliases != origValues["disableRoutesAndAliases"].(bool) {
|
||||
config.sources["disableRoutesAndAliases"] = string(SourceCLI)
|
||||
}
|
||||
// if config.DoNotCreateNewClient != origValues["doNotCreateNewClient"].(bool) {
|
||||
// config.sources["doNotCreateNewClient"] = string(SourceCLI)
|
||||
// }
|
||||
@@ -587,6 +598,10 @@ func mergeConfigs(dest, src *OlmConfig) {
|
||||
dest.SubnetRouter = src.SubnetRouter
|
||||
dest.sources["subnetRouter"] = string(SourceFile)
|
||||
}
|
||||
if src.DisableRoutesAndAliases {
|
||||
dest.DisableRoutesAndAliases = src.DisableRoutesAndAliases
|
||||
dest.sources["disableRoutesAndAliases"] = string(SourceFile)
|
||||
}
|
||||
// if src.DoNotCreateNewClient {
|
||||
// dest.DoNotCreateNewClient = src.DoNotCreateNewClient
|
||||
// dest.sources["doNotCreateNewClient"] = string(SourceFile)
|
||||
@@ -681,6 +696,7 @@ func (c *OlmConfig) ShowConfig() {
|
||||
fmt.Printf(" disable-relay = %v [%s]\n", c.DisableRelay, getSource("disableRelay"))
|
||||
fmt.Printf(" prefer-local-routes = %v [%s]\n", c.PreferLocalRoutes, getSource("preferLocalRoutes"))
|
||||
fmt.Printf(" subnet-router = %v [%s]\n", c.SubnetRouter, getSource("subnetRouter"))
|
||||
fmt.Printf(" disable-routes-and-aliases = %v [%s]\n", c.DisableRoutesAndAliases, getSource("disableRoutesAndAliases"))
|
||||
// fmt.Printf(" do-not-create-new-client = %v [%s]\n", c.DoNotCreateNewClient, getSource("doNotCreateNewClient"))
|
||||
if c.TlsClientCert != "" {
|
||||
fmt.Printf(" tls-cert = %s [%s]\n", c.TlsClientCert, getSource("tlsClientCert"))
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
module github.com/fosrl/olm
|
||||
|
||||
go 1.25.0
|
||||
go 1.26.0
|
||||
|
||||
require (
|
||||
github.com/Microsoft/go-winio v0.6.2
|
||||
@@ -9,8 +9,8 @@ require (
|
||||
github.com/google/nftables v0.3.0
|
||||
github.com/gorilla/websocket v1.5.3
|
||||
github.com/miekg/dns v1.1.70
|
||||
golang.org/x/net v0.56.0
|
||||
golang.org/x/sys v0.46.0
|
||||
golang.org/x/net v0.59.0
|
||||
golang.org/x/sys v0.48.0
|
||||
golang.zx2c4.com/wireguard v0.0.0-20250521234502-f333402bd9cb
|
||||
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20241231184526-a9ab2273dd10
|
||||
gvisor.dev/gvisor v0.0.0-20250503011706-39ed1f5ac29c
|
||||
@@ -24,7 +24,7 @@ require (
|
||||
github.com/mdlayher/socket v0.5.1 // indirect
|
||||
github.com/vishvananda/netlink v1.3.1 // indirect
|
||||
github.com/vishvananda/netns v0.0.5 // indirect
|
||||
golang.org/x/crypto v0.53.0 // indirect
|
||||
golang.org/x/crypto v0.57.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20251113190631-e25ba8c21ef6 // indirect
|
||||
golang.org/x/mod v0.34.0 // indirect
|
||||
golang.org/x/sync v0.20.0 // indirect
|
||||
@@ -35,4 +35,4 @@ require (
|
||||
)
|
||||
|
||||
// To be used ONLY for local development
|
||||
// replace github.com/fosrl/newt => ../newt
|
||||
replace github.com/fosrl/newt => ../newt
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
|
||||
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
|
||||
github.com/fosrl/newt v1.16.0 h1:Nf70uNFn/WqHoTvRg5xTPO3xz9vLgh3BsnMVMoniEEw=
|
||||
github.com/fosrl/newt v1.16.0/go.mod h1:l6kWoZPSaXT+ZRUjiyPgwflRqZWYaXpUj9oQ0sOPh4o=
|
||||
github.com/godbus/dbus/v5 v5.2.2 h1:TUR3TgtSVDmjiXOgAAyaZbYmIeP3DPkld3jgKGV8mXQ=
|
||||
github.com/godbus/dbus/v5 v5.2.2/go.mod h1:3AAv2+hPq5rdnr5txxxRwiGjPXamgoIHgz9FPBfOp3c=
|
||||
github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg=
|
||||
@@ -22,20 +20,20 @@ github.com/vishvananda/netlink v1.3.1 h1:3AEMt62VKqz90r0tmNhog0r/PpWKmrEShJU0wJW
|
||||
github.com/vishvananda/netlink v1.3.1/go.mod h1:ARtKouGSTGchR8aMwmkzC0qiNPrrWO5JS/XMVl45+b4=
|
||||
github.com/vishvananda/netns v0.0.5 h1:DfiHV+j8bA32MFM7bfEunvT8IAqQ/NzSJHtcmW5zdEY=
|
||||
github.com/vishvananda/netns v0.0.5/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM=
|
||||
golang.org/x/crypto v0.53.0 h1:QZ4Muo8THX6CizN2vPPd5fBGHyogrdK9fG4wLPFUsto=
|
||||
golang.org/x/crypto v0.53.0/go.mod h1:DNLU434OwVakk9PzuwV8w62mAJpRJL3vsgcfp4Qnsio=
|
||||
golang.org/x/crypto v0.57.0 h1:3ZVCjf8Ggz7zneR/EHRVx68Ctf+2pmIMP2UFhh9cC6M=
|
||||
golang.org/x/crypto v0.57.0/go.mod h1:Fdz0i5U6CoizGwLda9DttjSk6qlZo25zYNtR+ycvuZA=
|
||||
golang.org/x/exp v0.0.0-20251113190631-e25ba8c21ef6 h1:zfMcR1Cs4KNuomFFgGefv5N0czO2XZpUbxGUy8i8ug0=
|
||||
golang.org/x/exp v0.0.0-20251113190631-e25ba8c21ef6/go.mod h1:46edojNIoXTNOhySWIWdix628clX9ODXwPsQuG6hsK0=
|
||||
golang.org/x/mod v0.34.0 h1:xIHgNUUnW6sYkcM5Jleh05DvLOtwc6RitGHbDk4akRI=
|
||||
golang.org/x/mod v0.34.0/go.mod h1:ykgH52iCZe79kzLLMhyCUzhMci+nQj+0XkbXpNYtVjY=
|
||||
golang.org/x/net v0.56.0 h1:Rw8j/hFzGvJUZwNBXnAtf5sVDVt+65SK2C7IxCxZt5o=
|
||||
golang.org/x/net v0.56.0/go.mod h1:D3Ku6r+V6JROoZK144D2XfMHFcMq/0zSfLelVTCFKec=
|
||||
golang.org/x/net v0.59.0 h1:5zfYln+w5XCxwrnMMJPufRgNoXEaGxl0wo5GqPXyues=
|
||||
golang.org/x/net v0.59.0/go.mod h1:2DA/G1UfVbCpQPeWTmMPGY7Cs2PkBkwu743bVX5PIVg=
|
||||
golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4=
|
||||
golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
|
||||
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.46.0 h1:noSf2Fq6F8DBgS+LysIkx7rIExoNHJsxOAtPp4rthXw=
|
||||
golang.org/x/sys v0.46.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
|
||||
golang.org/x/sys v0.48.0 h1:bbX/i/6MgT9BVLM9RT1thmxL04yeTAhbEz4SyadbXoo=
|
||||
golang.org/x/sys v0.48.0/go.mod h1:hNLxWAXmnKAxqDtdwIYC4bM9oQPEecfsnNMuSxOs3og=
|
||||
golang.org/x/time v0.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE=
|
||||
golang.org/x/time v0.12.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
|
||||
golang.org/x/tools v0.43.0 h1:12BdW9CeB3Z+J/I/wj34VMl8X+fEXBxVR90JeMX5E7s=
|
||||
|
||||
@@ -256,25 +256,26 @@ func runOlmMainWithArgs(ctx context.Context, cancel context.CancelFunc, signalCt
|
||||
|
||||
if config.ID != "" && config.Secret != "" && config.Endpoint != "" {
|
||||
tunnelConfig := olmpkg.TunnelConfig{
|
||||
Endpoint: config.Endpoint,
|
||||
ID: config.ID,
|
||||
Secret: config.Secret,
|
||||
UserToken: config.UserToken,
|
||||
MTU: config.MTU,
|
||||
DNS: config.DNS,
|
||||
UpstreamDNS: config.UpstreamDNS,
|
||||
MatchDomains: config.MatchDomains,
|
||||
InterfaceName: config.InterfaceName,
|
||||
Holepunch: !config.DisableHolepunch,
|
||||
TlsClientCert: config.TlsClientCert,
|
||||
PingIntervalDuration: config.PingIntervalDuration,
|
||||
PingTimeoutDuration: config.PingTimeoutDuration,
|
||||
OrgID: config.OrgID,
|
||||
OverrideDNS: config.OverrideDNS,
|
||||
DisableRelay: config.DisableRelay,
|
||||
PreferLocalRoutes: config.PreferLocalRoutes,
|
||||
SubnetRouter: config.SubnetRouter,
|
||||
EnableUAPI: true,
|
||||
Endpoint: config.Endpoint,
|
||||
ID: config.ID,
|
||||
Secret: config.Secret,
|
||||
UserToken: config.UserToken,
|
||||
MTU: config.MTU,
|
||||
DNS: config.DNS,
|
||||
UpstreamDNS: config.UpstreamDNS,
|
||||
MatchDomains: config.MatchDomains,
|
||||
InterfaceName: config.InterfaceName,
|
||||
Holepunch: !config.DisableHolepunch,
|
||||
TlsClientCert: config.TlsClientCert,
|
||||
PingIntervalDuration: config.PingIntervalDuration,
|
||||
PingTimeoutDuration: config.PingTimeoutDuration,
|
||||
OrgID: config.OrgID,
|
||||
OverrideDNS: config.OverrideDNS,
|
||||
DisableRelay: config.DisableRelay,
|
||||
PreferLocalRoutes: config.PreferLocalRoutes,
|
||||
SubnetRouter: config.SubnetRouter,
|
||||
DisableRoutesAndAliases: config.DisableRoutesAndAliases,
|
||||
EnableUAPI: true,
|
||||
}
|
||||
go olm.StartTunnel(tunnelConfig)
|
||||
} else {
|
||||
|
||||
+52
-40
@@ -181,10 +181,17 @@ func (o *Olm) handleConnect(msg websocket.WSMessage) {
|
||||
logger.Warn("Failed to parse tunnel IP %q: %v", interfaceIP, err)
|
||||
}
|
||||
|
||||
// Create and start DNS proxy
|
||||
o.dnsProxy, err = dns.NewDNSProxy(o.middleDev, o.tunnelConfig.MTU, wgData.UtilitySubnet, o.tunnelConfig.UpstreamDNS, o.tunnelConfig.TunnelDNS, interfaceIP, o.tunnelConfig.MatchDomains, o.tunnelConfig.PublicDNS)
|
||||
if err != nil {
|
||||
logger.Error("Failed to create DNS proxy: %v", err)
|
||||
// Create the DNS proxy, unless routes/aliases are disabled - the proxy is
|
||||
// what resolves aliases, and the utility subnet it lives on is only
|
||||
// reachable through a system route we wouldn't add. o.dnsProxy stays nil
|
||||
// in that case; everything that uses it is nil-checked.
|
||||
if o.tunnelConfig.DisableRoutesAndAliases {
|
||||
logger.Info("Routes and aliases disabled: not adding system routes and not starting the DNS proxy (gateway routes are unaffected)")
|
||||
} else {
|
||||
o.dnsProxy, err = dns.NewDNSProxy(o.middleDev, o.tunnelConfig.MTU, wgData.UtilitySubnet, o.tunnelConfig.UpstreamDNS, o.tunnelConfig.TunnelDNS, interfaceIP, o.tunnelConfig.MatchDomains, o.tunnelConfig.PublicDNS)
|
||||
if err != nil {
|
||||
logger.Error("Failed to create DNS proxy: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Tell the system DNS monitor to exclude the proxy IP so that subsequent
|
||||
@@ -207,8 +214,10 @@ func (o *Olm) handleConnect(msg websocket.WSMessage) {
|
||||
}
|
||||
}
|
||||
|
||||
if err := network.AddRoutesWithSource([]string{wgData.UtilitySubnet}, o.tunnelConfig.InterfaceName, interfaceIP); err != nil { // also route the utility subnet
|
||||
logger.Error("Failed to add route for utility subnet: %v", err)
|
||||
if !o.tunnelConfig.DisableRoutesAndAliases {
|
||||
if err := network.AddRoutesWithSource([]string{wgData.UtilitySubnet}, o.tunnelConfig.InterfaceName, interfaceIP); err != nil { // also route the utility subnet
|
||||
logger.Error("Failed to add route for utility subnet: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Create peer manager with integrated peer monitoring
|
||||
@@ -223,6 +232,7 @@ func (o *Olm) handleConnect(msg websocket.WSMessage) {
|
||||
WSClient: o.websocket,
|
||||
APIServer: o.apiServer,
|
||||
PublicDNS: o.tunnelConfig.PublicDNS,
|
||||
DisableRoutes: o.tunnelConfig.DisableRoutesAndAliases,
|
||||
})
|
||||
|
||||
for i := range wgData.Sites {
|
||||
@@ -257,42 +267,44 @@ func (o *Olm) handleConnect(msg websocket.WSMessage) {
|
||||
// endpoints it already recorded now that there's somewhere to put them.
|
||||
o.flushPendingHolepunchBypassEndpoints()
|
||||
|
||||
if err := o.dnsProxy.Start(); err != nil { // start DNS proxy first so there is no downtime
|
||||
logger.Error("Failed to start DNS proxy: %v", err)
|
||||
if o.dnsProxy != nil {
|
||||
if err := o.dnsProxy.Start(); err != nil { // start DNS proxy first so there is no downtime
|
||||
logger.Error("Failed to start DNS proxy: %v", err)
|
||||
}
|
||||
|
||||
// Register JIT handler: when the DNS proxy resolves a local record, check whether
|
||||
// the owning site is already connected and, if not, initiate a JIT connection.
|
||||
o.dnsProxy.SetJITHandler(func(siteId int) {
|
||||
pm := o.getPeerManager()
|
||||
if pm == nil || o.websocket == nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Site already has an active peer connection - nothing to do.
|
||||
if _, exists := pm.GetPeer(siteId); exists {
|
||||
return
|
||||
}
|
||||
|
||||
o.peerSendMu.Lock()
|
||||
defer o.peerSendMu.Unlock()
|
||||
|
||||
// A JIT request for this site is already in-flight - avoid duplicate sends.
|
||||
if _, pending := o.jitPendingSites[siteId]; pending {
|
||||
return
|
||||
}
|
||||
|
||||
chainId := generateChainId()
|
||||
logger.Info("DNS-triggered JIT connect for site %d (chainId=%s)", siteId, chainId)
|
||||
stopFunc, _ := o.websocket.SendMessageInterval("olm/wg/server/peer/init", map[string]interface{}{
|
||||
"siteId": siteId,
|
||||
"chainId": chainId,
|
||||
}, 2*time.Second, 10)
|
||||
o.stopPeerInits[chainId] = stopFunc
|
||||
o.jitPendingSites[siteId] = chainId
|
||||
})
|
||||
}
|
||||
|
||||
// Register JIT handler: when the DNS proxy resolves a local record, check whether
|
||||
// the owning site is already connected and, if not, initiate a JIT connection.
|
||||
o.dnsProxy.SetJITHandler(func(siteId int) {
|
||||
pm := o.getPeerManager()
|
||||
if pm == nil || o.websocket == nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Site already has an active peer connection - nothing to do.
|
||||
if _, exists := pm.GetPeer(siteId); exists {
|
||||
return
|
||||
}
|
||||
|
||||
o.peerSendMu.Lock()
|
||||
defer o.peerSendMu.Unlock()
|
||||
|
||||
// A JIT request for this site is already in-flight - avoid duplicate sends.
|
||||
if _, pending := o.jitPendingSites[siteId]; pending {
|
||||
return
|
||||
}
|
||||
|
||||
chainId := generateChainId()
|
||||
logger.Info("DNS-triggered JIT connect for site %d (chainId=%s)", siteId, chainId)
|
||||
stopFunc, _ := o.websocket.SendMessageInterval("olm/wg/server/peer/init", map[string]interface{}{
|
||||
"siteId": siteId,
|
||||
"chainId": chainId,
|
||||
}, 2*time.Second, 10)
|
||||
o.stopPeerInits[chainId] = stopFunc
|
||||
o.jitPendingSites[siteId] = chainId
|
||||
})
|
||||
|
||||
if o.tunnelConfig.OverrideDNS {
|
||||
if o.tunnelConfig.OverrideDNS && o.dnsProxy != nil {
|
||||
if err := o.applyDNSOverride(true); err != nil {
|
||||
logger.Error("%v", err)
|
||||
return
|
||||
|
||||
+16
-15
@@ -289,21 +289,22 @@ func (o *Olm) registerAPICallbacks() {
|
||||
logger.Info("Received connection request via HTTP: id=%s, endpoint=%s", req.ID, req.Endpoint)
|
||||
|
||||
tunnelConfig := TunnelConfig{
|
||||
Endpoint: req.Endpoint,
|
||||
ID: req.ID,
|
||||
Secret: req.Secret,
|
||||
UserToken: req.UserToken,
|
||||
MTU: req.MTU,
|
||||
DNS: req.DNS,
|
||||
UpstreamDNS: req.UpstreamDNS,
|
||||
InterfaceName: req.InterfaceName,
|
||||
Holepunch: req.Holepunch,
|
||||
TlsClientCert: req.TlsClientCert,
|
||||
OrgID: req.OrgID,
|
||||
MatchDomains: req.MatchDomains,
|
||||
SubnetRouter: req.SubnetRouter,
|
||||
GatewaySiteIds: req.GatewaySiteIds,
|
||||
GatewaySiteResourceId: req.GatewaySiteResourceId,
|
||||
Endpoint: req.Endpoint,
|
||||
ID: req.ID,
|
||||
Secret: req.Secret,
|
||||
UserToken: req.UserToken,
|
||||
MTU: req.MTU,
|
||||
DNS: req.DNS,
|
||||
UpstreamDNS: req.UpstreamDNS,
|
||||
InterfaceName: req.InterfaceName,
|
||||
Holepunch: req.Holepunch,
|
||||
TlsClientCert: req.TlsClientCert,
|
||||
OrgID: req.OrgID,
|
||||
MatchDomains: req.MatchDomains,
|
||||
SubnetRouter: req.SubnetRouter,
|
||||
DisableRoutesAndAliases: req.DisableRoutesAndAliases,
|
||||
GatewaySiteIds: req.GatewaySiteIds,
|
||||
GatewaySiteResourceId: req.GatewaySiteResourceId,
|
||||
}
|
||||
|
||||
var err error
|
||||
|
||||
@@ -182,6 +182,16 @@ type TunnelConfig struct {
|
||||
// LAN address it originally arrived with. Linux only. Defaults to false.
|
||||
SubnetRouter bool
|
||||
|
||||
// DisableRoutesAndAliases, when enabled, stops olm from adding routes to
|
||||
// the host's routing table (server IPs, remote subnets, the utility
|
||||
// subnet) and from launching the DNS proxy, so aliases are not resolved
|
||||
// either. WireGuard AllowedIPs are still configured, so the tunnel can
|
||||
// still be used by anything that reaches it without the OS routing table
|
||||
// (e.g. a file descriptor/netstack consumer). Gateway routes (the
|
||||
// default-route-equivalent and its endpoint bypass routes) are unaffected
|
||||
// and are still installed. Defaults to false.
|
||||
DisableRoutesAndAliases bool
|
||||
|
||||
// GatewaySiteIds, when non-empty, designates these site IDs as gateway
|
||||
// (full-tunnel/default-route) candidates from the moment the tunnel
|
||||
// starts, for callers that want a gateway already established rather
|
||||
|
||||
+73
-16
@@ -36,6 +36,10 @@ type PeerManagerConfig struct {
|
||||
WSClient *websocket.Client
|
||||
APIServer *api.API
|
||||
PublicDNS []string
|
||||
// DisableRoutes stops the manager from adding/removing routes in the
|
||||
// system routing table for server IPs and remote subnets. Gateway routes
|
||||
// are unaffected.
|
||||
DisableRoutes bool
|
||||
}
|
||||
|
||||
type PeerManager struct {
|
||||
@@ -58,6 +62,7 @@ type PeerManager struct {
|
||||
allowedIPClaims map[string]map[int]bool
|
||||
APIServer *api.API
|
||||
publicDNS []string
|
||||
disableRoutes bool
|
||||
|
||||
PersistentKeepalive int
|
||||
|
||||
@@ -158,6 +163,7 @@ func NewPeerManager(config PeerManagerConfig) *PeerManager {
|
||||
allowedIPClaims: make(map[string]map[int]bool),
|
||||
APIServer: config.APIServer,
|
||||
publicDNS: config.PublicDNS,
|
||||
disableRoutes: config.DisableRoutes,
|
||||
lastOwnerChange: make(map[string]time.Time),
|
||||
gatewaySiteIds: make(map[int]bool),
|
||||
gatewayExcludedIPs: make(map[string]int),
|
||||
@@ -640,6 +646,59 @@ func (pm *PeerManager) GetAllPeers() []SiteConfig {
|
||||
return peers
|
||||
}
|
||||
|
||||
// addRoutes/removeRoutes/addServerRoute/removeServerRoute wrap the system
|
||||
// route helpers for site traffic (server IPs and remote subnets) and are a
|
||||
// no-op when route management is disabled. They deliberately do NOT cover the
|
||||
// gateway default-route-equivalent or its bypass routes, which are always
|
||||
// installed regardless (see activateGatewayLocked).
|
||||
func (pm *PeerManager) addRoutes(subnets []string) error {
|
||||
if pm.disableRoutes {
|
||||
return nil
|
||||
}
|
||||
return network.AddRoutesWithSource(subnets, pm.interfaceName, pm.localIP)
|
||||
}
|
||||
|
||||
func (pm *PeerManager) removeRoutes(subnets []string) error {
|
||||
if pm.disableRoutes {
|
||||
return nil
|
||||
}
|
||||
return network.RemoveRoutes(subnets, pm.interfaceName)
|
||||
}
|
||||
|
||||
func (pm *PeerManager) addServerRoute(serverIP string) error {
|
||||
if pm.disableRoutes {
|
||||
return nil
|
||||
}
|
||||
return network.AddRouteForServerIPWithSource(normalizeServerRouteDestination(serverIP), pm.interfaceName, pm.localIP)
|
||||
}
|
||||
|
||||
func (pm *PeerManager) removeServerRoute(serverIP string) error {
|
||||
if pm.disableRoutes {
|
||||
return nil
|
||||
}
|
||||
return network.RemoveRouteForServerIPWithSource(normalizeServerRouteDestination(serverIP), pm.interfaceName, pm.localIP)
|
||||
}
|
||||
|
||||
// The DNS proxy is not created when aliases are disabled, so every alias
|
||||
// record operation must tolerate a nil proxy.
|
||||
func (pm *PeerManager) addDNSRecord(alias string, address net.IP, siteId int) {
|
||||
if pm.dnsProxy != nil {
|
||||
pm.dnsProxy.AddDNSRecord(alias, address, siteId)
|
||||
}
|
||||
}
|
||||
|
||||
func (pm *PeerManager) removeDNSRecord(alias string, address net.IP) {
|
||||
if pm.dnsProxy != nil {
|
||||
pm.dnsProxy.RemoveDNSRecord(alias, address)
|
||||
}
|
||||
}
|
||||
|
||||
func (pm *PeerManager) removeDNSRecordForSite(alias string, address net.IP, siteId int) {
|
||||
if pm.dnsProxy != nil {
|
||||
pm.dnsProxy.RemoveDNSRecordForSite(alias, address, siteId)
|
||||
}
|
||||
}
|
||||
|
||||
func (pm *PeerManager) AddPeer(siteConfig SiteConfig) error {
|
||||
pm.mu.Lock()
|
||||
defer pm.mu.Unlock()
|
||||
@@ -649,7 +708,7 @@ func (pm *PeerManager) AddPeer(siteConfig SiteConfig) error {
|
||||
if address == nil {
|
||||
continue
|
||||
}
|
||||
pm.dnsProxy.AddDNSRecord(alias.Alias, address, siteConfig.SiteId)
|
||||
pm.addDNSRecord(alias.Alias, address, siteConfig.SiteId)
|
||||
}
|
||||
|
||||
if siteConfig.PublicKey == "" {
|
||||
@@ -694,11 +753,10 @@ func (pm *PeerManager) AddPeer(siteConfig SiteConfig) error {
|
||||
return err
|
||||
}
|
||||
|
||||
serverRouteDestination := normalizeServerRouteDestination(siteConfig.ServerIP)
|
||||
if err := network.AddRouteForServerIPWithSource(serverRouteDestination, pm.interfaceName, pm.localIP); err != nil {
|
||||
if err := pm.addServerRoute(siteConfig.ServerIP); err != nil {
|
||||
logger.Error("Failed to add route for server IP: %v", err)
|
||||
}
|
||||
if err := network.AddRoutesWithSource(siteConfig.RemoteSubnets, pm.interfaceName, pm.localIP); err != nil {
|
||||
if err := pm.addRoutes(siteConfig.RemoteSubnets); err != nil {
|
||||
logger.Error("Failed to add routes for remote subnets: %v", err)
|
||||
}
|
||||
|
||||
@@ -769,8 +827,7 @@ func (pm *PeerManager) RemovePeer(siteId int) error {
|
||||
return err
|
||||
}
|
||||
|
||||
serverRouteDestination := normalizeServerRouteDestination(peer.ServerIP)
|
||||
if err := network.RemoveRouteForServerIPWithSource(serverRouteDestination, pm.interfaceName, pm.localIP); err != nil {
|
||||
if err := pm.removeServerRoute(peer.ServerIP); err != nil {
|
||||
logger.Error("Failed to remove route for server IP: %v", err)
|
||||
}
|
||||
|
||||
@@ -792,7 +849,7 @@ func (pm *PeerManager) RemovePeer(siteId int) error {
|
||||
}
|
||||
}
|
||||
if !subnetStillInUse {
|
||||
if err := network.RemoveRoutes([]string{subnet}, pm.interfaceName); err != nil {
|
||||
if err := pm.removeRoutes([]string{subnet}); err != nil {
|
||||
logger.Error("Failed to remove route for remote subnet %s: %v", subnet, err)
|
||||
}
|
||||
}
|
||||
@@ -804,7 +861,7 @@ func (pm *PeerManager) RemovePeer(siteId int) error {
|
||||
if address == nil {
|
||||
continue
|
||||
}
|
||||
pm.dnsProxy.RemoveDNSRecord(alias.Alias, address)
|
||||
pm.removeDNSRecord(alias.Alias, address)
|
||||
}
|
||||
|
||||
// Release all IP claims and promote other peers as needed. Scan
|
||||
@@ -905,7 +962,7 @@ func (pm *PeerManager) UpdatePeer(siteConfig SiteConfig) error {
|
||||
if address == nil {
|
||||
continue
|
||||
}
|
||||
pm.dnsProxy.RemoveDNSRecord(alias.Alias, address)
|
||||
pm.removeDNSRecord(alias.Alias, address)
|
||||
}
|
||||
// Add new aliases
|
||||
for _, alias := range siteConfig.Aliases {
|
||||
@@ -913,7 +970,7 @@ func (pm *PeerManager) UpdatePeer(siteConfig SiteConfig) error {
|
||||
if address == nil {
|
||||
continue
|
||||
}
|
||||
pm.dnsProxy.AddDNSRecord(alias.Alias, address, siteConfig.SiteId)
|
||||
pm.addDNSRecord(alias.Alias, address, siteConfig.SiteId)
|
||||
}
|
||||
|
||||
if siteConfig.PublicKey == "" {
|
||||
@@ -1031,7 +1088,7 @@ func (pm *PeerManager) UpdatePeer(siteConfig SiteConfig) error {
|
||||
}
|
||||
}
|
||||
if !subnetStillInUse {
|
||||
if err := network.RemoveRoutes([]string{subnet}, pm.interfaceName); err != nil {
|
||||
if err := pm.removeRoutes([]string{subnet}); err != nil {
|
||||
logger.Error("Failed to remove route for subnet %s: %v", subnet, err)
|
||||
}
|
||||
}
|
||||
@@ -1039,7 +1096,7 @@ func (pm *PeerManager) UpdatePeer(siteConfig SiteConfig) error {
|
||||
|
||||
// Add routes for added subnets
|
||||
if len(addedSubnets) > 0 {
|
||||
if err := network.AddRoutesWithSource(addedSubnets, pm.interfaceName, pm.localIP); err != nil {
|
||||
if err := pm.addRoutes(addedSubnets); err != nil {
|
||||
logger.Error("Failed to add routes: %v", err)
|
||||
}
|
||||
}
|
||||
@@ -1250,7 +1307,7 @@ func (pm *PeerManager) AddRemoteSubnet(siteId int, cidr string) error {
|
||||
}
|
||||
|
||||
// Add route
|
||||
if err := network.AddRoutesWithSource([]string{cidr}, pm.interfaceName, pm.localIP); err != nil {
|
||||
if err := pm.addRoutes([]string{cidr}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -1310,7 +1367,7 @@ func (pm *PeerManager) RemoveRemoteSubnet(siteId int, ip string) error {
|
||||
|
||||
// Only remove route if no other peer needs it
|
||||
if !subnetStillInUse {
|
||||
if err := network.RemoveRoutes([]string{ip}, pm.interfaceName); err != nil {
|
||||
if err := pm.removeRoutes([]string{ip}); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@@ -1333,7 +1390,7 @@ func (pm *PeerManager) AddAlias(siteId int, alias Alias) error {
|
||||
|
||||
address := net.ParseIP(alias.AliasAddress)
|
||||
if address != nil {
|
||||
pm.dnsProxy.AddDNSRecord(alias.Alias, address, siteId)
|
||||
pm.addDNSRecord(alias.Alias, address, siteId)
|
||||
}
|
||||
|
||||
// Add an allowed IP for the alias
|
||||
@@ -1371,7 +1428,7 @@ func (pm *PeerManager) RemoveAlias(siteId int, aliasName string) error {
|
||||
|
||||
address := net.ParseIP(aliasToRemove.AliasAddress)
|
||||
if address != nil {
|
||||
pm.dnsProxy.RemoveDNSRecordForSite(aliasName, address, siteId)
|
||||
pm.removeDNSRecordForSite(aliasName, address, siteId)
|
||||
}
|
||||
|
||||
peer.Aliases = newAliases
|
||||
|
||||
Reference in New Issue
Block a user