From 0e5dc9d41229ef3f368aa5feb336934815b69a04 Mon Sep 17 00:00:00 2001 From: Viktor Liu <17948409+lixmal@users.noreply.github.com> Date: Wed, 18 Jun 2025 17:23:23 +0200 Subject: [PATCH] [client] Add more Android advanced settings (#4001) --- client/android/preferences.go | 138 +++++++++++++++++++++++--- client/iface/device/device_android.go | 11 +- client/iface/iface.go | 1 + client/iface/iface_new_android.go | 2 +- client/internal/config.go | 14 ++- client/internal/engine.go | 1 + 6 files changed, 149 insertions(+), 18 deletions(-) diff --git a/client/android/preferences.go b/client/android/preferences.go index 2a8b197e7..2d5668d1c 100644 --- a/client/android/preferences.go +++ b/client/android/preferences.go @@ -4,12 +4,12 @@ import ( "github.com/netbirdio/netbird/client/internal" ) -// Preferences export a subset of the internal config for gomobile +// Preferences exports a subset of the internal config for gomobile type Preferences struct { configInput internal.ConfigInput } -// NewPreferences create new Preferences instance +// NewPreferences creates a new Preferences instance func NewPreferences(configPath string) *Preferences { ci := internal.ConfigInput{ ConfigPath: configPath, @@ -17,7 +17,7 @@ func NewPreferences(configPath string) *Preferences { return &Preferences{ci} } -// GetManagementURL read url from config file +// GetManagementURL reads URL from config file func (p *Preferences) GetManagementURL() (string, error) { if p.configInput.ManagementURL != "" { return p.configInput.ManagementURL, nil @@ -30,12 +30,12 @@ func (p *Preferences) GetManagementURL() (string, error) { return cfg.ManagementURL.String(), err } -// SetManagementURL store the given url and wait for commit +// SetManagementURL stores the given URL and waits for commit func (p *Preferences) SetManagementURL(url string) { p.configInput.ManagementURL = url } -// GetAdminURL read url from config file +// GetAdminURL reads URL from config file func (p *Preferences) GetAdminURL() (string, error) { if p.configInput.AdminURL != "" { return p.configInput.AdminURL, nil @@ -48,12 +48,12 @@ func (p *Preferences) GetAdminURL() (string, error) { return cfg.AdminURL.String(), err } -// SetAdminURL store the given url and wait for commit +// SetAdminURL stores the given URL and waits for commit func (p *Preferences) SetAdminURL(url string) { p.configInput.AdminURL = url } -// GetPreSharedKey read preshared key from config file +// GetPreSharedKey reads pre-shared key from config file func (p *Preferences) GetPreSharedKey() (string, error) { if p.configInput.PreSharedKey != nil { return *p.configInput.PreSharedKey, nil @@ -66,17 +66,17 @@ func (p *Preferences) GetPreSharedKey() (string, error) { return cfg.PreSharedKey, err } -// SetPreSharedKey store the given key and wait for commit +// SetPreSharedKey stores the given key and waits for commit func (p *Preferences) SetPreSharedKey(key string) { p.configInput.PreSharedKey = &key } -// SetRosenpassEnabled store if rosenpass is enabled +// SetRosenpassEnabled stores whether Rosenpass is enabled func (p *Preferences) SetRosenpassEnabled(enabled bool) { p.configInput.RosenpassEnabled = &enabled } -// GetRosenpassEnabled read rosenpass enabled from config file +// GetRosenpassEnabled reads Rosenpass enabled status from config file func (p *Preferences) GetRosenpassEnabled() (bool, error) { if p.configInput.RosenpassEnabled != nil { return *p.configInput.RosenpassEnabled, nil @@ -89,12 +89,12 @@ func (p *Preferences) GetRosenpassEnabled() (bool, error) { return cfg.RosenpassEnabled, err } -// SetRosenpassPermissive store the given permissive and wait for commit +// SetRosenpassPermissive stores the given permissive setting and waits for commit func (p *Preferences) SetRosenpassPermissive(permissive bool) { p.configInput.RosenpassPermissive = &permissive } -// GetRosenpassPermissive read rosenpass permissive from config file +// GetRosenpassPermissive reads Rosenpass permissive setting from config file func (p *Preferences) GetRosenpassPermissive() (bool, error) { if p.configInput.RosenpassPermissive != nil { return *p.configInput.RosenpassPermissive, nil @@ -107,7 +107,119 @@ func (p *Preferences) GetRosenpassPermissive() (bool, error) { return cfg.RosenpassPermissive, err } -// Commit write out the changes into config file +// GetDisableClientRoutes reads disable client routes setting from config file +func (p *Preferences) GetDisableClientRoutes() (bool, error) { + if p.configInput.DisableClientRoutes != nil { + return *p.configInput.DisableClientRoutes, nil + } + + cfg, err := internal.ReadConfig(p.configInput.ConfigPath) + if err != nil { + return false, err + } + return cfg.DisableClientRoutes, err +} + +// SetDisableClientRoutes stores the given value and waits for commit +func (p *Preferences) SetDisableClientRoutes(disable bool) { + p.configInput.DisableClientRoutes = &disable +} + +// GetDisableServerRoutes reads disable server routes setting from config file +func (p *Preferences) GetDisableServerRoutes() (bool, error) { + if p.configInput.DisableServerRoutes != nil { + return *p.configInput.DisableServerRoutes, nil + } + + cfg, err := internal.ReadConfig(p.configInput.ConfigPath) + if err != nil { + return false, err + } + return cfg.DisableServerRoutes, err +} + +// SetDisableServerRoutes stores the given value and waits for commit +func (p *Preferences) SetDisableServerRoutes(disable bool) { + p.configInput.DisableServerRoutes = &disable +} + +// GetDisableDNS reads disable DNS setting from config file +func (p *Preferences) GetDisableDNS() (bool, error) { + if p.configInput.DisableDNS != nil { + return *p.configInput.DisableDNS, nil + } + + cfg, err := internal.ReadConfig(p.configInput.ConfigPath) + if err != nil { + return false, err + } + return cfg.DisableDNS, err +} + +// SetDisableDNS stores the given value and waits for commit +func (p *Preferences) SetDisableDNS(disable bool) { + p.configInput.DisableDNS = &disable +} + +// GetDisableFirewall reads disable firewall setting from config file +func (p *Preferences) GetDisableFirewall() (bool, error) { + if p.configInput.DisableFirewall != nil { + return *p.configInput.DisableFirewall, nil + } + + cfg, err := internal.ReadConfig(p.configInput.ConfigPath) + if err != nil { + return false, err + } + return cfg.DisableFirewall, err +} + +// SetDisableFirewall stores the given value and waits for commit +func (p *Preferences) SetDisableFirewall(disable bool) { + p.configInput.DisableFirewall = &disable +} + +// GetServerSSHAllowed reads server SSH allowed setting from config file +func (p *Preferences) GetServerSSHAllowed() (bool, error) { + if p.configInput.ServerSSHAllowed != nil { + return *p.configInput.ServerSSHAllowed, nil + } + + cfg, err := internal.ReadConfig(p.configInput.ConfigPath) + if err != nil { + return false, err + } + if cfg.ServerSSHAllowed == nil { + // Default to false for security on Android + return false, nil + } + return *cfg.ServerSSHAllowed, err +} + +// SetServerSSHAllowed stores the given value and waits for commit +func (p *Preferences) SetServerSSHAllowed(allowed bool) { + p.configInput.ServerSSHAllowed = &allowed +} + +// GetBlockInbound reads block inbound setting from config file +func (p *Preferences) GetBlockInbound() (bool, error) { + if p.configInput.BlockInbound != nil { + return *p.configInput.BlockInbound, nil + } + + cfg, err := internal.ReadConfig(p.configInput.ConfigPath) + if err != nil { + return false, err + } + return cfg.BlockInbound, err +} + +// SetBlockInbound stores the given value and waits for commit +func (p *Preferences) SetBlockInbound(block bool) { + p.configInput.BlockInbound = &block +} + +// Commit writes out the changes to the config file func (p *Preferences) Commit() error { _, err := internal.UpdateOrCreateConfig(p.configInput) return err diff --git a/client/iface/device/device_android.go b/client/iface/device/device_android.go index ab3e611e1..ae9e29bd1 100644 --- a/client/iface/device/device_android.go +++ b/client/iface/device/device_android.go @@ -24,6 +24,7 @@ type WGTunDevice struct { mtu int iceBind *bind.ICEBind tunAdapter TunAdapter + disableDNS bool name string device *device.Device @@ -32,7 +33,7 @@ type WGTunDevice struct { configurer WGConfigurer } -func NewTunDevice(address wgaddr.Address, port int, key string, mtu int, iceBind *bind.ICEBind, tunAdapter TunAdapter) *WGTunDevice { +func NewTunDevice(address wgaddr.Address, port int, key string, mtu int, iceBind *bind.ICEBind, tunAdapter TunAdapter, disableDNS bool) *WGTunDevice { return &WGTunDevice{ address: address, port: port, @@ -40,6 +41,7 @@ func NewTunDevice(address wgaddr.Address, port int, key string, mtu int, iceBind mtu: mtu, iceBind: iceBind, tunAdapter: tunAdapter, + disableDNS: disableDNS, } } @@ -49,6 +51,13 @@ func (t *WGTunDevice) Create(routes []string, dns string, searchDomains []string routesString := routesToString(routes) searchDomainsToString := searchDomainsToString(searchDomains) + // Skip DNS configuration when DisableDNS is enabled + if t.disableDNS { + log.Info("DNS is disabled, skipping DNS and search domain configuration") + dns = "" + searchDomainsToString = "" + } + fd, err := t.tunAdapter.ConfigureInterface(t.address.String(), t.mtu, dns, searchDomainsToString, routesString) if err != nil { log.Errorf("failed to create Android interface: %s", err) diff --git a/client/iface/iface.go b/client/iface/iface.go index 7d609f4cd..006dfe4e7 100644 --- a/client/iface/iface.go +++ b/client/iface/iface.go @@ -43,6 +43,7 @@ type WGIFaceOpts struct { MobileArgs *device.MobileIFaceArguments TransportNet transport.Net FilterFn bind.FilterFn + DisableDNS bool } // WGIface represents an interface instance diff --git a/client/iface/iface_new_android.go b/client/iface/iface_new_android.go index 35046b887..c8babea32 100644 --- a/client/iface/iface_new_android.go +++ b/client/iface/iface_new_android.go @@ -18,7 +18,7 @@ func NewWGIFace(opts WGIFaceOpts) (*WGIface, error) { wgIFace := &WGIface{ userspaceBind: true, - tun: device.NewTunDevice(wgAddress, opts.WGPort, opts.WGPrivKey, opts.MTU, iceBind, opts.MobileArgs.TunAdapter), + tun: device.NewTunDevice(wgAddress, opts.WGPort, opts.WGPrivKey, opts.MTU, iceBind, opts.MobileArgs.TunAdapter, opts.DisableDNS), wgProxyFactory: wgproxy.NewUSPFactory(iceBind), } return wgIFace, nil diff --git a/client/internal/config.go b/client/internal/config.go index 45a7620e1..37ee1e1bf 100644 --- a/client/internal/config.go +++ b/client/internal/config.go @@ -223,6 +223,8 @@ func createNewConfig(input ConfigInput) (*Config, error) { config := &Config{ // defaults to false only for new (post 0.26) configurations ServerSSHAllowed: util.False(), + // default to disabling server routes on Android for security + DisableServerRoutes: runtime.GOOS == "android", } if _, err := config.apply(input); err != nil { @@ -416,9 +418,15 @@ func (config *Config) apply(input ConfigInput) (updated bool, err error) { config.ServerSSHAllowed = input.ServerSSHAllowed updated = true } else if config.ServerSSHAllowed == nil { - // enables SSH for configs from old versions to preserve backwards compatibility - log.Infof("falling back to enabled SSH server for pre-existing configuration") - config.ServerSSHAllowed = util.True() + if runtime.GOOS == "android" { + // default to disabled SSH on Android for security + log.Infof("setting SSH server to false by default on Android") + config.ServerSSHAllowed = util.False() + } else { + // enables SSH for configs from old versions to preserve backwards compatibility + log.Infof("falling back to enabled SSH server for pre-existing configuration") + config.ServerSSHAllowed = util.True() + } updated = true } diff --git a/client/internal/engine.go b/client/internal/engine.go index 253ecb2a6..4ea6fbd94 100644 --- a/client/internal/engine.go +++ b/client/internal/engine.go @@ -1527,6 +1527,7 @@ func (e *Engine) newWgIface() (*iface.WGIface, error) { MTU: iface.DefaultMTU, TransportNet: transportNet, FilterFn: e.addrViaRoutes, + DisableDNS: e.config.DisableDNS, } switch runtime.GOOS {