Add DisableRoutesAndAliases

This commit is contained in:
Owen
2026-09-25 15:12:26 -04:00
parent c4474e6e41
commit 9ef3399e8f
9 changed files with 246 additions and 150 deletions
+19 -18
View File
@@ -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
+45 -29
View File
@@ -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"))
+5 -5
View File
@@ -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
+6 -8
View File
@@ -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=
+20 -19
View File
@@ -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
View File
@@ -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
View File
@@ -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
+10
View File
@@ -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
View File
@@ -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