From 7f7e10121ddd6d5b9b97021ee9c922038580f421 Mon Sep 17 00:00:00 2001 From: Pascal Fischer Date: Wed, 9 Aug 2023 15:21:53 +0200 Subject: [PATCH 01/56] starting engine by passing file descriptor on engine start --- client/internal/connect.go | 13 ++ client/internal/engine.go | 13 +- client/internal/mobile_dependency.go | 1 + client/ios/netbird/client.go | 166 ++++++++++++++++++ client/ios/netbird/dns_list.go | 26 +++ client/ios/netbird/dns_list_test.go | 24 +++ client/ios/netbird/gomobile.go | 5 + client/ios/netbird/login.go | 222 +++++++++++++++++++++++++ client/ios/netbird/peer_notifier.go | 36 ++++ client/ios/netbird/preferences.go | 78 +++++++++ client/ios/netbird/preferences_test.go | 120 +++++++++++++ client/system/info_darwin.go | 3 + client/system/info_ios.go | 30 ++++ iface/iface_android.go | 10 +- iface/iface_ios.go | 51 ++++++ iface/iface_nonandroid.go | 12 +- iface/tun_android.go | 5 +- iface/tun_darwin.go | 3 + iface/tun_ios.go | 105 ++++++++++++ iface/tun_unix.go | 2 +- 20 files changed, 913 insertions(+), 12 deletions(-) create mode 100644 client/ios/netbird/client.go create mode 100644 client/ios/netbird/dns_list.go create mode 100644 client/ios/netbird/dns_list_test.go create mode 100644 client/ios/netbird/gomobile.go create mode 100644 client/ios/netbird/login.go create mode 100644 client/ios/netbird/peer_notifier.go create mode 100644 client/ios/netbird/preferences.go create mode 100644 client/ios/netbird/preferences_test.go create mode 100644 client/system/info_ios.go create mode 100644 iface/iface_ios.go create mode 100644 iface/tun_ios.go diff --git a/client/internal/connect.go b/client/internal/connect.go index 87aab0b545b..3416d7aae49 100644 --- a/client/internal/connect.go +++ b/client/internal/connect.go @@ -42,6 +42,19 @@ func RunClientMobile(ctx context.Context, config *Config, statusRecorder *peer.S return runClient(ctx, config, statusRecorder, mobileDependency) } +func RunClientiOS(ctx context.Context, config *Config, statusRecorder *peer.Status, fileDescriptor int32, iFaceDiscover stdnet.ExternalIFaceDiscover, routeListener routemanager.RouteListener, dnsAddresses []string, dnsReadyListener dns.ReadyListener) error { + // func RunClientiOS(ctx context.Context, config *Config, statusRecorder *peer.Status, iFaceDiscover stdnet.ExternalIFaceDiscover, routeListener routemanager.RouteListener, dnsAddresses []string, dnsReadyListener dns.ReadyListener) error { + mobileDependency := MobileDependency{ + TunAdapter: nil, + FileDescriptor: fileDescriptor, + IFaceDiscover: iFaceDiscover, + RouteListener: routeListener, + HostDNSAddresses: dnsAddresses, + DnsReadyListener: dnsReadyListener, + } + return runClient(ctx, config, statusRecorder, mobileDependency) +} + func runClient(ctx context.Context, config *Config, statusRecorder *peer.Status, mobileDependency MobileDependency) error { backOff := &backoff.ExponentialBackOff{ InitialInterval: time.Second, diff --git a/client/internal/engine.go b/client/internal/engine.go index 038f39e5c58..8276aef5640 100644 --- a/client/internal/engine.go +++ b/client/internal/engine.go @@ -217,13 +217,16 @@ func (e *Engine) Start() error { e.routeManager = routemanager.NewManager(e.ctx, e.config.WgPrivateKey.PublicKey().String(), e.wgInterface, e.statusRecorder, routes) e.routeManager.SetRouteChangeListener(e.mobileDep.RouteListener) - if runtime.GOOS != "android" { - err = e.wgInterface.Create() - } else { - err = e.wgInterface.CreateOnMobile(iface.MobileIFaceArguments{ + switch runtime.GOOS { + case "android": + err = e.wgInterface.CreateOnAndroid(iface.MobileIFaceArguments{ Routes: e.routeManager.InitialRouteRange(), Dns: e.dnsServer.DnsIP(), }) + case "ios": + err = e.wgInterface.CreateOniOS(e.mobileDep.FileDescriptor) + default: + err = e.wgInterface.Create() } if err != nil { log.Errorf("failed creating tunnel interface %s: [%s]", wgIFaceName, err.Error()) @@ -466,7 +469,7 @@ func (e *Engine) updateSSH(sshConf *mgmProto.SSHConfig) error { } // start SSH server if it wasn't running if isNil(e.sshServer) { - //nil sshServer means it has not yet been started + // nil sshServer means it has not yet been started var err error e.sshServer, err = e.sshServerFunc(e.config.SSHKey, fmt.Sprintf("%s:%d", e.wgInterface.Address().IP.String(), nbssh.DefaultSSHPort)) diff --git a/client/internal/mobile_dependency.go b/client/internal/mobile_dependency.go index fc8fa61ce2a..0b02a63ec53 100644 --- a/client/internal/mobile_dependency.go +++ b/client/internal/mobile_dependency.go @@ -14,4 +14,5 @@ type MobileDependency struct { RouteListener routemanager.RouteListener HostDNSAddresses []string DnsReadyListener dns.ReadyListener + FileDescriptor int32 } diff --git a/client/ios/netbird/client.go b/client/ios/netbird/client.go new file mode 100644 index 00000000000..46ac734dfdf --- /dev/null +++ b/client/ios/netbird/client.go @@ -0,0 +1,166 @@ +package netbird + +import ( + "context" + "sync" + + log "github.com/sirupsen/logrus" + + "github.com/netbirdio/netbird/client/internal" + "github.com/netbirdio/netbird/client/internal/dns" + "github.com/netbirdio/netbird/client/internal/peer" + "github.com/netbirdio/netbird/client/internal/routemanager" + "github.com/netbirdio/netbird/client/internal/stdnet" + "github.com/netbirdio/netbird/client/system" + "github.com/netbirdio/netbird/formatter" + "github.com/netbirdio/netbird/iface" +) + +// ConnectionListener export internal Listener for mobile +type ConnectionListener interface { + peer.Listener +} + +// TunAdapter export internal TunAdapter for mobile +type TunAdapter interface { + iface.TunAdapter +} + +// IFaceDiscover export internal IFaceDiscover for mobile +type IFaceDiscover interface { + stdnet.ExternalIFaceDiscover +} + +// RouteListener export internal RouteListener for mobile +type RouteListener interface { + routemanager.RouteListener +} + +// DnsReadyListener export internal dns ReadyListener for mobile +type DnsReadyListener interface { + dns.ReadyListener +} + +// CustomLogger export internal CustomLogger for mobile +type CustomLogger interface { + Debug(message string) + Info(message string) + Error(message string) +} + +func init() { + formatter.SetLogcatFormatter(log.StandardLogger()) +} + +// Client struct manage the life circle of background service +type Client struct { + cfgFile string + iFaceDiscover IFaceDiscover + recorder *peer.Status + ctxCancel context.CancelFunc + ctxCancelLock *sync.Mutex + deviceName string + routeListener routemanager.RouteListener + logger CustomLogger + onHostDnsFn func([]string) +} + +// NewClient instantiate a new Client +func NewClient(cfgFile, deviceName string, iFaceDiscover IFaceDiscover, routeListener RouteListener, logger CustomLogger) *Client { + return &Client{ + cfgFile: cfgFile, + deviceName: deviceName, + iFaceDiscover: iFaceDiscover, + recorder: peer.NewRecorder(""), + ctxCancelLock: &sync.Mutex{}, + logger: logger, + routeListener: routeListener, + } +} + +// Run start the internal client. It is a blocker function +// func (c *Client) Run(fd int32, dns *DNSList, dnsReadyListener DnsReadyListener) error { +func (c *Client) Run(fd int32, dns *DNSList, dnsReadyListener DnsReadyListener) error { + c.logger.Info("Starting NetBird client") + cfg, err := internal.UpdateOrCreateConfig(internal.ConfigInput{ + ConfigPath: c.cfgFile, + }) + if err != nil { + return err + } + c.recorder.UpdateManagementAddress(cfg.ManagementURL.String()) + + var ctx context.Context + //nolint + ctxWithValues := context.WithValue(context.Background(), system.DeviceNameCtxKey, c.deviceName) + c.ctxCancelLock.Lock() + ctx, c.ctxCancel = context.WithCancel(ctxWithValues) + defer c.ctxCancel() + c.ctxCancelLock.Unlock() + + auth := NewAuthWithConfig(ctx, cfg) + // err = auth.login(urlOpener) + auth.loginWithSetupKeyAndSaveConfig("E9EEBA50-76A1-4C72-A939-C10655C1CC09", "iPhone") + if err != nil { + return err + } + + // todo do not throw error in case of cancelled context + ctx = internal.CtxInitState(ctx) + c.onHostDnsFn = func([]string) {} + return internal.RunClientiOS(ctx, cfg, c.recorder, fd, c.iFaceDiscover, c.routeListener, dns.items, dnsReadyListener) +} + +// Stop the internal client and free the resources +func (c *Client) Stop() { + c.ctxCancelLock.Lock() + defer c.ctxCancelLock.Unlock() + if c.ctxCancel == nil { + return + } + + c.ctxCancel() +} + +// ÏSetTraceLogLevel configure the logger to trace level +func (c *Client) SetTraceLogLevel() { + log.SetLevel(log.TraceLevel) +} + +// PeersList return with the list of the PeerInfos +func (c *Client) PeersList() *PeerInfoArray { + + fullStatus := c.recorder.GetFullStatus() + + peerInfos := make([]PeerInfo, len(fullStatus.Peers)) + for n, p := range fullStatus.Peers { + pi := PeerInfo{ + p.IP, + p.FQDN, + p.ConnStatus.String(), + } + peerInfos[n] = pi + } + return &PeerInfoArray{items: peerInfos} +} + +// OnUpdatedHostDNS update the DNS servers addresses for root zones +func (c *Client) OnUpdatedHostDNS(list *DNSList) error { + dnsServer, err := dns.GetServerDns() + if err != nil { + return err + } + + dnsServer.OnUpdatedHostDNSServer(list.items) + return nil +} + +// SetConnectionListener set the network connection listener +func (c *Client) SetConnectionListener(listener ConnectionListener) { + c.recorder.SetConnectionListener(listener) +} + +// RemoveConnectionListener remove connection listener +func (c *Client) RemoveConnectionListener() { + c.recorder.RemoveConnectionListener() +} diff --git a/client/ios/netbird/dns_list.go b/client/ios/netbird/dns_list.go new file mode 100644 index 00000000000..49e3b2f71aa --- /dev/null +++ b/client/ios/netbird/dns_list.go @@ -0,0 +1,26 @@ +package netbird + +import "fmt" + +// DNSList is a wrapper of []string +type DNSList struct { + items []string +} + +// Add new DNS address to the collection +func (array *DNSList) Add(s string) { + array.items = append(array.items, s) +} + +// Get return an element of the collection +func (array *DNSList) Get(i int) (string, error) { + if i >= len(array.items) || i < 0 { + return "", fmt.Errorf("out of range") + } + return array.items[i], nil +} + +// Size return with the size of the collection +func (array *DNSList) Size() int { + return len(array.items) +} diff --git a/client/ios/netbird/dns_list_test.go b/client/ios/netbird/dns_list_test.go new file mode 100644 index 00000000000..d88373dd882 --- /dev/null +++ b/client/ios/netbird/dns_list_test.go @@ -0,0 +1,24 @@ +package netbird + +import "testing" + +func TestDNSList_Get(t *testing.T) { + l := DNSList{ + items: make([]string, 1), + } + + _, err := l.Get(0) + if err != nil { + t.Errorf("invalid error: %s", err) + } + + _, err = l.Get(-1) + if err == nil { + t.Errorf("expected error but got nil") + } + + _, err = l.Get(1) + if err == nil { + t.Errorf("expected error but got nil") + } +} diff --git a/client/ios/netbird/gomobile.go b/client/ios/netbird/gomobile.go new file mode 100644 index 00000000000..76b4f7e358f --- /dev/null +++ b/client/ios/netbird/gomobile.go @@ -0,0 +1,5 @@ +package netbird + +import _ "golang.org/x/mobile/bind" + +// to keep our CI/CD that checks go.mod and go.sum files happy, we need to import the package above diff --git a/client/ios/netbird/login.go b/client/ios/netbird/login.go new file mode 100644 index 00000000000..da893ba5e23 --- /dev/null +++ b/client/ios/netbird/login.go @@ -0,0 +1,222 @@ +package netbird + +import ( + "context" + "fmt" + "time" + + "github.com/cenkalti/backoff/v4" + log "github.com/sirupsen/logrus" + "google.golang.org/grpc/codes" + gstatus "google.golang.org/grpc/status" + + "github.com/netbirdio/netbird/client/cmd" + "github.com/netbirdio/netbird/client/internal" + "github.com/netbirdio/netbird/client/internal/auth" + "github.com/netbirdio/netbird/client/system" +) + +// SSOListener is async listener for mobile framework +type SSOListener interface { + OnSuccess(bool) + OnError(error) +} + +// ErrListener is async listener for mobile framework +type ErrListener interface { + OnSuccess() + OnError(error) +} + +// URLOpener it is a callback interface. The Open function will be triggered if +// the backend want to show an url for the user +type URLOpener interface { + Open(string) +} + +// Auth can register or login new client +type Auth struct { + ctx context.Context + config *internal.Config + cfgPath string +} + +// NewAuth instantiate Auth struct and validate the management URL +func NewAuth(cfgPath string, mgmURL string) (*Auth, error) { + inputCfg := internal.ConfigInput{ + ManagementURL: mgmURL, + } + + cfg, err := internal.CreateInMemoryConfig(inputCfg) + if err != nil { + return nil, err + } + + return &Auth{ + ctx: context.Background(), + config: cfg, + cfgPath: cfgPath, + }, nil +} + +// NewAuthWithConfig instantiate Auth based on existing config +func NewAuthWithConfig(ctx context.Context, config *internal.Config) *Auth { + return &Auth{ + ctx: ctx, + config: config, + } +} + +// SaveConfigIfSSOSupported test the connectivity with the management server by retrieving the server device flow info. +// If it returns a flow info than save the configuration and return true. If it gets a codes.NotFound, it means that SSO +// is not supported and returns false without saving the configuration. For other errors return false. +func (a *Auth) SaveConfigIfSSOSupported(listener SSOListener) { + go func() { + sso, err := a.saveConfigIfSSOSupported() + if err != nil { + listener.OnError(err) + } else { + listener.OnSuccess(sso) + } + }() +} + +func (a *Auth) saveConfigIfSSOSupported() (bool, error) { + supportsSSO := true + err := a.withBackOff(a.ctx, func() (err error) { + _, err = internal.GetDeviceAuthorizationFlowInfo(a.ctx, a.config.PrivateKey, a.config.ManagementURL) + if s, ok := gstatus.FromError(err); ok && s.Code() == codes.NotFound { + _, err = internal.GetPKCEAuthorizationFlowInfo(a.ctx, a.config.PrivateKey, a.config.ManagementURL) + if s, ok := gstatus.FromError(err); ok && s.Code() == codes.NotFound { + supportsSSO = false + err = nil + } + + return err + } + + return err + }) + + if !supportsSSO { + return false, nil + } + + if err != nil { + return false, fmt.Errorf("backoff cycle failed: %v", err) + } + + err = internal.WriteOutConfig(a.cfgPath, a.config) + return true, err +} + +// LoginWithSetupKeyAndSaveConfig test the connectivity with the management server with the setup key. +func (a *Auth) LoginWithSetupKeyAndSaveConfig(resultListener ErrListener, setupKey string, deviceName string) { + go func() { + err := a.loginWithSetupKeyAndSaveConfig(setupKey, deviceName) + if err != nil { + resultListener.OnError(err) + } else { + resultListener.OnSuccess() + } + }() +} + +func (a *Auth) loginWithSetupKeyAndSaveConfig(setupKey string, deviceName string) error { + //nolint + ctxWithValues := context.WithValue(a.ctx, system.DeviceNameCtxKey, deviceName) + + err := a.withBackOff(a.ctx, func() error { + backoffErr := internal.Login(ctxWithValues, a.config, setupKey, "") + if s, ok := gstatus.FromError(backoffErr); ok && (s.Code() == codes.PermissionDenied) { + // we got an answer from management, exit backoff earlier + return backoff.Permanent(backoffErr) + } + return backoffErr + }) + if err != nil { + return fmt.Errorf("backoff cycle failed: %v", err) + } + + return internal.WriteOutConfig(a.cfgPath, a.config) +} + +// Login try register the client on the server +func (a *Auth) Login(resultListener ErrListener, urlOpener URLOpener) { + go func() { + err := a.login(urlOpener) + if err != nil { + resultListener.OnError(err) + } else { + resultListener.OnSuccess() + } + }() +} + +func (a *Auth) login(urlOpener URLOpener) error { + var needsLogin bool + + // check if we need to generate JWT token + err := a.withBackOff(a.ctx, func() (err error) { + needsLogin, err = internal.IsLoginRequired(a.ctx, a.config.PrivateKey, a.config.ManagementURL, a.config.SSHKey) + return + }) + if err != nil { + return fmt.Errorf("backoff cycle failed: %v", err) + } + + jwtToken := "" + if needsLogin { + tokenInfo, err := a.foregroundGetTokenInfo(urlOpener) + if err != nil { + return fmt.Errorf("interactive sso login failed: %v", err) + } + jwtToken = tokenInfo.GetTokenToUse() + } + + err = a.withBackOff(a.ctx, func() error { + err := internal.Login(a.ctx, a.config, "", jwtToken) + if s, ok := gstatus.FromError(err); ok && (s.Code() == codes.InvalidArgument || s.Code() == codes.PermissionDenied) { + return nil + } + return err + }) + if err != nil { + return fmt.Errorf("backoff cycle failed: %v", err) + } + + return nil +} + +func (a *Auth) foregroundGetTokenInfo(urlOpener URLOpener) (*auth.TokenInfo, error) { + oAuthFlow, err := auth.NewOAuthFlow(a.ctx, a.config) + if err != nil { + return nil, err + } + + flowInfo, err := oAuthFlow.RequestAuthInfo(context.TODO()) + if err != nil { + return nil, fmt.Errorf("getting a request OAuth flow info failed: %v", err) + } + + go urlOpener.Open(flowInfo.VerificationURIComplete) + + waitTimeout := time.Duration(flowInfo.ExpiresIn) + waitCTX, cancel := context.WithTimeout(a.ctx, waitTimeout*time.Second) + defer cancel() + tokenInfo, err := oAuthFlow.WaitToken(waitCTX, flowInfo) + if err != nil { + return nil, fmt.Errorf("waiting for browser login failed: %v", err) + } + + return &tokenInfo, nil +} + +func (a *Auth) withBackOff(ctx context.Context, bf func() error) error { + return backoff.RetryNotify( + bf, + backoff.WithContext(cmd.CLIBackOffSettings, ctx), + func(err error, duration time.Duration) { + log.Warnf("retrying Login to the Management service in %v due to error %v", duration, err) + }) +} diff --git a/client/ios/netbird/peer_notifier.go b/client/ios/netbird/peer_notifier.go new file mode 100644 index 00000000000..a23af2a2923 --- /dev/null +++ b/client/ios/netbird/peer_notifier.go @@ -0,0 +1,36 @@ +package netbird + +// PeerInfo describe information about the peers. It designed for the UI usage +type PeerInfo struct { + IP string + FQDN string + ConnStatus string // Todo replace to enum +} + +// PeerInfoCollection made for Java layer to get non default types as collection +type PeerInfoCollection interface { + Add(s string) PeerInfoCollection + Get(i int) string + Size() int +} + +// PeerInfoArray is the implementation of the PeerInfoCollection +type PeerInfoArray struct { + items []PeerInfo +} + +// Add new PeerInfo to the collection +func (array PeerInfoArray) Add(s PeerInfo) PeerInfoArray { + array.items = append(array.items, s) + return array +} + +// Get return an element of the collection +func (array PeerInfoArray) Get(i int) *PeerInfo { + return &array.items[i] +} + +// Size return with the size of the collection +func (array PeerInfoArray) Size() int { + return len(array.items) +} diff --git a/client/ios/netbird/preferences.go b/client/ios/netbird/preferences.go new file mode 100644 index 00000000000..d565029e7f9 --- /dev/null +++ b/client/ios/netbird/preferences.go @@ -0,0 +1,78 @@ +package netbird + +import ( + "github.com/netbirdio/netbird/client/internal" +) + +// Preferences export a subset of the internal config for gomobile +type Preferences struct { + configInput internal.ConfigInput +} + +// NewPreferences create new Preferences instance +func NewPreferences(configPath string) *Preferences { + ci := internal.ConfigInput{ + ConfigPath: configPath, + } + return &Preferences{ci} +} + +// GetManagementURL read url from config file +func (p *Preferences) GetManagementURL() (string, error) { + if p.configInput.ManagementURL != "" { + return p.configInput.ManagementURL, nil + } + + cfg, err := internal.ReadConfig(p.configInput.ConfigPath) + if err != nil { + return "", err + } + return cfg.ManagementURL.String(), err +} + +// SetManagementURL store the given url and wait for commit +func (p *Preferences) SetManagementURL(url string) { + p.configInput.ManagementURL = url +} + +// GetAdminURL read url from config file +func (p *Preferences) GetAdminURL() (string, error) { + if p.configInput.AdminURL != "" { + return p.configInput.AdminURL, nil + } + + cfg, err := internal.ReadConfig(p.configInput.ConfigPath) + if err != nil { + return "", err + } + return cfg.AdminURL.String(), err +} + +// SetAdminURL store the given url and wait for commit +func (p *Preferences) SetAdminURL(url string) { + p.configInput.AdminURL = url +} + +// GetPreSharedKey read preshared key from config file +func (p *Preferences) GetPreSharedKey() (string, error) { + if p.configInput.PreSharedKey != nil { + return *p.configInput.PreSharedKey, nil + } + + cfg, err := internal.ReadConfig(p.configInput.ConfigPath) + if err != nil { + return "", err + } + return cfg.PreSharedKey, err +} + +// SetPreSharedKey store the given key and wait for commit +func (p *Preferences) SetPreSharedKey(key string) { + p.configInput.PreSharedKey = &key +} + +// Commit write out the changes into config file +func (p *Preferences) Commit() error { + _, err := internal.UpdateOrCreateConfig(p.configInput) + return err +} diff --git a/client/ios/netbird/preferences_test.go b/client/ios/netbird/preferences_test.go new file mode 100644 index 00000000000..ee7e1c0292b --- /dev/null +++ b/client/ios/netbird/preferences_test.go @@ -0,0 +1,120 @@ +package netbird + +import ( + "path/filepath" + "testing" + + "github.com/netbirdio/netbird/client/internal" +) + +func TestPreferences_DefaultValues(t *testing.T) { + cfgFile := filepath.Join(t.TempDir(), "netbird.json") + p := NewPreferences(cfgFile) + defaultVar, err := p.GetAdminURL() + if err != nil { + t.Fatalf("failed to read default value: %s", err) + } + + if defaultVar != internal.DefaultAdminURL { + t.Errorf("invalid default admin url: %s", defaultVar) + } + + defaultVar, err = p.GetManagementURL() + if err != nil { + t.Fatalf("failed to read default management URL: %s", err) + } + + if defaultVar != internal.DefaultManagementURL { + t.Errorf("invalid default management url: %s", defaultVar) + } + + var preSharedKey string + preSharedKey, err = p.GetPreSharedKey() + if err != nil { + t.Fatalf("failed to read default preshared key: %s", err) + } + + if preSharedKey != "" { + t.Errorf("invalid preshared key: %s", preSharedKey) + } +} + +func TestPreferences_ReadUncommitedValues(t *testing.T) { + exampleString := "exampleString" + cfgFile := filepath.Join(t.TempDir(), "netbird.json") + p := NewPreferences(cfgFile) + + p.SetAdminURL(exampleString) + resp, err := p.GetAdminURL() + if err != nil { + t.Fatalf("failed to read admin url: %s", err) + } + + if resp != exampleString { + t.Errorf("unexpected admin url: %s", resp) + } + + p.SetManagementURL(exampleString) + resp, err = p.GetManagementURL() + if err != nil { + t.Fatalf("failed to read managmenet url: %s", err) + } + + if resp != exampleString { + t.Errorf("unexpected managemenet url: %s", resp) + } + + p.SetPreSharedKey(exampleString) + resp, err = p.GetPreSharedKey() + if err != nil { + t.Fatalf("failed to read preshared key: %s", err) + } + + if resp != exampleString { + t.Errorf("unexpected preshared key: %s", resp) + } +} + +func TestPreferences_Commit(t *testing.T) { + exampleURL := "https://myurl.com:443" + examplePresharedKey := "topsecret" + cfgFile := filepath.Join(t.TempDir(), "netbird.json") + p := NewPreferences(cfgFile) + + p.SetAdminURL(exampleURL) + p.SetManagementURL(exampleURL) + p.SetPreSharedKey(examplePresharedKey) + + err := p.Commit() + if err != nil { + t.Fatalf("failed to save changes: %s", err) + } + + p = NewPreferences(cfgFile) + resp, err := p.GetAdminURL() + if err != nil { + t.Fatalf("failed to read admin url: %s", err) + } + + if resp != exampleURL { + t.Errorf("unexpected admin url: %s", resp) + } + + resp, err = p.GetManagementURL() + if err != nil { + t.Fatalf("failed to read managmenet url: %s", err) + } + + if resp != exampleURL { + t.Errorf("unexpected managemenet url: %s", resp) + } + + resp, err = p.GetPreSharedKey() + if err != nil { + t.Fatalf("failed to read preshared key: %s", err) + } + + if resp != examplePresharedKey { + t.Errorf("unexpected preshared key: %s", resp) + } +} diff --git a/client/system/info_darwin.go b/client/system/info_darwin.go index e153539bb20..71fe03f091e 100644 --- a/client/system/info_darwin.go +++ b/client/system/info_darwin.go @@ -1,3 +1,6 @@ +//go:build !ios +// +build !ios + package system import ( diff --git a/client/system/info_ios.go b/client/system/info_ios.go new file mode 100644 index 00000000000..967c69a83b3 --- /dev/null +++ b/client/system/info_ios.go @@ -0,0 +1,30 @@ +//go:build ios +// +build ios + +package system + +import ( + "context" + "os" + "runtime" + + "github.com/netbirdio/netbird/version" +) + +// GetInfo retrieves and parses the system information +func GetInfo(ctx context.Context) *Info { + + // Convert fixed-size byte arrays to Go strings + sysName := "iOS" + machine := "machine" + release := "release" + swversion := "swversion" + + gio := &Info{Kernel: sysName, OSVersion: swversion, Core: release, Platform: machine, OS: sysName, GoOS: runtime.GOOS, CPUs: runtime.NumCPU()} + systemHostname, _ := os.Hostname() + gio.Hostname = extractDeviceName(ctx, systemHostname) + gio.WiretrusteeVersion = version.NetbirdVersion() + gio.UIVersion = extractUserAgent(ctx) + + return gio +} diff --git a/iface/iface_android.go b/iface/iface_android.go index 208eff7a8ee..6afa2d58034 100644 --- a/iface/iface_android.go +++ b/iface/iface_android.go @@ -28,14 +28,20 @@ func NewWGIFace(ifaceName string, address string, mtu int, tunAdapter TunAdapter return wgIFace, nil } -// CreateOnMobile creates a new Wireguard interface, sets a given IP and brings it up. +// CreateOnAndroid creates a new Wireguard interface, sets a given IP and brings it up. // Will reuse an existing one. -func (w *WGIface) CreateOnMobile(mIFaceArgs MobileIFaceArguments) error { +func (w *WGIface) CreateOnAndroid(mIFaceArgs MobileIFaceArguments) error { w.mu.Lock() defer w.mu.Unlock() return w.tun.Create(mIFaceArgs) } +// CreateOniOS creates a new Wireguard interface, sets a given IP and brings it up. +// Will reuse an existing one. +func (w *WGIface) CreateOniOS(tunFd int32) error { + return fmt.Errorf("this function has not implemented on mobile") +} + // Create this function make sense on mobile only func (w *WGIface) Create() error { return fmt.Errorf("this function has not implemented on mobile") diff --git a/iface/iface_ios.go b/iface/iface_ios.go new file mode 100644 index 00000000000..62432f7ed3b --- /dev/null +++ b/iface/iface_ios.go @@ -0,0 +1,51 @@ +//go:build ios +// +build ios + +package iface + +import ( + "fmt" + "sync" + + "github.com/pion/transport/v2" +) + +// NewWGIFace Creates a new WireGuard interface instance +func NewWGIFace(ifaceName string, address string, mtu int, tunAdapter TunAdapter, transportNet transport.Net) (*WGIface, error) { + wgIFace := &WGIface{ + mu: sync.Mutex{}, + } + + wgAddress, err := parseWGAddress(address) + if err != nil { + return wgIFace, err + } + + tun := newTunDevice(wgAddress, mtu, tunAdapter, transportNet) + wgIFace.tun = tun + + wgIFace.configurer = newWGConfigurer(tun.name) + + wgIFace.userspaceBind = !WireGuardModuleIsLoaded() + + return wgIFace, nil +} + +// CreateOniOS creates a new Wireguard interface, sets a given IP and brings it up. +// Will reuse an existing one. +func (w *WGIface) CreateOniOS(tunFd int32) error { + w.mu.Lock() + defer w.mu.Unlock() + return w.tun.Create(tunFd) +} + +// CreateOnAndroid creates a new Wireguard interface, sets a given IP and brings it up. +// Will reuse an existing one. +func (w *WGIface) CreateOnAndroid(mIFaceArgs MobileIFaceArguments) error { + return fmt.Errorf("this function has not implemented on mobile") +} + +// Create this function make sense on mobile only +func (w *WGIface) Create() error { + return fmt.Errorf("this function has not implemented on mobile") +} diff --git a/iface/iface_nonandroid.go b/iface/iface_nonandroid.go index da4ef13fd59..80a9ab769ce 100644 --- a/iface/iface_nonandroid.go +++ b/iface/iface_nonandroid.go @@ -1,4 +1,5 @@ -//go:build !android +//go:build !android && !ios +// +build !android,!ios package iface @@ -27,8 +28,13 @@ func NewWGIFace(iFaceName string, address string, mtu int, tunAdapter TunAdapter return wgIFace, nil } -// CreateOnMobile this function make sense on mobile only -func (w *WGIface) CreateOnMobile(mIFaceArgs MobileIFaceArguments) error { +// CreateOnAndroid this function make sense on mobile only +func (w *WGIface) CreateOnAndroid(mIFaceArgs MobileIFaceArguments) error { + return fmt.Errorf("this function has not implemented on non mobile") +} + +// CreateOniOS this function make sense on mobile only +func (w *WGIface) CreateOniOS(tunFd int32) error { return fmt.Errorf("this function has not implemented on non mobile") } diff --git a/iface/tun_android.go b/iface/tun_android.go index d45f05282f8..6f13296bd9a 100644 --- a/iface/tun_android.go +++ b/iface/tun_android.go @@ -1,3 +1,6 @@ +//go:build android +// +build android + package iface import ( @@ -55,7 +58,7 @@ func (t *tunDevice) Create(mIFaceArgs MobileIFaceArguments) error { t.device = device.NewDevice(t.wrapper, t.iceBind, device.NewLogger(device.LogLevelSilent, "[wiretrustee] ")) // without this property mobile devices can discover remote endpoints if the configured one was wrong. // this helps with support for the older NetBird clients that had a hardcoded direct mode - //t.device.DisableSomeRoamingForBrokenMobileSemantics() + // t.device.DisableSomeRoamingForBrokenMobileSemantics() err = t.device.Up() if err != nil { diff --git a/iface/tun_darwin.go b/iface/tun_darwin.go index 4cf3712bd17..7735479b63f 100644 --- a/iface/tun_darwin.go +++ b/iface/tun_darwin.go @@ -1,3 +1,6 @@ +//go:build !ios +// +build !ios + package iface import ( diff --git a/iface/tun_ios.go b/iface/tun_ios.go new file mode 100644 index 00000000000..eb39bf7871f --- /dev/null +++ b/iface/tun_ios.go @@ -0,0 +1,105 @@ +//go:build ios +// +build ios + +package iface + +import ( + "os" + "strings" + + "github.com/pion/transport/v2" + log "github.com/sirupsen/logrus" + "golang.org/x/sys/unix" + "golang.zx2c4.com/wireguard/device" + "golang.zx2c4.com/wireguard/tun" + + "github.com/netbirdio/netbird/iface/bind" +) + +type tunDevice struct { + address WGAddress + mtu int + tunAdapter TunAdapter + iceBind *bind.ICEBind + + fd int + name string + device *device.Device + wrapper *DeviceWrapper +} + +func newTunDevice(address WGAddress, mtu int, tunAdapter TunAdapter, transportNet transport.Net) *tunDevice { + return &tunDevice{ + address: address, + mtu: mtu, + tunAdapter: tunAdapter, + iceBind: bind.NewICEBind(transportNet), + } +} + +func (t *tunDevice) Create(tunFd int32) error { + log.Info("create tun interface") + + dupTunFd, err := unix.Dup(int(tunFd)) + if err != nil { + log.Errorf("Unable to dup tun fd: %v", err) + return err + } + + err = unix.SetNonblock(dupTunFd, true) + if err != nil { + log.Errorf("Unable to set tun fd as non blocking: %v", err) + unix.Close(dupTunFd) + return err + } + tun, err := tun.CreateTUNFromFile(os.NewFile(uintptr(dupTunFd), "/dev/tun"), 0) + if err != nil { + log.Errorf("Unable to create new tun device from fd: %v", err) + unix.Close(dupTunFd) + return err + } + + t.wrapper = newDeviceWrapper(tun) + log.Debug("Attaching to interface") + t.device = device.NewDevice(t.wrapper, t.iceBind, device.NewLogger(device.LogLevelSilent, "[wiretrustee] ")) + // without this property mobile devices can discover remote endpoints if the configured one was wrong. + // this helps with support for the older NetBird clients that had a hardcoded direct mode + // t.device.DisableSomeRoamingForBrokenMobileSemantics() + + err = t.device.Up() + if err != nil { + t.device.Close() + return err + } + log.Debugf("device is ready to use: %s", t.name) + return nil +} + +func (t *tunDevice) Device() *device.Device { + return t.device +} + +func (t *tunDevice) DeviceName() string { + return t.name +} + +func (t *tunDevice) WgAddress() WGAddress { + return t.address +} + +func (t *tunDevice) UpdateAddr(addr WGAddress) error { + // todo implement + return nil +} + +func (t *tunDevice) Close() (err error) { + if t.device != nil { + t.device.Close() + } + + return +} + +func (t *tunDevice) routesToString(routes []string) string { + return strings.Join(routes, ";") +} diff --git a/iface/tun_unix.go b/iface/tun_unix.go index f923362a464..627814fc737 100644 --- a/iface/tun_unix.go +++ b/iface/tun_unix.go @@ -1,4 +1,4 @@ -//go:build (linux || darwin) && !android +//go:build (linux || darwin) && !android && !ios package iface From 67430544516ceeb137e66f250487e21e9c31aac3 Mon Sep 17 00:00:00 2001 From: Pascal Fischer Date: Thu, 17 Aug 2023 13:35:38 +0200 Subject: [PATCH 02/56] inject logger that does not compile --- client/ios/netbird/client.go | 1 + 1 file changed, 1 insertion(+) diff --git a/client/ios/netbird/client.go b/client/ios/netbird/client.go index 46ac734dfdf..3c899881305 100644 --- a/client/ios/netbird/client.go +++ b/client/ios/netbird/client.go @@ -105,6 +105,7 @@ func (c *Client) Run(fd int32, dns *DNSList, dnsReadyListener DnsReadyListener) return err } + c.logger.Info("Auth successful") // todo do not throw error in case of cancelled context ctx = internal.CtxInitState(ctx) c.onHostDnsFn = func([]string) {} From 8653c323674c83366f80cd3a18d9e9f0c1ea3253 Mon Sep 17 00:00:00 2001 From: Pascal Fischer Date: Thu, 21 Sep 2023 16:42:44 +0200 Subject: [PATCH 03/56] logger and first client --- client/ios/netbird/client.go | 11 ++++------- client/ios/netbird/logger.go | 31 +++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+), 7 deletions(-) create mode 100644 client/ios/netbird/logger.go diff --git a/client/ios/netbird/client.go b/client/ios/netbird/client.go index 3c899881305..18779312ce5 100644 --- a/client/ios/netbird/client.go +++ b/client/ios/netbird/client.go @@ -61,27 +61,24 @@ type Client struct { ctxCancelLock *sync.Mutex deviceName string routeListener routemanager.RouteListener - logger CustomLogger onHostDnsFn func([]string) } // NewClient instantiate a new Client -func NewClient(cfgFile, deviceName string, iFaceDiscover IFaceDiscover, routeListener RouteListener, logger CustomLogger) *Client { +func NewClient(cfgFile, deviceName string, iFaceDiscover IFaceDiscover, routeListener RouteListener) *Client { return &Client{ cfgFile: cfgFile, deviceName: deviceName, iFaceDiscover: iFaceDiscover, recorder: peer.NewRecorder(""), ctxCancelLock: &sync.Mutex{}, - logger: logger, routeListener: routeListener, } } // Run start the internal client. It is a blocker function -// func (c *Client) Run(fd int32, dns *DNSList, dnsReadyListener DnsReadyListener) error { func (c *Client) Run(fd int32, dns *DNSList, dnsReadyListener DnsReadyListener) error { - c.logger.Info("Starting NetBird client") + log.Infof("Starting NetBird client") cfg, err := internal.UpdateOrCreateConfig(internal.ConfigInput{ ConfigPath: c.cfgFile, }) @@ -100,12 +97,12 @@ func (c *Client) Run(fd int32, dns *DNSList, dnsReadyListener DnsReadyListener) auth := NewAuthWithConfig(ctx, cfg) // err = auth.login(urlOpener) - auth.loginWithSetupKeyAndSaveConfig("E9EEBA50-76A1-4C72-A939-C10655C1CC09", "iPhone") + auth.loginWithSetupKeyAndSaveConfig("C3803F45-435B-4333-96EB-50F9EC723355", "iPhone") if err != nil { return err } - c.logger.Info("Auth successful") + log.Infof("Auth successful") // todo do not throw error in case of cancelled context ctx = internal.CtxInitState(ctx) c.onHostDnsFn = func([]string) {} diff --git a/client/ios/netbird/logger.go b/client/ios/netbird/logger.go new file mode 100644 index 00000000000..96b75d7d302 --- /dev/null +++ b/client/ios/netbird/logger.go @@ -0,0 +1,31 @@ +package netbird + +import ( + "os" + + "github.com/netbirdio/netbird/util" +) + +var logFile *os.File + +// InitializeLog initializes the log file. +func InitializeLog(logLevel string, filePath string) error { + var err error + err = util.InitLog(logLevel, filePath) + return err +} + +// // CloseLog closes the log file. +// func CloseLog() { +// if logFile != nil { +// logFile.Close() +// } +// } +// +// // Log writes a message to the log file. +// func Log(message string) { +// if logFile != nil { +// ts := time.Now().Format(time.RFC3339) +// fmt.Fprintf(logFile, "%s: %s\n", ts, message) +// } +// } From e733cdcf335682cba73b44e1f1db58132783709e Mon Sep 17 00:00:00 2001 From: Pascal Fischer Date: Mon, 25 Sep 2023 13:02:56 +0200 Subject: [PATCH 04/56] first working connection --- iface/iface_ios.go | 2 +- iface/ipc_parser_android.go | 3 + iface/ipc_parser_ios.go | 63 ++++++++++++++++ iface/tun_ios.go | 2 +- iface/wg_configurer_ios.go | 117 ++++++++++++++++++++++++++++++ iface/wg_configurer_nonandroid.go | 4 +- 6 files changed, 187 insertions(+), 4 deletions(-) create mode 100644 iface/ipc_parser_ios.go create mode 100644 iface/wg_configurer_ios.go diff --git a/iface/iface_ios.go b/iface/iface_ios.go index 62432f7ed3b..901faec30a0 100644 --- a/iface/iface_ios.go +++ b/iface/iface_ios.go @@ -24,7 +24,7 @@ func NewWGIFace(ifaceName string, address string, mtu int, tunAdapter TunAdapter tun := newTunDevice(wgAddress, mtu, tunAdapter, transportNet) wgIFace.tun = tun - wgIFace.configurer = newWGConfigurer(tun.name) + wgIFace.configurer = newWGConfigurer(tun) wgIFace.userspaceBind = !WireGuardModuleIsLoaded() diff --git a/iface/ipc_parser_android.go b/iface/ipc_parser_android.go index e1dd66856b0..56e52d1a01e 100644 --- a/iface/ipc_parser_android.go +++ b/iface/ipc_parser_android.go @@ -1,3 +1,6 @@ +//go:build android +// +build android + package iface import ( diff --git a/iface/ipc_parser_ios.go b/iface/ipc_parser_ios.go new file mode 100644 index 00000000000..de5e50664c3 --- /dev/null +++ b/iface/ipc_parser_ios.go @@ -0,0 +1,63 @@ +//go:build ios +// +build ios + +package iface + +import ( + "encoding/hex" + "fmt" + "strings" + + "golang.zx2c4.com/wireguard/wgctrl/wgtypes" +) + +func toWgUserspaceString(wgCfg wgtypes.Config) string { + var sb strings.Builder + if wgCfg.PrivateKey != nil { + hexKey := hex.EncodeToString(wgCfg.PrivateKey[:]) + sb.WriteString(fmt.Sprintf("private_key=%s\n", hexKey)) + } + + if wgCfg.ListenPort != nil { + sb.WriteString(fmt.Sprintf("listen_port=%d\n", *wgCfg.ListenPort)) + } + + if wgCfg.ReplacePeers { + sb.WriteString("replace_peers=true\n") + } + + if wgCfg.FirewallMark != nil { + sb.WriteString(fmt.Sprintf("fwmark=%d\n", *wgCfg.FirewallMark)) + } + + for _, p := range wgCfg.Peers { + hexKey := hex.EncodeToString(p.PublicKey[:]) + sb.WriteString(fmt.Sprintf("public_key=%s\n", hexKey)) + + if p.PresharedKey != nil { + preSharedHexKey := hex.EncodeToString(p.PresharedKey[:]) + sb.WriteString(fmt.Sprintf("preshared_key=%s\n", preSharedHexKey)) + } + + if p.Remove { + sb.WriteString("remove=true") + } + + if p.ReplaceAllowedIPs { + sb.WriteString("replace_allowed_ips=true\n") + } + + for _, aip := range p.AllowedIPs { + sb.WriteString(fmt.Sprintf("allowed_ip=%s\n", aip.String())) + } + + if p.Endpoint != nil { + sb.WriteString(fmt.Sprintf("endpoint=%s\n", p.Endpoint.String())) + } + + if p.PersistentKeepaliveInterval != nil { + sb.WriteString(fmt.Sprintf("persistent_keepalive_interval=%d\n", int(p.PersistentKeepaliveInterval.Seconds()))) + } + } + return sb.String() +} diff --git a/iface/tun_ios.go b/iface/tun_ios.go index eb39bf7871f..4ea80c9a2d6 100644 --- a/iface/tun_ios.go +++ b/iface/tun_ios.go @@ -38,7 +38,7 @@ func newTunDevice(address WGAddress, mtu int, tunAdapter TunAdapter, transportNe } func (t *tunDevice) Create(tunFd int32) error { - log.Info("create tun interface") + log.Infof("create tun interface") dupTunFd, err := unix.Dup(int(tunFd)) if err != nil { diff --git a/iface/wg_configurer_ios.go b/iface/wg_configurer_ios.go new file mode 100644 index 00000000000..23240227894 --- /dev/null +++ b/iface/wg_configurer_ios.go @@ -0,0 +1,117 @@ +//go:build ios +// +build ios + +package iface + +import ( + "errors" + "net" + "time" + + log "github.com/sirupsen/logrus" + + "golang.zx2c4.com/wireguard/wgctrl/wgtypes" +) + +var ( + errFuncNotImplemented = errors.New("function not implemented") +) + +type wGConfigurer struct { + tunDevice *tunDevice +} + +func newWGConfigurer(tunDevice *tunDevice) wGConfigurer { + return wGConfigurer{ + tunDevice: tunDevice, + } +} + +func (c *wGConfigurer) configureInterface(privateKey string, port int) error { + log.Debugf("adding Wireguard private key") + key, err := wgtypes.ParseKey(privateKey) + if err != nil { + return err + } + fwmark := 0 + config := wgtypes.Config{ + PrivateKey: &key, + ReplacePeers: true, + FirewallMark: &fwmark, + ListenPort: &port, + } + + return c.tunDevice.Device().IpcSet(toWgUserspaceString(config)) +} + +func (c *wGConfigurer) updatePeer(peerKey string, allowedIps string, keepAlive time.Duration, endpoint *net.UDPAddr, preSharedKey *wgtypes.Key) error { + // parse allowed ips + _, ipNet, err := net.ParseCIDR(allowedIps) + if err != nil { + return err + } + + peerKeyParsed, err := wgtypes.ParseKey(peerKey) + if err != nil { + return err + } + peer := wgtypes.PeerConfig{ + PublicKey: peerKeyParsed, + ReplaceAllowedIPs: true, + AllowedIPs: []net.IPNet{*ipNet}, + PersistentKeepaliveInterval: &keepAlive, + PresharedKey: preSharedKey, + Endpoint: endpoint, + } + + config := wgtypes.Config{ + Peers: []wgtypes.PeerConfig{peer}, + } + + return c.tunDevice.Device().IpcSet(toWgUserspaceString(config)) +} + +func (c *wGConfigurer) removePeer(peerKey string) error { + peerKeyParsed, err := wgtypes.ParseKey(peerKey) + if err != nil { + return err + } + + peer := wgtypes.PeerConfig{ + PublicKey: peerKeyParsed, + Remove: true, + } + + config := wgtypes.Config{ + Peers: []wgtypes.PeerConfig{peer}, + } + return c.tunDevice.Device().IpcSet(toWgUserspaceString(config)) +} + +func (c *wGConfigurer) addAllowedIP(peerKey string, allowedIP string) error { + _, ipNet, err := net.ParseCIDR(allowedIP) + if err != nil { + return err + } + + peerKeyParsed, err := wgtypes.ParseKey(peerKey) + if err != nil { + return err + } + peer := wgtypes.PeerConfig{ + PublicKey: peerKeyParsed, + UpdateOnly: true, + ReplaceAllowedIPs: false, + AllowedIPs: []net.IPNet{*ipNet}, + } + + config := wgtypes.Config{ + Peers: []wgtypes.PeerConfig{peer}, + } + + return c.tunDevice.Device().IpcSet(toWgUserspaceString(config)) +} + +func (c *wGConfigurer) removeAllowedIP(peerKey string, allowedIP string) error { + return errFuncNotImplemented +} diff --git a/iface/wg_configurer_nonandroid.go b/iface/wg_configurer_nonandroid.go index 6749c0966ab..239dd94fe30 100644 --- a/iface/wg_configurer_nonandroid.go +++ b/iface/wg_configurer_nonandroid.go @@ -1,4 +1,4 @@ -//go:build !android +//go:build !android && !ios package iface @@ -44,7 +44,7 @@ func (c *wGConfigurer) configureInterface(privateKey string, port int) error { } func (c *wGConfigurer) updatePeer(peerKey string, allowedIps string, keepAlive time.Duration, endpoint *net.UDPAddr, preSharedKey *wgtypes.Key) error { - //parse allowed ips + // parse allowed ips _, ipNet, err := net.ParseCIDR(allowedIps) if err != nil { return err From 8b8e4bbc6a27c49b3bb8fc54da1f2e3d0b6c567b Mon Sep 17 00:00:00 2001 From: Pascal Fischer Date: Thu, 5 Oct 2023 20:15:44 +0200 Subject: [PATCH 05/56] support for routes and working connection --- client/internal/engine.go | 4 ++- client/internal/routemanager/firewall_ios.go | 31 +++++++++++++++++++ .../routemanager/firewall_nonlinux.go | 4 +-- client/internal/routemanager/manager.go | 7 +++-- client/internal/routemanager/notifier.go | 17 +++++++--- .../internal/routemanager/server_android.go | 2 ++ 6 files changed, 55 insertions(+), 10 deletions(-) create mode 100644 client/internal/routemanager/firewall_ios.go diff --git a/client/internal/engine.go b/client/internal/engine.go index cb820518175..6444e6d37b2 100644 --- a/client/internal/engine.go +++ b/client/internal/engine.go @@ -214,7 +214,7 @@ func (e *Engine) Start() error { } } - e.routeManager = routemanager.NewManager(e.ctx, e.config.WgPrivateKey.PublicKey().String(), e.wgInterface, e.statusRecorder, routes) + e.routeManager = routemanager.NewManager(e.ctx, e.config.WgPrivateKey.PublicKey().String(), e.wgInterface, e.statusRecorder, routes, wgAddr) e.routeManager.SetRouteChangeListener(e.mobileDep.RouteListener) switch runtime.GOOS { @@ -225,6 +225,8 @@ func (e *Engine) Start() error { }) case "ios": err = e.wgInterface.CreateOniOS(e.mobileDep.FileDescriptor) + log.Debugf("wireguardAddress: %s", wgAddr) + e.mobileDep.RouteListener.OnNewRouteSetting("", "100.127.93.142/16") default: err = e.wgInterface.Create() } diff --git a/client/internal/routemanager/firewall_ios.go b/client/internal/routemanager/firewall_ios.go new file mode 100644 index 00000000000..387f501f14f --- /dev/null +++ b/client/internal/routemanager/firewall_ios.go @@ -0,0 +1,31 @@ +//go:build ios + +package routemanager + +import ( + "context" +) + +// newFirewall returns a nil manager +func newFirewall(context.Context) (firewallManager, error) { + return iOSFirewallManager{}, nil +} + +type iOSFirewallManager struct { +} + +func (i iOSFirewallManager) RestoreOrCreateContainers() error { + return nil +} + +func (i iOSFirewallManager) InsertRoutingRules(pair routerPair) error { + return nil +} + +func (i iOSFirewallManager) RemoveRoutingRules(pair routerPair) error { + return nil +} + +func (i iOSFirewallManager) CleanRoutingRules() { + return +} diff --git a/client/internal/routemanager/firewall_nonlinux.go b/client/internal/routemanager/firewall_nonlinux.go index ae0627048fc..2d3eb29a72c 100644 --- a/client/internal/routemanager/firewall_nonlinux.go +++ b/client/internal/routemanager/firewall_nonlinux.go @@ -1,5 +1,5 @@ -//go:build !linux -// +build !linux +//go:build !linux && !ios +// +build !linux,!ios package routemanager diff --git a/client/internal/routemanager/manager.go b/client/internal/routemanager/manager.go index b31fe632749..1be182d0acf 100644 --- a/client/internal/routemanager/manager.go +++ b/client/internal/routemanager/manager.go @@ -35,7 +35,7 @@ type DefaultManager struct { } // NewManager returns a new route manager -func NewManager(ctx context.Context, pubKey string, wgInterface *iface.WGIface, statusRecorder *peer.Status, initialRoutes []*route.Route) *DefaultManager { +func NewManager(ctx context.Context, pubKey string, wgInterface *iface.WGIface, statusRecorder *peer.Status, initialRoutes []*route.Route, wgAddr string) *DefaultManager { srvRouter, err := newServerRouter(ctx, wgInterface) if err != nil { log.Errorf("server router is not supported: %s", err) @@ -50,10 +50,11 @@ func NewManager(ctx context.Context, pubKey string, wgInterface *iface.WGIface, statusRecorder: statusRecorder, wgInterface: wgInterface, pubKey: pubKey, - notifier: newNotifier(), + notifier: newNotifier(wgAddr), } - if runtime.GOOS == "android" { + log.Debug("initializing route manager") + if runtime.GOOS == "android" || runtime.GOOS == "ios" { cr := dm.clientRoutes(initialRoutes) dm.notifier.setInitialClientRoutes(cr) } diff --git a/client/internal/routemanager/notifier.go b/client/internal/routemanager/notifier.go index e3781116655..aa2be7606a5 100644 --- a/client/internal/routemanager/notifier.go +++ b/client/internal/routemanager/notifier.go @@ -2,18 +2,23 @@ package routemanager import ( "sort" + "strings" "sync" + log "github.com/sirupsen/logrus" + "github.com/netbirdio/netbird/route" ) // RouteListener is a callback interface for mobile system type RouteListener interface { // OnNewRouteSetting invoke when new route setting has been arrived - OnNewRouteSetting() + OnNewRouteSetting(string, string) } type notifier struct { + // ownIPAddr is the ip address of the netbird interface including the netmask + ownIPAddr string initialRouteRangers []string routeRangers []string @@ -21,8 +26,11 @@ type notifier struct { routeListenerMux sync.Mutex } -func newNotifier() *notifier { - return ¬ifier{} +func newNotifier(ip string) *notifier { + log.Debugf("creating notifier with own ip: %s", ip) + return ¬ifier{ + ownIPAddr: ip, + } } func (n *notifier) setListener(listener RouteListener) { @@ -69,7 +77,8 @@ func (n *notifier) notify() { } go func(l RouteListener) { - l.OnNewRouteSetting() + log.Debugf("notifying route listener with route ranges: %s and own ip: %s", strings.Join(n.routeRangers, ","), n.ownIPAddr) + l.OnNewRouteSetting(strings.Join(n.routeRangers, ","), n.ownIPAddr) }(n.routeListener) } diff --git a/client/internal/routemanager/server_android.go b/client/internal/routemanager/server_android.go index d130acc0081..e00fb5f704d 100644 --- a/client/internal/routemanager/server_android.go +++ b/client/internal/routemanager/server_android.go @@ -1,3 +1,5 @@ +//go:build android + package routemanager import ( From ec8eb76b42f7719790af50750f94e9ce93331c18 Mon Sep 17 00:00:00 2001 From: Pascal Fischer Date: Fri, 6 Oct 2023 16:32:30 +0200 Subject: [PATCH 06/56] small refactor for better code quality in swift --- client/internal/engine.go | 8 +++++--- client/internal/routemanager/manager.go | 4 ++-- client/internal/routemanager/notifier.go | 16 ++++++---------- 3 files changed, 13 insertions(+), 15 deletions(-) diff --git a/client/internal/engine.go b/client/internal/engine.go index 6444e6d37b2..0868eece1a7 100644 --- a/client/internal/engine.go +++ b/client/internal/engine.go @@ -214,7 +214,9 @@ func (e *Engine) Start() error { } } - e.routeManager = routemanager.NewManager(e.ctx, e.config.WgPrivateKey.PublicKey().String(), e.wgInterface, e.statusRecorder, routes, wgAddr) + log.Debugf("Initial routes contain %d routes", len(routes)) + e.routeManager = routemanager.NewManager(e.ctx, e.config.WgPrivateKey.PublicKey().String(), e.wgInterface, e.statusRecorder, routes) + e.mobileDep.RouteListener.SetInterfaceIP(wgAddr) e.routeManager.SetRouteChangeListener(e.mobileDep.RouteListener) switch runtime.GOOS { @@ -225,8 +227,8 @@ func (e *Engine) Start() error { }) case "ios": err = e.wgInterface.CreateOniOS(e.mobileDep.FileDescriptor) - log.Debugf("wireguardAddress: %s", wgAddr) - e.mobileDep.RouteListener.OnNewRouteSetting("", "100.127.93.142/16") + log.Debugf("sending initial route range %s to iOS", strings.Join(e.routeManager.InitialRouteRange(), ",")) + e.mobileDep.RouteListener.OnNewRouteSetting(strings.Join(e.routeManager.InitialRouteRange(), ",")) default: err = e.wgInterface.Create() } diff --git a/client/internal/routemanager/manager.go b/client/internal/routemanager/manager.go index 1be182d0acf..2f8482dbf1d 100644 --- a/client/internal/routemanager/manager.go +++ b/client/internal/routemanager/manager.go @@ -35,7 +35,7 @@ type DefaultManager struct { } // NewManager returns a new route manager -func NewManager(ctx context.Context, pubKey string, wgInterface *iface.WGIface, statusRecorder *peer.Status, initialRoutes []*route.Route, wgAddr string) *DefaultManager { +func NewManager(ctx context.Context, pubKey string, wgInterface *iface.WGIface, statusRecorder *peer.Status, initialRoutes []*route.Route) *DefaultManager { srvRouter, err := newServerRouter(ctx, wgInterface) if err != nil { log.Errorf("server router is not supported: %s", err) @@ -50,7 +50,7 @@ func NewManager(ctx context.Context, pubKey string, wgInterface *iface.WGIface, statusRecorder: statusRecorder, wgInterface: wgInterface, pubKey: pubKey, - notifier: newNotifier(wgAddr), + notifier: newNotifier(), } log.Debug("initializing route manager") diff --git a/client/internal/routemanager/notifier.go b/client/internal/routemanager/notifier.go index aa2be7606a5..7da4f920b2d 100644 --- a/client/internal/routemanager/notifier.go +++ b/client/internal/routemanager/notifier.go @@ -13,12 +13,11 @@ import ( // RouteListener is a callback interface for mobile system type RouteListener interface { // OnNewRouteSetting invoke when new route setting has been arrived - OnNewRouteSetting(string, string) + OnNewRouteSetting(string) + SetInterfaceIP(string) } type notifier struct { - // ownIPAddr is the ip address of the netbird interface including the netmask - ownIPAddr string initialRouteRangers []string routeRangers []string @@ -26,11 +25,8 @@ type notifier struct { routeListenerMux sync.Mutex } -func newNotifier(ip string) *notifier { - log.Debugf("creating notifier with own ip: %s", ip) - return ¬ifier{ - ownIPAddr: ip, - } +func newNotifier() *notifier { + return ¬ifier{} } func (n *notifier) setListener(listener RouteListener) { @@ -77,8 +73,8 @@ func (n *notifier) notify() { } go func(l RouteListener) { - log.Debugf("notifying route listener with route ranges: %s and own ip: %s", strings.Join(n.routeRangers, ","), n.ownIPAddr) - l.OnNewRouteSetting(strings.Join(n.routeRangers, ","), n.ownIPAddr) + log.Debugf("notifying route listener with route ranges: %s", strings.Join(n.routeRangers, ",")) + l.OnNewRouteSetting(strings.Join(n.routeRangers, ",")) }(n.routeListener) } From 7f958e93384e59f72d3e1afc24f7c09b553dada6 Mon Sep 17 00:00:00 2001 From: Pascal Fischer Date: Mon, 9 Oct 2023 14:58:48 +0200 Subject: [PATCH 07/56] trying to add DNS --- client/internal/connect.go | 12 ++--- client/internal/dns/file_linux.go | 2 +- client/internal/dns/host.go | 14 +++--- client/internal/dns/host_android.go | 2 +- client/internal/dns/host_darwin.go | 4 +- client/internal/dns/host_ios.go | 25 +++++++++ client/internal/dns/host_windows.go | 2 +- client/internal/dns/network_manager_linux.go | 2 +- client/internal/dns/resolvconf_linux.go | 2 +- client/internal/dns/server.go | 18 +++++-- client/internal/dns/server_test.go | 4 +- client/internal/dns/systemd_linux.go | 2 +- client/internal/engine.go | 6 ++- client/internal/mobile_dependency.go | 1 + client/ios/netbird/client.go | 53 ++++++++++++-------- client/ios/netbird/login.go | 2 +- 16 files changed, 101 insertions(+), 50 deletions(-) create mode 100644 client/internal/dns/host_ios.go diff --git a/client/internal/connect.go b/client/internal/connect.go index aaf09a3381a..c5fdf42749d 100644 --- a/client/internal/connect.go +++ b/client/internal/connect.go @@ -42,15 +42,11 @@ func RunClientMobile(ctx context.Context, config *Config, statusRecorder *peer.S return runClient(ctx, config, statusRecorder, mobileDependency) } -func RunClientiOS(ctx context.Context, config *Config, statusRecorder *peer.Status, fileDescriptor int32, iFaceDiscover stdnet.ExternalIFaceDiscover, routeListener routemanager.RouteListener, dnsAddresses []string, dnsReadyListener dns.ReadyListener) error { - // func RunClientiOS(ctx context.Context, config *Config, statusRecorder *peer.Status, iFaceDiscover stdnet.ExternalIFaceDiscover, routeListener routemanager.RouteListener, dnsAddresses []string, dnsReadyListener dns.ReadyListener) error { +func RunClientiOS(ctx context.Context, config *Config, statusRecorder *peer.Status, fileDescriptor int32, routeListener routemanager.RouteListener, dnsManager dns.IosDnsManager) error { mobileDependency := MobileDependency{ - TunAdapter: nil, - FileDescriptor: fileDescriptor, - IFaceDiscover: iFaceDiscover, - RouteListener: routeListener, - HostDNSAddresses: dnsAddresses, - DnsReadyListener: dnsReadyListener, + FileDescriptor: fileDescriptor, + RouteListener: routeListener, + DnsManager: dnsManager, } return runClient(ctx, config, statusRecorder, mobileDependency) } diff --git a/client/internal/dns/file_linux.go b/client/internal/dns/file_linux.go index 0172e3413be..fb59ba63bec 100644 --- a/client/internal/dns/file_linux.go +++ b/client/internal/dns/file_linux.go @@ -39,7 +39,7 @@ func (f *fileConfigurator) supportCustomPort() bool { return false } -func (f *fileConfigurator) applyDNSConfig(config hostDNSConfig) error { +func (f *fileConfigurator) applyDNSConfig(config HostDNSConfig) error { backupFileExist := false _, err := os.Stat(fileDefaultResolvConfBackupLocation) if err == nil { diff --git a/client/internal/dns/host.go b/client/internal/dns/host.go index 743ececdcc5..16c6c032d09 100644 --- a/client/internal/dns/host.go +++ b/client/internal/dns/host.go @@ -8,12 +8,12 @@ import ( ) type hostManager interface { - applyDNSConfig(config hostDNSConfig) error + applyDNSConfig(config HostDNSConfig) error restoreHostDNS() error supportCustomPort() bool } -type hostDNSConfig struct { +type HostDNSConfig struct { domains []domainConfig routeAll bool serverIP string @@ -27,12 +27,12 @@ type domainConfig struct { } type mockHostConfigurator struct { - applyDNSConfigFunc func(config hostDNSConfig) error + applyDNSConfigFunc func(config HostDNSConfig) error restoreHostDNSFunc func() error supportCustomPortFunc func() bool } -func (m *mockHostConfigurator) applyDNSConfig(config hostDNSConfig) error { +func (m *mockHostConfigurator) applyDNSConfig(config HostDNSConfig) error { if m.applyDNSConfigFunc != nil { return m.applyDNSConfigFunc(config) } @@ -55,14 +55,14 @@ func (m *mockHostConfigurator) supportCustomPort() bool { func newNoopHostMocker() hostManager { return &mockHostConfigurator{ - applyDNSConfigFunc: func(config hostDNSConfig) error { return nil }, + applyDNSConfigFunc: func(config HostDNSConfig) error { return nil }, restoreHostDNSFunc: func() error { return nil }, supportCustomPortFunc: func() bool { return true }, } } -func dnsConfigToHostDNSConfig(dnsConfig nbdns.Config, ip string, port int) hostDNSConfig { - config := hostDNSConfig{ +func dnsConfigToHostDNSConfig(dnsConfig nbdns.Config, ip string, port int) HostDNSConfig { + config := HostDNSConfig{ routeAll: false, serverIP: ip, serverPort: port, diff --git a/client/internal/dns/host_android.go b/client/internal/dns/host_android.go index 4ab7b32d883..169cc7c4726 100644 --- a/client/internal/dns/host_android.go +++ b/client/internal/dns/host_android.go @@ -7,7 +7,7 @@ func newHostManager(wgInterface WGIface) (hostManager, error) { return &androidHostManager{}, nil } -func (a androidHostManager) applyDNSConfig(config hostDNSConfig) error { +func (a androidHostManager) applyDNSConfig(config HostDNSConfig) error { return nil } diff --git a/client/internal/dns/host_darwin.go b/client/internal/dns/host_darwin.go index f02c32c2280..c0a21361118 100644 --- a/client/internal/dns/host_darwin.go +++ b/client/internal/dns/host_darwin.go @@ -1,3 +1,5 @@ +//go:build !ios + package dns import ( @@ -42,7 +44,7 @@ func (s *systemConfigurator) supportCustomPort() bool { return true } -func (s *systemConfigurator) applyDNSConfig(config hostDNSConfig) error { +func (s *systemConfigurator) applyDNSConfig(config HostDNSConfig) error { var err error if config.routeAll { diff --git a/client/internal/dns/host_ios.go b/client/internal/dns/host_ios.go new file mode 100644 index 00000000000..3dd93fa0730 --- /dev/null +++ b/client/internal/dns/host_ios.go @@ -0,0 +1,25 @@ +package dns + +type iosHostManager struct { + dnsManager IosDnsManager + config HostDNSConfig +} + +func newHostManager(wgInterface WGIface, dnsManager IosDnsManager) (hostManager, error) { + return &iosHostManager{ + dnsManager: dnsManager, + }, nil +} + +func (a iosHostManager) applyDNSConfig(config HostDNSConfig) error { + a.dnsManager.applyDns("bla") + return nil +} + +func (a iosHostManager) restoreHostDNS() error { + return nil +} + +func (a iosHostManager) supportCustomPort() bool { + return false +} diff --git a/client/internal/dns/host_windows.go b/client/internal/dns/host_windows.go index cea806bd2e7..ffb35ef6b91 100644 --- a/client/internal/dns/host_windows.go +++ b/client/internal/dns/host_windows.go @@ -45,7 +45,7 @@ func (s *registryConfigurator) supportCustomPort() bool { return false } -func (r *registryConfigurator) applyDNSConfig(config hostDNSConfig) error { +func (r *registryConfigurator) applyDNSConfig(config HostDNSConfig) error { var err error if config.routeAll { err = r.addDNSSetupForAll(config.serverIP) diff --git a/client/internal/dns/network_manager_linux.go b/client/internal/dns/network_manager_linux.go index 0b7ae7d4c2e..805bd53900f 100644 --- a/client/internal/dns/network_manager_linux.go +++ b/client/internal/dns/network_manager_linux.go @@ -93,7 +93,7 @@ func (n *networkManagerDbusConfigurator) supportCustomPort() bool { return false } -func (n *networkManagerDbusConfigurator) applyDNSConfig(config hostDNSConfig) error { +func (n *networkManagerDbusConfigurator) applyDNSConfig(config HostDNSConfig) error { connSettings, configVersion, err := n.getAppliedConnectionSettings() if err != nil { return fmt.Errorf("got an error while retrieving the applied connection settings, error: %s", err) diff --git a/client/internal/dns/resolvconf_linux.go b/client/internal/dns/resolvconf_linux.go index b358d3bd5fe..17e4c019603 100644 --- a/client/internal/dns/resolvconf_linux.go +++ b/client/internal/dns/resolvconf_linux.go @@ -27,7 +27,7 @@ func (r *resolvconf) supportCustomPort() bool { return false } -func (r *resolvconf) applyDNSConfig(config hostDNSConfig) error { +func (r *resolvconf) applyDNSConfig(config HostDNSConfig) error { var err error if !config.routeAll { err = r.restoreHostDNS() diff --git a/client/internal/dns/server.go b/client/internal/dns/server.go index 31946c13ea0..389d882adfd 100644 --- a/client/internal/dns/server.go +++ b/client/internal/dns/server.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "net/netip" + "runtime" "sync" "github.com/miekg/dns" @@ -18,9 +19,14 @@ type ReadyListener interface { OnReady() } +// IosDnsManager is a dns manager interface for iosß +type IosDnsManager interface { + applyDns(string) +} + // Server is a dns server interface type Server interface { - Initialize() error + Initialize(manager IosDnsManager) error Stop() DnsIP() string UpdateDNSServer(serial uint64, update nbdns.Config) error @@ -41,7 +47,7 @@ type DefaultServer struct { hostManager hostManager updateSerial uint64 previousConfigHash uint64 - currentConfig hostDNSConfig + currentConfig HostDNSConfig // permanent related properties permanent bool @@ -108,7 +114,7 @@ func newDefaultServer(ctx context.Context, wgInterface WGIface, dnsService servi } // Initialize instantiate host manager and the dns service -func (s *DefaultServer) Initialize() (err error) { +func (s *DefaultServer) Initialize(manager IosDnsManager) (err error) { s.mux.Lock() defer s.mux.Unlock() @@ -123,7 +129,11 @@ func (s *DefaultServer) Initialize() (err error) { } } - s.hostManager, err = newHostManager(s.wgInterface) + if runtime.GOOS == "ios" { + s.hostManager, err = newHostManager(nil, manager) + } else { + s.hostManager, err = newHostManager(s.wgInterface, nil) + } return } diff --git a/client/internal/dns/server_test.go b/client/internal/dns/server_test.go index 119ac684c95..c23b3124902 100644 --- a/client/internal/dns/server_test.go +++ b/client/internal/dns/server_test.go @@ -527,7 +527,7 @@ func TestDNSServerUpstreamDeactivateCallback(t *testing.T) { registeredMap: make(registrationMap), }, hostManager: hostManager, - currentConfig: hostDNSConfig{ + currentConfig: HostDNSConfig{ domains: []domainConfig{ {false, "domain0", false}, {false, "domain1", false}, @@ -537,7 +537,7 @@ func TestDNSServerUpstreamDeactivateCallback(t *testing.T) { } var domainsUpdate string - hostManager.applyDNSConfigFunc = func(config hostDNSConfig) error { + hostManager.applyDNSConfigFunc = func(config HostDNSConfig) error { domains := []string{} for _, item := range config.domains { if item.disabled { diff --git a/client/internal/dns/systemd_linux.go b/client/internal/dns/systemd_linux.go index 0358b0251f2..354ade2e4f7 100644 --- a/client/internal/dns/systemd_linux.go +++ b/client/internal/dns/systemd_linux.go @@ -81,7 +81,7 @@ func (s *systemdDbusConfigurator) supportCustomPort() bool { return true } -func (s *systemdDbusConfigurator) applyDNSConfig(config hostDNSConfig) error { +func (s *systemdDbusConfigurator) applyDNSConfig(config HostDNSConfig) error { parsedIP, err := netip.ParseAddr(config.serverIP) if err != nil { return fmt.Errorf("unable to parse ip address, error: %s", err) diff --git a/client/internal/engine.go b/client/internal/engine.go index 0868eece1a7..585e9a5a50e 100644 --- a/client/internal/engine.go +++ b/client/internal/engine.go @@ -271,7 +271,11 @@ func (e *Engine) Start() error { e.acl = acl } - err = e.dnsServer.Initialize() + if runtime.GOOS == "ios" { + err = e.dnsServer.Initialize(e.mobileDep.DnsManager) + } else { + err = e.dnsServer.Initialize(nil) + } if err != nil { e.close() return err diff --git a/client/internal/mobile_dependency.go b/client/internal/mobile_dependency.go index 0b02a63ec53..fc01a9de314 100644 --- a/client/internal/mobile_dependency.go +++ b/client/internal/mobile_dependency.go @@ -14,5 +14,6 @@ type MobileDependency struct { RouteListener routemanager.RouteListener HostDNSAddresses []string DnsReadyListener dns.ReadyListener + DnsManager dns.IosDnsManager FileDescriptor int32 } diff --git a/client/ios/netbird/client.go b/client/ios/netbird/client.go index 18779312ce5..f21c658f170 100644 --- a/client/ios/netbird/client.go +++ b/client/ios/netbird/client.go @@ -10,10 +10,8 @@ import ( "github.com/netbirdio/netbird/client/internal/dns" "github.com/netbirdio/netbird/client/internal/peer" "github.com/netbirdio/netbird/client/internal/routemanager" - "github.com/netbirdio/netbird/client/internal/stdnet" "github.com/netbirdio/netbird/client/system" "github.com/netbirdio/netbird/formatter" - "github.com/netbirdio/netbird/iface" ) // ConnectionListener export internal Listener for mobile @@ -21,24 +19,14 @@ type ConnectionListener interface { peer.Listener } -// TunAdapter export internal TunAdapter for mobile -type TunAdapter interface { - iface.TunAdapter -} - -// IFaceDiscover export internal IFaceDiscover for mobile -type IFaceDiscover interface { - stdnet.ExternalIFaceDiscover -} - // RouteListener export internal RouteListener for mobile type RouteListener interface { routemanager.RouteListener } -// DnsReadyListener export internal dns ReadyListener for mobile -type DnsReadyListener interface { - dns.ReadyListener +// DnsManager export internal dns Manager for mobile +type DnsManager interface { + dns.IosDnsManager } // CustomLogger export internal CustomLogger for mobile @@ -55,29 +43,29 @@ func init() { // Client struct manage the life circle of background service type Client struct { cfgFile string - iFaceDiscover IFaceDiscover recorder *peer.Status ctxCancel context.CancelFunc ctxCancelLock *sync.Mutex deviceName string routeListener routemanager.RouteListener onHostDnsFn func([]string) + dnsManager dns.IosDnsManager } // NewClient instantiate a new Client -func NewClient(cfgFile, deviceName string, iFaceDiscover IFaceDiscover, routeListener RouteListener) *Client { +func NewClient(cfgFile, deviceName string, routeListener RouteListener, dnsManager DnsManager) *Client { return &Client{ cfgFile: cfgFile, deviceName: deviceName, - iFaceDiscover: iFaceDiscover, recorder: peer.NewRecorder(""), ctxCancelLock: &sync.Mutex{}, routeListener: routeListener, + dnsManager: dnsManager, } } // Run start the internal client. It is a blocker function -func (c *Client) Run(fd int32, dns *DNSList, dnsReadyListener DnsReadyListener) error { +func (c *Client) Run(fd int32) error { log.Infof("Starting NetBird client") cfg, err := internal.UpdateOrCreateConfig(internal.ConfigInput{ ConfigPath: c.cfgFile, @@ -106,7 +94,32 @@ func (c *Client) Run(fd int32, dns *DNSList, dnsReadyListener DnsReadyListener) // todo do not throw error in case of cancelled context ctx = internal.CtxInitState(ctx) c.onHostDnsFn = func([]string) {} - return internal.RunClientiOS(ctx, cfg, c.recorder, fd, c.iFaceDiscover, c.routeListener, dns.items, dnsReadyListener) + return internal.RunClientiOS(ctx, cfg, c.recorder, fd, c.routeListener, c.dnsManager) +} + +func (c *Client) Auth(urlOpener URLOpener) error { + cfg, err := internal.UpdateOrCreateConfig(internal.ConfigInput{ + ConfigPath: c.cfgFile, + }) + if err != nil { + return err + } + c.recorder.UpdateManagementAddress(cfg.ManagementURL.String()) + + var ctx context.Context + //nolint + ctxWithValues := context.WithValue(context.Background(), system.DeviceNameCtxKey, c.deviceName) + c.ctxCancelLock.Lock() + ctx, c.ctxCancel = context.WithCancel(ctxWithValues) + defer c.ctxCancel() + c.ctxCancelLock.Unlock() + + auth := NewAuthWithConfig(ctx, cfg) + err = auth.login(urlOpener) + if err != nil { + return err + } + } // Stop the internal client and free the resources diff --git a/client/ios/netbird/login.go b/client/ios/netbird/login.go index da893ba5e23..3aaa24af2dc 100644 --- a/client/ios/netbird/login.go +++ b/client/ios/netbird/login.go @@ -189,7 +189,7 @@ func (a *Auth) login(urlOpener URLOpener) error { } func (a *Auth) foregroundGetTokenInfo(urlOpener URLOpener) (*auth.TokenInfo, error) { - oAuthFlow, err := auth.NewOAuthFlow(a.ctx, a.config) + oAuthFlow, err := auth.NewOAuthFlow(a.ctx, a.config, false) if err != nil { return nil, err } From c4c59ed3a75807837e0ddce61fde6af0ad196cd9 Mon Sep 17 00:00:00 2001 From: Pascal Fischer Date: Mon, 9 Oct 2023 14:59:21 +0200 Subject: [PATCH 08/56] fix --- client/ios/netbird/client.go | 1 + 1 file changed, 1 insertion(+) diff --git a/client/ios/netbird/client.go b/client/ios/netbird/client.go index f21c658f170..73d565d4698 100644 --- a/client/ios/netbird/client.go +++ b/client/ios/netbird/client.go @@ -120,6 +120,7 @@ func (c *Client) Auth(urlOpener URLOpener) error { return err } + return nil } // Stop the internal client and free the resources From de46393a7c72f6102516b7bc9e3fe25767f4a9e7 Mon Sep 17 00:00:00 2001 From: Pascal Fischer Date: Mon, 23 Oct 2023 18:31:40 +0200 Subject: [PATCH 09/56] updated --- client/internal/dns/host_ios.go | 25 +++- client/internal/dns/server.go | 2 +- client/internal/engine.go | 1 + client/ios/{netbird => NetBirdSDK}/client.go | 121 ++++++++++-------- .../ios/{netbird => NetBirdSDK}/gomobile.go | 2 +- client/ios/NetBirdSDK/logger.go | 16 +++ client/ios/{netbird => NetBirdSDK}/login.go | 48 +------ .../{netbird => NetBirdSDK}/peer_notifier.go | 26 +++- .../{netbird => NetBirdSDK}/preferences.go | 2 +- .../preferences_test.go | 2 +- client/ios/netbird/dns_list.go | 26 ---- client/ios/netbird/dns_list_test.go | 24 ---- client/ios/netbird/logger.go | 31 ----- client/system/info.go | 24 ++++ client/system/info_ios.go | 13 +- 15 files changed, 170 insertions(+), 193 deletions(-) rename client/ios/{netbird => NetBirdSDK}/client.go (57%) rename client/ios/{netbird => NetBirdSDK}/gomobile.go (87%) create mode 100644 client/ios/NetBirdSDK/logger.go rename client/ios/{netbird => NetBirdSDK}/login.go (81%) rename client/ios/{netbird => NetBirdSDK}/peer_notifier.go (53%) rename client/ios/{netbird => NetBirdSDK}/preferences.go (99%) rename client/ios/{netbird => NetBirdSDK}/preferences_test.go (99%) delete mode 100644 client/ios/netbird/dns_list.go delete mode 100644 client/ios/netbird/dns_list_test.go delete mode 100644 client/ios/netbird/logger.go diff --git a/client/internal/dns/host_ios.go b/client/internal/dns/host_ios.go index 3dd93fa0730..fa143dc7a63 100644 --- a/client/internal/dns/host_ios.go +++ b/client/internal/dns/host_ios.go @@ -1,5 +1,12 @@ package dns +import ( + "strconv" + "strings" + + log "github.com/sirupsen/logrus" +) + type iosHostManager struct { dnsManager IosDnsManager config HostDNSConfig @@ -12,7 +19,23 @@ func newHostManager(wgInterface WGIface, dnsManager IosDnsManager) (hostManager, } func (a iosHostManager) applyDNSConfig(config HostDNSConfig) error { - a.dnsManager.applyDns("bla") + var configAsString []string + configAsString = append(configAsString, config.serverIP) + configAsString = append(configAsString, strconv.Itoa(config.serverPort)) + configAsString = append(configAsString, strconv.FormatBool(config.routeAll)) + var domainConfigAsString []string + for _, domain := range config.domains { + var domainAsString []string + domainAsString = append(domainAsString, strconv.FormatBool(domain.disabled)) + domainAsString = append(domainAsString, domain.domain) + domainAsString = append(domainAsString, strconv.FormatBool(domain.matchOnly)) + domainConfigAsString = append(domainConfigAsString, strings.Join(domainAsString, "|")) + } + domainConfig := strings.Join(domainConfigAsString, ";") + configAsString = append(configAsString, domainConfig) + outputString := strings.Join(configAsString, ",") + log.Debug("applyDNSConfig: " + outputString) + a.dnsManager.ApplyDns(outputString) return nil } diff --git a/client/internal/dns/server.go b/client/internal/dns/server.go index 389d882adfd..03ba6f717e9 100644 --- a/client/internal/dns/server.go +++ b/client/internal/dns/server.go @@ -21,7 +21,7 @@ type ReadyListener interface { // IosDnsManager is a dns manager interface for iosß type IosDnsManager interface { - applyDns(string) + ApplyDns(string) } // Server is a dns server interface diff --git a/client/internal/engine.go b/client/internal/engine.go index 585e9a5a50e..9d041031e99 100644 --- a/client/internal/engine.go +++ b/client/internal/engine.go @@ -217,6 +217,7 @@ func (e *Engine) Start() error { log.Debugf("Initial routes contain %d routes", len(routes)) e.routeManager = routemanager.NewManager(e.ctx, e.config.WgPrivateKey.PublicKey().String(), e.wgInterface, e.statusRecorder, routes) e.mobileDep.RouteListener.SetInterfaceIP(wgAddr) + e.routeManager.SetRouteChangeListener(e.mobileDep.RouteListener) switch runtime.GOOS { diff --git a/client/ios/netbird/client.go b/client/ios/NetBirdSDK/client.go similarity index 57% rename from client/ios/netbird/client.go rename to client/ios/NetBirdSDK/client.go index 73d565d4698..5cea91b386e 100644 --- a/client/ios/netbird/client.go +++ b/client/ios/NetBirdSDK/client.go @@ -1,12 +1,14 @@ -package netbird +package NetBirdSDK import ( "context" "sync" + "time" log "github.com/sirupsen/logrus" "github.com/netbirdio/netbird/client/internal" + "github.com/netbirdio/netbird/client/internal/auth" "github.com/netbirdio/netbird/client/internal/dns" "github.com/netbirdio/netbird/client/internal/peer" "github.com/netbirdio/netbird/client/internal/routemanager" @@ -14,11 +16,6 @@ import ( "github.com/netbirdio/netbird/formatter" ) -// ConnectionListener export internal Listener for mobile -type ConnectionListener interface { - peer.Listener -} - // RouteListener export internal RouteListener for mobile type RouteListener interface { routemanager.RouteListener @@ -47,16 +44,21 @@ type Client struct { ctxCancel context.CancelFunc ctxCancelLock *sync.Mutex deviceName string + osName string + osVersion string routeListener routemanager.RouteListener onHostDnsFn func([]string) dnsManager dns.IosDnsManager + loginComplete bool } // NewClient instantiate a new Client -func NewClient(cfgFile, deviceName string, routeListener RouteListener, dnsManager DnsManager) *Client { +func NewClient(cfgFile, deviceName string, osVersion string, osName string, routeListener RouteListener, dnsManager DnsManager) *Client { return &Client{ cfgFile: cfgFile, deviceName: deviceName, + osName: osName, + osVersion: osVersion, recorder: peer.NewRecorder(""), ctxCancelLock: &sync.Mutex{}, routeListener: routeListener, @@ -78,14 +80,15 @@ func (c *Client) Run(fd int32) error { var ctx context.Context //nolint ctxWithValues := context.WithValue(context.Background(), system.DeviceNameCtxKey, c.deviceName) + ctxWithValues = context.WithValue(ctxWithValues, system.OsNameCtxKey, c.osName) + ctxWithValues = context.WithValue(ctxWithValues, system.OsVersionCtxKey, c.osVersion) c.ctxCancelLock.Lock() ctx, c.ctxCancel = context.WithCancel(ctxWithValues) defer c.ctxCancel() c.ctxCancelLock.Unlock() auth := NewAuthWithConfig(ctx, cfg) - // err = auth.login(urlOpener) - auth.loginWithSetupKeyAndSaveConfig("C3803F45-435B-4333-96EB-50F9EC723355", "iPhone") + err = auth.Login() if err != nil { return err } @@ -97,32 +100,6 @@ func (c *Client) Run(fd int32) error { return internal.RunClientiOS(ctx, cfg, c.recorder, fd, c.routeListener, c.dnsManager) } -func (c *Client) Auth(urlOpener URLOpener) error { - cfg, err := internal.UpdateOrCreateConfig(internal.ConfigInput{ - ConfigPath: c.cfgFile, - }) - if err != nil { - return err - } - c.recorder.UpdateManagementAddress(cfg.ManagementURL.String()) - - var ctx context.Context - //nolint - ctxWithValues := context.WithValue(context.Background(), system.DeviceNameCtxKey, c.deviceName) - c.ctxCancelLock.Lock() - ctx, c.ctxCancel = context.WithCancel(ctxWithValues) - defer c.ctxCancel() - c.ctxCancelLock.Unlock() - - auth := NewAuthWithConfig(ctx, cfg) - err = auth.login(urlOpener) - if err != nil { - return err - } - - return nil -} - // Stop the internal client and free the resources func (c *Client) Stop() { c.ctxCancelLock.Lock() @@ -139,8 +116,8 @@ func (c *Client) SetTraceLogLevel() { log.SetLevel(log.TraceLevel) } -// PeersList return with the list of the PeerInfos -func (c *Client) PeersList() *PeerInfoArray { +// getStatusDetails return with the list of the PeerInfos +func (c *Client) GetStatusDetails() *StatusDetails { fullStatus := c.recorder.GetFullStatus() @@ -153,26 +130,70 @@ func (c *Client) PeersList() *PeerInfoArray { } peerInfos[n] = pi } - return &PeerInfoArray{items: peerInfos} + return &StatusDetails{items: peerInfos, fqdn: fullStatus.LocalPeerState.FQDN, ip: fullStatus.LocalPeerState.IP} +} + +func (c *Client) GetManagementStatus() bool { + return c.recorder.GetFullStatus().ManagementState.Connected } -// OnUpdatedHostDNS update the DNS servers addresses for root zones -func (c *Client) OnUpdatedHostDNS(list *DNSList) error { - dnsServer, err := dns.GetServerDns() +func (c *Client) IsLoginRequired() bool { + var ctx context.Context + ctxWithValues := context.WithValue(context.Background(), system.DeviceNameCtxKey, c.deviceName) + c.ctxCancelLock.Lock() + defer c.ctxCancelLock.Unlock() + ctx, c.ctxCancel = context.WithCancel(ctxWithValues) + + cfg, _ := internal.UpdateOrCreateConfig(internal.ConfigInput{ + ConfigPath: c.cfgFile, + }) + + needsLogin, _ := internal.IsLoginRequired(ctx, cfg.PrivateKey, cfg.ManagementURL, cfg.SSHKey) + return needsLogin +} + +func (c *Client) LoginForMobile() string { + var ctx context.Context + ctxWithValues := context.WithValue(context.Background(), system.DeviceNameCtxKey, c.deviceName) + c.ctxCancelLock.Lock() + defer c.ctxCancelLock.Unlock() + ctx, c.ctxCancel = context.WithCancel(ctxWithValues) + + cfg, _ := internal.UpdateOrCreateConfig(internal.ConfigInput{ + ConfigPath: c.cfgFile, + }) + + oAuthFlow, err := auth.NewOAuthFlow(ctx, cfg, false) if err != nil { - return err + return err.Error() + } + + flowInfo, err := oAuthFlow.RequestAuthInfo(context.TODO()) + if err != nil { + return err.Error() } - dnsServer.OnUpdatedHostDNSServer(list.items) - return nil + // This could cause a potential race condition with loading the extension which need to be handled on swift side + go func() { + waitTimeout := time.Duration(flowInfo.ExpiresIn) + waitCTX, cancel := context.WithTimeout(ctx, waitTimeout*time.Second) + defer cancel() + tokenInfo, err := oAuthFlow.WaitToken(waitCTX, flowInfo) + if err != nil { + return + } + jwtToken := tokenInfo.GetTokenToUse() + _ = internal.Login(ctx, cfg, "", jwtToken) + c.loginComplete = true + }() + + return flowInfo.VerificationURIComplete } -// SetConnectionListener set the network connection listener -func (c *Client) SetConnectionListener(listener ConnectionListener) { - c.recorder.SetConnectionListener(listener) +func (c *Client) IsLoginComplete() bool { + return c.loginComplete } -// RemoveConnectionListener remove connection listener -func (c *Client) RemoveConnectionListener() { - c.recorder.RemoveConnectionListener() +func (c *Client) ClearLoginComplete() { + c.loginComplete = false } diff --git a/client/ios/netbird/gomobile.go b/client/ios/NetBirdSDK/gomobile.go similarity index 87% rename from client/ios/netbird/gomobile.go rename to client/ios/NetBirdSDK/gomobile.go index 76b4f7e358f..9eadd6a7f37 100644 --- a/client/ios/netbird/gomobile.go +++ b/client/ios/NetBirdSDK/gomobile.go @@ -1,4 +1,4 @@ -package netbird +package NetBirdSDK import _ "golang.org/x/mobile/bind" diff --git a/client/ios/NetBirdSDK/logger.go b/client/ios/NetBirdSDK/logger.go new file mode 100644 index 00000000000..674e296fb36 --- /dev/null +++ b/client/ios/NetBirdSDK/logger.go @@ -0,0 +1,16 @@ +package NetBirdSDK + +import ( + "os" + + "github.com/netbirdio/netbird/util" +) + +var logFile *os.File + +// InitializeLog initializes the log file. +func InitializeLog(logLevel string, filePath string) error { + var err error + err = util.InitLog(logLevel, filePath) + return err +} diff --git a/client/ios/netbird/login.go b/client/ios/NetBirdSDK/login.go similarity index 81% rename from client/ios/netbird/login.go rename to client/ios/NetBirdSDK/login.go index 3aaa24af2dc..50a0425387d 100644 --- a/client/ios/netbird/login.go +++ b/client/ios/NetBirdSDK/login.go @@ -1,4 +1,4 @@ -package netbird +package NetBirdSDK import ( "context" @@ -70,18 +70,7 @@ func NewAuthWithConfig(ctx context.Context, config *internal.Config) *Auth { // SaveConfigIfSSOSupported test the connectivity with the management server by retrieving the server device flow info. // If it returns a flow info than save the configuration and return true. If it gets a codes.NotFound, it means that SSO // is not supported and returns false without saving the configuration. For other errors return false. -func (a *Auth) SaveConfigIfSSOSupported(listener SSOListener) { - go func() { - sso, err := a.saveConfigIfSSOSupported() - if err != nil { - listener.OnError(err) - } else { - listener.OnSuccess(sso) - } - }() -} - -func (a *Auth) saveConfigIfSSOSupported() (bool, error) { +func (a *Auth) SaveConfigIfSSOSupported() (bool, error) { supportsSSO := true err := a.withBackOff(a.ctx, func() (err error) { _, err = internal.GetDeviceAuthorizationFlowInfo(a.ctx, a.config.PrivateKey, a.config.ManagementURL) @@ -111,18 +100,7 @@ func (a *Auth) saveConfigIfSSOSupported() (bool, error) { } // LoginWithSetupKeyAndSaveConfig test the connectivity with the management server with the setup key. -func (a *Auth) LoginWithSetupKeyAndSaveConfig(resultListener ErrListener, setupKey string, deviceName string) { - go func() { - err := a.loginWithSetupKeyAndSaveConfig(setupKey, deviceName) - if err != nil { - resultListener.OnError(err) - } else { - resultListener.OnSuccess() - } - }() -} - -func (a *Auth) loginWithSetupKeyAndSaveConfig(setupKey string, deviceName string) error { +func (a *Auth) LoginWithSetupKeyAndSaveConfig(setupKey string, deviceName string) error { //nolint ctxWithValues := context.WithValue(a.ctx, system.DeviceNameCtxKey, deviceName) @@ -141,19 +119,7 @@ func (a *Auth) loginWithSetupKeyAndSaveConfig(setupKey string, deviceName string return internal.WriteOutConfig(a.cfgPath, a.config) } -// Login try register the client on the server -func (a *Auth) Login(resultListener ErrListener, urlOpener URLOpener) { - go func() { - err := a.login(urlOpener) - if err != nil { - resultListener.OnError(err) - } else { - resultListener.OnSuccess() - } - }() -} - -func (a *Auth) login(urlOpener URLOpener) error { +func (a *Auth) Login() error { var needsLogin bool // check if we need to generate JWT token @@ -167,11 +133,7 @@ func (a *Auth) login(urlOpener URLOpener) error { jwtToken := "" if needsLogin { - tokenInfo, err := a.foregroundGetTokenInfo(urlOpener) - if err != nil { - return fmt.Errorf("interactive sso login failed: %v", err) - } - jwtToken = tokenInfo.GetTokenToUse() + return fmt.Errorf("Not authenticated") } err = a.withBackOff(a.ctx, func() error { diff --git a/client/ios/netbird/peer_notifier.go b/client/ios/NetBirdSDK/peer_notifier.go similarity index 53% rename from client/ios/netbird/peer_notifier.go rename to client/ios/NetBirdSDK/peer_notifier.go index a23af2a2923..e52008d9f0a 100644 --- a/client/ios/netbird/peer_notifier.go +++ b/client/ios/NetBirdSDK/peer_notifier.go @@ -1,4 +1,4 @@ -package netbird +package NetBirdSDK // PeerInfo describe information about the peers. It designed for the UI usage type PeerInfo struct { @@ -12,25 +12,39 @@ type PeerInfoCollection interface { Add(s string) PeerInfoCollection Get(i int) string Size() int + GetFQDN() string + GetIP() string } -// PeerInfoArray is the implementation of the PeerInfoCollection -type PeerInfoArray struct { +// StatusDetails is the implementation of the PeerInfoCollection +type StatusDetails struct { items []PeerInfo + fqdn string + ip string } // Add new PeerInfo to the collection -func (array PeerInfoArray) Add(s PeerInfo) PeerInfoArray { +func (array StatusDetails) Add(s PeerInfo) StatusDetails { array.items = append(array.items, s) return array } // Get return an element of the collection -func (array PeerInfoArray) Get(i int) *PeerInfo { +func (array StatusDetails) Get(i int) *PeerInfo { return &array.items[i] } // Size return with the size of the collection -func (array PeerInfoArray) Size() int { +func (array StatusDetails) Size() int { return len(array.items) } + +// GetFQDN return with the FQDN of the local peer +func (array StatusDetails) GetFQDN() string { + return array.fqdn +} + +// GetIP return with the IP of the local peer +func (array StatusDetails) GetIP() string { + return array.ip +} diff --git a/client/ios/netbird/preferences.go b/client/ios/NetBirdSDK/preferences.go similarity index 99% rename from client/ios/netbird/preferences.go rename to client/ios/NetBirdSDK/preferences.go index d565029e7f9..297d53ff08e 100644 --- a/client/ios/netbird/preferences.go +++ b/client/ios/NetBirdSDK/preferences.go @@ -1,4 +1,4 @@ -package netbird +package NetBirdSDK import ( "github.com/netbirdio/netbird/client/internal" diff --git a/client/ios/netbird/preferences_test.go b/client/ios/NetBirdSDK/preferences_test.go similarity index 99% rename from client/ios/netbird/preferences_test.go rename to client/ios/NetBirdSDK/preferences_test.go index ee7e1c0292b..bb4531b6141 100644 --- a/client/ios/netbird/preferences_test.go +++ b/client/ios/NetBirdSDK/preferences_test.go @@ -1,4 +1,4 @@ -package netbird +package NetBirdSDK import ( "path/filepath" diff --git a/client/ios/netbird/dns_list.go b/client/ios/netbird/dns_list.go deleted file mode 100644 index 49e3b2f71aa..00000000000 --- a/client/ios/netbird/dns_list.go +++ /dev/null @@ -1,26 +0,0 @@ -package netbird - -import "fmt" - -// DNSList is a wrapper of []string -type DNSList struct { - items []string -} - -// Add new DNS address to the collection -func (array *DNSList) Add(s string) { - array.items = append(array.items, s) -} - -// Get return an element of the collection -func (array *DNSList) Get(i int) (string, error) { - if i >= len(array.items) || i < 0 { - return "", fmt.Errorf("out of range") - } - return array.items[i], nil -} - -// Size return with the size of the collection -func (array *DNSList) Size() int { - return len(array.items) -} diff --git a/client/ios/netbird/dns_list_test.go b/client/ios/netbird/dns_list_test.go deleted file mode 100644 index d88373dd882..00000000000 --- a/client/ios/netbird/dns_list_test.go +++ /dev/null @@ -1,24 +0,0 @@ -package netbird - -import "testing" - -func TestDNSList_Get(t *testing.T) { - l := DNSList{ - items: make([]string, 1), - } - - _, err := l.Get(0) - if err != nil { - t.Errorf("invalid error: %s", err) - } - - _, err = l.Get(-1) - if err == nil { - t.Errorf("expected error but got nil") - } - - _, err = l.Get(1) - if err == nil { - t.Errorf("expected error but got nil") - } -} diff --git a/client/ios/netbird/logger.go b/client/ios/netbird/logger.go deleted file mode 100644 index 96b75d7d302..00000000000 --- a/client/ios/netbird/logger.go +++ /dev/null @@ -1,31 +0,0 @@ -package netbird - -import ( - "os" - - "github.com/netbirdio/netbird/util" -) - -var logFile *os.File - -// InitializeLog initializes the log file. -func InitializeLog(logLevel string, filePath string) error { - var err error - err = util.InitLog(logLevel, filePath) - return err -} - -// // CloseLog closes the log file. -// func CloseLog() { -// if logFile != nil { -// logFile.Close() -// } -// } -// -// // Log writes a message to the log file. -// func Log(message string) { -// if logFile != nil { -// ts := time.Now().Format(time.RFC3339) -// fmt.Fprintf(logFile, "%s: %s\n", ts, message) -// } -// } diff --git a/client/system/info.go b/client/system/info.go index a495ed1e91a..b6254ef476c 100644 --- a/client/system/info.go +++ b/client/system/info.go @@ -12,6 +12,12 @@ import ( // DeviceNameCtxKey context key for device name const DeviceNameCtxKey = "deviceName" +// OsVersionCtxKey context key for operating system version +const OsVersionCtxKey = "OsVersion" + +// OsNameCtxKey context key for operating system name +const OsNameCtxKey = "OsName" + // Info is an object that contains machine information // Most of the code is taken from https://github.com/matishsiao/goInfo type Info struct { @@ -52,6 +58,24 @@ func extractDeviceName(ctx context.Context, defaultName string) string { return v } +// extractOsVersion extracts operating system version from context or returns the default +func extractOsVersion(ctx context.Context, defaultName string) string { + v, ok := ctx.Value(OsVersionCtxKey).(string) + if !ok { + return defaultName + } + return v +} + +// extractOsName extracts operating system name from context or returns the default +func extractOsName(ctx context.Context, defaultName string) string { + v, ok := ctx.Value(OsNameCtxKey).(string) + if !ok { + return defaultName + } + return v +} + // GetDesktopUIUserAgent returns the Desktop ui user agent func GetDesktopUIUserAgent() string { return "netbird-desktop-ui/" + version.NetbirdVersion() diff --git a/client/system/info_ios.go b/client/system/info_ios.go index 967c69a83b3..762117afa6b 100644 --- a/client/system/info_ios.go +++ b/client/system/info_ios.go @@ -5,7 +5,6 @@ package system import ( "context" - "os" "runtime" "github.com/netbirdio/netbird/version" @@ -15,14 +14,12 @@ import ( func GetInfo(ctx context.Context) *Info { // Convert fixed-size byte arrays to Go strings - sysName := "iOS" - machine := "machine" - release := "release" - swversion := "swversion" + sysName := extractOsName(ctx, "sysName") + swVersion := extractOsVersion(ctx, "swVersion") - gio := &Info{Kernel: sysName, OSVersion: swversion, Core: release, Platform: machine, OS: sysName, GoOS: runtime.GOOS, CPUs: runtime.NumCPU()} - systemHostname, _ := os.Hostname() - gio.Hostname = extractDeviceName(ctx, systemHostname) + gio := &Info{Kernel: sysName, OSVersion: swVersion, Core: swVersion, Platform: "unknown", OS: sysName, GoOS: runtime.GOOS, CPUs: runtime.NumCPU()} + // systemHostname, _ := os.Hostname() + gio.Hostname = extractDeviceName(ctx, "hostname") gio.WiretrusteeVersion = version.NetbirdVersion() gio.UIVersion = extractUserAgent(ctx) From 79f60b86c4b0a2337577deb9c0e84cac29e6ac4b Mon Sep 17 00:00:00 2001 From: Pascal Fischer Date: Fri, 27 Oct 2023 11:11:25 +0200 Subject: [PATCH 10/56] fix route deletion --- client/internal/engine.go | 2 - client/internal/routemanager/manager.go | 3 +- client/internal/routemanager/notifier.go | 3 -- client/internal/routemanager/systemops_ios.go | 15 ++++++ .../routemanager/systemops_nonandroid.go | 2 +- iface/wg_configurer_ios.go | 54 +++++++++++++++++-- 6 files changed, 68 insertions(+), 11 deletions(-) create mode 100644 client/internal/routemanager/systemops_ios.go diff --git a/client/internal/engine.go b/client/internal/engine.go index 9d041031e99..fc5937fb1cd 100644 --- a/client/internal/engine.go +++ b/client/internal/engine.go @@ -228,8 +228,6 @@ func (e *Engine) Start() error { }) case "ios": err = e.wgInterface.CreateOniOS(e.mobileDep.FileDescriptor) - log.Debugf("sending initial route range %s to iOS", strings.Join(e.routeManager.InitialRouteRange(), ",")) - e.mobileDep.RouteListener.OnNewRouteSetting(strings.Join(e.routeManager.InitialRouteRange(), ",")) default: err = e.wgInterface.Create() } diff --git a/client/internal/routemanager/manager.go b/client/internal/routemanager/manager.go index 2f8482dbf1d..b31fe632749 100644 --- a/client/internal/routemanager/manager.go +++ b/client/internal/routemanager/manager.go @@ -53,8 +53,7 @@ func NewManager(ctx context.Context, pubKey string, wgInterface *iface.WGIface, notifier: newNotifier(), } - log.Debug("initializing route manager") - if runtime.GOOS == "android" || runtime.GOOS == "ios" { + if runtime.GOOS == "android" { cr := dm.clientRoutes(initialRoutes) dm.notifier.setInitialClientRoutes(cr) } diff --git a/client/internal/routemanager/notifier.go b/client/internal/routemanager/notifier.go index 7da4f920b2d..752cdd7dba4 100644 --- a/client/internal/routemanager/notifier.go +++ b/client/internal/routemanager/notifier.go @@ -59,9 +59,6 @@ func (n *notifier) onNewRoutes(idMap map[string][]*route.Route) { n.routeRangers = newNets - if !n.hasDiff(n.initialRouteRangers, newNets) { - return - } n.notify() } diff --git a/client/internal/routemanager/systemops_ios.go b/client/internal/routemanager/systemops_ios.go new file mode 100644 index 00000000000..aae0f8dc8f2 --- /dev/null +++ b/client/internal/routemanager/systemops_ios.go @@ -0,0 +1,15 @@ +//go:build ios + +package routemanager + +import ( + "net/netip" +) + +func addToRouteTableIfNoExists(prefix netip.Prefix, addr string) error { + return nil +} + +func removeFromRouteTableIfNonSystem(prefix netip.Prefix, addr string) error { + return nil +} diff --git a/client/internal/routemanager/systemops_nonandroid.go b/client/internal/routemanager/systemops_nonandroid.go index 3ddf72686de..11a4890c06d 100644 --- a/client/internal/routemanager/systemops_nonandroid.go +++ b/client/internal/routemanager/systemops_nonandroid.go @@ -1,4 +1,4 @@ -//go:build !android +//go:build !android && !ios package routemanager diff --git a/iface/wg_configurer_ios.go b/iface/wg_configurer_ios.go index 23240227894..4b1c89be0a9 100644 --- a/iface/wg_configurer_ios.go +++ b/iface/wg_configurer_ios.go @@ -4,12 +4,14 @@ package iface import ( + "encoding/hex" "errors" + "fmt" "net" + "strings" "time" log "github.com/sirupsen/logrus" - "golang.zx2c4.com/wireguard/wgctrl/wgtypes" ) @@ -112,6 +114,52 @@ func (c *wGConfigurer) addAllowedIP(peerKey string, allowedIP string) error { return c.tunDevice.Device().IpcSet(toWgUserspaceString(config)) } -func (c *wGConfigurer) removeAllowedIP(peerKey string, allowedIP string) error { - return errFuncNotImplemented +func (c *wGConfigurer) removeAllowedIP(peerKey string, ip string) error { + ipc, err := c.tunDevice.Device().IpcGet() + if err != nil { + return err + } + + peerKeyParsed, err := wgtypes.ParseKey(peerKey) + hexKey := hex.EncodeToString(peerKeyParsed[:]) + + lines := strings.Split(ipc, "\n") + + output := "" + foundPeer := false + removedAllowedIP := false + for _, line := range lines { + line = strings.TrimSpace(line) + + // If we're within the details of the found peer and encounter another public key, + // this means we're starting another peer's details. So, reset the flag. + if strings.HasPrefix(line, "public_key=") && foundPeer { + foundPeer = false + } + + // Identify the peer with the specific public key + if line == fmt.Sprintf("public_key=%s", hexKey) { + foundPeer = true + } + + // If we're within the details of the found peer and find the specific allowed IP, skip this line + if foundPeer && line == "allowed_ip="+ip { + removedAllowedIP = true + continue + } + + // Append the line to the output string + if strings.HasPrefix(line, "private_key=") || strings.HasPrefix(line, "listen_port=") || + strings.HasPrefix(line, "public_key=") || strings.HasPrefix(line, "preshared_key=") || + strings.HasPrefix(line, "endpoint=") || strings.HasPrefix(line, "persistent_keepalive_interval=") || + strings.HasPrefix(line, "allowed_ip=") { + output += line + "\n" + } + } + + if !removedAllowedIP { + return fmt.Errorf("allowedIP not found") + } else { + return c.tunDevice.Device().IpcSet(output) + } } From 64084ca130751d2ec9f271f711aa5b2f44d667d7 Mon Sep 17 00:00:00 2001 From: Pascal Fischer Date: Fri, 3 Nov 2023 14:26:07 +0100 Subject: [PATCH 11/56] trying to bind the DNS resolver dialer to an interface --- client/internal/connect.go | 3 +- client/internal/dns/server.go | 19 +++--- client/internal/dns/upstream.go | 94 ++++++++++++++++++++++++++-- client/internal/engine.go | 2 +- client/internal/mobile_dependency.go | 1 + client/ios/NetBirdSDK/client.go | 5 +- 6 files changed, 109 insertions(+), 15 deletions(-) diff --git a/client/internal/connect.go b/client/internal/connect.go index c5fdf42749d..aa3ac629b5d 100644 --- a/client/internal/connect.go +++ b/client/internal/connect.go @@ -42,9 +42,10 @@ func RunClientMobile(ctx context.Context, config *Config, statusRecorder *peer.S return runClient(ctx, config, statusRecorder, mobileDependency) } -func RunClientiOS(ctx context.Context, config *Config, statusRecorder *peer.Status, fileDescriptor int32, routeListener routemanager.RouteListener, dnsManager dns.IosDnsManager) error { +func RunClientiOS(ctx context.Context, config *Config, statusRecorder *peer.Status, fileDescriptor int32, routeListener routemanager.RouteListener, dnsManager dns.IosDnsManager, interfaceName string) error { mobileDependency := MobileDependency{ FileDescriptor: fileDescriptor, + InterfaceName: interfaceName, RouteListener: routeListener, DnsManager: dnsManager, } diff --git a/client/internal/dns/server.go b/client/internal/dns/server.go index 03ba6f717e9..fb763bec2d3 100644 --- a/client/internal/dns/server.go +++ b/client/internal/dns/server.go @@ -53,6 +53,9 @@ type DefaultServer struct { permanent bool hostsDnsList []string hostsDnsListLock sync.Mutex + + interfaceName string + wgAddr string } type handlerWithStop interface { @@ -66,7 +69,7 @@ type muxUpdate struct { } // NewDefaultServer returns a new dns server -func NewDefaultServer(ctx context.Context, wgInterface WGIface, customAddress string) (*DefaultServer, error) { +func NewDefaultServer(ctx context.Context, wgInterface WGIface, customAddress string, interfaceName string, wgAddr string) (*DefaultServer, error) { var addrPort *netip.AddrPort if customAddress != "" { parsedAddrPort, err := netip.ParseAddrPort(customAddress) @@ -83,13 +86,13 @@ func NewDefaultServer(ctx context.Context, wgInterface WGIface, customAddress st dnsService = newServiceViaListener(wgInterface, addrPort) } - return newDefaultServer(ctx, wgInterface, dnsService), nil + return newDefaultServer(ctx, wgInterface, dnsService, interfaceName, wgAddr), nil } // NewDefaultServerPermanentUpstream returns a new dns server. It optimized for mobile systems func NewDefaultServerPermanentUpstream(ctx context.Context, wgInterface WGIface, hostsDnsList []string) *DefaultServer { log.Debugf("host dns address list is: %v", hostsDnsList) - ds := newDefaultServer(ctx, wgInterface, newServiceViaMemory(wgInterface)) + ds := newDefaultServer(ctx, wgInterface, newServiceViaMemory(wgInterface), "", "") ds.permanent = true ds.hostsDnsList = hostsDnsList ds.addHostRootZone() @@ -97,7 +100,7 @@ func NewDefaultServerPermanentUpstream(ctx context.Context, wgInterface WGIface, return ds } -func newDefaultServer(ctx context.Context, wgInterface WGIface, dnsService service) *DefaultServer { +func newDefaultServer(ctx context.Context, wgInterface WGIface, dnsService service, interfaceName string, wgAddr string) *DefaultServer { ctx, stop := context.WithCancel(ctx) defaultServer := &DefaultServer{ ctx: ctx, @@ -107,7 +110,9 @@ func newDefaultServer(ctx context.Context, wgInterface WGIface, dnsService servi localResolver: &localResolver{ registeredMap: make(registrationMap), }, - wgInterface: wgInterface, + wgInterface: wgInterface, + interfaceName: interfaceName, + wgAddr: wgAddr, } return defaultServer @@ -295,7 +300,7 @@ func (s *DefaultServer) buildUpstreamHandlerUpdate(nameServerGroups []*nbdns.Nam continue } - handler := newUpstreamResolver(s.ctx) + handler := newUpstreamResolver(s.ctx, s.interfaceName, s.wgAddr) for _, ns := range nsGroup.NameServers { if ns.NSType != nbdns.UDPNameServerType { log.Warnf("skiping nameserver %s with type %s, this peer supports only %s", @@ -468,7 +473,7 @@ func (s *DefaultServer) upstreamCallbacks( } func (s *DefaultServer) addHostRootZone() { - handler := newUpstreamResolver(s.ctx) + handler := newUpstreamResolver(s.ctx, s.interfaceName, s.wgAddr) handler.upstreamServers = make([]string, len(s.hostsDnsList)) for n, ua := range s.hostsDnsList { handler.upstreamServers[n] = fmt.Sprintf("%s:53", ua) diff --git a/client/internal/dns/upstream.go b/client/internal/dns/upstream.go index b4febd7a410..69d1a58d607 100644 --- a/client/internal/dns/upstream.go +++ b/client/internal/dns/upstream.go @@ -4,14 +4,19 @@ import ( "context" "errors" "fmt" + "math/rand" "net" + "net/netip" "sync" "sync/atomic" + "syscall" "time" "github.com/cenkalti/backoff/v4" + "github.com/libp2p/go-netroute" "github.com/miekg/dns" log "github.com/sirupsen/logrus" + "golang.org/x/sys/unix" ) const ( @@ -40,12 +45,80 @@ type upstreamResolver struct { reactivate func() } -func newUpstreamResolver(parentCTX context.Context) *upstreamResolver { +// func newUpstreamResolver(parentCTX context.Context) *upstreamResolver { +// ctx, cancel := context.WithCancel(parentCTX) +// return &upstreamResolver{ +// ctx: ctx, +// cancel: cancel, +// upstreamClient: &dns.Client{}, +// upstreamTimeout: upstreamTimeout, +// reactivatePeriod: reactivatePeriod, +// failsTillDeact: failsTillDeact, +// } +// } + +func getInterfaceIndex(interfaceName string) (int, error) { + iface, err := net.InterfaceByName(interfaceName) + if err != nil { + return 0, err + } + + return iface.Index, nil +} + +func newUpstreamResolver(parentCTX context.Context, interfaceName string, wgAddr string) *upstreamResolver { ctx, cancel := context.WithCancel(parentCTX) + + // Specify the local IP address you want to bind to + localIP, _, err := net.ParseCIDR(wgAddr) // Should be our interface IP + if err != nil { + log.Errorf("error while parsing CIDR: %s", err) + } + index, err := getInterfaceIndex(interfaceName) + rand.Seed(time.Now().UnixNano()) + port := rand.Intn(4001) + 1000 + log.Debugf("UpstreamResolver interface name: %s, index: %d, ip: %s, port: %d", interfaceName, index, localIP, port) + if err != nil { + log.Debugf("unable to get interface index for %s: %s", interfaceName, err) + } + localIFaceIndex := index // Should be our interface index + // Create a custom dialer with the LocalAddr set to the desired IP + dialer := &net.Dialer{ + LocalAddr: &net.UDPAddr{ + IP: localIP, + Port: port, // Let the OS pick a free port + }, + Control: func(network, address string, c syscall.RawConn) error { + var operr error + fn := func(s uintptr) { + operr = syscall.SetsockoptInt(int(s), unix.IPPROTO_IP, unix.IP_BOUND_IF, localIFaceIndex) + } + + if err := c.Control(fn); err != nil { + return err + } + + return operr + }, + } + // pktConn, err := dialer.Dial("udp", "100.127.136.151:10053") + // if err != nil { + // log.Errorf("error while dialing: %s", err) + // + // } else { + // pktConn.Write([]byte("hello")) + // pktConn.Close() + // } + + // Create a new DNS client with the custom dialer + client := &dns.Client{ + Dialer: dialer, + } + return &upstreamResolver{ ctx: ctx, cancel: cancel, - upstreamClient: &dns.Client{}, + upstreamClient: client, upstreamTimeout: upstreamTimeout, reactivatePeriod: reactivatePeriod, failsTillDeact: failsTillDeact, @@ -61,7 +134,7 @@ func (u *upstreamResolver) stop() { func (u *upstreamResolver) ServeDNS(w dns.ResponseWriter, r *dns.Msg) { defer u.checkUpstreamFails() - log.WithField("question", r.Question[0]).Trace("received an upstream question") + log.WithField("question", r.Question[0]).Debug("received an upstream question") select { case <-u.ctx.Done(): @@ -70,6 +143,19 @@ func (u *upstreamResolver) ServeDNS(w dns.ResponseWriter, r *dns.Msg) { } for _, upstream := range u.upstreamServers { + log.Debugf("querying the upstream %s", upstream) + rr, errR := netroute.New() + if errR != nil { + log.Errorf("unable to create networute: %s", errR) + } else { + add := netip.MustParseAddrPort(upstream) + _, gateway, preferredSrc, errR := rr.Route(add.Addr().AsSlice()) + if errR != nil { + log.Errorf("getting routes returned an error: %v", errR) + } else { + log.Infof("upstream %s gateway: %s, preferredSrc: %s", add.Addr(), gateway, preferredSrc) + } + } ctx, cancel := context.WithTimeout(u.ctx, u.upstreamTimeout) rm, t, err := u.upstreamClient.ExchangeContext(ctx, r, upstream) @@ -87,7 +173,7 @@ func (u *upstreamResolver) ServeDNS(w dns.ResponseWriter, r *dns.Msg) { return } - log.Tracef("took %s to query the upstream %s", t, upstream) + log.Debugf("took %s to query the upstream %s", t, upstream) err = w.WriteMsg(rm) if err != nil { diff --git a/client/internal/engine.go b/client/internal/engine.go index fc5937fb1cd..58f459de534 100644 --- a/client/internal/engine.go +++ b/client/internal/engine.go @@ -206,7 +206,7 @@ func (e *Engine) Start() error { } else { // todo fix custom address if e.dnsServer == nil { - e.dnsServer, err = dns.NewDefaultServer(e.ctx, e.wgInterface, e.config.CustomDNSAddress) + e.dnsServer, err = dns.NewDefaultServer(e.ctx, e.wgInterface, e.config.CustomDNSAddress, e.mobileDep.InterfaceName, wgAddr) if err != nil { e.close() return err diff --git a/client/internal/mobile_dependency.go b/client/internal/mobile_dependency.go index fc01a9de314..b027937ad5d 100644 --- a/client/internal/mobile_dependency.go +++ b/client/internal/mobile_dependency.go @@ -16,4 +16,5 @@ type MobileDependency struct { DnsReadyListener dns.ReadyListener DnsManager dns.IosDnsManager FileDescriptor int32 + InterfaceName string } diff --git a/client/ios/NetBirdSDK/client.go b/client/ios/NetBirdSDK/client.go index 5cea91b386e..ca87c05f4b3 100644 --- a/client/ios/NetBirdSDK/client.go +++ b/client/ios/NetBirdSDK/client.go @@ -67,8 +67,9 @@ func NewClient(cfgFile, deviceName string, osVersion string, osName string, rout } // Run start the internal client. It is a blocker function -func (c *Client) Run(fd int32) error { +func (c *Client) Run(fd int32, interfaceName string) error { log.Infof("Starting NetBird client") + log.Debugf("Tunnel uses interface: %s", interfaceName) cfg, err := internal.UpdateOrCreateConfig(internal.ConfigInput{ ConfigPath: c.cfgFile, }) @@ -97,7 +98,7 @@ func (c *Client) Run(fd int32) error { // todo do not throw error in case of cancelled context ctx = internal.CtxInitState(ctx) c.onHostDnsFn = func([]string) {} - return internal.RunClientiOS(ctx, cfg, c.recorder, fd, c.routeListener, c.dnsManager) + return internal.RunClientiOS(ctx, cfg, c.recorder, fd, c.routeListener, c.dnsManager, interfaceName) } // Stop the internal client and free the resources From 65052e5cba8ad11907d8c35e4d2af20d944d4ed1 Mon Sep 17 00:00:00 2001 From: Maycon Santos Date: Fri, 3 Nov 2023 20:35:52 +0100 Subject: [PATCH 12/56] use dns.Client.Exchange --- client/internal/dns/upstream.go | 98 ++++++++++++++++----------------- 1 file changed, 48 insertions(+), 50 deletions(-) diff --git a/client/internal/dns/upstream.go b/client/internal/dns/upstream.go index 69d1a58d607..d94bbe59247 100644 --- a/client/internal/dns/upstream.go +++ b/client/internal/dns/upstream.go @@ -4,16 +4,14 @@ import ( "context" "errors" "fmt" - "math/rand" "net" - "net/netip" + "runtime" "sync" "sync/atomic" "syscall" "time" "github.com/cenkalti/backoff/v4" - "github.com/libp2p/go-netroute" "github.com/miekg/dns" log "github.com/sirupsen/logrus" "golang.org/x/sys/unix" @@ -40,6 +38,9 @@ type upstreamResolver struct { mutex sync.Mutex reactivatePeriod time.Duration upstreamTimeout time.Duration + lIP net.IP + lName string + iIndex int deactivate func() reactivate func() @@ -60,6 +61,7 @@ type upstreamResolver struct { func getInterfaceIndex(interfaceName string) (int, error) { iface, err := net.InterfaceByName(interfaceName) if err != nil { + log.Errorf("unable to get interface by name error: %s", err) return 0, err } @@ -75,54 +77,52 @@ func newUpstreamResolver(parentCTX context.Context, interfaceName string, wgAddr log.Errorf("error while parsing CIDR: %s", err) } index, err := getInterfaceIndex(interfaceName) - rand.Seed(time.Now().UnixNano()) - port := rand.Intn(4001) + 1000 - log.Debugf("UpstreamResolver interface name: %s, index: %d, ip: %s, port: %d", interfaceName, index, localIP, port) + log.Debugf("UpstreamResolver interface name: %s, index: %d, ip: %s", interfaceName, index, localIP) if err != nil { log.Debugf("unable to get interface index for %s: %s", interfaceName, err) } localIFaceIndex := index // Should be our interface index - // Create a custom dialer with the LocalAddr set to the desired IP + + return &upstreamResolver{ + ctx: ctx, + cancel: cancel, + upstreamTimeout: upstreamTimeout, + reactivatePeriod: reactivatePeriod, + failsTillDeact: failsTillDeact, + lIP: localIP, + iIndex: localIFaceIndex, + lName: interfaceName, + } +} + +func (u *upstreamResolver) getClient() *dns.Client { dialer := &net.Dialer{ LocalAddr: &net.UDPAddr{ - IP: localIP, - Port: port, // Let the OS pick a free port + IP: u.lIP, + Port: 0, // Let the OS pick a free port }, + Timeout: upstreamTimeout, Control: func(network, address string, c syscall.RawConn) error { var operr error fn := func(s uintptr) { - operr = syscall.SetsockoptInt(int(s), unix.IPPROTO_IP, unix.IP_BOUND_IF, localIFaceIndex) + operr = unix.SetsockoptInt(int(s), unix.IPPROTO_IP, unix.IP_BOUND_IF, u.iIndex) } if err := c.Control(fn); err != nil { return err } + if operr != nil { + log.Errorf("error while setting socket option: %s", operr) + } + return operr }, } - // pktConn, err := dialer.Dial("udp", "100.127.136.151:10053") - // if err != nil { - // log.Errorf("error while dialing: %s", err) - // - // } else { - // pktConn.Write([]byte("hello")) - // pktConn.Close() - // } - - // Create a new DNS client with the custom dialer client := &dns.Client{ Dialer: dialer, } - - return &upstreamResolver{ - ctx: ctx, - cancel: cancel, - upstreamClient: client, - upstreamTimeout: upstreamTimeout, - reactivatePeriod: reactivatePeriod, - failsTillDeact: failsTillDeact, - } + return client } func (u *upstreamResolver) stop() { @@ -134,7 +134,7 @@ func (u *upstreamResolver) stop() { func (u *upstreamResolver) ServeDNS(w dns.ResponseWriter, r *dns.Msg) { defer u.checkUpstreamFails() - log.WithField("question", r.Question[0]).Debug("received an upstream question") + //log.WithField("question", r.Question[0]).Debug("received an upstream question") select { case <-u.ctx.Done(): @@ -143,23 +143,20 @@ func (u *upstreamResolver) ServeDNS(w dns.ResponseWriter, r *dns.Msg) { } for _, upstream := range u.upstreamServers { - log.Debugf("querying the upstream %s", upstream) - rr, errR := netroute.New() - if errR != nil { - log.Errorf("unable to create networute: %s", errR) + var ( + err error + t time.Duration + rm *dns.Msg + ) + upstreamExchangeClient := u.getClient() + if runtime.GOOS != "ios" { + ctx, cancel := context.WithTimeout(u.ctx, u.upstreamTimeout) + rm, t, err = upstreamExchangeClient.ExchangeContext(ctx, r, upstream) + cancel() } else { - add := netip.MustParseAddrPort(upstream) - _, gateway, preferredSrc, errR := rr.Route(add.Addr().AsSlice()) - if errR != nil { - log.Errorf("getting routes returned an error: %v", errR) - } else { - log.Infof("upstream %s gateway: %s, preferredSrc: %s", add.Addr(), gateway, preferredSrc) - } + log.Debugf("ios upstream resolver: %s", upstream) + rm, t, err = upstreamExchangeClient.Exchange(r, upstream) } - ctx, cancel := context.WithTimeout(u.ctx, u.upstreamTimeout) - rm, t, err := u.upstreamClient.ExchangeContext(ctx, r, upstream) - - cancel() if err != nil { if err == context.DeadlineExceeded || isTimeout(err) { @@ -169,7 +166,7 @@ func (u *upstreamResolver) ServeDNS(w dns.ResponseWriter, r *dns.Msg) { } u.failsCount.Add(1) log.WithError(err).WithField("upstream", upstream). - Error("got an error while querying the upstream") + Error("got other error while querying the upstream") return } @@ -204,10 +201,11 @@ func (u *upstreamResolver) checkUpstreamFails() { case <-u.ctx.Done(): return default: - log.Warnf("upstream resolving is disabled for %v", reactivatePeriod) - u.deactivate() - u.disabled = true - go u.waitUntilResponse() + //todo test the deactivation logic, it seems to affect the client + //log.Warnf("upstream resolving is disabled for %v", reactivatePeriod) + //u.deactivate() + //u.disabled = true + //go u.waitUntilResponse() } } From e193df3bc721dab724a3de48a41226e63648817c Mon Sep 17 00:00:00 2001 From: Pascal Fischer Date: Sat, 4 Nov 2023 19:46:47 +0100 Subject: [PATCH 13/56] fix metadata send on startup --- client/ios/NetBirdSDK/client.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/client/ios/NetBirdSDK/client.go b/client/ios/NetBirdSDK/client.go index ca87c05f4b3..c5580c8d652 100644 --- a/client/ios/NetBirdSDK/client.go +++ b/client/ios/NetBirdSDK/client.go @@ -141,6 +141,8 @@ func (c *Client) GetManagementStatus() bool { func (c *Client) IsLoginRequired() bool { var ctx context.Context ctxWithValues := context.WithValue(context.Background(), system.DeviceNameCtxKey, c.deviceName) + ctxWithValues = context.WithValue(ctxWithValues, system.OsNameCtxKey, c.osName) + ctxWithValues = context.WithValue(ctxWithValues, system.OsVersionCtxKey, c.osVersion) c.ctxCancelLock.Lock() defer c.ctxCancelLock.Unlock() ctx, c.ctxCancel = context.WithCancel(ctxWithValues) @@ -156,6 +158,8 @@ func (c *Client) IsLoginRequired() bool { func (c *Client) LoginForMobile() string { var ctx context.Context ctxWithValues := context.WithValue(context.Background(), system.DeviceNameCtxKey, c.deviceName) + ctxWithValues = context.WithValue(ctxWithValues, system.OsNameCtxKey, c.osName) + ctxWithValues = context.WithValue(ctxWithValues, system.OsVersionCtxKey, c.osVersion) c.ctxCancelLock.Lock() defer c.ctxCancelLock.Unlock() ctx, c.ctxCancel = context.WithCancel(ctxWithValues) From 5632d222cc464e166b94be7f1144260bf8878a7a Mon Sep 17 00:00:00 2001 From: Pascal Fischer Date: Mon, 6 Nov 2023 12:32:25 +0100 Subject: [PATCH 14/56] switching between client to query upstream --- client/internal/dns/upstream.go | 51 +++++++++++++++++++-------------- 1 file changed, 29 insertions(+), 22 deletions(-) diff --git a/client/internal/dns/upstream.go b/client/internal/dns/upstream.go index d94bbe59247..0962e8a3a81 100644 --- a/client/internal/dns/upstream.go +++ b/client/internal/dns/upstream.go @@ -39,6 +39,7 @@ type upstreamResolver struct { reactivatePeriod time.Duration upstreamTimeout time.Duration lIP net.IP + lNet *net.IPNet lName string iIndex int @@ -46,18 +47,6 @@ type upstreamResolver struct { reactivate func() } -// func newUpstreamResolver(parentCTX context.Context) *upstreamResolver { -// ctx, cancel := context.WithCancel(parentCTX) -// return &upstreamResolver{ -// ctx: ctx, -// cancel: cancel, -// upstreamClient: &dns.Client{}, -// upstreamTimeout: upstreamTimeout, -// reactivatePeriod: reactivatePeriod, -// failsTillDeact: failsTillDeact, -// } -// } - func getInterfaceIndex(interfaceName string) (int, error) { iface, err := net.InterfaceByName(interfaceName) if err != nil { @@ -72,7 +61,7 @@ func newUpstreamResolver(parentCTX context.Context, interfaceName string, wgAddr ctx, cancel := context.WithCancel(parentCTX) // Specify the local IP address you want to bind to - localIP, _, err := net.ParseCIDR(wgAddr) // Should be our interface IP + localIP, localNet, err := net.ParseCIDR(wgAddr) // Should be our interface IP if err != nil { log.Errorf("error while parsing CIDR: %s", err) } @@ -90,12 +79,15 @@ func newUpstreamResolver(parentCTX context.Context, interfaceName string, wgAddr reactivatePeriod: reactivatePeriod, failsTillDeact: failsTillDeact, lIP: localIP, + lNet: localNet, iIndex: localIFaceIndex, lName: interfaceName, } } -func (u *upstreamResolver) getClient() *dns.Client { +// getClientPrivate returns a new DNS client bound to the local IP address of the Netbird interface +// This method is needed for iOS +func (u *upstreamResolver) getClientPrivate() *dns.Client { dialer := &net.Dialer{ LocalAddr: &net.UDPAddr{ IP: u.lIP, @@ -134,7 +126,7 @@ func (u *upstreamResolver) stop() { func (u *upstreamResolver) ServeDNS(w dns.ResponseWriter, r *dns.Msg) { defer u.checkUpstreamFails() - //log.WithField("question", r.Question[0]).Debug("received an upstream question") + log.WithField("question", r.Question[0]).Trace("received an upstream question") select { case <-u.ctx.Done(): @@ -148,13 +140,23 @@ func (u *upstreamResolver) ServeDNS(w dns.ResponseWriter, r *dns.Msg) { t time.Duration rm *dns.Msg ) - upstreamExchangeClient := u.getClient() + + upstreamExchangeClient := &dns.Client{} if runtime.GOOS != "ios" { ctx, cancel := context.WithTimeout(u.ctx, u.upstreamTimeout) rm, t, err = upstreamExchangeClient.ExchangeContext(ctx, r, upstream) cancel() } else { log.Debugf("ios upstream resolver: %s", upstream) + upstreamHost, _, err := net.SplitHostPort(upstream) + if err != nil { + log.Errorf("error while parsing upstream host: %s", err) + } + upstreamIP := net.ParseIP(upstreamHost) + if u.lNet.Contains(upstreamIP) || net.IP.IsPrivate(upstreamIP) { + log.Debugf("using private client to query upstream: %s", upstream) + upstreamExchangeClient = u.getClientPrivate() + } rm, t, err = upstreamExchangeClient.Exchange(r, upstream) } @@ -170,7 +172,12 @@ func (u *upstreamResolver) ServeDNS(w dns.ResponseWriter, r *dns.Msg) { return } - log.Debugf("took %s to query the upstream %s", t, upstream) + if !rm.Response { + log.WithError(err).WithField("upstream", upstream). + Warn("no response from upstream") + } + + log.Tracef("took %s to query the upstream %s", t, upstream) err = w.WriteMsg(rm) if err != nil { @@ -201,11 +208,11 @@ func (u *upstreamResolver) checkUpstreamFails() { case <-u.ctx.Done(): return default: - //todo test the deactivation logic, it seems to affect the client - //log.Warnf("upstream resolving is disabled for %v", reactivatePeriod) - //u.deactivate() - //u.disabled = true - //go u.waitUntilResponse() + // todo test the deactivation logic, it seems to affect the client + // log.Warnf("upstream resolving is disabled for %v", reactivatePeriod) + // u.deactivate() + // u.disabled = true + // go u.waitUntilResponse() } } From 1c23a0e70cacb609c7e8158c9e970b94451695ea Mon Sep 17 00:00:00 2001 From: Pascal Fischer Date: Tue, 7 Nov 2023 10:12:58 +0100 Subject: [PATCH 15/56] fix panic on no dns response --- client/internal/dns/upstream.go | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/client/internal/dns/upstream.go b/client/internal/dns/upstream.go index 0962e8a3a81..d5a74c3da6a 100644 --- a/client/internal/dns/upstream.go +++ b/client/internal/dns/upstream.go @@ -147,7 +147,6 @@ func (u *upstreamResolver) ServeDNS(w dns.ResponseWriter, r *dns.Msg) { rm, t, err = upstreamExchangeClient.ExchangeContext(ctx, r, upstream) cancel() } else { - log.Debugf("ios upstream resolver: %s", upstream) upstreamHost, _, err := net.SplitHostPort(upstream) if err != nil { log.Errorf("error while parsing upstream host: %s", err) @@ -172,9 +171,16 @@ func (u *upstreamResolver) ServeDNS(w dns.ResponseWriter, r *dns.Msg) { return } + if rm == nil { + log.WithError(err).WithField("upstream", upstream). + Warn("no response from upstream") + return + } + // those checks need to be independent of each other due to memory address issues if !rm.Response { log.WithError(err).WithField("upstream", upstream). Warn("no response from upstream") + return } log.Tracef("took %s to query the upstream %s", t, upstream) From 2b249ab9c9057cd4bb4414a4029794e063e9998e Mon Sep 17 00:00:00 2001 From: Pascal Fischer Date: Tue, 7 Nov 2023 15:52:19 +0100 Subject: [PATCH 16/56] fix after merge changes --- client/internal/connect.go | 10 ++--- client/internal/dns/notifier.go | 2 +- client/internal/dns/server.go | 1 + client/internal/listener/network_change.go | 3 +- client/internal/routemanager/notifier.go | 11 ++--- client/ios/NetBirdSDK/client.go | 48 +++++++++++----------- 6 files changed, 37 insertions(+), 38 deletions(-) diff --git a/client/internal/connect.go b/client/internal/connect.go index 747146d10ae..d4d17e30b74 100644 --- a/client/internal/connect.go +++ b/client/internal/connect.go @@ -43,12 +43,12 @@ func RunClientMobile(ctx context.Context, config *Config, statusRecorder *peer.S return runClient(ctx, config, statusRecorder, mobileDependency) } -func RunClientiOS(ctx context.Context, config *Config, statusRecorder *peer.Status, fileDescriptor int32, routeListener routemanager.RouteListener, dnsManager dns.IosDnsManager, interfaceName string) error { +func RunClientiOS(ctx context.Context, config *Config, statusRecorder *peer.Status, fileDescriptor int32, networkChangeListener listener.NetworkChangeListener, dnsManager dns.IosDnsManager, interfaceName string) error { mobileDependency := MobileDependency{ - FileDescriptor: fileDescriptor, - InterfaceName: interfaceName, - RouteListener: routeListener, - DnsManager: dnsManager, + FileDescriptor: fileDescriptor, + InterfaceName: interfaceName, + NetworkChangeListener: networkChangeListener, + DnsManager: dnsManager, } return runClient(ctx, config, statusRecorder, mobileDependency) } diff --git a/client/internal/dns/notifier.go b/client/internal/dns/notifier.go index 85c270e5859..35cb6ff8244 100644 --- a/client/internal/dns/notifier.go +++ b/client/internal/dns/notifier.go @@ -52,6 +52,6 @@ func (n *notifier) notify() { } go func(l listener.NetworkChangeListener) { - l.OnNetworkChanged() + l.OnNetworkChanged("") }(n.listener) } diff --git a/client/internal/dns/server.go b/client/internal/dns/server.go index 122aae7b5ad..185818ed56c 100644 --- a/client/internal/dns/server.go +++ b/client/internal/dns/server.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "net/netip" + "runtime" "sync" "github.com/miekg/dns" diff --git a/client/internal/listener/network_change.go b/client/internal/listener/network_change.go index ff9cb11f5a3..08bf5fd5230 100644 --- a/client/internal/listener/network_change.go +++ b/client/internal/listener/network_change.go @@ -3,5 +3,6 @@ package listener // NetworkChangeListener is a callback interface for mobile system type NetworkChangeListener interface { // OnNetworkChanged invoke when network settings has been changed - OnNetworkChanged() + OnNetworkChanged(string) + SetInterfaceIP(string) } diff --git a/client/internal/routemanager/notifier.go b/client/internal/routemanager/notifier.go index a10c76ac08c..6de1646f592 100644 --- a/client/internal/routemanager/notifier.go +++ b/client/internal/routemanager/notifier.go @@ -2,18 +2,15 @@ package routemanager import ( "sort" + "strings" "sync" + log "github.com/sirupsen/logrus" + + "github.com/netbirdio/netbird/client/internal/listener" "github.com/netbirdio/netbird/route" ) -// RouteListener is a callback interface for mobile system -// type RouteListener interface { -// // OnNewRouteSetting invoke when new route setting has been arrived -// OnNewRouteSetting(string) -// SetInterfaceIP(string) -// } - type notifier struct { initialRouteRangers []string routeRangers []string diff --git a/client/ios/NetBirdSDK/client.go b/client/ios/NetBirdSDK/client.go index c5580c8d652..8e46267d0b0 100644 --- a/client/ios/NetBirdSDK/client.go +++ b/client/ios/NetBirdSDK/client.go @@ -10,15 +10,15 @@ import ( "github.com/netbirdio/netbird/client/internal" "github.com/netbirdio/netbird/client/internal/auth" "github.com/netbirdio/netbird/client/internal/dns" + "github.com/netbirdio/netbird/client/internal/listener" "github.com/netbirdio/netbird/client/internal/peer" - "github.com/netbirdio/netbird/client/internal/routemanager" "github.com/netbirdio/netbird/client/system" "github.com/netbirdio/netbird/formatter" ) // RouteListener export internal RouteListener for mobile -type RouteListener interface { - routemanager.RouteListener +type NetworkChangeListener interface { + listener.NetworkChangeListener } // DnsManager export internal dns Manager for mobile @@ -39,30 +39,30 @@ func init() { // Client struct manage the life circle of background service type Client struct { - cfgFile string - recorder *peer.Status - ctxCancel context.CancelFunc - ctxCancelLock *sync.Mutex - deviceName string - osName string - osVersion string - routeListener routemanager.RouteListener - onHostDnsFn func([]string) - dnsManager dns.IosDnsManager - loginComplete bool + cfgFile string + recorder *peer.Status + ctxCancel context.CancelFunc + ctxCancelLock *sync.Mutex + deviceName string + osName string + osVersion string + networkChangeListener listener.NetworkChangeListener + onHostDnsFn func([]string) + dnsManager dns.IosDnsManager + loginComplete bool } // NewClient instantiate a new Client -func NewClient(cfgFile, deviceName string, osVersion string, osName string, routeListener RouteListener, dnsManager DnsManager) *Client { +func NewClient(cfgFile, deviceName string, osVersion string, osName string, networkChangeListener NetworkChangeListener, dnsManager DnsManager) *Client { return &Client{ - cfgFile: cfgFile, - deviceName: deviceName, - osName: osName, - osVersion: osVersion, - recorder: peer.NewRecorder(""), - ctxCancelLock: &sync.Mutex{}, - routeListener: routeListener, - dnsManager: dnsManager, + cfgFile: cfgFile, + deviceName: deviceName, + osName: osName, + osVersion: osVersion, + recorder: peer.NewRecorder(""), + ctxCancelLock: &sync.Mutex{}, + networkChangeListener: networkChangeListener, + dnsManager: dnsManager, } } @@ -98,7 +98,7 @@ func (c *Client) Run(fd int32, interfaceName string) error { // todo do not throw error in case of cancelled context ctx = internal.CtxInitState(ctx) c.onHostDnsFn = func([]string) {} - return internal.RunClientiOS(ctx, cfg, c.recorder, fd, c.routeListener, c.dnsManager, interfaceName) + return internal.RunClientiOS(ctx, cfg, c.recorder, fd, c.networkChangeListener, c.dnsManager, interfaceName) } // Stop the internal client and free the resources From 0a8249e0447b0d10a770343def43d8d70375f16e Mon Sep 17 00:00:00 2001 From: Pascal Fischer Date: Wed, 8 Nov 2023 16:37:56 +0100 Subject: [PATCH 17/56] add engine ready listener --- client/internal/connect.go | 8 +++++++- client/internal/listener/engine_ready.go | 7 +++++++ client/internal/mobile_dependency.go | 1 + client/ios/NetBirdSDK/client.go | 9 +++++++-- 4 files changed, 22 insertions(+), 3 deletions(-) create mode 100644 client/internal/listener/engine_ready.go diff --git a/client/internal/connect.go b/client/internal/connect.go index d4d17e30b74..c4840b4bbc9 100644 --- a/client/internal/connect.go +++ b/client/internal/connect.go @@ -3,6 +3,7 @@ package internal import ( "context" "fmt" + "runtime" "strings" "time" @@ -43,11 +44,12 @@ func RunClientMobile(ctx context.Context, config *Config, statusRecorder *peer.S return runClient(ctx, config, statusRecorder, mobileDependency) } -func RunClientiOS(ctx context.Context, config *Config, statusRecorder *peer.Status, fileDescriptor int32, networkChangeListener listener.NetworkChangeListener, dnsManager dns.IosDnsManager, interfaceName string) error { +func RunClientiOS(ctx context.Context, config *Config, statusRecorder *peer.Status, fileDescriptor int32, networkChangeListener listener.NetworkChangeListener, dnsManager dns.IosDnsManager, interfaceName string, engineReadyListener listener.EngineReadyListener) error { mobileDependency := MobileDependency{ FileDescriptor: fileDescriptor, InterfaceName: interfaceName, NetworkChangeListener: networkChangeListener, + EngineReadyListener: engineReadyListener, DnsManager: dnsManager, } return runClient(ctx, config, statusRecorder, mobileDependency) @@ -189,6 +191,10 @@ func runClient(ctx context.Context, config *Config, statusRecorder *peer.Status, return wrapErr(err) } + if runtime.GOOS == "ios" { + mobileDependency.EngineReadyListener.Notify() + } + log.Print("Netbird engine started, my IP is: ", peerConfig.Address) state.Set(StatusConnected) diff --git a/client/internal/listener/engine_ready.go b/client/internal/listener/engine_ready.go new file mode 100644 index 00000000000..760aa0e2fdd --- /dev/null +++ b/client/internal/listener/engine_ready.go @@ -0,0 +1,7 @@ +package listener + +// EngineReadyListener is a callback interface for mobile system +type EngineReadyListener interface { + // Notify invoke when engine is ready + Notify() +} diff --git a/client/internal/mobile_dependency.go b/client/internal/mobile_dependency.go index 0f762a5708e..874cbda4be8 100644 --- a/client/internal/mobile_dependency.go +++ b/client/internal/mobile_dependency.go @@ -12,6 +12,7 @@ type MobileDependency struct { TunAdapter iface.TunAdapter IFaceDiscover stdnet.ExternalIFaceDiscover NetworkChangeListener listener.NetworkChangeListener + EngineReadyListener listener.EngineReadyListener HostDNSAddresses []string DnsReadyListener dns.ReadyListener DnsManager dns.IosDnsManager diff --git a/client/ios/NetBirdSDK/client.go b/client/ios/NetBirdSDK/client.go index 8e46267d0b0..4b6351df682 100644 --- a/client/ios/NetBirdSDK/client.go +++ b/client/ios/NetBirdSDK/client.go @@ -33,6 +33,11 @@ type CustomLogger interface { Error(message string) } +// EngineReadyListener export internal EngineReadyListener for mobile +type EngineReadyListener interface { + listener.EngineReadyListener +} + func init() { formatter.SetLogcatFormatter(log.StandardLogger()) } @@ -67,7 +72,7 @@ func NewClient(cfgFile, deviceName string, osVersion string, osName string, netw } // Run start the internal client. It is a blocker function -func (c *Client) Run(fd int32, interfaceName string) error { +func (c *Client) Run(fd int32, interfaceName string, engineReadyListener EngineReadyListener) error { log.Infof("Starting NetBird client") log.Debugf("Tunnel uses interface: %s", interfaceName) cfg, err := internal.UpdateOrCreateConfig(internal.ConfigInput{ @@ -98,7 +103,7 @@ func (c *Client) Run(fd int32, interfaceName string) error { // todo do not throw error in case of cancelled context ctx = internal.CtxInitState(ctx) c.onHostDnsFn = func([]string) {} - return internal.RunClientiOS(ctx, cfg, c.recorder, fd, c.networkChangeListener, c.dnsManager, interfaceName) + return internal.RunClientiOS(ctx, cfg, c.recorder, fd, c.networkChangeListener, c.dnsManager, interfaceName, engineReadyListener) } // Stop the internal client and free the resources From a37c946abe865d3b7580c745207990e80574a5c7 Mon Sep 17 00:00:00 2001 From: Pascal Fischer Date: Thu, 9 Nov 2023 19:58:28 +0100 Subject: [PATCH 18/56] replace engine listener with connection listener --- client/internal/connect.go | 8 +------- client/internal/mobile_dependency.go | 1 - client/ios/NetBirdSDK/client.go | 24 +++++++++++++++--------- 3 files changed, 16 insertions(+), 17 deletions(-) diff --git a/client/internal/connect.go b/client/internal/connect.go index c4840b4bbc9..d4d17e30b74 100644 --- a/client/internal/connect.go +++ b/client/internal/connect.go @@ -3,7 +3,6 @@ package internal import ( "context" "fmt" - "runtime" "strings" "time" @@ -44,12 +43,11 @@ func RunClientMobile(ctx context.Context, config *Config, statusRecorder *peer.S return runClient(ctx, config, statusRecorder, mobileDependency) } -func RunClientiOS(ctx context.Context, config *Config, statusRecorder *peer.Status, fileDescriptor int32, networkChangeListener listener.NetworkChangeListener, dnsManager dns.IosDnsManager, interfaceName string, engineReadyListener listener.EngineReadyListener) error { +func RunClientiOS(ctx context.Context, config *Config, statusRecorder *peer.Status, fileDescriptor int32, networkChangeListener listener.NetworkChangeListener, dnsManager dns.IosDnsManager, interfaceName string) error { mobileDependency := MobileDependency{ FileDescriptor: fileDescriptor, InterfaceName: interfaceName, NetworkChangeListener: networkChangeListener, - EngineReadyListener: engineReadyListener, DnsManager: dnsManager, } return runClient(ctx, config, statusRecorder, mobileDependency) @@ -191,10 +189,6 @@ func runClient(ctx context.Context, config *Config, statusRecorder *peer.Status, return wrapErr(err) } - if runtime.GOOS == "ios" { - mobileDependency.EngineReadyListener.Notify() - } - log.Print("Netbird engine started, my IP is: ", peerConfig.Address) state.Set(StatusConnected) diff --git a/client/internal/mobile_dependency.go b/client/internal/mobile_dependency.go index 874cbda4be8..0f762a5708e 100644 --- a/client/internal/mobile_dependency.go +++ b/client/internal/mobile_dependency.go @@ -12,7 +12,6 @@ type MobileDependency struct { TunAdapter iface.TunAdapter IFaceDiscover stdnet.ExternalIFaceDiscover NetworkChangeListener listener.NetworkChangeListener - EngineReadyListener listener.EngineReadyListener HostDNSAddresses []string DnsReadyListener dns.ReadyListener DnsManager dns.IosDnsManager diff --git a/client/ios/NetBirdSDK/client.go b/client/ios/NetBirdSDK/client.go index 4b6351df682..4f0bddca7a4 100644 --- a/client/ios/NetBirdSDK/client.go +++ b/client/ios/NetBirdSDK/client.go @@ -16,6 +16,11 @@ import ( "github.com/netbirdio/netbird/formatter" ) +// ConnectionListener export internal Listener for mobile +type ConnectionListener interface { + peer.Listener +} + // RouteListener export internal RouteListener for mobile type NetworkChangeListener interface { listener.NetworkChangeListener @@ -33,11 +38,6 @@ type CustomLogger interface { Error(message string) } -// EngineReadyListener export internal EngineReadyListener for mobile -type EngineReadyListener interface { - listener.EngineReadyListener -} - func init() { formatter.SetLogcatFormatter(log.StandardLogger()) } @@ -72,7 +72,7 @@ func NewClient(cfgFile, deviceName string, osVersion string, osName string, netw } // Run start the internal client. It is a blocker function -func (c *Client) Run(fd int32, interfaceName string, engineReadyListener EngineReadyListener) error { +func (c *Client) Run(fd int32, interfaceName string) error { log.Infof("Starting NetBird client") log.Debugf("Tunnel uses interface: %s", interfaceName) cfg, err := internal.UpdateOrCreateConfig(internal.ConfigInput{ @@ -103,7 +103,7 @@ func (c *Client) Run(fd int32, interfaceName string, engineReadyListener EngineR // todo do not throw error in case of cancelled context ctx = internal.CtxInitState(ctx) c.onHostDnsFn = func([]string) {} - return internal.RunClientiOS(ctx, cfg, c.recorder, fd, c.networkChangeListener, c.dnsManager, interfaceName, engineReadyListener) + return internal.RunClientiOS(ctx, cfg, c.recorder, fd, c.networkChangeListener, c.dnsManager, interfaceName) } // Stop the internal client and free the resources @@ -139,8 +139,14 @@ func (c *Client) GetStatusDetails() *StatusDetails { return &StatusDetails{items: peerInfos, fqdn: fullStatus.LocalPeerState.FQDN, ip: fullStatus.LocalPeerState.IP} } -func (c *Client) GetManagementStatus() bool { - return c.recorder.GetFullStatus().ManagementState.Connected +// SetConnectionListener set the network connection listener +func (c *Client) SetConnectionListener(listener ConnectionListener) { + c.recorder.SetConnectionListener(listener) +} + +// RemoveConnectionListener remove connection listener +func (c *Client) RemoveConnectionListener() { + c.recorder.RemoveConnectionListener() } func (c *Client) IsLoginRequired() bool { From b2300216bbe6c7f6091a754bd87ebeb822a911e9 Mon Sep 17 00:00:00 2001 From: Pascal Fischer Date: Thu, 16 Nov 2023 13:37:34 +0100 Subject: [PATCH 19/56] disable relay connection for iOS until proxy is refactored into bind --- client/internal/peer/conn.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/client/internal/peer/conn.go b/client/internal/peer/conn.go index 9247ed3c55f..db43c6ca19c 100644 --- a/client/internal/peer/conn.go +++ b/client/internal/peer/conn.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "net" + "runtime" "strings" "sync" "time" @@ -225,6 +226,10 @@ func (conn *Conn) candidateTypes() []ice.CandidateType { if hasICEForceRelayConn() { return []ice.CandidateType{ice.CandidateTypeRelay} } + // TODO: remove this once we have refactored userspace proxy into the bind package + if runtime.GOOS == "ios" { + return []ice.CandidateType{ice.CandidateTypeHost, ice.CandidateTypeServerReflexive} + } return []ice.CandidateType{ice.CandidateTypeHost, ice.CandidateTypeServerReflexive, ice.CandidateTypeRelay} } @@ -464,7 +469,7 @@ func (conn *Conn) cleanup() error { err := conn.statusRecorder.UpdatePeerState(peerState) if err != nil { // pretty common error because by that time Engine can already remove the peer and status won't be available. - //todo rethink status updates + // todo rethink status updates log.Debugf("error while updating peer's %s state, err: %v", conn.config.Key, err) } From ad1cf388fb4a0e16e74add310b3b2cbc73d4f42e Mon Sep 17 00:00:00 2001 From: Pascal Fischer Date: Wed, 6 Dec 2023 12:08:12 +0100 Subject: [PATCH 20/56] Extract private upstream for iOS and fix function headers for other OS --- client/internal/dns/file_linux.go | 2 +- client/internal/dns/host_android.go | 2 +- client/internal/dns/host_darwin.go | 2 +- client/internal/dns/host_linux.go | 2 +- client/internal/dns/host_windows.go | 2 +- client/internal/dns/upstream.go | 34 -------------------- client/internal/dns/upstream_ios.go | 44 ++++++++++++++++++++++++++ client/internal/dns/upstream_nonios.go | 19 +++++++++++ 8 files changed, 68 insertions(+), 39 deletions(-) create mode 100644 client/internal/dns/upstream_ios.go create mode 100644 client/internal/dns/upstream_nonios.go diff --git a/client/internal/dns/file_linux.go b/client/internal/dns/file_linux.go index 67128f79a96..5a2ef9da91b 100644 --- a/client/internal/dns/file_linux.go +++ b/client/internal/dns/file_linux.go @@ -138,7 +138,7 @@ func prepareResolvConfContent(searchDomains, nameServers, others []string) bytes return buf } -func searchDomains(config hostDNSConfig) []string { +func searchDomains(config HostDNSConfig) []string { listOfDomains := make([]string, 0) for _, dConf := range config.domains { if dConf.matchOnly || dConf.disabled { diff --git a/client/internal/dns/host_android.go b/client/internal/dns/host_android.go index 169cc7c4726..624d42dfb30 100644 --- a/client/internal/dns/host_android.go +++ b/client/internal/dns/host_android.go @@ -3,7 +3,7 @@ package dns type androidHostManager struct { } -func newHostManager(wgInterface WGIface) (hostManager, error) { +func newHostManager(wgInterface WGIface, dnsManager IosDnsManager) (hostManager, error) { return &androidHostManager{}, nil } diff --git a/client/internal/dns/host_darwin.go b/client/internal/dns/host_darwin.go index c0a21361118..a3ab9e6d378 100644 --- a/client/internal/dns/host_darwin.go +++ b/client/internal/dns/host_darwin.go @@ -34,7 +34,7 @@ type systemConfigurator struct { createdKeys map[string]struct{} } -func newHostManager(_ WGIface) (hostManager, error) { +func newHostManager(_ WGIface, dnsManager IosDnsManager) (hostManager, error) { return &systemConfigurator{ createdKeys: make(map[string]struct{}), }, nil diff --git a/client/internal/dns/host_linux.go b/client/internal/dns/host_linux.go index 7838c988fb9..763ff48c86f 100644 --- a/client/internal/dns/host_linux.go +++ b/client/internal/dns/host_linux.go @@ -25,7 +25,7 @@ const ( type osManagerType int -func newHostManager(wgInterface WGIface) (hostManager, error) { +func newHostManager(wgInterface WGIface, dnsManager IosDnsManager) (hostManager, error) { osManager, err := getOSDNSManagerType() if err != nil { return nil, err diff --git a/client/internal/dns/host_windows.go b/client/internal/dns/host_windows.go index 1e88a6c7bb9..52da1a0b1ff 100644 --- a/client/internal/dns/host_windows.go +++ b/client/internal/dns/host_windows.go @@ -29,7 +29,7 @@ type registryConfigurator struct { routingAll bool } -func newHostManager(wgInterface WGIface) (hostManager, error) { +func newHostManager(wgInterface WGIface, dnsManager IosDnsManager) (hostManager, error) { guid, err := wgInterface.GetInterfaceGUIDString() if err != nil { return nil, err diff --git a/client/internal/dns/upstream.go b/client/internal/dns/upstream.go index b93dd5bb479..112212b8a1f 100644 --- a/client/internal/dns/upstream.go +++ b/client/internal/dns/upstream.go @@ -8,13 +8,11 @@ import ( "runtime" "sync" "sync/atomic" - "syscall" "time" "github.com/cenkalti/backoff/v4" "github.com/miekg/dns" log "github.com/sirupsen/logrus" - "golang.org/x/sys/unix" ) const ( @@ -85,38 +83,6 @@ func newUpstreamResolver(parentCTX context.Context, interfaceName string, wgAddr } } -// getClientPrivate returns a new DNS client bound to the local IP address of the Netbird interface -// This method is needed for iOS -func (u *upstreamResolver) getClientPrivate() *dns.Client { - dialer := &net.Dialer{ - LocalAddr: &net.UDPAddr{ - IP: u.lIP, - Port: 0, // Let the OS pick a free port - }, - Timeout: upstreamTimeout, - Control: func(network, address string, c syscall.RawConn) error { - var operr error - fn := func(s uintptr) { - operr = unix.SetsockoptInt(int(s), unix.IPPROTO_IP, unix.IP_BOUND_IF, u.iIndex) - } - - if err := c.Control(fn); err != nil { - return err - } - - if operr != nil { - log.Errorf("error while setting socket option: %s", operr) - } - - return operr - }, - } - client := &dns.Client{ - Dialer: dialer, - } - return client -} - func (u *upstreamResolver) stop() { log.Debugf("stopping serving DNS for upstreams %s", u.upstreamServers) u.cancel() diff --git a/client/internal/dns/upstream_ios.go b/client/internal/dns/upstream_ios.go new file mode 100644 index 00000000000..a2dd31ef2ad --- /dev/null +++ b/client/internal/dns/upstream_ios.go @@ -0,0 +1,44 @@ +//go:build ios + +package dns + +import ( + "net" + "syscall" + + "github.com/miekg/dns" + log "github.com/sirupsen/logrus" + "golang.org/x/sys/unix" +) + +// getClientPrivate returns a new DNS client bound to the local IP address of the Netbird interface +// This method is needed for iOS +func (u *upstreamResolver) getClientPrivate() *dns.Client { + dialer := &net.Dialer{ + LocalAddr: &net.UDPAddr{ + IP: u.lIP, + Port: 0, // Let the OS pick a free port + }, + Timeout: upstreamTimeout, + Control: func(network, address string, c syscall.RawConn) error { + var operr error + fn := func(s uintptr) { + operr = unix.SetsockoptInt(int(s), unix.IPPROTO_IP, unix.IP_BOUND_IF, u.iIndex) + } + + if err := c.Control(fn); err != nil { + return err + } + + if operr != nil { + log.Errorf("error while setting socket option: %s", operr) + } + + return operr + }, + } + client := &dns.Client{ + Dialer: dialer, + } + return client +} diff --git a/client/internal/dns/upstream_nonios.go b/client/internal/dns/upstream_nonios.go new file mode 100644 index 00000000000..a2a541489cd --- /dev/null +++ b/client/internal/dns/upstream_nonios.go @@ -0,0 +1,19 @@ +//go:build !ios + +package dns + +import ( + "net" + + "github.com/miekg/dns" +) + +// getClientPrivate returns a new DNS client bound to the local IP address of the Netbird interface +// This method is needed for iOS +func (u *upstreamResolver) getClientPrivate() *dns.Client { + dialer := &net.Dialer{} + client := &dns.Client{ + Dialer: dialer, + } + return client +} From e03c07a3dc7fe05dd53233fb5c2333bc67185612 Mon Sep 17 00:00:00 2001 From: Pascal Fischer Date: Wed, 6 Dec 2023 12:24:58 +0100 Subject: [PATCH 21/56] Update mock Server --- client/internal/dns/mockServer.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/internal/dns/mockServer.go b/client/internal/dns/mockServer.go index 3534fc0c3fd..23fa7e83051 100644 --- a/client/internal/dns/mockServer.go +++ b/client/internal/dns/mockServer.go @@ -14,7 +14,7 @@ type MockServer struct { } // Initialize mock implementation of Initialize from Server interface -func (m *MockServer) Initialize() error { +func (m *MockServer) Initialize(manager IosDnsManager) error { if m.InitializeFunc != nil { return m.InitializeFunc() } @@ -33,7 +33,7 @@ func (m *MockServer) DnsIP() string { } func (m *MockServer) OnUpdatedHostDNSServer(strings []string) { - //TODO implement me + // TODO implement me panic("implement me") } From 975e8e816a2e0adb9782be1761268588f496b34c Mon Sep 17 00:00:00 2001 From: Pascal Fischer Date: Wed, 6 Dec 2023 12:46:45 +0100 Subject: [PATCH 22/56] Fix dns server and upstream tests --- client/internal/dns/server_test.go | 16 ++++++++-------- client/internal/dns/upstream_test.go | 10 +++++----- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/client/internal/dns/server_test.go b/client/internal/dns/server_test.go index 031543d8015..57dff07bd07 100644 --- a/client/internal/dns/server_test.go +++ b/client/internal/dns/server_test.go @@ -268,11 +268,11 @@ func TestUpdateDNSServer(t *testing.T) { t.Log(err) } }() - dnsServer, err := NewDefaultServer(context.Background(), wgIface, "") + dnsServer, err := NewDefaultServer(context.Background(), wgIface, "", "", "") if err != nil { t.Fatal(err) } - err = dnsServer.Initialize() + err = dnsServer.Initialize(nil) if err != nil { t.Fatal(err) } @@ -368,13 +368,13 @@ func TestDNSFakeResolverHandleUpdates(t *testing.T) { return } - dnsServer, err := NewDefaultServer(context.Background(), wgIface, "") + dnsServer, err := NewDefaultServer(context.Background(), wgIface, "", "", "") if err != nil { t.Errorf("create DNS server: %v", err) return } - err = dnsServer.Initialize() + err = dnsServer.Initialize(nil) if err != nil { t.Errorf("run DNS server: %v", err) return @@ -463,7 +463,7 @@ func TestDNSServerStartStop(t *testing.T) { for _, testCase := range testCases { t.Run(testCase.name, func(t *testing.T) { - dnsServer, err := NewDefaultServer(context.Background(), &mocWGIface{}, testCase.addrPort) + dnsServer, err := NewDefaultServer(context.Background(), &mocWGIface{}, testCase.addrPort, "", "") if err != nil { t.Fatalf("%v", err) } @@ -595,7 +595,7 @@ func TestDNSPermanent_updateHostDNS_emptyUpstream(t *testing.T) { var dnsList []string dnsConfig := nbdns.Config{} dnsServer := NewDefaultServerPermanentUpstream(context.Background(), wgIFace, dnsList, dnsConfig, nil) - err = dnsServer.Initialize() + err = dnsServer.Initialize(nil) if err != nil { t.Errorf("failed to initialize DNS server: %v", err) return @@ -619,7 +619,7 @@ func TestDNSPermanent_updateUpstream(t *testing.T) { defer wgIFace.Close() dnsConfig := nbdns.Config{} dnsServer := NewDefaultServerPermanentUpstream(context.Background(), wgIFace, []string{"8.8.8.8"}, dnsConfig, nil) - err = dnsServer.Initialize() + err = dnsServer.Initialize(nil) if err != nil { t.Errorf("failed to initialize DNS server: %v", err) return @@ -711,7 +711,7 @@ func TestDNSPermanent_matchOnly(t *testing.T) { defer wgIFace.Close() dnsConfig := nbdns.Config{} dnsServer := NewDefaultServerPermanentUpstream(context.Background(), wgIFace, []string{"8.8.8.8"}, dnsConfig, nil) - err = dnsServer.Initialize() + err = dnsServer.Initialize(nil) if err != nil { t.Errorf("failed to initialize DNS server: %v", err) return diff --git a/client/internal/dns/upstream_test.go b/client/internal/dns/upstream_test.go index 0a5de0b18ea..f29bc21a53d 100644 --- a/client/internal/dns/upstream_test.go +++ b/client/internal/dns/upstream_test.go @@ -49,15 +49,15 @@ func TestUpstreamResolver_ServeDNS(t *testing.T) { timeout: upstreamTimeout, responseShouldBeNil: true, }, - //{ + // { // name: "Should Resolve CNAME Record", // inputMSG: new(dns.Msg).SetQuestion("one.one.one.one", dns.TypeCNAME), - //}, - //{ + // }, + // { // name: "Should Not Write When Not Found A Record", // inputMSG: new(dns.Msg).SetQuestion("not.found.com", dns.TypeA), // responseShouldBeNil: true, - //}, + // }, } // should resolve if first upstream times out // should not write when both fails @@ -66,7 +66,7 @@ func TestUpstreamResolver_ServeDNS(t *testing.T) { for _, testCase := range testCases { t.Run(testCase.name, func(t *testing.T) { ctx, cancel := context.WithCancel(context.TODO()) - resolver := newUpstreamResolver(ctx) + resolver := newUpstreamResolver(ctx, "", "") resolver.upstreamServers = testCase.InputServers resolver.upstreamTimeout = testCase.timeout if testCase.cancelCTX { From 71f1cf80b8c3fedf714df07e7e8fb4ec3d8b575c Mon Sep 17 00:00:00 2001 From: Pascal Fischer Date: Wed, 6 Dec 2023 13:02:32 +0100 Subject: [PATCH 23/56] Fix engine null pointer with mobile dependencies for other OS --- client/internal/engine.go | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/client/internal/engine.go b/client/internal/engine.go index c1258e6ac0a..41e1ceabe98 100644 --- a/client/internal/engine.go +++ b/client/internal/engine.go @@ -205,15 +205,14 @@ func (e *Engine) Start() error { go e.mobileDep.DnsReadyListener.OnReady() } } else if e.dnsServer == nil { - e.dnsServer, err = dns.NewDefaultServer(e.ctx, e.wgInterface, e.config.CustomDNSAddress, e.mobileDep.InterfaceName, wgAddr) - if err != nil { - e.close() - return err - } - } + e.dnsServer, err = dns.NewDefaultServer(e.ctx, e.wgInterface, e.config.CustomDNSAddress, e.mobileDep.InterfaceName, wgAddr) + if err != nil { + e.close() + return err + } + } e.routeManager = routemanager.NewManager(e.ctx, e.config.WgPrivateKey.PublicKey().String(), e.wgInterface, e.statusRecorder, routes) - e.mobileDep.NetworkChangeListener.SetInterfaceIP(wgAddr) e.routeManager.SetRouteChangeListener(e.mobileDep.NetworkChangeListener) switch runtime.GOOS { @@ -224,6 +223,7 @@ func (e *Engine) Start() error { SearchDomains: e.dnsServer.SearchDomains(), }) case "ios": + e.mobileDep.NetworkChangeListener.SetInterfaceIP(wgAddr) err = e.wgInterface.CreateOniOS(e.mobileDep.FileDescriptor) default: err = e.wgInterface.Create() From 0f7343dd5810c0bd1e451cb1199c6ca5c5cc75f9 Mon Sep 17 00:00:00 2001 From: Pascal Fischer Date: Wed, 6 Dec 2023 13:22:40 +0100 Subject: [PATCH 24/56] Revert back to disabling upstream on no response --- client/internal/dns/upstream.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/client/internal/dns/upstream.go b/client/internal/dns/upstream.go index 112212b8a1f..dec6ff34da5 100644 --- a/client/internal/dns/upstream.go +++ b/client/internal/dns/upstream.go @@ -181,10 +181,10 @@ func (u *upstreamResolver) checkUpstreamFails() { return default: // todo test the deactivation logic, it seems to affect the client - // log.Warnf("upstream resolving is disabled for %v", reactivatePeriod) - // u.deactivate() - // u.disabled = true - // go u.waitUntilResponse() + log.Warnf("upstream resolving is disabled for %v", reactivatePeriod) + u.deactivate() + u.disabled = true + go u.waitUntilResponse() } } From 5f3f5dc1c61eb6146c150ba2a535a1380599d318 Mon Sep 17 00:00:00 2001 From: Pascal Fischer Date: Wed, 6 Dec 2023 14:01:57 +0100 Subject: [PATCH 25/56] Fix some of the remarks from the linter --- client/ios/NetBirdSDK/client.go | 8 ++++++++ client/ios/NetBirdSDK/logger.go | 8 +------- client/ios/NetBirdSDK/login.go | 25 ----------------------- client/ios/NetBirdSDK/preferences_test.go | 8 ++++---- client/system/info.go | 18 ---------------- client/system/info_ios.go | 18 ++++++++++++++++ 6 files changed, 31 insertions(+), 54 deletions(-) diff --git a/client/ios/NetBirdSDK/client.go b/client/ios/NetBirdSDK/client.go index 4f0bddca7a4..ef61eee3fcb 100644 --- a/client/ios/NetBirdSDK/client.go +++ b/client/ios/NetBirdSDK/client.go @@ -86,7 +86,9 @@ func (c *Client) Run(fd int32, interfaceName string) error { var ctx context.Context //nolint ctxWithValues := context.WithValue(context.Background(), system.DeviceNameCtxKey, c.deviceName) + //nolint ctxWithValues = context.WithValue(ctxWithValues, system.OsNameCtxKey, c.osName) + //nolint ctxWithValues = context.WithValue(ctxWithValues, system.OsVersionCtxKey, c.osVersion) c.ctxCancelLock.Lock() ctx, c.ctxCancel = context.WithCancel(ctxWithValues) @@ -151,8 +153,11 @@ func (c *Client) RemoveConnectionListener() { func (c *Client) IsLoginRequired() bool { var ctx context.Context + //nolint ctxWithValues := context.WithValue(context.Background(), system.DeviceNameCtxKey, c.deviceName) + //nolint ctxWithValues = context.WithValue(ctxWithValues, system.OsNameCtxKey, c.osName) + //nolint ctxWithValues = context.WithValue(ctxWithValues, system.OsVersionCtxKey, c.osVersion) c.ctxCancelLock.Lock() defer c.ctxCancelLock.Unlock() @@ -168,8 +173,11 @@ func (c *Client) IsLoginRequired() bool { func (c *Client) LoginForMobile() string { var ctx context.Context + //nolint ctxWithValues := context.WithValue(context.Background(), system.DeviceNameCtxKey, c.deviceName) + //nolint ctxWithValues = context.WithValue(ctxWithValues, system.OsNameCtxKey, c.osName) + //nolint ctxWithValues = context.WithValue(ctxWithValues, system.OsVersionCtxKey, c.osVersion) c.ctxCancelLock.Lock() defer c.ctxCancelLock.Unlock() diff --git a/client/ios/NetBirdSDK/logger.go b/client/ios/NetBirdSDK/logger.go index 674e296fb36..f1ad1b9f6a6 100644 --- a/client/ios/NetBirdSDK/logger.go +++ b/client/ios/NetBirdSDK/logger.go @@ -1,16 +1,10 @@ package NetBirdSDK import ( - "os" - "github.com/netbirdio/netbird/util" ) -var logFile *os.File - // InitializeLog initializes the log file. func InitializeLog(logLevel string, filePath string) error { - var err error - err = util.InitLog(logLevel, filePath) - return err + return util.InitLog(logLevel, filePath) } diff --git a/client/ios/NetBirdSDK/login.go b/client/ios/NetBirdSDK/login.go index 50a0425387d..257329e5c9f 100644 --- a/client/ios/NetBirdSDK/login.go +++ b/client/ios/NetBirdSDK/login.go @@ -12,7 +12,6 @@ import ( "github.com/netbirdio/netbird/client/cmd" "github.com/netbirdio/netbird/client/internal" - "github.com/netbirdio/netbird/client/internal/auth" "github.com/netbirdio/netbird/client/system" ) @@ -150,30 +149,6 @@ func (a *Auth) Login() error { return nil } -func (a *Auth) foregroundGetTokenInfo(urlOpener URLOpener) (*auth.TokenInfo, error) { - oAuthFlow, err := auth.NewOAuthFlow(a.ctx, a.config, false) - if err != nil { - return nil, err - } - - flowInfo, err := oAuthFlow.RequestAuthInfo(context.TODO()) - if err != nil { - return nil, fmt.Errorf("getting a request OAuth flow info failed: %v", err) - } - - go urlOpener.Open(flowInfo.VerificationURIComplete) - - waitTimeout := time.Duration(flowInfo.ExpiresIn) - waitCTX, cancel := context.WithTimeout(a.ctx, waitTimeout*time.Second) - defer cancel() - tokenInfo, err := oAuthFlow.WaitToken(waitCTX, flowInfo) - if err != nil { - return nil, fmt.Errorf("waiting for browser login failed: %v", err) - } - - return &tokenInfo, nil -} - func (a *Auth) withBackOff(ctx context.Context, bf func() error) error { return backoff.RetryNotify( bf, diff --git a/client/ios/NetBirdSDK/preferences_test.go b/client/ios/NetBirdSDK/preferences_test.go index bb4531b6141..aa6a475aeab 100644 --- a/client/ios/NetBirdSDK/preferences_test.go +++ b/client/ios/NetBirdSDK/preferences_test.go @@ -57,11 +57,11 @@ func TestPreferences_ReadUncommitedValues(t *testing.T) { p.SetManagementURL(exampleString) resp, err = p.GetManagementURL() if err != nil { - t.Fatalf("failed to read managmenet url: %s", err) + t.Fatalf("failed to read management url: %s", err) } if resp != exampleString { - t.Errorf("unexpected managemenet url: %s", resp) + t.Errorf("unexpected management url: %s", resp) } p.SetPreSharedKey(exampleString) @@ -102,11 +102,11 @@ func TestPreferences_Commit(t *testing.T) { resp, err = p.GetManagementURL() if err != nil { - t.Fatalf("failed to read managmenet url: %s", err) + t.Fatalf("failed to read management url: %s", err) } if resp != exampleURL { - t.Errorf("unexpected managemenet url: %s", resp) + t.Errorf("unexpected management url: %s", resp) } resp, err = p.GetPreSharedKey() diff --git a/client/system/info.go b/client/system/info.go index b6254ef476c..2d5b7192ece 100644 --- a/client/system/info.go +++ b/client/system/info.go @@ -58,24 +58,6 @@ func extractDeviceName(ctx context.Context, defaultName string) string { return v } -// extractOsVersion extracts operating system version from context or returns the default -func extractOsVersion(ctx context.Context, defaultName string) string { - v, ok := ctx.Value(OsVersionCtxKey).(string) - if !ok { - return defaultName - } - return v -} - -// extractOsName extracts operating system name from context or returns the default -func extractOsName(ctx context.Context, defaultName string) string { - v, ok := ctx.Value(OsNameCtxKey).(string) - if !ok { - return defaultName - } - return v -} - // GetDesktopUIUserAgent returns the Desktop ui user agent func GetDesktopUIUserAgent() string { return "netbird-desktop-ui/" + version.NetbirdVersion() diff --git a/client/system/info_ios.go b/client/system/info_ios.go index 762117afa6b..1a1203f79c9 100644 --- a/client/system/info_ios.go +++ b/client/system/info_ios.go @@ -25,3 +25,21 @@ func GetInfo(ctx context.Context) *Info { return gio } + +// extractOsVersion extracts operating system version from context or returns the default +func extractOsVersion(ctx context.Context, defaultName string) string { + v, ok := ctx.Value(OsVersionCtxKey).(string) + if !ok { + return defaultName + } + return v +} + +// extractOsName extracts operating system name from context or returns the default +func extractOsName(ctx context.Context, defaultName string) string { + v, ok := ctx.Value(OsNameCtxKey).(string) + if !ok { + return defaultName + } + return v +} From d6d2e642475db8297dd8502e313dff5462a3dded Mon Sep 17 00:00:00 2001 From: Pascal Fischer Date: Wed, 6 Dec 2023 14:53:42 +0100 Subject: [PATCH 26/56] Fix linter --- client/internal/dns/upstream.go | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/client/internal/dns/upstream.go b/client/internal/dns/upstream.go index dec6ff34da5..318890621bb 100644 --- a/client/internal/dns/upstream.go +++ b/client/internal/dns/upstream.go @@ -102,56 +102,57 @@ func (u *upstreamResolver) ServeDNS(w dns.ResponseWriter, r *dns.Msg) { for _, upstream := range u.upstreamServers { var ( - err error - t time.Duration - rm *dns.Msg + exchangeErr error + t time.Duration + rm *dns.Msg ) upstreamExchangeClient := &dns.Client{} if runtime.GOOS != "ios" { ctx, cancel := context.WithTimeout(u.ctx, u.upstreamTimeout) - rm, t, err = upstreamExchangeClient.ExchangeContext(ctx, r, upstream) + rm, t, exchangeErr = upstreamExchangeClient.ExchangeContext(ctx, r, upstream) cancel() } else { upstreamHost, _, err := net.SplitHostPort(upstream) if err != nil { log.Errorf("error while parsing upstream host: %s", err) + return } upstreamIP := net.ParseIP(upstreamHost) if u.lNet.Contains(upstreamIP) || net.IP.IsPrivate(upstreamIP) { log.Debugf("using private client to query upstream: %s", upstream) upstreamExchangeClient = u.getClientPrivate() } - rm, t, err = upstreamExchangeClient.Exchange(r, upstream) + rm, t, exchangeErr = upstreamExchangeClient.Exchange(r, upstream) } - if err != nil { - if err == context.DeadlineExceeded || isTimeout(err) { - log.WithError(err).WithField("upstream", upstream). + if exchangeErr != nil { + if exchangeErr == context.DeadlineExceeded || isTimeout(exchangeErr) { + log.WithError(exchangeErr).WithField("upstream", upstream). Warn("got an error while connecting to upstream") continue } u.failsCount.Add(1) - log.WithError(err).WithField("upstream", upstream). + log.WithError(exchangeErr).WithField("upstream", upstream). Error("got other error while querying the upstream") return } if rm == nil { - log.WithError(err).WithField("upstream", upstream). + log.WithError(exchangeErr).WithField("upstream", upstream). Warn("no response from upstream") return } // those checks need to be independent of each other due to memory address issues if !rm.Response { - log.WithError(err).WithField("upstream", upstream). + log.WithError(exchangeErr).WithField("upstream", upstream). Warn("no response from upstream") return } log.Tracef("took %s to query the upstream %s", t, upstream) - err = w.WriteMsg(rm) + err := w.WriteMsg(rm) if err != nil { log.WithError(err).Error("got an error while writing the upstream resolver response") } From f854ec9bb667eedeee4ab1246981a0a0e53f3a80 Mon Sep 17 00:00:00 2001 From: Pascal Fischer Date: Wed, 6 Dec 2023 15:46:38 +0100 Subject: [PATCH 27/56] re-arrange duration calculation --- client/ios/NetBirdSDK/client.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/ios/NetBirdSDK/client.go b/client/ios/NetBirdSDK/client.go index ef61eee3fcb..eae2fc7b44b 100644 --- a/client/ios/NetBirdSDK/client.go +++ b/client/ios/NetBirdSDK/client.go @@ -199,8 +199,8 @@ func (c *Client) LoginForMobile() string { // This could cause a potential race condition with loading the extension which need to be handled on swift side go func() { - waitTimeout := time.Duration(flowInfo.ExpiresIn) - waitCTX, cancel := context.WithTimeout(ctx, waitTimeout*time.Second) + waitTimeout := time.Duration(flowInfo.ExpiresIn) * time.Second + waitCTX, cancel := context.WithTimeout(ctx, waitTimeout) defer cancel() tokenInfo, err := oAuthFlow.WaitToken(waitCTX, flowInfo) if err != nil { From c88e8139c795cc57149e282fc93e391d5a51e117 Mon Sep 17 00:00:00 2001 From: Pascal Fischer Date: Wed, 6 Dec 2023 16:13:31 +0100 Subject: [PATCH 28/56] revert exported HostDNSConfig --- client/internal/dns/file_linux.go | 4 ++-- client/internal/dns/host.go | 14 +++++++------- client/internal/dns/host_android.go | 2 +- client/internal/dns/host_darwin.go | 2 +- client/internal/dns/host_ios.go | 4 ++-- client/internal/dns/host_windows.go | 2 +- client/internal/dns/network_manager_linux.go | 5 +++-- client/internal/dns/resolvconf_linux.go | 2 +- client/internal/dns/server.go | 6 +++--- client/internal/dns/server_test.go | 4 ++-- client/internal/dns/systemd_linux.go | 2 +- 11 files changed, 24 insertions(+), 23 deletions(-) diff --git a/client/internal/dns/file_linux.go b/client/internal/dns/file_linux.go index 5a2ef9da91b..81b16459bc9 100644 --- a/client/internal/dns/file_linux.go +++ b/client/internal/dns/file_linux.go @@ -35,7 +35,7 @@ func (f *fileConfigurator) supportCustomPort() bool { return false } -func (f *fileConfigurator) applyDNSConfig(config HostDNSConfig) error { +func (f *fileConfigurator) applyDNSConfig(config hostDNSConfig) error { backupFileExist := false _, err := os.Stat(fileDefaultResolvConfBackupLocation) if err == nil { @@ -138,7 +138,7 @@ func prepareResolvConfContent(searchDomains, nameServers, others []string) bytes return buf } -func searchDomains(config HostDNSConfig) []string { +func searchDomains(config hostDNSConfig) []string { listOfDomains := make([]string, 0) for _, dConf := range config.domains { if dConf.matchOnly || dConf.disabled { diff --git a/client/internal/dns/host.go b/client/internal/dns/host.go index 34a0769a24b..05460c13c47 100644 --- a/client/internal/dns/host.go +++ b/client/internal/dns/host.go @@ -8,12 +8,12 @@ import ( ) type hostManager interface { - applyDNSConfig(config HostDNSConfig) error + applyDNSConfig(config hostDNSConfig) error restoreHostDNS() error supportCustomPort() bool } -type HostDNSConfig struct { +type hostDNSConfig struct { domains []domainConfig routeAll bool serverIP string @@ -27,12 +27,12 @@ type domainConfig struct { } type mockHostConfigurator struct { - applyDNSConfigFunc func(config HostDNSConfig) error + applyDNSConfigFunc func(config hostDNSConfig) error restoreHostDNSFunc func() error supportCustomPortFunc func() bool } -func (m *mockHostConfigurator) applyDNSConfig(config HostDNSConfig) error { +func (m *mockHostConfigurator) applyDNSConfig(config hostDNSConfig) error { if m.applyDNSConfigFunc != nil { return m.applyDNSConfigFunc(config) } @@ -55,14 +55,14 @@ func (m *mockHostConfigurator) supportCustomPort() bool { func newNoopHostMocker() hostManager { return &mockHostConfigurator{ - applyDNSConfigFunc: func(config HostDNSConfig) error { return nil }, + applyDNSConfigFunc: func(config hostDNSConfig) error { return nil }, restoreHostDNSFunc: func() error { return nil }, supportCustomPortFunc: func() bool { return true }, } } -func dnsConfigToHostDNSConfig(dnsConfig nbdns.Config, ip string, port int) HostDNSConfig { - config := HostDNSConfig{ +func dnsConfigTohostDNSConfig(dnsConfig nbdns.Config, ip string, port int) hostDNSConfig { + config := hostDNSConfig{ routeAll: false, serverIP: ip, serverPort: port, diff --git a/client/internal/dns/host_android.go b/client/internal/dns/host_android.go index 624d42dfb30..3bd72aa87bb 100644 --- a/client/internal/dns/host_android.go +++ b/client/internal/dns/host_android.go @@ -7,7 +7,7 @@ func newHostManager(wgInterface WGIface, dnsManager IosDnsManager) (hostManager, return &androidHostManager{}, nil } -func (a androidHostManager) applyDNSConfig(config HostDNSConfig) error { +func (a androidHostManager) applyDNSConfig(config hostDNSConfig) error { return nil } diff --git a/client/internal/dns/host_darwin.go b/client/internal/dns/host_darwin.go index a3ab9e6d378..2acb29fc8d7 100644 --- a/client/internal/dns/host_darwin.go +++ b/client/internal/dns/host_darwin.go @@ -44,7 +44,7 @@ func (s *systemConfigurator) supportCustomPort() bool { return true } -func (s *systemConfigurator) applyDNSConfig(config HostDNSConfig) error { +func (s *systemConfigurator) applyDNSConfig(config hostDNSConfig) error { var err error if config.routeAll { diff --git a/client/internal/dns/host_ios.go b/client/internal/dns/host_ios.go index fa143dc7a63..7659d458a72 100644 --- a/client/internal/dns/host_ios.go +++ b/client/internal/dns/host_ios.go @@ -9,7 +9,7 @@ import ( type iosHostManager struct { dnsManager IosDnsManager - config HostDNSConfig + config hostDNSConfig } func newHostManager(wgInterface WGIface, dnsManager IosDnsManager) (hostManager, error) { @@ -18,7 +18,7 @@ func newHostManager(wgInterface WGIface, dnsManager IosDnsManager) (hostManager, }, nil } -func (a iosHostManager) applyDNSConfig(config HostDNSConfig) error { +func (a iosHostManager) applyDNSConfig(config hostDNSConfig) error { var configAsString []string configAsString = append(configAsString, config.serverIP) configAsString = append(configAsString, strconv.Itoa(config.serverPort)) diff --git a/client/internal/dns/host_windows.go b/client/internal/dns/host_windows.go index 52da1a0b1ff..c7ad5e46ed3 100644 --- a/client/internal/dns/host_windows.go +++ b/client/internal/dns/host_windows.go @@ -43,7 +43,7 @@ func (s *registryConfigurator) supportCustomPort() bool { return false } -func (r *registryConfigurator) applyDNSConfig(config HostDNSConfig) error { +func (r *registryConfigurator) applyDNSConfig(config hostDNSConfig) error { var err error if config.routeAll { err = r.addDNSSetupForAll(config.serverIP) diff --git a/client/internal/dns/network_manager_linux.go b/client/internal/dns/network_manager_linux.go index 548c6b8fddc..bd83f2da921 100644 --- a/client/internal/dns/network_manager_linux.go +++ b/client/internal/dns/network_manager_linux.go @@ -12,8 +12,9 @@ import ( "github.com/godbus/dbus/v5" "github.com/hashicorp/go-version" "github.com/miekg/dns" - nbversion "github.com/netbirdio/netbird/version" log "github.com/sirupsen/logrus" + + nbversion "github.com/netbirdio/netbird/version" ) const ( @@ -93,7 +94,7 @@ func (n *networkManagerDbusConfigurator) supportCustomPort() bool { return false } -func (n *networkManagerDbusConfigurator) applyDNSConfig(config HostDNSConfig) error { +func (n *networkManagerDbusConfigurator) applyDNSConfig(config hostDNSConfig) error { connSettings, configVersion, err := n.getAppliedConnectionSettings() if err != nil { return fmt.Errorf("got an error while retrieving the applied connection settings, error: %s", err) diff --git a/client/internal/dns/resolvconf_linux.go b/client/internal/dns/resolvconf_linux.go index 9bde4b15a30..1ae2de3dde3 100644 --- a/client/internal/dns/resolvconf_linux.go +++ b/client/internal/dns/resolvconf_linux.go @@ -39,7 +39,7 @@ func (r *resolvconf) supportCustomPort() bool { return false } -func (r *resolvconf) applyDNSConfig(config HostDNSConfig) error { +func (r *resolvconf) applyDNSConfig(config hostDNSConfig) error { var err error if !config.routeAll { err = r.restoreHostDNS() diff --git a/client/internal/dns/server.go b/client/internal/dns/server.go index 1aa65ef1846..732b43c74bc 100644 --- a/client/internal/dns/server.go +++ b/client/internal/dns/server.go @@ -49,7 +49,7 @@ type DefaultServer struct { hostManager hostManager updateSerial uint64 previousConfigHash uint64 - currentConfig HostDNSConfig + currentConfig hostDNSConfig // permanent related properties permanent bool @@ -101,7 +101,7 @@ func NewDefaultServerPermanentUpstream(ctx context.Context, wgInterface WGIface, ds.permanent = true ds.hostsDnsList = hostsDnsList ds.addHostRootZone() - ds.currentConfig = dnsConfigToHostDNSConfig(config, ds.service.RuntimeIP(), ds.service.RuntimePort()) + ds.currentConfig = dnsConfigTohostDNSConfig(config, ds.service.RuntimeIP(), ds.service.RuntimePort()) ds.searchDomainNotifier = newNotifier(ds.SearchDomains()) ds.searchDomainNotifier.setListener(listener) setServerDns(ds) @@ -271,7 +271,7 @@ func (s *DefaultServer) applyConfiguration(update nbdns.Config) error { s.updateMux(muxUpdates) s.updateLocalResolver(localRecords) - s.currentConfig = dnsConfigToHostDNSConfig(update, s.service.RuntimeIP(), s.service.RuntimePort()) + s.currentConfig = dnsConfigTohostDNSConfig(update, s.service.RuntimeIP(), s.service.RuntimePort()) hostUpdate := s.currentConfig if s.service.RuntimePort() != defaultPort && !s.hostManager.supportCustomPort() { diff --git a/client/internal/dns/server_test.go b/client/internal/dns/server_test.go index 57dff07bd07..ce7a799f1e9 100644 --- a/client/internal/dns/server_test.go +++ b/client/internal/dns/server_test.go @@ -527,7 +527,7 @@ func TestDNSServerUpstreamDeactivateCallback(t *testing.T) { registeredMap: make(registrationMap), }, hostManager: hostManager, - currentConfig: HostDNSConfig{ + currentConfig: hostDNSConfig{ domains: []domainConfig{ {false, "domain0", false}, {false, "domain1", false}, @@ -537,7 +537,7 @@ func TestDNSServerUpstreamDeactivateCallback(t *testing.T) { } var domainsUpdate string - hostManager.applyDNSConfigFunc = func(config HostDNSConfig) error { + hostManager.applyDNSConfigFunc = func(config hostDNSConfig) error { domains := []string{} for _, item := range config.domains { if item.disabled { diff --git a/client/internal/dns/systemd_linux.go b/client/internal/dns/systemd_linux.go index 354ade2e4f7..0358b0251f2 100644 --- a/client/internal/dns/systemd_linux.go +++ b/client/internal/dns/systemd_linux.go @@ -81,7 +81,7 @@ func (s *systemdDbusConfigurator) supportCustomPort() bool { return true } -func (s *systemdDbusConfigurator) applyDNSConfig(config HostDNSConfig) error { +func (s *systemdDbusConfigurator) applyDNSConfig(config hostDNSConfig) error { parsedIP, err := netip.ParseAddr(config.serverIP) if err != nil { return fmt.Errorf("unable to parse ip address, error: %s", err) From 148a537c193ce283967d12313f770a20ca9346ef Mon Sep 17 00:00:00 2001 From: Pascal Fischer Date: Wed, 6 Dec 2023 16:32:39 +0100 Subject: [PATCH 29/56] remove unused engine listener --- client/internal/listener/engine_ready.go | 7 ------- client/internal/routemanager/notifier.go | 3 --- 2 files changed, 10 deletions(-) delete mode 100644 client/internal/listener/engine_ready.go diff --git a/client/internal/listener/engine_ready.go b/client/internal/listener/engine_ready.go deleted file mode 100644 index 760aa0e2fdd..00000000000 --- a/client/internal/listener/engine_ready.go +++ /dev/null @@ -1,7 +0,0 @@ -package listener - -// EngineReadyListener is a callback interface for mobile system -type EngineReadyListener interface { - // Notify invoke when engine is ready - Notify() -} diff --git a/client/internal/routemanager/notifier.go b/client/internal/routemanager/notifier.go index 6de1646f592..e27d08db57a 100644 --- a/client/internal/routemanager/notifier.go +++ b/client/internal/routemanager/notifier.go @@ -5,8 +5,6 @@ import ( "strings" "sync" - log "github.com/sirupsen/logrus" - "github.com/netbirdio/netbird/client/internal/listener" "github.com/netbirdio/netbird/route" ) @@ -64,7 +62,6 @@ func (n *notifier) notify() { } go func(l listener.NetworkChangeListener) { - log.Debugf("notifying route listener with route ranges: %s", strings.Join(n.routeRangers, ",")) l.OnNetworkChanged(strings.Join(n.routeRangers, ",")) }(n.listener) } From ca9ea29255c66220536d6b57c65bd36dd2242d43 Mon Sep 17 00:00:00 2001 From: Pascal Fischer Date: Wed, 6 Dec 2023 16:57:56 +0100 Subject: [PATCH 30/56] remove development logs --- client/internal/dns/host_ios.go | 3 --- client/internal/dns/upstream.go | 3 +-- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/client/internal/dns/host_ios.go b/client/internal/dns/host_ios.go index 7659d458a72..c90882520f8 100644 --- a/client/internal/dns/host_ios.go +++ b/client/internal/dns/host_ios.go @@ -3,8 +3,6 @@ package dns import ( "strconv" "strings" - - log "github.com/sirupsen/logrus" ) type iosHostManager struct { @@ -34,7 +32,6 @@ func (a iosHostManager) applyDNSConfig(config hostDNSConfig) error { domainConfig := strings.Join(domainConfigAsString, ";") configAsString = append(configAsString, domainConfig) outputString := strings.Join(configAsString, ",") - log.Debug("applyDNSConfig: " + outputString) a.dnsManager.ApplyDns(outputString) return nil } diff --git a/client/internal/dns/upstream.go b/client/internal/dns/upstream.go index 318890621bb..ed9cdb8cd94 100644 --- a/client/internal/dns/upstream.go +++ b/client/internal/dns/upstream.go @@ -64,7 +64,7 @@ func newUpstreamResolver(parentCTX context.Context, interfaceName string, wgAddr log.Errorf("error while parsing CIDR: %s", err) } index, err := getInterfaceIndex(interfaceName) - log.Debugf("UpstreamResolver interface name: %s, index: %d, ip: %s", interfaceName, index, localIP) + if err != nil { log.Debugf("unable to get interface index for %s: %s", interfaceName, err) } @@ -120,7 +120,6 @@ func (u *upstreamResolver) ServeDNS(w dns.ResponseWriter, r *dns.Msg) { } upstreamIP := net.ParseIP(upstreamHost) if u.lNet.Contains(upstreamIP) || net.IP.IsPrivate(upstreamIP) { - log.Debugf("using private client to query upstream: %s", upstream) upstreamExchangeClient = u.getClientPrivate() } rm, t, exchangeErr = upstreamExchangeClient.Exchange(r, upstream) From 52be5de69468df280ad8a99ef130104f122ada87 Mon Sep 17 00:00:00 2001 From: Pascal Fischer Date: Fri, 8 Dec 2023 12:17:55 +0100 Subject: [PATCH 31/56] refactor dns code and interface name propagation --- client/internal/connect.go | 3 +- client/internal/dns/host_android.go | 2 +- client/internal/dns/host_darwin.go | 2 +- client/internal/dns/host_ios.go | 2 +- client/internal/dns/host_linux.go | 2 +- client/internal/dns/host_windows.go | 2 +- client/internal/dns/server.go | 47 +++++++++++---------------- client/internal/dns/server_android.go | 10 ++++++ client/internal/dns/server_darwin.go | 7 ++++ client/internal/dns/server_ios.go | 6 ++++ client/internal/dns/server_linux.go | 5 +++ client/internal/dns/server_test.go | 4 +-- client/internal/dns/server_windows.go | 5 +++ client/internal/dns/upstream.go | 28 ++++++++-------- client/internal/engine.go | 25 +++++++------- client/internal/mobile_dependency.go | 1 - client/ios/NetBirdSDK/client.go | 3 +- iface/iface_ios.go | 2 +- iface/tun_ios.go | 3 +- 19 files changed, 93 insertions(+), 66 deletions(-) create mode 100644 client/internal/dns/server_android.go create mode 100644 client/internal/dns/server_darwin.go create mode 100644 client/internal/dns/server_ios.go create mode 100644 client/internal/dns/server_linux.go create mode 100644 client/internal/dns/server_windows.go diff --git a/client/internal/connect.go b/client/internal/connect.go index d4d17e30b74..d8784c0c865 100644 --- a/client/internal/connect.go +++ b/client/internal/connect.go @@ -43,10 +43,9 @@ func RunClientMobile(ctx context.Context, config *Config, statusRecorder *peer.S return runClient(ctx, config, statusRecorder, mobileDependency) } -func RunClientiOS(ctx context.Context, config *Config, statusRecorder *peer.Status, fileDescriptor int32, networkChangeListener listener.NetworkChangeListener, dnsManager dns.IosDnsManager, interfaceName string) error { +func RunClientiOS(ctx context.Context, config *Config, statusRecorder *peer.Status, fileDescriptor int32, networkChangeListener listener.NetworkChangeListener, dnsManager dns.IosDnsManager) error { mobileDependency := MobileDependency{ FileDescriptor: fileDescriptor, - InterfaceName: interfaceName, NetworkChangeListener: networkChangeListener, DnsManager: dnsManager, } diff --git a/client/internal/dns/host_android.go b/client/internal/dns/host_android.go index 3bd72aa87bb..4ab7b32d883 100644 --- a/client/internal/dns/host_android.go +++ b/client/internal/dns/host_android.go @@ -3,7 +3,7 @@ package dns type androidHostManager struct { } -func newHostManager(wgInterface WGIface, dnsManager IosDnsManager) (hostManager, error) { +func newHostManager(wgInterface WGIface) (hostManager, error) { return &androidHostManager{}, nil } diff --git a/client/internal/dns/host_darwin.go b/client/internal/dns/host_darwin.go index 2acb29fc8d7..3713b2e18e7 100644 --- a/client/internal/dns/host_darwin.go +++ b/client/internal/dns/host_darwin.go @@ -34,7 +34,7 @@ type systemConfigurator struct { createdKeys map[string]struct{} } -func newHostManager(_ WGIface, dnsManager IosDnsManager) (hostManager, error) { +func newHostManager(_ WGIface) (hostManager, error) { return &systemConfigurator{ createdKeys: make(map[string]struct{}), }, nil diff --git a/client/internal/dns/host_ios.go b/client/internal/dns/host_ios.go index c90882520f8..0eec4979286 100644 --- a/client/internal/dns/host_ios.go +++ b/client/internal/dns/host_ios.go @@ -10,7 +10,7 @@ type iosHostManager struct { config hostDNSConfig } -func newHostManager(wgInterface WGIface, dnsManager IosDnsManager) (hostManager, error) { +func newHostManager(dnsManager IosDnsManager) (hostManager, error) { return &iosHostManager{ dnsManager: dnsManager, }, nil diff --git a/client/internal/dns/host_linux.go b/client/internal/dns/host_linux.go index 763ff48c86f..7838c988fb9 100644 --- a/client/internal/dns/host_linux.go +++ b/client/internal/dns/host_linux.go @@ -25,7 +25,7 @@ const ( type osManagerType int -func newHostManager(wgInterface WGIface, dnsManager IosDnsManager) (hostManager, error) { +func newHostManager(wgInterface WGIface) (hostManager, error) { osManager, err := getOSDNSManagerType() if err != nil { return nil, err diff --git a/client/internal/dns/host_windows.go b/client/internal/dns/host_windows.go index c7ad5e46ed3..3814be00b7f 100644 --- a/client/internal/dns/host_windows.go +++ b/client/internal/dns/host_windows.go @@ -29,7 +29,7 @@ type registryConfigurator struct { routingAll bool } -func newHostManager(wgInterface WGIface, dnsManager IosDnsManager) (hostManager, error) { +func newHostManager(wgInterface WGIface) (hostManager, error) { guid, err := wgInterface.GetInterfaceGUIDString() if err != nil { return nil, err diff --git a/client/internal/dns/server.go b/client/internal/dns/server.go index 732b43c74bc..4ff3ce3ecdb 100644 --- a/client/internal/dns/server.go +++ b/client/internal/dns/server.go @@ -4,7 +4,6 @@ import ( "context" "fmt" "net/netip" - "runtime" "sync" "github.com/miekg/dns" @@ -27,7 +26,7 @@ type IosDnsManager interface { // Server is a dns server interface type Server interface { - Initialize(manager IosDnsManager) error + Initialize() error Stop() DnsIP() string UpdateDNSServer(serial uint64, update nbdns.Config) error @@ -56,11 +55,9 @@ type DefaultServer struct { hostsDnsList []string hostsDnsListLock sync.Mutex - interfaceName string - wgAddr string - // make sense on mobile only searchDomainNotifier *notifier + iosDnsManager IosDnsManager } type handlerWithStop interface { @@ -74,7 +71,7 @@ type muxUpdate struct { } // NewDefaultServer returns a new dns server -func NewDefaultServer(ctx context.Context, wgInterface WGIface, customAddress string, interfaceName string, wgAddr string) (*DefaultServer, error) { +func NewDefaultServer(ctx context.Context, wgInterface WGIface, customAddress string) (*DefaultServer, error) { var addrPort *netip.AddrPort if customAddress != "" { parsedAddrPort, err := netip.ParseAddrPort(customAddress) @@ -91,13 +88,13 @@ func NewDefaultServer(ctx context.Context, wgInterface WGIface, customAddress st dnsService = newServiceViaListener(wgInterface, addrPort) } - return newDefaultServer(ctx, wgInterface, dnsService, interfaceName, wgAddr), nil + return newDefaultServer(ctx, wgInterface, dnsService), nil } // NewDefaultServerPermanentUpstream returns a new dns server. It optimized for mobile systems func NewDefaultServerPermanentUpstream(ctx context.Context, wgInterface WGIface, hostsDnsList []string, config nbdns.Config, listener listener.NetworkChangeListener) *DefaultServer { log.Debugf("host dns address list is: %v", hostsDnsList) - ds := newDefaultServer(ctx, wgInterface, newServiceViaMemory(wgInterface), "", "") + ds := newDefaultServer(ctx, wgInterface, newServiceViaMemory(wgInterface)) ds.permanent = true ds.hostsDnsList = hostsDnsList ds.addHostRootZone() @@ -108,7 +105,14 @@ func NewDefaultServerPermanentUpstream(ctx context.Context, wgInterface WGIface, return ds } -func newDefaultServer(ctx context.Context, wgInterface WGIface, dnsService service, interfaceName string, wgAddr string) *DefaultServer { +// NewDefaultServerIos returns a new dns server. It optimized for ios +func NewDefaultServerIos(ctx context.Context, wgInterface WGIface, iosDnsManager IosDnsManager) *DefaultServer { + ds := newDefaultServer(ctx, wgInterface, newServiceViaMemory(wgInterface)) + ds.iosDnsManager = iosDnsManager + return ds +} + +func newDefaultServer(ctx context.Context, wgInterface WGIface, dnsService service) *DefaultServer { ctx, stop := context.WithCancel(ctx) defaultServer := &DefaultServer{ ctx: ctx, @@ -118,16 +122,14 @@ func newDefaultServer(ctx context.Context, wgInterface WGIface, dnsService servi localResolver: &localResolver{ registeredMap: make(registrationMap), }, - wgInterface: wgInterface, - interfaceName: interfaceName, - wgAddr: wgAddr, + wgInterface: wgInterface, } return defaultServer } // Initialize instantiate host manager and the dns service -func (s *DefaultServer) Initialize(manager IosDnsManager) (err error) { +func (s *DefaultServer) Initialize() (err error) { s.mux.Lock() defer s.mux.Unlock() @@ -135,19 +137,8 @@ func (s *DefaultServer) Initialize(manager IosDnsManager) (err error) { return nil } - if s.permanent { - err = s.service.Listen() - if err != nil { - return err - } - } - - if runtime.GOOS == "ios" { - s.hostManager, err = newHostManager(nil, manager) - } else { - s.hostManager, err = newHostManager(s.wgInterface, nil) - } - return + s.hostManager, err = s.initialize() + return err } // DnsIP returns the DNS resolver server IP address @@ -327,7 +318,7 @@ func (s *DefaultServer) buildUpstreamHandlerUpdate(nameServerGroups []*nbdns.Nam continue } - handler := newUpstreamResolver(s.ctx, s.interfaceName, s.wgAddr) + handler := newUpstreamResolver(s.ctx, s.wgInterface.Name(), s.wgInterface.Address().String()) for _, ns := range nsGroup.NameServers { if ns.NSType != nbdns.UDPNameServerType { log.Warnf("skipping nameserver %s with type %s, this peer supports only %s", @@ -500,7 +491,7 @@ func (s *DefaultServer) upstreamCallbacks( } func (s *DefaultServer) addHostRootZone() { - handler := newUpstreamResolver(s.ctx, s.interfaceName, s.wgAddr) + handler := newUpstreamResolver(s.ctx, s.wgInterface.Name(), s.wgInterface.Address().String()) handler.upstreamServers = make([]string, len(s.hostsDnsList)) for n, ua := range s.hostsDnsList { a, err := netip.ParseAddr(ua) diff --git a/client/internal/dns/server_android.go b/client/internal/dns/server_android.go new file mode 100644 index 00000000000..f3e8d08390f --- /dev/null +++ b/client/internal/dns/server_android.go @@ -0,0 +1,10 @@ +package dns + +func (s *DefaultServer) initialize() (manager hostManager, err error) { + err = s.service.Listen() + if err != nil { + return err + } + + return newHostManager() +} diff --git a/client/internal/dns/server_darwin.go b/client/internal/dns/server_darwin.go new file mode 100644 index 00000000000..d5a018f09b7 --- /dev/null +++ b/client/internal/dns/server_darwin.go @@ -0,0 +1,7 @@ +//go:build !ios + +package dns + +func (s *DefaultServer) initialize() (manager hostManager, err error) { + return newHostManager() +} diff --git a/client/internal/dns/server_ios.go b/client/internal/dns/server_ios.go new file mode 100644 index 00000000000..731319314b9 --- /dev/null +++ b/client/internal/dns/server_ios.go @@ -0,0 +1,6 @@ +package dns + +func (s *DefaultServer) initialize() (manager hostManager, err error) { + // todo add ioDnsManager to constuctor + return newHostManager(s.iosDnsManager) +} diff --git a/client/internal/dns/server_linux.go b/client/internal/dns/server_linux.go new file mode 100644 index 00000000000..5e1494e9ef8 --- /dev/null +++ b/client/internal/dns/server_linux.go @@ -0,0 +1,5 @@ +package dns + +func (s *DefaultServer) initialize() (manager hostManager, err error) { + return newHostManager(s.wgInterface) +} diff --git a/client/internal/dns/server_test.go b/client/internal/dns/server_test.go index ce7a799f1e9..2934e458dd9 100644 --- a/client/internal/dns/server_test.go +++ b/client/internal/dns/server_test.go @@ -268,11 +268,11 @@ func TestUpdateDNSServer(t *testing.T) { t.Log(err) } }() - dnsServer, err := NewDefaultServer(context.Background(), wgIface, "", "", "") + dnsServer, err := NewDefaultServer(context.Background(), wgIface, "") if err != nil { t.Fatal(err) } - err = dnsServer.Initialize(nil) + err = dnsServer.Initialize() if err != nil { t.Fatal(err) } diff --git a/client/internal/dns/server_windows.go b/client/internal/dns/server_windows.go new file mode 100644 index 00000000000..5e1494e9ef8 --- /dev/null +++ b/client/internal/dns/server_windows.go @@ -0,0 +1,5 @@ +package dns + +func (s *DefaultServer) initialize() (manager hostManager, err error) { + return newHostManager(s.wgInterface) +} diff --git a/client/internal/dns/upstream.go b/client/internal/dns/upstream.go index ed9cdb8cd94..fe154207338 100644 --- a/client/internal/dns/upstream.go +++ b/client/internal/dns/upstream.go @@ -102,56 +102,56 @@ func (u *upstreamResolver) ServeDNS(w dns.ResponseWriter, r *dns.Msg) { for _, upstream := range u.upstreamServers { var ( - exchangeErr error - t time.Duration - rm *dns.Msg + err error + t time.Duration + rm *dns.Msg + upstreamHost string ) upstreamExchangeClient := &dns.Client{} if runtime.GOOS != "ios" { ctx, cancel := context.WithTimeout(u.ctx, u.upstreamTimeout) - rm, t, exchangeErr = upstreamExchangeClient.ExchangeContext(ctx, r, upstream) + rm, t, err = upstreamExchangeClient.ExchangeContext(ctx, r, upstream) cancel() } else { - upstreamHost, _, err := net.SplitHostPort(upstream) + upstreamHost, _, err = net.SplitHostPort(upstream) if err != nil { log.Errorf("error while parsing upstream host: %s", err) - return } upstreamIP := net.ParseIP(upstreamHost) if u.lNet.Contains(upstreamIP) || net.IP.IsPrivate(upstreamIP) { upstreamExchangeClient = u.getClientPrivate() } - rm, t, exchangeErr = upstreamExchangeClient.Exchange(r, upstream) + rm, t, err = upstreamExchangeClient.Exchange(r, upstream) } - if exchangeErr != nil { - if exchangeErr == context.DeadlineExceeded || isTimeout(exchangeErr) { - log.WithError(exchangeErr).WithField("upstream", upstream). + if err != nil { + if err == context.DeadlineExceeded || isTimeout(err) { + log.WithError(err).WithField("upstream", upstream). Warn("got an error while connecting to upstream") continue } u.failsCount.Add(1) - log.WithError(exchangeErr).WithField("upstream", upstream). + log.WithError(err).WithField("upstream", upstream). Error("got other error while querying the upstream") return } if rm == nil { - log.WithError(exchangeErr).WithField("upstream", upstream). + log.WithError(err).WithField("upstream", upstream). Warn("no response from upstream") return } // those checks need to be independent of each other due to memory address issues if !rm.Response { - log.WithError(exchangeErr).WithField("upstream", upstream). + log.WithError(err).WithField("upstream", upstream). Warn("no response from upstream") return } log.Tracef("took %s to query the upstream %s", t, upstream) - err := w.WriteMsg(rm) + err = w.WriteMsg(rm) if err != nil { log.WithError(err).Error("got an error while writing the upstream resolver response") } diff --git a/client/internal/engine.go b/client/internal/engine.go index 41e1ceabe98..05de39995af 100644 --- a/client/internal/engine.go +++ b/client/internal/engine.go @@ -194,7 +194,8 @@ func (e *Engine) Start() error { var routes []*route.Route - if runtime.GOOS == "android" { + switch runtime.GOOS { + case "android": var dnsConfig *nbdns.Config routes, dnsConfig, err = e.readInitialSettings() if err != nil { @@ -204,11 +205,17 @@ func (e *Engine) Start() error { e.dnsServer = dns.NewDefaultServerPermanentUpstream(e.ctx, e.wgInterface, e.mobileDep.HostDNSAddresses, *dnsConfig, e.mobileDep.NetworkChangeListener) go e.mobileDep.DnsReadyListener.OnReady() } - } else if e.dnsServer == nil { - e.dnsServer, err = dns.NewDefaultServer(e.ctx, e.wgInterface, e.config.CustomDNSAddress, e.mobileDep.InterfaceName, wgAddr) - if err != nil { - e.close() - return err + case "ios": + if e.dnsServer == nil { + e.dnsServer = dns.NewDefaultServerIos(e.ctx, e.wgInterface, e.mobileDep.DnsManager) + } + default: + if e.dnsServer == nil { + e.dnsServer, err = dns.NewDefaultServer(e.ctx, e.wgInterface, e.config.CustomDNSAddress) + if err != nil { + e.close() + return err + } } } @@ -267,11 +274,7 @@ func (e *Engine) Start() error { e.acl = acl } - if runtime.GOOS == "ios" { - err = e.dnsServer.Initialize(e.mobileDep.DnsManager) - } else { - err = e.dnsServer.Initialize(nil) - } + err = e.dnsServer.Initialize() if err != nil { e.close() return err diff --git a/client/internal/mobile_dependency.go b/client/internal/mobile_dependency.go index 0f762a5708e..1a2a4c2b2f0 100644 --- a/client/internal/mobile_dependency.go +++ b/client/internal/mobile_dependency.go @@ -16,5 +16,4 @@ type MobileDependency struct { DnsReadyListener dns.ReadyListener DnsManager dns.IosDnsManager FileDescriptor int32 - InterfaceName string } diff --git a/client/ios/NetBirdSDK/client.go b/client/ios/NetBirdSDK/client.go index eae2fc7b44b..7c2525901ff 100644 --- a/client/ios/NetBirdSDK/client.go +++ b/client/ios/NetBirdSDK/client.go @@ -105,7 +105,8 @@ func (c *Client) Run(fd int32, interfaceName string) error { // todo do not throw error in case of cancelled context ctx = internal.CtxInitState(ctx) c.onHostDnsFn = func([]string) {} - return internal.RunClientiOS(ctx, cfg, c.recorder, fd, c.networkChangeListener, c.dnsManager, interfaceName) + cfg.WgIface = interfaceName + return internal.RunClientiOS(ctx, cfg, c.recorder, fd, c.networkChangeListener, c.dnsManager) } // Stop the internal client and free the resources diff --git a/iface/iface_ios.go b/iface/iface_ios.go index 901faec30a0..dd68d7792cc 100644 --- a/iface/iface_ios.go +++ b/iface/iface_ios.go @@ -21,7 +21,7 @@ func NewWGIFace(ifaceName string, address string, mtu int, tunAdapter TunAdapter return wgIFace, err } - tun := newTunDevice(wgAddress, mtu, tunAdapter, transportNet) + tun := newTunDevice(ifaceName, wgAddress, mtu, tunAdapter, transportNet) wgIFace.tun = tun wgIFace.configurer = newWGConfigurer(tun) diff --git a/iface/tun_ios.go b/iface/tun_ios.go index 4ea80c9a2d6..04c7c67c0ac 100644 --- a/iface/tun_ios.go +++ b/iface/tun_ios.go @@ -28,8 +28,9 @@ type tunDevice struct { wrapper *DeviceWrapper } -func newTunDevice(address WGAddress, mtu int, tunAdapter TunAdapter, transportNet transport.Net) *tunDevice { +func newTunDevice(name string, address WGAddress, mtu int, tunAdapter TunAdapter, transportNet transport.Net) *tunDevice { return &tunDevice{ + name: name, address: address, mtu: mtu, tunAdapter: tunAdapter, From ecfac9d8bc644fd96d6ca8d741f99ec47697b0b8 Mon Sep 17 00:00:00 2001 From: Pascal Fischer Date: Fri, 8 Dec 2023 12:21:46 +0100 Subject: [PATCH 32/56] clean dns server test --- client/internal/dns/server_test.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/client/internal/dns/server_test.go b/client/internal/dns/server_test.go index 2934e458dd9..875a1a46f95 100644 --- a/client/internal/dns/server_test.go +++ b/client/internal/dns/server_test.go @@ -368,13 +368,13 @@ func TestDNSFakeResolverHandleUpdates(t *testing.T) { return } - dnsServer, err := NewDefaultServer(context.Background(), wgIface, "", "", "") + dnsServer, err := NewDefaultServer(context.Background(), wgIface, "") if err != nil { t.Errorf("create DNS server: %v", err) return } - err = dnsServer.Initialize(nil) + err = dnsServer.Initialize() if err != nil { t.Errorf("run DNS server: %v", err) return @@ -463,7 +463,7 @@ func TestDNSServerStartStop(t *testing.T) { for _, testCase := range testCases { t.Run(testCase.name, func(t *testing.T) { - dnsServer, err := NewDefaultServer(context.Background(), &mocWGIface{}, testCase.addrPort, "", "") + dnsServer, err := NewDefaultServer(context.Background(), &mocWGIface{}, testCase.addrPort) if err != nil { t.Fatalf("%v", err) } @@ -595,7 +595,7 @@ func TestDNSPermanent_updateHostDNS_emptyUpstream(t *testing.T) { var dnsList []string dnsConfig := nbdns.Config{} dnsServer := NewDefaultServerPermanentUpstream(context.Background(), wgIFace, dnsList, dnsConfig, nil) - err = dnsServer.Initialize(nil) + err = dnsServer.Initialize() if err != nil { t.Errorf("failed to initialize DNS server: %v", err) return @@ -619,7 +619,7 @@ func TestDNSPermanent_updateUpstream(t *testing.T) { defer wgIFace.Close() dnsConfig := nbdns.Config{} dnsServer := NewDefaultServerPermanentUpstream(context.Background(), wgIFace, []string{"8.8.8.8"}, dnsConfig, nil) - err = dnsServer.Initialize(nil) + err = dnsServer.Initialize() if err != nil { t.Errorf("failed to initialize DNS server: %v", err) return @@ -711,7 +711,7 @@ func TestDNSPermanent_matchOnly(t *testing.T) { defer wgIFace.Close() dnsConfig := nbdns.Config{} dnsServer := NewDefaultServerPermanentUpstream(context.Background(), wgIFace, []string{"8.8.8.8"}, dnsConfig, nil) - err = dnsServer.Initialize(nil) + err = dnsServer.Initialize() if err != nil { t.Errorf("failed to initialize DNS server: %v", err) return From 6d9fd4bdbd4175d1e2686b82c266c3da254ecc7a Mon Sep 17 00:00:00 2001 From: Pascal Fischer Date: Fri, 8 Dec 2023 13:18:14 +0100 Subject: [PATCH 33/56] disable upstream deactivation for iOS --- client/internal/dns/upstream.go | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/client/internal/dns/upstream.go b/client/internal/dns/upstream.go index fe154207338..3b2fe65f718 100644 --- a/client/internal/dns/upstream.go +++ b/client/internal/dns/upstream.go @@ -181,10 +181,12 @@ func (u *upstreamResolver) checkUpstreamFails() { return default: // todo test the deactivation logic, it seems to affect the client - log.Warnf("upstream resolving is disabled for %v", reactivatePeriod) - u.deactivate() - u.disabled = true - go u.waitUntilResponse() + if runtime.GOOS != "ios" { + log.Warnf("upstream resolving is disabled for %v", reactivatePeriod) + u.deactivate() + u.disabled = true + go u.waitUntilResponse() + } } } From c35c2fbcc69db9b021aad7c667dbc16a813bc4ac Mon Sep 17 00:00:00 2001 From: Pascal Fischer Date: Fri, 8 Dec 2023 13:23:31 +0100 Subject: [PATCH 34/56] remove files after merge --- client/internal/routemanager/firewall_ios.go | 31 ------------------- .../routemanager/firewall_nonlinux.go | 0 2 files changed, 31 deletions(-) delete mode 100644 client/internal/routemanager/firewall_ios.go delete mode 100644 client/internal/routemanager/firewall_nonlinux.go diff --git a/client/internal/routemanager/firewall_ios.go b/client/internal/routemanager/firewall_ios.go deleted file mode 100644 index 387f501f14f..00000000000 --- a/client/internal/routemanager/firewall_ios.go +++ /dev/null @@ -1,31 +0,0 @@ -//go:build ios - -package routemanager - -import ( - "context" -) - -// newFirewall returns a nil manager -func newFirewall(context.Context) (firewallManager, error) { - return iOSFirewallManager{}, nil -} - -type iOSFirewallManager struct { -} - -func (i iOSFirewallManager) RestoreOrCreateContainers() error { - return nil -} - -func (i iOSFirewallManager) InsertRoutingRules(pair routerPair) error { - return nil -} - -func (i iOSFirewallManager) RemoveRoutingRules(pair routerPair) error { - return nil -} - -func (i iOSFirewallManager) CleanRoutingRules() { - return -} diff --git a/client/internal/routemanager/firewall_nonlinux.go b/client/internal/routemanager/firewall_nonlinux.go deleted file mode 100644 index e69de29bb2d..00000000000 From 010398424bd4fe57ed21f38dc390fe9fc8f98dfd Mon Sep 17 00:00:00 2001 From: Pascal Fischer Date: Fri, 8 Dec 2023 13:33:24 +0100 Subject: [PATCH 35/56] fix dns server darwin --- client/internal/dns/server_darwin.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/internal/dns/server_darwin.go b/client/internal/dns/server_darwin.go index d5a018f09b7..feeb6935295 100644 --- a/client/internal/dns/server_darwin.go +++ b/client/internal/dns/server_darwin.go @@ -3,5 +3,5 @@ package dns func (s *DefaultServer) initialize() (manager hostManager, err error) { - return newHostManager() + return newHostManager(s.wgInterface) } From 9f6c3da127dd005282da479e488b214549315f0d Mon Sep 17 00:00:00 2001 From: Pascal Fischer Date: Fri, 8 Dec 2023 13:43:48 +0100 Subject: [PATCH 36/56] fix server mock --- client/internal/dns/mockServer.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/internal/dns/mockServer.go b/client/internal/dns/mockServer.go index 23fa7e83051..ed4116b9d84 100644 --- a/client/internal/dns/mockServer.go +++ b/client/internal/dns/mockServer.go @@ -14,7 +14,7 @@ type MockServer struct { } // Initialize mock implementation of Initialize from Server interface -func (m *MockServer) Initialize(manager IosDnsManager) error { +func (m *MockServer) Initialize() error { if m.InitializeFunc != nil { return m.InitializeFunc() } From cbb1f0e0ef38ef2d2f3d797d3e166ea1df3f1a94 Mon Sep 17 00:00:00 2001 From: Pascal Fischer Date: Fri, 8 Dec 2023 13:54:33 +0100 Subject: [PATCH 37/56] fix build flags --- client/internal/dns/server_linux.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/client/internal/dns/server_linux.go b/client/internal/dns/server_linux.go index 5e1494e9ef8..7d702783904 100644 --- a/client/internal/dns/server_linux.go +++ b/client/internal/dns/server_linux.go @@ -1,3 +1,5 @@ +//go:build !android + package dns func (s *DefaultServer) initialize() (manager hostManager, err error) { From 6e86dad6107d6ed79de1522b4f290ae88a807e06 Mon Sep 17 00:00:00 2001 From: Pascal Fischer Date: Fri, 8 Dec 2023 14:58:37 +0100 Subject: [PATCH 38/56] move service listen back to initialize --- client/internal/dns/server.go | 7 +++++++ client/internal/dns/server_android.go | 5 ----- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/client/internal/dns/server.go b/client/internal/dns/server.go index 4ff3ce3ecdb..6f76bb83583 100644 --- a/client/internal/dns/server.go +++ b/client/internal/dns/server.go @@ -137,6 +137,13 @@ func (s *DefaultServer) Initialize() (err error) { return nil } + if s.permanent { + err = s.service.Listen() + if err != nil { + return err + } + } + s.hostManager, err = s.initialize() return err } diff --git a/client/internal/dns/server_android.go b/client/internal/dns/server_android.go index f3e8d08390f..7ca12d69dc9 100644 --- a/client/internal/dns/server_android.go +++ b/client/internal/dns/server_android.go @@ -1,10 +1,5 @@ package dns func (s *DefaultServer) initialize() (manager hostManager, err error) { - err = s.service.Listen() - if err != nil { - return err - } - return newHostManager() } From d69d4cf28fc19230563a5b106c6fb4dc11e10005 Mon Sep 17 00:00:00 2001 From: Pascal Fischer Date: Fri, 8 Dec 2023 15:10:40 +0100 Subject: [PATCH 39/56] add wgInterface to hostManager initialization on android --- client/internal/dns/server_android.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/internal/dns/server_android.go b/client/internal/dns/server_android.go index 7ca12d69dc9..5e1494e9ef8 100644 --- a/client/internal/dns/server_android.go +++ b/client/internal/dns/server_android.go @@ -1,5 +1,5 @@ package dns func (s *DefaultServer) initialize() (manager hostManager, err error) { - return newHostManager() + return newHostManager(s.wgInterface) } From 4d5760c0c94ecfd8ad7c3cf683ee4430acd25242 Mon Sep 17 00:00:00 2001 From: Pascal Fischer Date: Fri, 8 Dec 2023 17:26:32 +0100 Subject: [PATCH 40/56] fix typo and remove unused function --- client/internal/dns/server.go | 2 +- client/internal/dns/upstream_test.go | 9 --------- client/system/info_ios.go | 1 - iface/tun_ios.go | 5 ----- 4 files changed, 1 insertion(+), 16 deletions(-) diff --git a/client/internal/dns/server.go b/client/internal/dns/server.go index 6f76bb83583..02550ef5db4 100644 --- a/client/internal/dns/server.go +++ b/client/internal/dns/server.go @@ -19,7 +19,7 @@ type ReadyListener interface { OnReady() } -// IosDnsManager is a dns manager interface for iosß +// IosDnsManager is a dns manager interface for iOS type IosDnsManager interface { ApplyDns(string) } diff --git a/client/internal/dns/upstream_test.go b/client/internal/dns/upstream_test.go index f29bc21a53d..36282f1c167 100644 --- a/client/internal/dns/upstream_test.go +++ b/client/internal/dns/upstream_test.go @@ -49,15 +49,6 @@ func TestUpstreamResolver_ServeDNS(t *testing.T) { timeout: upstreamTimeout, responseShouldBeNil: true, }, - // { - // name: "Should Resolve CNAME Record", - // inputMSG: new(dns.Msg).SetQuestion("one.one.one.one", dns.TypeCNAME), - // }, - // { - // name: "Should Not Write When Not Found A Record", - // inputMSG: new(dns.Msg).SetQuestion("not.found.com", dns.TypeA), - // responseShouldBeNil: true, - // }, } // should resolve if first upstream times out // should not write when both fails diff --git a/client/system/info_ios.go b/client/system/info_ios.go index 1a1203f79c9..c0e51ec6001 100644 --- a/client/system/info_ios.go +++ b/client/system/info_ios.go @@ -18,7 +18,6 @@ func GetInfo(ctx context.Context) *Info { swVersion := extractOsVersion(ctx, "swVersion") gio := &Info{Kernel: sysName, OSVersion: swVersion, Core: swVersion, Platform: "unknown", OS: sysName, GoOS: runtime.GOOS, CPUs: runtime.NumCPU()} - // systemHostname, _ := os.Hostname() gio.Hostname = extractDeviceName(ctx, "hostname") gio.WiretrusteeVersion = version.NetbirdVersion() gio.UIVersion = extractUserAgent(ctx) diff --git a/iface/tun_ios.go b/iface/tun_ios.go index 04c7c67c0ac..7a9ce5622ec 100644 --- a/iface/tun_ios.go +++ b/iface/tun_ios.go @@ -5,7 +5,6 @@ package iface import ( "os" - "strings" "github.com/pion/transport/v2" log "github.com/sirupsen/logrus" @@ -100,7 +99,3 @@ func (t *tunDevice) Close() (err error) { return } - -func (t *tunDevice) routesToString(routes []string) string { - return strings.Join(routes, ";") -} From ed06c0caa01533902351565b46aa073e157ed5b5 Mon Sep 17 00:00:00 2001 From: Pascal Fischer Date: Fri, 8 Dec 2023 17:54:27 +0100 Subject: [PATCH 41/56] extract upstream exchange for ios and rest --- client/internal/dns/upstream.go | 25 ++----------------------- client/internal/dns/upstream_ios.go | 7 +++++++ client/internal/dns/upstream_nonios.go | 17 ++++++++--------- 3 files changed, 17 insertions(+), 32 deletions(-) diff --git a/client/internal/dns/upstream.go b/client/internal/dns/upstream.go index 3b2fe65f718..96b8edf7321 100644 --- a/client/internal/dns/upstream.go +++ b/client/internal/dns/upstream.go @@ -101,29 +101,8 @@ func (u *upstreamResolver) ServeDNS(w dns.ResponseWriter, r *dns.Msg) { } for _, upstream := range u.upstreamServers { - var ( - err error - t time.Duration - rm *dns.Msg - upstreamHost string - ) - - upstreamExchangeClient := &dns.Client{} - if runtime.GOOS != "ios" { - ctx, cancel := context.WithTimeout(u.ctx, u.upstreamTimeout) - rm, t, err = upstreamExchangeClient.ExchangeContext(ctx, r, upstream) - cancel() - } else { - upstreamHost, _, err = net.SplitHostPort(upstream) - if err != nil { - log.Errorf("error while parsing upstream host: %s", err) - } - upstreamIP := net.ParseIP(upstreamHost) - if u.lNet.Contains(upstreamIP) || net.IP.IsPrivate(upstreamIP) { - upstreamExchangeClient = u.getClientPrivate() - } - rm, t, err = upstreamExchangeClient.Exchange(r, upstream) - } + + rm, t, err := u.upstreamExchange(upstream, r) if err != nil { if err == context.DeadlineExceeded || isTimeout(err) { diff --git a/client/internal/dns/upstream_ios.go b/client/internal/dns/upstream_ios.go index a2dd31ef2ad..defae2ebb74 100644 --- a/client/internal/dns/upstream_ios.go +++ b/client/internal/dns/upstream_ios.go @@ -5,12 +5,19 @@ package dns import ( "net" "syscall" + "time" "github.com/miekg/dns" log "github.com/sirupsen/logrus" "golang.org/x/sys/unix" ) +func (u *upstreamResolver) upstreamExchange(upstream string, r *dns.Msg) (rm *dns.Msg, t time.Duration, err error) { + client := u.getClientPrivate() + return client.Exchange(r, upstream) + +} + // getClientPrivate returns a new DNS client bound to the local IP address of the Netbird interface // This method is needed for iOS func (u *upstreamResolver) getClientPrivate() *dns.Client { diff --git a/client/internal/dns/upstream_nonios.go b/client/internal/dns/upstream_nonios.go index a2a541489cd..365ec872f80 100644 --- a/client/internal/dns/upstream_nonios.go +++ b/client/internal/dns/upstream_nonios.go @@ -3,17 +3,16 @@ package dns import ( - "net" + "context" + "time" "github.com/miekg/dns" ) -// getClientPrivate returns a new DNS client bound to the local IP address of the Netbird interface -// This method is needed for iOS -func (u *upstreamResolver) getClientPrivate() *dns.Client { - dialer := &net.Dialer{} - client := &dns.Client{ - Dialer: dialer, - } - return client +func (u *upstreamResolver) upstreamExchange(upstream string, r *dns.Msg) (rm *dns.Msg, t time.Duration, err error) { + upstreamExchangeClient := &dns.Client{} + ctx, cancel := context.WithTimeout(u.ctx, u.upstreamTimeout) + rm, t, err = upstreamExchangeClient.ExchangeContext(ctx, r, upstream) + cancel() + return rm, t, err } From fd40be5ebdd757cb0e6b761dbdd1fffb33cc1231 Mon Sep 17 00:00:00 2001 From: Pascal Fischer Date: Fri, 8 Dec 2023 17:58:36 +0100 Subject: [PATCH 42/56] remove todo --- client/internal/dns/server_ios.go | 1 - 1 file changed, 1 deletion(-) diff --git a/client/internal/dns/server_ios.go b/client/internal/dns/server_ios.go index 731319314b9..d04e7ab4430 100644 --- a/client/internal/dns/server_ios.go +++ b/client/internal/dns/server_ios.go @@ -1,6 +1,5 @@ package dns func (s *DefaultServer) initialize() (manager hostManager, err error) { - // todo add ioDnsManager to constuctor return newHostManager(s.iosDnsManager) } From 284ec54081067c8cc3daae0fad03bccb3cccc793 Mon Sep 17 00:00:00 2001 From: Pascal Fischer Date: Mon, 11 Dec 2023 14:38:35 +0100 Subject: [PATCH 43/56] separate upstream logic to ios file --- .../dns/{mockServer.go => mock_server.go} | 0 client/internal/dns/server.go | 11 ++++- client/internal/dns/upstream.go | 40 ------------------- client/internal/dns/upstream_ios.go | 26 +++++++++++- client/internal/dns/upstream_nonios.go | 13 ++++++ 5 files changed, 47 insertions(+), 43 deletions(-) rename client/internal/dns/{mockServer.go => mock_server.go} (100%) diff --git a/client/internal/dns/mockServer.go b/client/internal/dns/mock_server.go similarity index 100% rename from client/internal/dns/mockServer.go rename to client/internal/dns/mock_server.go diff --git a/client/internal/dns/server.go b/client/internal/dns/server.go index 02550ef5db4..f63e7344c9c 100644 --- a/client/internal/dns/server.go +++ b/client/internal/dns/server.go @@ -325,7 +325,10 @@ func (s *DefaultServer) buildUpstreamHandlerUpdate(nameServerGroups []*nbdns.Nam continue } - handler := newUpstreamResolver(s.ctx, s.wgInterface.Name(), s.wgInterface.Address().String()) + handler, err := newUpstreamResolver(s.ctx, s.wgInterface.Name(), s.wgInterface.Address().IP) + if err != nil { + return nil, fmt.Errorf("unable to create a new upstream resolver, error: %v", err) + } for _, ns := range nsGroup.NameServers { if ns.NSType != nbdns.UDPNameServerType { log.Warnf("skipping nameserver %s with type %s, this peer supports only %s", @@ -498,7 +501,11 @@ func (s *DefaultServer) upstreamCallbacks( } func (s *DefaultServer) addHostRootZone() { - handler := newUpstreamResolver(s.ctx, s.wgInterface.Name(), s.wgInterface.Address().String()) + handler, err := newUpstreamResolver(s.ctx, s.wgInterface.Name(), s.wgInterface.Address().IP) + if err != nil { + log.Errorf("unable to create a new upstream resolver, error: %v", err) + return + } handler.upstreamServers = make([]string, len(s.hostsDnsList)) for n, ua := range s.hostsDnsList { a, err := netip.ParseAddr(ua) diff --git a/client/internal/dns/upstream.go b/client/internal/dns/upstream.go index 96b8edf7321..ff37367a175 100644 --- a/client/internal/dns/upstream.go +++ b/client/internal/dns/upstream.go @@ -37,52 +37,12 @@ type upstreamResolver struct { reactivatePeriod time.Duration upstreamTimeout time.Duration lIP net.IP - lNet *net.IPNet - lName string iIndex int deactivate func() reactivate func() } -func getInterfaceIndex(interfaceName string) (int, error) { - iface, err := net.InterfaceByName(interfaceName) - if err != nil { - log.Errorf("unable to get interface by name error: %s", err) - return 0, err - } - - return iface.Index, nil -} - -func newUpstreamResolver(parentCTX context.Context, interfaceName string, wgAddr string) *upstreamResolver { - ctx, cancel := context.WithCancel(parentCTX) - - // Specify the local IP address you want to bind to - localIP, localNet, err := net.ParseCIDR(wgAddr) // Should be our interface IP - if err != nil { - log.Errorf("error while parsing CIDR: %s", err) - } - index, err := getInterfaceIndex(interfaceName) - - if err != nil { - log.Debugf("unable to get interface index for %s: %s", interfaceName, err) - } - localIFaceIndex := index // Should be our interface index - - return &upstreamResolver{ - ctx: ctx, - cancel: cancel, - upstreamTimeout: upstreamTimeout, - reactivatePeriod: reactivatePeriod, - failsTillDeact: failsTillDeact, - lIP: localIP, - lNet: localNet, - iIndex: localIFaceIndex, - lName: interfaceName, - } -} - func (u *upstreamResolver) stop() { log.Debugf("stopping serving DNS for upstreams %s", u.upstreamServers) u.cancel() diff --git a/client/internal/dns/upstream_ios.go b/client/internal/dns/upstream_ios.go index defae2ebb74..6c6efe32684 100644 --- a/client/internal/dns/upstream_ios.go +++ b/client/internal/dns/upstream_ios.go @@ -12,10 +12,29 @@ import ( "golang.org/x/sys/unix" ) +func newUpstreamResolver(parentCTX context.Context, interfaceName string, ip net.IP) (*upstreamResolver, error) { + ctx, cancel := context.WithCancel(parentCTX) + + index, err := getInterfaceIndex(interfaceName) + if err != nil { + log.Debugf("unable to get interface index for %s: %s", interfaceName, err) + return nil, err + } + + return &upstreamResolver{ + ctx: ctx, + cancel: cancel, + upstreamTimeout: upstreamTimeout, + reactivatePeriod: reactivatePeriod, + failsTillDeact: failsTillDeact, + lIP: ip, + iIndex: index, + }, nil +} + func (u *upstreamResolver) upstreamExchange(upstream string, r *dns.Msg) (rm *dns.Msg, t time.Duration, err error) { client := u.getClientPrivate() return client.Exchange(r, upstream) - } // getClientPrivate returns a new DNS client bound to the local IP address of the Netbird interface @@ -49,3 +68,8 @@ func (u *upstreamResolver) getClientPrivate() *dns.Client { } return client } + +func getInterfaceIndex(interfaceName string) (int, error) { + iface, err := net.InterfaceByName(interfaceName) + return iface.Index, err +} diff --git a/client/internal/dns/upstream_nonios.go b/client/internal/dns/upstream_nonios.go index 365ec872f80..42a0b9a9c98 100644 --- a/client/internal/dns/upstream_nonios.go +++ b/client/internal/dns/upstream_nonios.go @@ -4,11 +4,24 @@ package dns import ( "context" + "net" "time" "github.com/miekg/dns" ) +func newUpstreamResolver(parentCTX context.Context, interfaceName string, ip net.IP) (*upstreamResolver, error) { + ctx, cancel := context.WithCancel(parentCTX) + + return &upstreamResolver{ + ctx: ctx, + cancel: cancel, + upstreamTimeout: upstreamTimeout, + reactivatePeriod: reactivatePeriod, + failsTillDeact: failsTillDeact, + }, nil +} + func (u *upstreamResolver) upstreamExchange(upstream string, r *dns.Msg) (rm *dns.Msg, t time.Duration, err error) { upstreamExchangeClient := &dns.Client{} ctx, cancel := context.WithTimeout(u.ctx, u.upstreamTimeout) From 974e845e962e55252df2a9874325b614850ea48b Mon Sep 17 00:00:00 2001 From: Pascal Fischer Date: Mon, 11 Dec 2023 14:53:41 +0100 Subject: [PATCH 44/56] Fix upstream test --- client/internal/dns/upstream_test.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/client/internal/dns/upstream_test.go b/client/internal/dns/upstream_test.go index 36282f1c167..2a8fdfdc77c 100644 --- a/client/internal/dns/upstream_test.go +++ b/client/internal/dns/upstream_test.go @@ -2,6 +2,7 @@ package dns import ( "context" + "net" "strings" "testing" "time" @@ -57,7 +58,7 @@ func TestUpstreamResolver_ServeDNS(t *testing.T) { for _, testCase := range testCases { t.Run(testCase.name, func(t *testing.T) { ctx, cancel := context.WithCancel(context.TODO()) - resolver := newUpstreamResolver(ctx, "", "") + resolver, _ := newUpstreamResolver(ctx, "", net.IP{}) resolver.upstreamServers = testCase.InputServers resolver.upstreamTimeout = testCase.timeout if testCase.cancelCTX { From d6b5f050fe69a8768a545d2d766f65ccf573a6d3 Mon Sep 17 00:00:00 2001 From: Pascal Fischer Date: Mon, 11 Dec 2023 17:15:06 +0100 Subject: [PATCH 45/56] use interface and embedded struct for upstream --- client/internal/dns/upstream.go | 31 +++++++++++++++++++++----- client/internal/dns/upstream_ios.go | 27 ++++++++++++---------- client/internal/dns/upstream_nonios.go | 18 +++++++-------- 3 files changed, 50 insertions(+), 26 deletions(-) diff --git a/client/internal/dns/upstream.go b/client/internal/dns/upstream.go index ff37367a175..2edeca1a93d 100644 --- a/client/internal/dns/upstream.go +++ b/client/internal/dns/upstream.go @@ -25,7 +25,12 @@ type upstreamClient interface { ExchangeContext(ctx context.Context, m *dns.Msg, a string) (r *dns.Msg, rtt time.Duration, err error) } -type upstreamResolver struct { +type UpstreamResolver interface { + serveDNS(r *dns.Msg) (*dns.Msg, time.Duration, error) + upstreamExchange(upstream string, r *dns.Msg) (*dns.Msg, time.Duration, error) +} + +type upstreamResolverBase struct { ctx context.Context cancel context.CancelFunc upstreamClient upstreamClient @@ -43,13 +48,25 @@ type upstreamResolver struct { reactivate func() } -func (u *upstreamResolver) stop() { +func newUpstreamResolverBase(parentCTX context.Context) *upstreamResolverBase { + ctx, cancel := context.WithCancel(parentCTX) + + return &upstreamResolverBase{ + ctx: ctx, + cancel: cancel, + upstreamTimeout: upstreamTimeout, + reactivatePeriod: reactivatePeriod, + failsTillDeact: failsTillDeact, + } +} + +func (u *upstreamResolverBase) stop() { log.Debugf("stopping serving DNS for upstreams %s", u.upstreamServers) u.cancel() } // ServeDNS handles a DNS request -func (u *upstreamResolver) ServeDNS(w dns.ResponseWriter, r *dns.Msg) { +func (u *upstreamResolverBase) ServeDNS(w dns.ResponseWriter, r *dns.Msg) { defer u.checkUpstreamFails() log.WithField("question", r.Question[0]).Trace("received an upstream question") @@ -102,12 +119,16 @@ func (u *upstreamResolver) ServeDNS(w dns.ResponseWriter, r *dns.Msg) { log.Error("all queries to the upstream nameservers failed with timeout") } +func (u *upstreamResolverBase) upstreamExchange(upstream string, r *dns.Msg) (rm *dns.Msg, t time.Duration, err error) { + return nil, 0, fmt.Errorf("not implemented") +} + // checkUpstreamFails counts fails and disables or enables upstream resolving // // If fails count is greater that failsTillDeact, upstream resolving // will be disabled for reactivatePeriod, after that time period fails counter // will be reset and upstream will be reactivated. -func (u *upstreamResolver) checkUpstreamFails() { +func (u *upstreamResolverBase) checkUpstreamFails() { u.mutex.Lock() defer u.mutex.Unlock() @@ -130,7 +151,7 @@ func (u *upstreamResolver) checkUpstreamFails() { } // waitUntilResponse retries, in an exponential interval, querying the upstream servers until it gets a positive response -func (u *upstreamResolver) waitUntilResponse() { +func (u *upstreamResolverBase) waitUntilResponse() { exponentialBackOff := &backoff.ExponentialBackOff{ InitialInterval: 500 * time.Millisecond, RandomizationFactor: 0.5, diff --git a/client/internal/dns/upstream_ios.go b/client/internal/dns/upstream_ios.go index 6c6efe32684..1e6cf7ef824 100644 --- a/client/internal/dns/upstream_ios.go +++ b/client/internal/dns/upstream_ios.go @@ -3,6 +3,7 @@ package dns import ( + "context" "net" "syscall" "time" @@ -12,8 +13,14 @@ import ( "golang.org/x/sys/unix" ) -func newUpstreamResolver(parentCTX context.Context, interfaceName string, ip net.IP) (*upstreamResolver, error) { - ctx, cancel := context.WithCancel(parentCTX) +type upstreamResolverIOS struct { + *upstreamResolverBase + lIP net.IP + iIndex int +} + +func newUpstreamResolver(parentCTX context.Context, interfaceName string, ip net.IP) (*upstreamResolverIOS, error) { + upstreamResolverBase := newUpstreamResolverBase(parentCTX) index, err := getInterfaceIndex(interfaceName) if err != nil { @@ -21,25 +28,21 @@ func newUpstreamResolver(parentCTX context.Context, interfaceName string, ip net return nil, err } - return &upstreamResolver{ - ctx: ctx, - cancel: cancel, - upstreamTimeout: upstreamTimeout, - reactivatePeriod: reactivatePeriod, - failsTillDeact: failsTillDeact, - lIP: ip, - iIndex: index, + return &upstreamResolverIOS{ + upstreamResolverBase: upstreamResolverBase, + lIP: ip, + iIndex: index, }, nil } -func (u *upstreamResolver) upstreamExchange(upstream string, r *dns.Msg) (rm *dns.Msg, t time.Duration, err error) { +func (u *upstreamResolverIOS) upstreamExchange(upstream string, r *dns.Msg) (rm *dns.Msg, t time.Duration, err error) { client := u.getClientPrivate() return client.Exchange(r, upstream) } // getClientPrivate returns a new DNS client bound to the local IP address of the Netbird interface // This method is needed for iOS -func (u *upstreamResolver) getClientPrivate() *dns.Client { +func (u *upstreamResolverIOS) getClientPrivate() *dns.Client { dialer := &net.Dialer{ LocalAddr: &net.UDPAddr{ IP: u.lIP, diff --git a/client/internal/dns/upstream_nonios.go b/client/internal/dns/upstream_nonios.go index 42a0b9a9c98..942af81f00e 100644 --- a/client/internal/dns/upstream_nonios.go +++ b/client/internal/dns/upstream_nonios.go @@ -10,19 +10,19 @@ import ( "github.com/miekg/dns" ) -func newUpstreamResolver(parentCTX context.Context, interfaceName string, ip net.IP) (*upstreamResolver, error) { - ctx, cancel := context.WithCancel(parentCTX) +type upstreamResolverNonIOS struct { + *upstreamResolverBase +} + +func newUpstreamResolver(parentCTX context.Context, interfaceName string, ip net.IP) (*upstreamResolverNonIOS, error) { + upstreamResolverBase := newUpstreamResolverBase(parentCTX) - return &upstreamResolver{ - ctx: ctx, - cancel: cancel, - upstreamTimeout: upstreamTimeout, - reactivatePeriod: reactivatePeriod, - failsTillDeact: failsTillDeact, + return &upstreamResolverNonIOS{ + upstreamResolverBase: upstreamResolverBase, }, nil } -func (u *upstreamResolver) upstreamExchange(upstream string, r *dns.Msg) (rm *dns.Msg, t time.Duration, err error) { +func (u *upstreamResolverNonIOS) upstreamExchange(upstream string, r *dns.Msg) (rm *dns.Msg, t time.Duration, err error) { upstreamExchangeClient := &dns.Client{} ctx, cancel := context.WithTimeout(u.ctx, u.upstreamTimeout) rm, t, err = upstreamExchangeClient.ExchangeContext(ctx, r, upstream) From 3acdf79cfc5489befdb82197a25dad93ed00ebc1 Mon Sep 17 00:00:00 2001 From: Pascal Fischer Date: Mon, 11 Dec 2023 17:58:30 +0100 Subject: [PATCH 46/56] set properly upstream client --- client/internal/dns/upstream.go | 9 +++------ client/internal/dns/upstream_ios.go | 9 ++++++--- client/internal/dns/upstream_nonios.go | 9 +++++---- 3 files changed, 14 insertions(+), 13 deletions(-) diff --git a/client/internal/dns/upstream.go b/client/internal/dns/upstream.go index 2edeca1a93d..14a2f229442 100644 --- a/client/internal/dns/upstream.go +++ b/client/internal/dns/upstream.go @@ -22,7 +22,7 @@ const ( ) type upstreamClient interface { - ExchangeContext(ctx context.Context, m *dns.Msg, a string) (r *dns.Msg, rtt time.Duration, err error) + exchange(upstream string, r *dns.Msg) (*dns.Msg, time.Duration, error) } type UpstreamResolver interface { @@ -79,7 +79,7 @@ func (u *upstreamResolverBase) ServeDNS(w dns.ResponseWriter, r *dns.Msg) { for _, upstream := range u.upstreamServers { - rm, t, err := u.upstreamExchange(upstream, r) + rm, t, err := u.upstreamClient.exchange(upstream, r) if err != nil { if err == context.DeadlineExceeded || isTimeout(err) { @@ -173,10 +173,7 @@ func (u *upstreamResolverBase) waitUntilResponse() { var err error for _, upstream := range u.upstreamServers { - ctx, cancel := context.WithTimeout(u.ctx, u.upstreamTimeout) - _, _, err = u.upstreamClient.ExchangeContext(ctx, r, upstream) - - cancel() + _, _, err = u.upstreamClient.exchange(upstream, r) if err == nil { return nil diff --git a/client/internal/dns/upstream_ios.go b/client/internal/dns/upstream_ios.go index 1e6cf7ef824..5bc696dcf83 100644 --- a/client/internal/dns/upstream_ios.go +++ b/client/internal/dns/upstream_ios.go @@ -28,14 +28,17 @@ func newUpstreamResolver(parentCTX context.Context, interfaceName string, ip net return nil, err } - return &upstreamResolverIOS{ + ios := &upstreamResolverIOS{ upstreamResolverBase: upstreamResolverBase, lIP: ip, iIndex: index, - }, nil + } + ios.upstreamClient = ios + + return ios, nil } -func (u *upstreamResolverIOS) upstreamExchange(upstream string, r *dns.Msg) (rm *dns.Msg, t time.Duration, err error) { +func (u *upstreamResolverIOS) exchange(upstream string, r *dns.Msg) (rm *dns.Msg, t time.Duration, err error) { client := u.getClientPrivate() return client.Exchange(r, upstream) } diff --git a/client/internal/dns/upstream_nonios.go b/client/internal/dns/upstream_nonios.go index 942af81f00e..242a91b5e8d 100644 --- a/client/internal/dns/upstream_nonios.go +++ b/client/internal/dns/upstream_nonios.go @@ -16,13 +16,14 @@ type upstreamResolverNonIOS struct { func newUpstreamResolver(parentCTX context.Context, interfaceName string, ip net.IP) (*upstreamResolverNonIOS, error) { upstreamResolverBase := newUpstreamResolverBase(parentCTX) - - return &upstreamResolverNonIOS{ + nonIOS := &upstreamResolverNonIOS{ upstreamResolverBase: upstreamResolverBase, - }, nil + } + upstreamResolverBase.upstreamClient = nonIOS + return nonIOS, nil } -func (u *upstreamResolverNonIOS) upstreamExchange(upstream string, r *dns.Msg) (rm *dns.Msg, t time.Duration, err error) { +func (u *upstreamResolverNonIOS) exchange(upstream string, r *dns.Msg) (rm *dns.Msg, t time.Duration, err error) { upstreamExchangeClient := &dns.Client{} ctx, cancel := context.WithTimeout(u.ctx, u.upstreamTimeout) rm, t, err = upstreamExchangeClient.ExchangeContext(ctx, r, upstream) From 680f21ea1f9b8f09acfcd7c1711253039531aea6 Mon Sep 17 00:00:00 2001 From: Pascal Fischer Date: Mon, 11 Dec 2023 18:00:54 +0100 Subject: [PATCH 47/56] remove placeholder --- client/internal/dns/upstream.go | 4 ---- 1 file changed, 4 deletions(-) diff --git a/client/internal/dns/upstream.go b/client/internal/dns/upstream.go index 14a2f229442..99f49246def 100644 --- a/client/internal/dns/upstream.go +++ b/client/internal/dns/upstream.go @@ -119,10 +119,6 @@ func (u *upstreamResolverBase) ServeDNS(w dns.ResponseWriter, r *dns.Msg) { log.Error("all queries to the upstream nameservers failed with timeout") } -func (u *upstreamResolverBase) upstreamExchange(upstream string, r *dns.Msg) (rm *dns.Msg, t time.Duration, err error) { - return nil, 0, fmt.Errorf("not implemented") -} - // checkUpstreamFails counts fails and disables or enables upstream resolving // // If fails count is greater that failsTillDeact, upstream resolving From e86153ad8515c70f3e8e75f80944f36901c9dd23 Mon Sep 17 00:00:00 2001 From: Pascal Fischer Date: Mon, 11 Dec 2023 18:04:51 +0100 Subject: [PATCH 48/56] remove ios specific attributes --- client/internal/dns/upstream.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/client/internal/dns/upstream.go b/client/internal/dns/upstream.go index 99f49246def..786d79e7762 100644 --- a/client/internal/dns/upstream.go +++ b/client/internal/dns/upstream.go @@ -41,8 +41,6 @@ type upstreamResolverBase struct { mutex sync.Mutex reactivatePeriod time.Duration upstreamTimeout time.Duration - lIP net.IP - iIndex int deactivate func() reactivate func() From d91f2e2ff1dc9f856c70b0d7c3508c716371cf5a Mon Sep 17 00:00:00 2001 From: Pascal Fischer Date: Mon, 11 Dec 2023 18:15:58 +0100 Subject: [PATCH 49/56] fix upstream test --- client/internal/dns/upstream_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/internal/dns/upstream_test.go b/client/internal/dns/upstream_test.go index 2a8fdfdc77c..f404c95d2ab 100644 --- a/client/internal/dns/upstream_test.go +++ b/client/internal/dns/upstream_test.go @@ -106,12 +106,12 @@ type mockUpstreamResolver struct { } // ExchangeContext mock implementation of ExchangeContext from upstreamResolver -func (c mockUpstreamResolver) ExchangeContext(_ context.Context, _ *dns.Msg, _ string) (r *dns.Msg, rtt time.Duration, err error) { +func (c mockUpstreamResolver) exchange(upstream string, r *dns.Msg) (*dns.Msg, time.Duration, error) { return c.r, c.rtt, c.err } func TestUpstreamResolver_DeactivationReactivation(t *testing.T) { - resolver := &upstreamResolver{ + resolver := &upstreamResolverBase{ ctx: context.TODO(), upstreamClient: &mockUpstreamResolver{ err: nil, From cc15f06b80be4e3122e20020f85b1eea97fd46c3 Mon Sep 17 00:00:00 2001 From: Pascal Fischer Date: Mon, 11 Dec 2023 18:36:43 +0100 Subject: [PATCH 50/56] merge ipc parser and wg configurer for mobile --- client/internal/dns/host.go | 2 +- client/internal/dns/server.go | 4 +- iface/ipc_parser_ios.go | 63 ---------- ...parser_android.go => ipc_parser_mobile.go} | 4 +- iface/wg_configurer_android.go | 114 ------------------ ...figurer_ios.go => wg_configurer_mobile.go} | 4 +- ...nandroid.go => wg_configurer_nonmobile.go} | 0 7 files changed, 7 insertions(+), 184 deletions(-) delete mode 100644 iface/ipc_parser_ios.go rename iface/{ipc_parser_android.go => ipc_parser_mobile.go} (96%) delete mode 100644 iface/wg_configurer_android.go rename iface/{wg_configurer_ios.go => wg_configurer_mobile.go} (98%) rename iface/{wg_configurer_nonandroid.go => wg_configurer_nonmobile.go} (100%) diff --git a/client/internal/dns/host.go b/client/internal/dns/host.go index 05460c13c47..4fd164c45b1 100644 --- a/client/internal/dns/host.go +++ b/client/internal/dns/host.go @@ -61,7 +61,7 @@ func newNoopHostMocker() hostManager { } } -func dnsConfigTohostDNSConfig(dnsConfig nbdns.Config, ip string, port int) hostDNSConfig { +func dnsConfigToHostDNSConfig(dnsConfig nbdns.Config, ip string, port int) hostDNSConfig { config := hostDNSConfig{ routeAll: false, serverIP: ip, diff --git a/client/internal/dns/server.go b/client/internal/dns/server.go index f63e7344c9c..e788d0e8797 100644 --- a/client/internal/dns/server.go +++ b/client/internal/dns/server.go @@ -98,7 +98,7 @@ func NewDefaultServerPermanentUpstream(ctx context.Context, wgInterface WGIface, ds.permanent = true ds.hostsDnsList = hostsDnsList ds.addHostRootZone() - ds.currentConfig = dnsConfigTohostDNSConfig(config, ds.service.RuntimeIP(), ds.service.RuntimePort()) + ds.currentConfig = dnsConfigToHostDNSConfig(config, ds.service.RuntimeIP(), ds.service.RuntimePort()) ds.searchDomainNotifier = newNotifier(ds.SearchDomains()) ds.searchDomainNotifier.setListener(listener) setServerDns(ds) @@ -269,7 +269,7 @@ func (s *DefaultServer) applyConfiguration(update nbdns.Config) error { s.updateMux(muxUpdates) s.updateLocalResolver(localRecords) - s.currentConfig = dnsConfigTohostDNSConfig(update, s.service.RuntimeIP(), s.service.RuntimePort()) + s.currentConfig = dnsConfigToHostDNSConfig(update, s.service.RuntimeIP(), s.service.RuntimePort()) hostUpdate := s.currentConfig if s.service.RuntimePort() != defaultPort && !s.hostManager.supportCustomPort() { diff --git a/iface/ipc_parser_ios.go b/iface/ipc_parser_ios.go deleted file mode 100644 index de5e50664c3..00000000000 --- a/iface/ipc_parser_ios.go +++ /dev/null @@ -1,63 +0,0 @@ -//go:build ios -// +build ios - -package iface - -import ( - "encoding/hex" - "fmt" - "strings" - - "golang.zx2c4.com/wireguard/wgctrl/wgtypes" -) - -func toWgUserspaceString(wgCfg wgtypes.Config) string { - var sb strings.Builder - if wgCfg.PrivateKey != nil { - hexKey := hex.EncodeToString(wgCfg.PrivateKey[:]) - sb.WriteString(fmt.Sprintf("private_key=%s\n", hexKey)) - } - - if wgCfg.ListenPort != nil { - sb.WriteString(fmt.Sprintf("listen_port=%d\n", *wgCfg.ListenPort)) - } - - if wgCfg.ReplacePeers { - sb.WriteString("replace_peers=true\n") - } - - if wgCfg.FirewallMark != nil { - sb.WriteString(fmt.Sprintf("fwmark=%d\n", *wgCfg.FirewallMark)) - } - - for _, p := range wgCfg.Peers { - hexKey := hex.EncodeToString(p.PublicKey[:]) - sb.WriteString(fmt.Sprintf("public_key=%s\n", hexKey)) - - if p.PresharedKey != nil { - preSharedHexKey := hex.EncodeToString(p.PresharedKey[:]) - sb.WriteString(fmt.Sprintf("preshared_key=%s\n", preSharedHexKey)) - } - - if p.Remove { - sb.WriteString("remove=true") - } - - if p.ReplaceAllowedIPs { - sb.WriteString("replace_allowed_ips=true\n") - } - - for _, aip := range p.AllowedIPs { - sb.WriteString(fmt.Sprintf("allowed_ip=%s\n", aip.String())) - } - - if p.Endpoint != nil { - sb.WriteString(fmt.Sprintf("endpoint=%s\n", p.Endpoint.String())) - } - - if p.PersistentKeepaliveInterval != nil { - sb.WriteString(fmt.Sprintf("persistent_keepalive_interval=%d\n", int(p.PersistentKeepaliveInterval.Seconds()))) - } - } - return sb.String() -} diff --git a/iface/ipc_parser_android.go b/iface/ipc_parser_mobile.go similarity index 96% rename from iface/ipc_parser_android.go rename to iface/ipc_parser_mobile.go index 56e52d1a01e..8fef4bc7643 100644 --- a/iface/ipc_parser_android.go +++ b/iface/ipc_parser_mobile.go @@ -1,5 +1,5 @@ -//go:build android -// +build android +//go:build android && ios +// +build android,ios package iface diff --git a/iface/wg_configurer_android.go b/iface/wg_configurer_android.go deleted file mode 100644 index 9328467a676..00000000000 --- a/iface/wg_configurer_android.go +++ /dev/null @@ -1,114 +0,0 @@ -package iface - -import ( - "errors" - "net" - "time" - - log "github.com/sirupsen/logrus" - - "golang.zx2c4.com/wireguard/wgctrl/wgtypes" -) - -var ( - errFuncNotImplemented = errors.New("function not implemented") -) - -type wGConfigurer struct { - tunDevice *tunDevice -} - -func newWGConfigurer(tunDevice *tunDevice) wGConfigurer { - return wGConfigurer{ - tunDevice: tunDevice, - } -} - -func (c *wGConfigurer) configureInterface(privateKey string, port int) error { - log.Debugf("adding Wireguard private key") - key, err := wgtypes.ParseKey(privateKey) - if err != nil { - return err - } - fwmark := 0 - config := wgtypes.Config{ - PrivateKey: &key, - ReplacePeers: true, - FirewallMark: &fwmark, - ListenPort: &port, - } - - return c.tunDevice.Device().IpcSet(toWgUserspaceString(config)) -} - -func (c *wGConfigurer) updatePeer(peerKey string, allowedIps string, keepAlive time.Duration, endpoint *net.UDPAddr, preSharedKey *wgtypes.Key) error { - //parse allowed ips - _, ipNet, err := net.ParseCIDR(allowedIps) - if err != nil { - return err - } - - peerKeyParsed, err := wgtypes.ParseKey(peerKey) - if err != nil { - return err - } - peer := wgtypes.PeerConfig{ - PublicKey: peerKeyParsed, - ReplaceAllowedIPs: true, - AllowedIPs: []net.IPNet{*ipNet}, - PersistentKeepaliveInterval: &keepAlive, - PresharedKey: preSharedKey, - Endpoint: endpoint, - } - - config := wgtypes.Config{ - Peers: []wgtypes.PeerConfig{peer}, - } - - return c.tunDevice.Device().IpcSet(toWgUserspaceString(config)) -} - -func (c *wGConfigurer) removePeer(peerKey string) error { - peerKeyParsed, err := wgtypes.ParseKey(peerKey) - if err != nil { - return err - } - - peer := wgtypes.PeerConfig{ - PublicKey: peerKeyParsed, - Remove: true, - } - - config := wgtypes.Config{ - Peers: []wgtypes.PeerConfig{peer}, - } - return c.tunDevice.Device().IpcSet(toWgUserspaceString(config)) -} - -func (c *wGConfigurer) addAllowedIP(peerKey string, allowedIP string) error { - _, ipNet, err := net.ParseCIDR(allowedIP) - if err != nil { - return err - } - - peerKeyParsed, err := wgtypes.ParseKey(peerKey) - if err != nil { - return err - } - peer := wgtypes.PeerConfig{ - PublicKey: peerKeyParsed, - UpdateOnly: true, - ReplaceAllowedIPs: false, - AllowedIPs: []net.IPNet{*ipNet}, - } - - config := wgtypes.Config{ - Peers: []wgtypes.PeerConfig{peer}, - } - - return c.tunDevice.Device().IpcSet(toWgUserspaceString(config)) -} - -func (c *wGConfigurer) removeAllowedIP(peerKey string, allowedIP string) error { - return errFuncNotImplemented -} diff --git a/iface/wg_configurer_ios.go b/iface/wg_configurer_mobile.go similarity index 98% rename from iface/wg_configurer_ios.go rename to iface/wg_configurer_mobile.go index 4b1c89be0a9..e8d9461ffa3 100644 --- a/iface/wg_configurer_ios.go +++ b/iface/wg_configurer_mobile.go @@ -1,5 +1,5 @@ -//go:build ios -// +build ios +//go:build ios && android +// +build ios,android package iface diff --git a/iface/wg_configurer_nonandroid.go b/iface/wg_configurer_nonmobile.go similarity index 100% rename from iface/wg_configurer_nonandroid.go rename to iface/wg_configurer_nonmobile.go From bacc322fa02ef1272c3bb2984f585053940b299f Mon Sep 17 00:00:00 2001 From: Pascal Fischer Date: Mon, 11 Dec 2023 18:46:43 +0100 Subject: [PATCH 51/56] fix build annotation --- iface/ipc_parser_mobile.go | 4 ++-- iface/wg_configurer_mobile.go | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/iface/ipc_parser_mobile.go b/iface/ipc_parser_mobile.go index 8fef4bc7643..7d4af81399a 100644 --- a/iface/ipc_parser_mobile.go +++ b/iface/ipc_parser_mobile.go @@ -1,5 +1,5 @@ -//go:build android && ios -// +build android,ios +//go:build android || ios +// +build android ios package iface diff --git a/iface/wg_configurer_mobile.go b/iface/wg_configurer_mobile.go index e8d9461ffa3..7f6e5595da2 100644 --- a/iface/wg_configurer_mobile.go +++ b/iface/wg_configurer_mobile.go @@ -1,5 +1,5 @@ -//go:build ios && android -// +build ios,android +//go:build ios || android +// +build ios android package iface From 5b4e8475968fd8d6a1fe288961ae80df5fa2d5d7 Mon Sep 17 00:00:00 2001 From: Pascal Fischer Date: Thu, 14 Dec 2023 11:59:17 +0100 Subject: [PATCH 52/56] use json for DNS settings handover through gomobile --- client/internal/dns/file_linux.go | 32 ++++++------- client/internal/dns/file_linux_test.go | 10 ++-- client/internal/dns/host.go | 50 ++++++++++---------- client/internal/dns/host_android.go | 2 +- client/internal/dns/host_darwin.go | 34 ++++++------- client/internal/dns/host_ios.go | 27 ++++------- client/internal/dns/host_windows.go | 26 +++++----- client/internal/dns/local_test.go | 8 ++-- client/internal/dns/network_manager_linux.go | 22 ++++----- client/internal/dns/resolvconf_linux.go | 10 ++-- client/internal/dns/server.go | 42 ++++++++-------- client/internal/dns/server_test.go | 28 +++++------ client/internal/dns/service_listener.go | 2 +- client/internal/dns/systemd_linux.go | 30 ++++++------ client/internal/dns/upstream.go | 2 +- client/internal/dns/upstream_test.go | 2 +- 16 files changed, 159 insertions(+), 168 deletions(-) diff --git a/client/internal/dns/file_linux.go b/client/internal/dns/file_linux.go index 81b16459bc9..e21612ba1cf 100644 --- a/client/internal/dns/file_linux.go +++ b/client/internal/dns/file_linux.go @@ -35,21 +35,21 @@ func (f *fileConfigurator) supportCustomPort() bool { return false } -func (f *fileConfigurator) applyDNSConfig(config hostDNSConfig) error { +func (f *fileConfigurator) applyDNSConfig(config HostDNSConfig) error { backupFileExist := false _, err := os.Stat(fileDefaultResolvConfBackupLocation) if err == nil { backupFileExist = true } - if !config.routeAll { + if !config.RouteAll { if backupFileExist { err = f.restore() if err != nil { return fmt.Errorf("unable to configure DNS for this peer using file manager without a Primary nameserver group. Restoring the original file return err: %s", err) } } - return fmt.Errorf("unable to configure DNS for this peer using file manager without a nameserver group with all domains configured") + return fmt.Errorf("unable to configure DNS for this peer using file manager without a nameserver group with all Domains configured") } if !backupFileExist { @@ -70,7 +70,7 @@ func (f *fileConfigurator) applyDNSConfig(config hostDNSConfig) error { buf := prepareResolvConfContent( searchDomainList, - append([]string{config.serverIP}, nameServers...), + append([]string{config.ServerIP}, nameServers...), others) log.Debugf("creating managed file %s", defaultResolvConfPath) @@ -83,7 +83,7 @@ func (f *fileConfigurator) applyDNSConfig(config hostDNSConfig) error { return fmt.Errorf("got an creating resolver file %s. Error: %s", defaultResolvConfPath, err) } - log.Infof("created a NetBird managed %s file with your DNS settings. Added %d search domains. Search list: %s", defaultResolvConfPath, len(searchDomainList), searchDomainList) + log.Infof("created a NetBird managed %s file with your DNS settings. Added %d search Domains. Search list: %s", defaultResolvConfPath, len(searchDomainList), searchDomainList) return nil } @@ -138,14 +138,14 @@ func prepareResolvConfContent(searchDomains, nameServers, others []string) bytes return buf } -func searchDomains(config hostDNSConfig) []string { +func searchDomains(config HostDNSConfig) []string { listOfDomains := make([]string, 0) - for _, dConf := range config.domains { - if dConf.matchOnly || dConf.disabled { + for _, dConf := range config.Domains { + if dConf.MatchOnly || dConf.Disabled { continue } - listOfDomains = append(listOfDomains, dConf.domain) + listOfDomains = append(listOfDomains, dConf.Domain) } return listOfDomains } @@ -177,7 +177,7 @@ func originalDNSConfigs(resolvconfFile string) (searchDomains, nameServers, othe continue } - if strings.HasPrefix(line, "domain") { + if strings.HasPrefix(line, "Domain") { continue } @@ -214,7 +214,7 @@ func originalDNSConfigs(resolvconfFile string) (searchDomains, nameServers, othe return } -// merge search domains lists and cut off the list if it is too long +// merge search Domains lists and cut off the list if it is too long func mergeSearchDomains(searchDomains []string, originalSearchDomains []string) []string { lineSize := len("search") searchDomainsList := make([]string, 0, len(searchDomains)+len(originalSearchDomains)) @@ -225,23 +225,23 @@ func mergeSearchDomains(searchDomains []string, originalSearchDomains []string) return searchDomainsList } -// validateAndFillSearchDomains checks if the search domains list is not too long and if the line is not too long +// validateAndFillSearchDomains checks if the search Domains list is not too long and if the line is not too long // extend s slice with vs elements // return with the number of characters in the searchDomains line func validateAndFillSearchDomains(initialLineChars int, s *[]string, vs []string) int { for _, sd := range vs { tmpCharsNumber := initialLineChars + 1 + len(sd) if tmpCharsNumber > fileMaxLineCharsLimit { - // lets log all skipped domains - log.Infof("search list line is larger than %d characters. Skipping append of %s domain", fileMaxLineCharsLimit, sd) + // lets log all skipped Domains + log.Infof("search list line is larger than %d characters. Skipping append of %s Domain", fileMaxLineCharsLimit, sd) continue } initialLineChars = tmpCharsNumber if len(*s) >= fileMaxNumberOfSearchDomains { - // lets log all skipped domains - log.Infof("already appended %d domains to search list. Skipping append of %s domain", fileMaxNumberOfSearchDomains, sd) + // lets log all skipped Domains + log.Infof("already appended %d Domains to search list. Skipping append of %s Domain", fileMaxNumberOfSearchDomains, sd) continue } *s = append(*s, sd) diff --git a/client/internal/dns/file_linux_test.go b/client/internal/dns/file_linux_test.go index 369a47ef4c8..f87999fe4c1 100644 --- a/client/internal/dns/file_linux_test.go +++ b/client/internal/dns/file_linux_test.go @@ -10,7 +10,7 @@ func Test_mergeSearchDomains(t *testing.T) { originDomains := []string{"a", "b"} mergedDomains := mergeSearchDomains(searchDomains, originDomains) if len(mergedDomains) != 4 { - t.Errorf("invalid len of result domains: %d, want: %d", len(mergedDomains), 4) + t.Errorf("invalid len of result Domains: %d, want: %d", len(mergedDomains), 4) } } @@ -19,7 +19,7 @@ func Test_mergeSearchTooMuchDomains(t *testing.T) { originDomains := []string{"h", "i"} mergedDomains := mergeSearchDomains(searchDomains, originDomains) if len(mergedDomains) != 6 { - t.Errorf("invalid len of result domains: %d, want: %d", len(mergedDomains), 6) + t.Errorf("invalid len of result Domains: %d, want: %d", len(mergedDomains), 6) } } @@ -28,7 +28,7 @@ func Test_mergeSearchTooMuchDomainsInOrigin(t *testing.T) { originDomains := []string{"c", "d", "e", "f", "g"} mergedDomains := mergeSearchDomains(searchDomains, originDomains) if len(mergedDomains) != 6 { - t.Errorf("invalid len of result domains: %d, want: %d", len(mergedDomains), 6) + t.Errorf("invalid len of result Domains: %d, want: %d", len(mergedDomains), 6) } } @@ -37,7 +37,7 @@ func Test_mergeSearchTooLongDomain(t *testing.T) { originDomains := []string{"b"} mergedDomains := mergeSearchDomains(searchDomains, originDomains) if len(mergedDomains) != 1 { - t.Errorf("invalid len of result domains: %d, want: %d", len(mergedDomains), 1) + t.Errorf("invalid len of result Domains: %d, want: %d", len(mergedDomains), 1) } searchDomains = []string{"b"} @@ -45,7 +45,7 @@ func Test_mergeSearchTooLongDomain(t *testing.T) { mergedDomains = mergeSearchDomains(searchDomains, originDomains) if len(mergedDomains) != 1 { - t.Errorf("invalid len of result domains: %d, want: %d", len(mergedDomains), 1) + t.Errorf("invalid len of result Domains: %d, want: %d", len(mergedDomains), 1) } } diff --git a/client/internal/dns/host.go b/client/internal/dns/host.go index 4fd164c45b1..ee50b39d0ba 100644 --- a/client/internal/dns/host.go +++ b/client/internal/dns/host.go @@ -8,31 +8,31 @@ import ( ) type hostManager interface { - applyDNSConfig(config hostDNSConfig) error + applyDNSConfig(config HostDNSConfig) error restoreHostDNS() error supportCustomPort() bool } -type hostDNSConfig struct { - domains []domainConfig - routeAll bool - serverIP string - serverPort int +type HostDNSConfig struct { + Domains []DomainConfig `json:"domains"` + RouteAll bool `json:"routeAll"` + ServerIP string `json:"serverIP"` + ServerPort int `json:"serverPort"` } -type domainConfig struct { - disabled bool - domain string - matchOnly bool +type DomainConfig struct { + Disabled bool `json:"disabled"` + Domain string `json:"domain"` + MatchOnly bool `json:"matchOnly"` } type mockHostConfigurator struct { - applyDNSConfigFunc func(config hostDNSConfig) error + applyDNSConfigFunc func(config HostDNSConfig) error restoreHostDNSFunc func() error supportCustomPortFunc func() bool } -func (m *mockHostConfigurator) applyDNSConfig(config hostDNSConfig) error { +func (m *mockHostConfigurator) applyDNSConfig(config HostDNSConfig) error { if m.applyDNSConfigFunc != nil { return m.applyDNSConfigFunc(config) } @@ -55,38 +55,38 @@ func (m *mockHostConfigurator) supportCustomPort() bool { func newNoopHostMocker() hostManager { return &mockHostConfigurator{ - applyDNSConfigFunc: func(config hostDNSConfig) error { return nil }, + applyDNSConfigFunc: func(config HostDNSConfig) error { return nil }, restoreHostDNSFunc: func() error { return nil }, supportCustomPortFunc: func() bool { return true }, } } -func dnsConfigToHostDNSConfig(dnsConfig nbdns.Config, ip string, port int) hostDNSConfig { - config := hostDNSConfig{ - routeAll: false, - serverIP: ip, - serverPort: port, +func dnsConfigToHostDNSConfig(dnsConfig nbdns.Config, ip string, port int) HostDNSConfig { + config := HostDNSConfig{ + RouteAll: false, + ServerIP: ip, + ServerPort: port, } for _, nsConfig := range dnsConfig.NameServerGroups { if len(nsConfig.NameServers) == 0 { continue } if nsConfig.Primary { - config.routeAll = true + config.RouteAll = true } for _, domain := range nsConfig.Domains { - config.domains = append(config.domains, domainConfig{ - domain: strings.TrimSuffix(domain, "."), - matchOnly: !nsConfig.SearchDomainsEnabled, + config.Domains = append(config.Domains, DomainConfig{ + Domain: strings.TrimSuffix(domain, "."), + MatchOnly: !nsConfig.SearchDomainsEnabled, }) } } for _, customZone := range dnsConfig.CustomZones { - config.domains = append(config.domains, domainConfig{ - domain: strings.TrimSuffix(customZone.Domain, "."), - matchOnly: false, + config.Domains = append(config.Domains, DomainConfig{ + Domain: strings.TrimSuffix(customZone.Domain, "."), + MatchOnly: false, }) } diff --git a/client/internal/dns/host_android.go b/client/internal/dns/host_android.go index 4ab7b32d883..169cc7c4726 100644 --- a/client/internal/dns/host_android.go +++ b/client/internal/dns/host_android.go @@ -7,7 +7,7 @@ func newHostManager(wgInterface WGIface) (hostManager, error) { return &androidHostManager{}, nil } -func (a androidHostManager) applyDNSConfig(config hostDNSConfig) error { +func (a androidHostManager) applyDNSConfig(config HostDNSConfig) error { return nil } diff --git a/client/internal/dns/host_darwin.go b/client/internal/dns/host_darwin.go index 3713b2e18e7..303deb5e4a5 100644 --- a/client/internal/dns/host_darwin.go +++ b/client/internal/dns/host_darwin.go @@ -44,11 +44,11 @@ func (s *systemConfigurator) supportCustomPort() bool { return true } -func (s *systemConfigurator) applyDNSConfig(config hostDNSConfig) error { +func (s *systemConfigurator) applyDNSConfig(config HostDNSConfig) error { var err error - if config.routeAll { - err = s.addDNSSetupForAll(config.serverIP, config.serverPort) + if config.RouteAll { + err = s.addDNSSetupForAll(config.ServerIP, config.ServerPort) if err != nil { return err } @@ -58,7 +58,7 @@ func (s *systemConfigurator) applyDNSConfig(config hostDNSConfig) error { return err } s.primaryServiceID = "" - log.Infof("removed %s:%d as main DNS resolver for this peer", config.serverIP, config.serverPort) + log.Infof("removed %s:%d as main DNS resolver for this peer", config.ServerIP, config.ServerPort) } var ( @@ -66,22 +66,22 @@ func (s *systemConfigurator) applyDNSConfig(config hostDNSConfig) error { matchDomains []string ) - for _, dConf := range config.domains { - if dConf.disabled { + for _, dConf := range config.Domains { + if dConf.Disabled { continue } - if dConf.matchOnly { - matchDomains = append(matchDomains, dConf.domain) + if dConf.MatchOnly { + matchDomains = append(matchDomains, dConf.Domain) continue } - searchDomains = append(searchDomains, dConf.domain) + searchDomains = append(searchDomains, dConf.Domain) } matchKey := getKeyWithInput(netbirdDNSStateKeyFormat, matchSuffix) if len(matchDomains) != 0 { - err = s.addMatchDomains(matchKey, strings.Join(matchDomains, " "), config.serverIP, config.serverPort) + err = s.addMatchDomains(matchKey, strings.Join(matchDomains, " "), config.ServerIP, config.ServerPort) } else { - log.Infof("removing match domains from the system") + log.Infof("removing match Domains from the system") err = s.removeKeyFromSystemConfig(matchKey) } if err != nil { @@ -90,9 +90,9 @@ func (s *systemConfigurator) applyDNSConfig(config hostDNSConfig) error { searchKey := getKeyWithInput(netbirdDNSStateKeyFormat, searchSuffix) if len(searchDomains) != 0 { - err = s.addSearchDomains(searchKey, strings.Join(searchDomains, " "), config.serverIP, config.serverPort) + err = s.addSearchDomains(searchKey, strings.Join(searchDomains, " "), config.ServerIP, config.ServerPort) } else { - log.Infof("removing search domains from the system") + log.Infof("removing search Domains from the system") err = s.removeKeyFromSystemConfig(searchKey) } if err != nil { @@ -110,7 +110,7 @@ func (s *systemConfigurator) restoreHostDNS() error { if strings.Contains(key, matchSuffix) { keyType = "match" } - log.Infof("removing %s domains from system", keyType) + log.Infof("removing %s Domains from system", keyType) } if s.primaryServiceID != "" { lines += buildRemoveKeyOperation(getKeyWithInput(primaryServiceSetupKeyFormat, s.primaryServiceID)) @@ -143,7 +143,7 @@ func (s *systemConfigurator) addSearchDomains(key, domains string, ip string, po return err } - log.Infof("added %d search domains to the state. Domain list: %s", len(strings.Split(domains, " ")), domains) + log.Infof("added %d search Domains to the state. Domain list: %s", len(strings.Split(domains, " ")), domains) s.createdKeys[key] = struct{}{} @@ -156,7 +156,7 @@ func (s *systemConfigurator) addMatchDomains(key, domains, dnsServer string, por return err } - log.Infof("added %d match domains to the state. Domain list: %s", len(strings.Split(domains, " ")), domains) + log.Infof("added %d match Domains to the state. Domain list: %s", len(strings.Split(domains, " ")), domains) s.createdKeys[key] = struct{}{} @@ -178,7 +178,7 @@ func (s *systemConfigurator) addDNSState(state, domains, dnsServer string, port _, err := runSystemConfigCommand(stdinCommands) if err != nil { - return fmt.Errorf("got error while applying state for domains %s, error: %s", domains, err) + return fmt.Errorf("got error while applying state for Domains %s, error: %s", domains, err) } return nil } diff --git a/client/internal/dns/host_ios.go b/client/internal/dns/host_ios.go index 0eec4979286..969a54513af 100644 --- a/client/internal/dns/host_ios.go +++ b/client/internal/dns/host_ios.go @@ -1,13 +1,13 @@ package dns import ( - "strconv" - "strings" + "encoding/json" + "fmt" ) type iosHostManager struct { dnsManager IosDnsManager - config hostDNSConfig + config HostDNSConfig } func newHostManager(dnsManager IosDnsManager) (hostManager, error) { @@ -16,23 +16,12 @@ func newHostManager(dnsManager IosDnsManager) (hostManager, error) { }, nil } -func (a iosHostManager) applyDNSConfig(config hostDNSConfig) error { - var configAsString []string - configAsString = append(configAsString, config.serverIP) - configAsString = append(configAsString, strconv.Itoa(config.serverPort)) - configAsString = append(configAsString, strconv.FormatBool(config.routeAll)) - var domainConfigAsString []string - for _, domain := range config.domains { - var domainAsString []string - domainAsString = append(domainAsString, strconv.FormatBool(domain.disabled)) - domainAsString = append(domainAsString, domain.domain) - domainAsString = append(domainAsString, strconv.FormatBool(domain.matchOnly)) - domainConfigAsString = append(domainConfigAsString, strings.Join(domainAsString, "|")) +func (a iosHostManager) applyDNSConfig(config HostDNSConfig) error { + jsonData, err := json.Marshal(config) + if err != nil { + return err } - domainConfig := strings.Join(domainConfigAsString, ";") - configAsString = append(configAsString, domainConfig) - outputString := strings.Join(configAsString, ",") - a.dnsManager.ApplyDns(outputString) + a.dnsManager.ApplyDns(fmt.Sprint(jsonData)) return nil } diff --git a/client/internal/dns/host_windows.go b/client/internal/dns/host_windows.go index 3814be00b7f..7a8f8e6166e 100644 --- a/client/internal/dns/host_windows.go +++ b/client/internal/dns/host_windows.go @@ -43,10 +43,10 @@ func (s *registryConfigurator) supportCustomPort() bool { return false } -func (r *registryConfigurator) applyDNSConfig(config hostDNSConfig) error { +func (r *registryConfigurator) applyDNSConfig(config HostDNSConfig) error { var err error - if config.routeAll { - err = r.addDNSSetupForAll(config.serverIP) + if config.RouteAll { + err = r.addDNSSetupForAll(config.ServerIP) if err != nil { return err } @@ -56,7 +56,7 @@ func (r *registryConfigurator) applyDNSConfig(config hostDNSConfig) error { return err } r.routingAll = false - log.Infof("removed %s as main DNS forwarder for this peer", config.serverIP) + log.Infof("removed %s as main DNS forwarder for this peer", config.ServerIP) } var ( @@ -64,18 +64,18 @@ func (r *registryConfigurator) applyDNSConfig(config hostDNSConfig) error { matchDomains []string ) - for _, dConf := range config.domains { - if dConf.disabled { + for _, dConf := range config.Domains { + if dConf.Disabled { continue } - if !dConf.matchOnly { - searchDomains = append(searchDomains, dConf.domain) + if !dConf.MatchOnly { + searchDomains = append(searchDomains, dConf.Domain) } - matchDomains = append(matchDomains, "."+dConf.domain) + matchDomains = append(matchDomains, "."+dConf.Domain) } if len(matchDomains) != 0 { - err = r.addDNSMatchPolicy(matchDomains, config.serverIP) + err = r.addDNSMatchPolicy(matchDomains, config.ServerIP) } else { err = removeRegistryKeyFromDNSPolicyConfig(dnsPolicyConfigMatchPath) } @@ -135,7 +135,7 @@ func (r *registryConfigurator) addDNSMatchPolicy(domains []string, ip string) er return fmt.Errorf("unable to set registry value for %s, error: %s", dnsPolicyConfigConfigOptionsKey, err) } - log.Infof("added %d match domains to the state. Domain list: %s", len(domains), domains) + log.Infof("added %d match Domains to the state. Domain list: %s", len(domains), domains) return nil } @@ -152,10 +152,10 @@ func (r *registryConfigurator) restoreHostDNS() error { func (r *registryConfigurator) updateSearchDomains(domains []string) error { err := r.setInterfaceRegistryKeyStringValue(interfaceConfigSearchListKey, strings.Join(domains, ",")) if err != nil { - return fmt.Errorf("adding search domain failed with error: %s", err) + return fmt.Errorf("adding search Domain failed with error: %s", err) } - log.Infof("updated the search domains in the registry with %d domains. Domain list: %s", len(domains), domains) + log.Infof("updated the search Domains in the registry with %d Domains. Domain list: %s", len(domains), domains) return nil } diff --git a/client/internal/dns/local_test.go b/client/internal/dns/local_test.go index db69d9ad86d..2110c63e76c 100644 --- a/client/internal/dns/local_test.go +++ b/client/internal/dns/local_test.go @@ -1,10 +1,12 @@ package dns import ( - "github.com/miekg/dns" - nbdns "github.com/netbirdio/netbird/dns" "strings" "testing" + + "github.com/miekg/dns" + + nbdns "github.com/netbirdio/netbird/dns" ) func TestLocalResolver_ServeDNS(t *testing.T) { @@ -73,7 +75,7 @@ func TestLocalResolver_ServeDNS(t *testing.T) { answerString := responseMSG.Answer[0].String() if !strings.Contains(answerString, testCase.inputRecord.Name) { - t.Fatalf("answer doesn't contain the same domain name: \nWant: %s\nGot:%s", testCase.name, answerString) + t.Fatalf("answer doesn't contain the same Domain name: \nWant: %s\nGot:%s", testCase.name, answerString) } if !strings.Contains(answerString, dns.Type(testCase.inputRecord.Type).String()) { t.Fatalf("answer doesn't contain the correct type: \nWant: %s\nGot:%s", dns.Type(testCase.inputRecord.Type).String(), answerString) diff --git a/client/internal/dns/network_manager_linux.go b/client/internal/dns/network_manager_linux.go index bd83f2da921..6b190143916 100644 --- a/client/internal/dns/network_manager_linux.go +++ b/client/internal/dns/network_manager_linux.go @@ -94,7 +94,7 @@ func (n *networkManagerDbusConfigurator) supportCustomPort() bool { return false } -func (n *networkManagerDbusConfigurator) applyDNSConfig(config hostDNSConfig) error { +func (n *networkManagerDbusConfigurator) applyDNSConfig(config HostDNSConfig) error { connSettings, configVersion, err := n.getAppliedConnectionSettings() if err != nil { return fmt.Errorf("got an error while retrieving the applied connection settings, error: %s", err) @@ -102,7 +102,7 @@ func (n *networkManagerDbusConfigurator) applyDNSConfig(config hostDNSConfig) er connSettings.cleanDeprecatedSettings() - dnsIP, err := netip.ParseAddr(config.serverIP) + dnsIP, err := netip.ParseAddr(config.ServerIP) if err != nil { return fmt.Errorf("unable to parse ip address, error: %s", err) } @@ -112,40 +112,40 @@ func (n *networkManagerDbusConfigurator) applyDNSConfig(config hostDNSConfig) er searchDomains []string matchDomains []string ) - for _, dConf := range config.domains { - if dConf.disabled { + for _, dConf := range config.Domains { + if dConf.Disabled { continue } - if dConf.matchOnly { - matchDomains = append(matchDomains, "~."+dns.Fqdn(dConf.domain)) + if dConf.MatchOnly { + matchDomains = append(matchDomains, "~."+dns.Fqdn(dConf.Domain)) continue } - searchDomains = append(searchDomains, dns.Fqdn(dConf.domain)) + searchDomains = append(searchDomains, dns.Fqdn(dConf.Domain)) } newDomainList := append(searchDomains, matchDomains...) //nolint:gocritic priority := networkManagerDbusSearchDomainOnlyPriority switch { - case config.routeAll: + case config.RouteAll: priority = networkManagerDbusPrimaryDNSPriority newDomainList = append(newDomainList, "~.") if !n.routingAll { - log.Infof("configured %s:%d as main DNS forwarder for this peer", config.serverIP, config.serverPort) + log.Infof("configured %s:%d as main DNS forwarder for this peer", config.ServerIP, config.ServerPort) } case len(matchDomains) > 0: priority = networkManagerDbusWithMatchDomainPriority } if priority != networkManagerDbusPrimaryDNSPriority && n.routingAll { - log.Infof("removing %s:%d as main DNS forwarder for this peer", config.serverIP, config.serverPort) + log.Infof("removing %s:%d as main DNS forwarder for this peer", config.ServerIP, config.ServerPort) n.routingAll = false } connSettings[networkManagerDbusIPv4Key][networkManagerDbusDNSPriorityKey] = dbus.MakeVariant(priority) connSettings[networkManagerDbusIPv4Key][networkManagerDbusDNSSearchKey] = dbus.MakeVariant(newDomainList) - log.Infof("adding %d search domains and %d match domains. Search list: %s , Match list: %s", len(searchDomains), len(matchDomains), searchDomains, matchDomains) + log.Infof("adding %d search Domains and %d match Domains. Search list: %s , Match list: %s", len(searchDomains), len(matchDomains), searchDomains, matchDomains) err = n.reApplyConnectionSettings(connSettings, configVersion) if err != nil { return fmt.Errorf("got an error while reapplying the connection with new settings, error: %s", err) diff --git a/client/internal/dns/resolvconf_linux.go b/client/internal/dns/resolvconf_linux.go index 1ae2de3dde3..dfe4c00f7be 100644 --- a/client/internal/dns/resolvconf_linux.go +++ b/client/internal/dns/resolvconf_linux.go @@ -39,14 +39,14 @@ func (r *resolvconf) supportCustomPort() bool { return false } -func (r *resolvconf) applyDNSConfig(config hostDNSConfig) error { +func (r *resolvconf) applyDNSConfig(config HostDNSConfig) error { var err error - if !config.routeAll { + if !config.RouteAll { err = r.restoreHostDNS() if err != nil { log.Error(err) } - return fmt.Errorf("unable to configure DNS for this peer using resolvconf manager without a nameserver group with all domains configured") + return fmt.Errorf("unable to configure DNS for this peer using resolvconf manager without a nameserver group with all Domains configured") } searchDomainList := searchDomains(config) @@ -54,7 +54,7 @@ func (r *resolvconf) applyDNSConfig(config hostDNSConfig) error { buf := prepareResolvConfContent( searchDomainList, - append([]string{config.serverIP}, r.originalNameServers...), + append([]string{config.ServerIP}, r.originalNameServers...), r.othersConfigs) err = r.applyConfig(buf) @@ -62,7 +62,7 @@ func (r *resolvconf) applyDNSConfig(config hostDNSConfig) error { return err } - log.Infof("added %d search domains. Search list: %s", len(searchDomainList), searchDomainList) + log.Infof("added %d search Domains. Search list: %s", len(searchDomainList), searchDomainList) return nil } diff --git a/client/internal/dns/server.go b/client/internal/dns/server.go index e788d0e8797..d1bc8e29362 100644 --- a/client/internal/dns/server.go +++ b/client/internal/dns/server.go @@ -48,7 +48,7 @@ type DefaultServer struct { hostManager hostManager updateSerial uint64 previousConfigHash uint64 - currentConfig hostDNSConfig + currentConfig HostDNSConfig // permanent related properties permanent bool @@ -236,20 +236,20 @@ func (s *DefaultServer) UpdateDNSServer(serial uint64, update nbdns.Config) erro func (s *DefaultServer) SearchDomains() []string { var searchDomains []string - for _, dConf := range s.currentConfig.domains { - if dConf.disabled { + for _, dConf := range s.currentConfig.Domains { + if dConf.Disabled { continue } - if dConf.matchOnly { + if dConf.MatchOnly { continue } - searchDomains = append(searchDomains, dConf.domain) + searchDomains = append(searchDomains, dConf.Domain) } return searchDomains } func (s *DefaultServer) applyConfiguration(update nbdns.Config) error { - // is the service should be disabled, we stop the listener or fake resolver + // is the service should be Disabled, we stop the listener or fake resolver // and proceed with a regular update to clean up the handlers and records if update.ServiceEnable { _ = s.service.Listen() @@ -275,7 +275,7 @@ func (s *DefaultServer) applyConfiguration(update nbdns.Config) error { if s.service.RuntimePort() != defaultPort && !s.hostManager.supportCustomPort() { log.Warnf("the DNS manager of this peer doesn't support custom port. Disabling primary DNS setup. " + "Learn more at: https://docs.netbird.io/how-to/manage-dns-in-your-network#local-resolver") - hostUpdate.routeAll = false + hostUpdate.RouteAll = false } if err = s.hostManager.applyDNSConfig(hostUpdate); err != nil { @@ -344,7 +344,7 @@ func (s *DefaultServer) buildUpstreamHandlerUpdate(nameServerGroups []*nbdns.Nam continue } - // when upstream fails to resolve domain several times over all it servers + // when upstream fails to resolve Domain several times over all it servers // it will calls this hook to exclude self from the configuration and // reapply DNS settings, but it not touch the original configuration and serial number // because it is temporal deactivation until next try @@ -364,13 +364,13 @@ func (s *DefaultServer) buildUpstreamHandlerUpdate(nameServerGroups []*nbdns.Nam if len(nsGroup.Domains) == 0 { handler.stop() - return nil, fmt.Errorf("received a non primary nameserver group with an empty domain list") + return nil, fmt.Errorf("received a non primary nameserver group with an empty Domain list") } for _, domain := range nsGroup.Domains { if domain == "" { handler.stop() - return nil, fmt.Errorf("received a nameserver group with an empty domain element") + return nil, fmt.Errorf("received a nameserver group with an empty Domain element") } muxUpdates = append(muxUpdates, muxUpdate{ domain: domain, @@ -461,14 +461,14 @@ func (s *DefaultServer) upstreamCallbacks( } if nsGroup.Primary { removeIndex[nbdns.RootZone] = -1 - s.currentConfig.routeAll = false + s.currentConfig.RouteAll = false } - for i, item := range s.currentConfig.domains { - if _, found := removeIndex[item.domain]; found { - s.currentConfig.domains[i].disabled = true - s.service.DeregisterMux(item.domain) - removeIndex[item.domain] = i + for i, item := range s.currentConfig.Domains { + if _, found := removeIndex[item.Domain]; found { + s.currentConfig.Domains[i].Disabled = true + s.service.DeregisterMux(item.Domain) + removeIndex[item.Domain] = i } } if err := s.hostManager.applyDNSConfig(s.currentConfig); err != nil { @@ -480,21 +480,21 @@ func (s *DefaultServer) upstreamCallbacks( defer s.mux.Unlock() for domain, i := range removeIndex { - if i == -1 || i >= len(s.currentConfig.domains) || s.currentConfig.domains[i].domain != domain { + if i == -1 || i >= len(s.currentConfig.Domains) || s.currentConfig.Domains[i].Domain != domain { continue } - s.currentConfig.domains[i].disabled = false + s.currentConfig.Domains[i].Disabled = false s.service.RegisterMux(domain, handler) } l := log.WithField("nameservers", nsGroup.NameServers) - l.Debug("reactivate temporary disabled nameserver group") + l.Debug("reactivate temporary Disabled nameserver group") if nsGroup.Primary { - s.currentConfig.routeAll = true + s.currentConfig.RouteAll = true } if err := s.hostManager.applyDNSConfig(s.currentConfig); err != nil { - l.WithError(err).Error("reactivate temporary disabled nameserver group, DNS update apply") + l.WithError(err).Error("reactivate temporary Disabled nameserver group, DNS update apply") } } return diff --git a/client/internal/dns/server_test.go b/client/internal/dns/server_test.go index 875a1a46f95..49ec105bb55 100644 --- a/client/internal/dns/server_test.go +++ b/client/internal/dns/server_test.go @@ -527,8 +527,8 @@ func TestDNSServerUpstreamDeactivateCallback(t *testing.T) { registeredMap: make(registrationMap), }, hostManager: hostManager, - currentConfig: hostDNSConfig{ - domains: []domainConfig{ + currentConfig: HostDNSConfig{ + Domains: []DomainConfig{ {false, "domain0", false}, {false, "domain1", false}, {false, "domain2", false}, @@ -537,13 +537,13 @@ func TestDNSServerUpstreamDeactivateCallback(t *testing.T) { } var domainsUpdate string - hostManager.applyDNSConfigFunc = func(config hostDNSConfig) error { + hostManager.applyDNSConfigFunc = func(config HostDNSConfig) error { domains := []string{} - for _, item := range config.domains { - if item.disabled { + for _, item := range config.Domains { + if item.Disabled { continue } - domains = append(domains, item.domain) + domains = append(domains, item.Domain) } domainsUpdate = strings.Join(domains, ",") return nil @@ -559,29 +559,29 @@ func TestDNSServerUpstreamDeactivateCallback(t *testing.T) { deactivate() expected := "domain0,domain2" domains := []string{} - for _, item := range server.currentConfig.domains { - if item.disabled { + for _, item := range server.currentConfig.Domains { + if item.Disabled { continue } - domains = append(domains, item.domain) + domains = append(domains, item.Domain) } got := strings.Join(domains, ",") if expected != got { - t.Errorf("expected domains list: %q, got %q", expected, got) + t.Errorf("expected Domains list: %q, got %q", expected, got) } reactivate() expected = "domain0,domain1,domain2" domains = []string{} - for _, item := range server.currentConfig.domains { - if item.disabled { + for _, item := range server.currentConfig.Domains { + if item.Disabled { continue } - domains = append(domains, item.domain) + domains = append(domains, item.Domain) } got = strings.Join(domains, ",") if expected != got { - t.Errorf("expected domains list: %q, got %q", expected, domainsUpdate) + t.Errorf("expected Domains list: %q, got %q", expected, domainsUpdate) } } diff --git a/client/internal/dns/service_listener.go b/client/internal/dns/service_listener.go index 232f6ebc257..aad1cf4f1d4 100644 --- a/client/internal/dns/service_listener.go +++ b/client/internal/dns/service_listener.go @@ -173,7 +173,7 @@ func (s *serviceViaListener) evalListenAddress() (string, int, error) { } // shouldApplyPortFwd decides whether to apply eBPF program to capture DNS traffic on port 53. -// This is needed because on some operating systems if we start a DNS server not on a default port 53, the domain name +// This is needed because on some operating systems if we start a DNS server not on a default port 53, the Domain name // resolution won't work. // So, in case we are running on Linux and picked a non-default port (53) we should fall back to the eBPF solution that will capture // traffic on port 53 and forward it to a local DNS server running on 5053. diff --git a/client/internal/dns/systemd_linux.go b/client/internal/dns/systemd_linux.go index 0358b0251f2..715d96f602c 100644 --- a/client/internal/dns/systemd_linux.go +++ b/client/internal/dns/systemd_linux.go @@ -81,8 +81,8 @@ func (s *systemdDbusConfigurator) supportCustomPort() bool { return true } -func (s *systemdDbusConfigurator) applyDNSConfig(config hostDNSConfig) error { - parsedIP, err := netip.ParseAddr(config.serverIP) +func (s *systemdDbusConfigurator) applyDNSConfig(config HostDNSConfig) error { + parsedIP, err := netip.ParseAddr(config.ServerIP) if err != nil { return fmt.Errorf("unable to parse ip address, error: %s", err) } @@ -93,7 +93,7 @@ func (s *systemdDbusConfigurator) applyDNSConfig(config hostDNSConfig) error { } err = s.callLinkMethod(systemdDbusSetDNSMethodSuffix, []systemdDbusDNSInput{defaultLinkInput}) if err != nil { - return fmt.Errorf("setting the interface DNS server %s:%d failed with error: %s", config.serverIP, config.serverPort, err) + return fmt.Errorf("setting the interface DNS server %s:%d failed with error: %s", config.ServerIP, config.ServerPort, err) } var ( @@ -101,24 +101,24 @@ func (s *systemdDbusConfigurator) applyDNSConfig(config hostDNSConfig) error { matchDomains []string domainsInput []systemdDbusLinkDomainsInput ) - for _, dConf := range config.domains { - if dConf.disabled { + for _, dConf := range config.Domains { + if dConf.Disabled { continue } domainsInput = append(domainsInput, systemdDbusLinkDomainsInput{ - Domain: dns.Fqdn(dConf.domain), - MatchOnly: dConf.matchOnly, + Domain: dns.Fqdn(dConf.Domain), + MatchOnly: dConf.MatchOnly, }) - if dConf.matchOnly { - matchDomains = append(matchDomains, dConf.domain) + if dConf.MatchOnly { + matchDomains = append(matchDomains, dConf.Domain) continue } - searchDomains = append(searchDomains, dConf.domain) + searchDomains = append(searchDomains, dConf.Domain) } - if config.routeAll { - log.Infof("configured %s:%d as main DNS forwarder for this peer", config.serverIP, config.serverPort) + if config.RouteAll { + log.Infof("configured %s:%d as main DNS forwarder for this peer", config.ServerIP, config.ServerPort) err = s.callLinkMethod(systemdDbusSetDefaultRouteMethodSuffix, true) if err != nil { return fmt.Errorf("setting link as default dns router, failed with error: %s", err) @@ -129,10 +129,10 @@ func (s *systemdDbusConfigurator) applyDNSConfig(config hostDNSConfig) error { }) s.routingAll = true } else if s.routingAll { - log.Infof("removing %s:%d as main DNS forwarder for this peer", config.serverIP, config.serverPort) + log.Infof("removing %s:%d as main DNS forwarder for this peer", config.ServerIP, config.ServerPort) } - log.Infof("adding %d search domains and %d match domains. Search list: %s , Match list: %s", len(searchDomains), len(matchDomains), searchDomains, matchDomains) + log.Infof("adding %d search Domains and %d match Domains. Search list: %s , Match list: %s", len(searchDomains), len(matchDomains), searchDomains, matchDomains) err = s.setDomainsForInterface(domainsInput) if err != nil { log.Error(err) @@ -143,7 +143,7 @@ func (s *systemdDbusConfigurator) applyDNSConfig(config hostDNSConfig) error { func (s *systemdDbusConfigurator) setDomainsForInterface(domainsInput []systemdDbusLinkDomainsInput) error { err := s.callLinkMethod(systemdDbusSetDomainsMethodSuffix, domainsInput) if err != nil { - return fmt.Errorf("setting domains configuration failed with error: %s", err) + return fmt.Errorf("setting Domains configuration failed with error: %s", err) } return s.flushCaches() } diff --git a/client/internal/dns/upstream.go b/client/internal/dns/upstream.go index 786d79e7762..a716e0f24fa 100644 --- a/client/internal/dns/upstream.go +++ b/client/internal/dns/upstream.go @@ -136,7 +136,7 @@ func (u *upstreamResolverBase) checkUpstreamFails() { default: // todo test the deactivation logic, it seems to affect the client if runtime.GOOS != "ios" { - log.Warnf("upstream resolving is disabled for %v", reactivatePeriod) + log.Warnf("upstream resolving is Disabled for %v", reactivatePeriod) u.deactivate() u.disabled = true go u.waitUntilResponse() diff --git a/client/internal/dns/upstream_test.go b/client/internal/dns/upstream_test.go index f404c95d2ab..6e4962d30bd 100644 --- a/client/internal/dns/upstream_test.go +++ b/client/internal/dns/upstream_test.go @@ -148,7 +148,7 @@ func TestUpstreamResolver_DeactivationReactivation(t *testing.T) { } if !resolver.disabled { - t.Errorf("resolver should be disabled") + t.Errorf("resolver should be Disabled") return } From 8827c523553336e7a0cdd5aad10217201f0a1845 Mon Sep 17 00:00:00 2001 From: Pascal Fischer Date: Thu, 14 Dec 2023 12:27:07 +0100 Subject: [PATCH 53/56] add logs for DNS json string --- client/internal/dns/host_ios.go | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/client/internal/dns/host_ios.go b/client/internal/dns/host_ios.go index 969a54513af..5058d6ba423 100644 --- a/client/internal/dns/host_ios.go +++ b/client/internal/dns/host_ios.go @@ -2,7 +2,8 @@ package dns import ( "encoding/json" - "fmt" + + log "github.com/sirupsen/logrus" ) type iosHostManager struct { @@ -21,7 +22,9 @@ func (a iosHostManager) applyDNSConfig(config HostDNSConfig) error { if err != nil { return err } - a.dnsManager.ApplyDns(fmt.Sprint(jsonData)) + jsonString := string(jsonData) + log.Debugf("Applying DNS settings: %s", jsonString) + a.dnsManager.ApplyDns(jsonString) return nil } From 22655159ea6672586341b6f82a9861edd06c58ab Mon Sep 17 00:00:00 2001 From: Pascal Fischer Date: Thu, 14 Dec 2023 14:09:01 +0100 Subject: [PATCH 54/56] bring back check on ios for private upstream --- client/internal/dns/server.go | 4 ++-- client/internal/dns/upstream_ios.go | 16 ++++++++++++++-- client/internal/dns/upstream_nonios.go | 2 +- client/internal/dns/upstream_test.go | 2 +- 4 files changed, 18 insertions(+), 6 deletions(-) diff --git a/client/internal/dns/server.go b/client/internal/dns/server.go index d1bc8e29362..436bddac0b2 100644 --- a/client/internal/dns/server.go +++ b/client/internal/dns/server.go @@ -325,7 +325,7 @@ func (s *DefaultServer) buildUpstreamHandlerUpdate(nameServerGroups []*nbdns.Nam continue } - handler, err := newUpstreamResolver(s.ctx, s.wgInterface.Name(), s.wgInterface.Address().IP) + handler, err := newUpstreamResolver(s.ctx, s.wgInterface.Name(), s.wgInterface.Address().IP, s.wgInterface.Address().Network) if err != nil { return nil, fmt.Errorf("unable to create a new upstream resolver, error: %v", err) } @@ -501,7 +501,7 @@ func (s *DefaultServer) upstreamCallbacks( } func (s *DefaultServer) addHostRootZone() { - handler, err := newUpstreamResolver(s.ctx, s.wgInterface.Name(), s.wgInterface.Address().IP) + handler, err := newUpstreamResolver(s.ctx, s.wgInterface.Name(), s.wgInterface.Address().IP, s.wgInterface.Address().Network) if err != nil { log.Errorf("unable to create a new upstream resolver, error: %v", err) return diff --git a/client/internal/dns/upstream_ios.go b/client/internal/dns/upstream_ios.go index 5bc696dcf83..2dac271eb3c 100644 --- a/client/internal/dns/upstream_ios.go +++ b/client/internal/dns/upstream_ios.go @@ -16,10 +16,11 @@ import ( type upstreamResolverIOS struct { *upstreamResolverBase lIP net.IP + lNet *net.IPNet iIndex int } -func newUpstreamResolver(parentCTX context.Context, interfaceName string, ip net.IP) (*upstreamResolverIOS, error) { +func newUpstreamResolver(parentCTX context.Context, interfaceName string, ip net.IP, net *net.IPNet) (*upstreamResolverIOS, error) { upstreamResolverBase := newUpstreamResolverBase(parentCTX) index, err := getInterfaceIndex(interfaceName) @@ -31,6 +32,7 @@ func newUpstreamResolver(parentCTX context.Context, interfaceName string, ip net ios := &upstreamResolverIOS{ upstreamResolverBase: upstreamResolverBase, lIP: ip, + lNet: net, iIndex: index, } ios.upstreamClient = ios @@ -39,7 +41,17 @@ func newUpstreamResolver(parentCTX context.Context, interfaceName string, ip net } func (u *upstreamResolverIOS) exchange(upstream string, r *dns.Msg) (rm *dns.Msg, t time.Duration, err error) { - client := u.getClientPrivate() + client := &dns.Client{} + upstreamHost, _, err := net.SplitHostPort(upstream) + if err != nil { + log.Errorf("error while parsing upstream host: %s", err) + } + upstreamIP := net.ParseIP(upstreamHost) + if u.lNet.Contains(upstreamIP) || net.IP.IsPrivate(upstreamIP) { + log.Debugf("using private client to query upstream: %s", upstream) + client = u.getClientPrivate() + } + u.getClientPrivate() return client.Exchange(r, upstream) } diff --git a/client/internal/dns/upstream_nonios.go b/client/internal/dns/upstream_nonios.go index 242a91b5e8d..a146f3f98ba 100644 --- a/client/internal/dns/upstream_nonios.go +++ b/client/internal/dns/upstream_nonios.go @@ -14,7 +14,7 @@ type upstreamResolverNonIOS struct { *upstreamResolverBase } -func newUpstreamResolver(parentCTX context.Context, interfaceName string, ip net.IP) (*upstreamResolverNonIOS, error) { +func newUpstreamResolver(parentCTX context.Context, interfaceName string, ip net.IP, net *net.IPNet) (*upstreamResolverNonIOS, error) { upstreamResolverBase := newUpstreamResolverBase(parentCTX) nonIOS := &upstreamResolverNonIOS{ upstreamResolverBase: upstreamResolverBase, diff --git a/client/internal/dns/upstream_test.go b/client/internal/dns/upstream_test.go index 6e4962d30bd..d73e04ce0b7 100644 --- a/client/internal/dns/upstream_test.go +++ b/client/internal/dns/upstream_test.go @@ -58,7 +58,7 @@ func TestUpstreamResolver_ServeDNS(t *testing.T) { for _, testCase := range testCases { t.Run(testCase.name, func(t *testing.T) { ctx, cancel := context.WithCancel(context.TODO()) - resolver, _ := newUpstreamResolver(ctx, "", net.IP{}) + resolver, _ := newUpstreamResolver(ctx, "", net.IP{}, &net.IPNet{}) resolver.upstreamServers = testCase.InputServers resolver.upstreamTimeout = testCase.timeout if testCase.cancelCTX { From d08ef29de94282fa2dfa02cbfc12eb2d3c38f9b4 Mon Sep 17 00:00:00 2001 From: Pascal Fischer Date: Fri, 15 Dec 2023 19:09:19 +0100 Subject: [PATCH 55/56] remove wrong (and unused) line --- client/internal/dns/upstream_ios.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/internal/dns/upstream_ios.go b/client/internal/dns/upstream_ios.go index 2dac271eb3c..7283efa2089 100644 --- a/client/internal/dns/upstream_ios.go +++ b/client/internal/dns/upstream_ios.go @@ -51,7 +51,7 @@ func (u *upstreamResolverIOS) exchange(upstream string, r *dns.Msg) (rm *dns.Msg log.Debugf("using private client to query upstream: %s", upstream) client = u.getClientPrivate() } - u.getClientPrivate() + return client.Exchange(r, upstream) } From 077d0b94f3aa404a6d1551589170b79f486fa7b6 Mon Sep 17 00:00:00 2001 From: Pascal Fischer Date: Fri, 15 Dec 2023 19:20:22 +0100 Subject: [PATCH 56/56] fix wrongly updated comments on DNSSetting export --- client/internal/dns/file_linux.go | 10 +++++----- client/internal/dns/file_linux_test.go | 10 +++++----- client/internal/dns/host_darwin.go | 12 ++++++------ client/internal/dns/host_windows.go | 6 +++--- client/internal/dns/local_test.go | 2 +- client/internal/dns/network_manager_linux.go | 2 +- client/internal/dns/resolvconf_linux.go | 4 ++-- client/internal/dns/server.go | 6 +++--- client/internal/dns/server_test.go | 4 ++-- client/internal/dns/service_listener.go | 2 +- client/internal/dns/systemd_linux.go | 4 ++-- 11 files changed, 31 insertions(+), 31 deletions(-) diff --git a/client/internal/dns/file_linux.go b/client/internal/dns/file_linux.go index e21612ba1cf..f49e9fb93ad 100644 --- a/client/internal/dns/file_linux.go +++ b/client/internal/dns/file_linux.go @@ -49,7 +49,7 @@ func (f *fileConfigurator) applyDNSConfig(config HostDNSConfig) error { return fmt.Errorf("unable to configure DNS for this peer using file manager without a Primary nameserver group. Restoring the original file return err: %s", err) } } - return fmt.Errorf("unable to configure DNS for this peer using file manager without a nameserver group with all Domains configured") + return fmt.Errorf("unable to configure DNS for this peer using file manager without a nameserver group with all domains configured") } if !backupFileExist { @@ -83,7 +83,7 @@ func (f *fileConfigurator) applyDNSConfig(config HostDNSConfig) error { return fmt.Errorf("got an creating resolver file %s. Error: %s", defaultResolvConfPath, err) } - log.Infof("created a NetBird managed %s file with your DNS settings. Added %d search Domains. Search list: %s", defaultResolvConfPath, len(searchDomainList), searchDomainList) + log.Infof("created a NetBird managed %s file with your DNS settings. Added %d search domains. Search list: %s", defaultResolvConfPath, len(searchDomainList), searchDomainList) return nil } @@ -177,7 +177,7 @@ func originalDNSConfigs(resolvconfFile string) (searchDomains, nameServers, othe continue } - if strings.HasPrefix(line, "Domain") { + if strings.HasPrefix(line, "domain") { continue } @@ -233,7 +233,7 @@ func validateAndFillSearchDomains(initialLineChars int, s *[]string, vs []string tmpCharsNumber := initialLineChars + 1 + len(sd) if tmpCharsNumber > fileMaxLineCharsLimit { // lets log all skipped Domains - log.Infof("search list line is larger than %d characters. Skipping append of %s Domain", fileMaxLineCharsLimit, sd) + log.Infof("search list line is larger than %d characters. Skipping append of %s domain", fileMaxLineCharsLimit, sd) continue } @@ -241,7 +241,7 @@ func validateAndFillSearchDomains(initialLineChars int, s *[]string, vs []string if len(*s) >= fileMaxNumberOfSearchDomains { // lets log all skipped Domains - log.Infof("already appended %d Domains to search list. Skipping append of %s Domain", fileMaxNumberOfSearchDomains, sd) + log.Infof("already appended %d domains to search list. Skipping append of %s domain", fileMaxNumberOfSearchDomains, sd) continue } *s = append(*s, sd) diff --git a/client/internal/dns/file_linux_test.go b/client/internal/dns/file_linux_test.go index f87999fe4c1..369a47ef4c8 100644 --- a/client/internal/dns/file_linux_test.go +++ b/client/internal/dns/file_linux_test.go @@ -10,7 +10,7 @@ func Test_mergeSearchDomains(t *testing.T) { originDomains := []string{"a", "b"} mergedDomains := mergeSearchDomains(searchDomains, originDomains) if len(mergedDomains) != 4 { - t.Errorf("invalid len of result Domains: %d, want: %d", len(mergedDomains), 4) + t.Errorf("invalid len of result domains: %d, want: %d", len(mergedDomains), 4) } } @@ -19,7 +19,7 @@ func Test_mergeSearchTooMuchDomains(t *testing.T) { originDomains := []string{"h", "i"} mergedDomains := mergeSearchDomains(searchDomains, originDomains) if len(mergedDomains) != 6 { - t.Errorf("invalid len of result Domains: %d, want: %d", len(mergedDomains), 6) + t.Errorf("invalid len of result domains: %d, want: %d", len(mergedDomains), 6) } } @@ -28,7 +28,7 @@ func Test_mergeSearchTooMuchDomainsInOrigin(t *testing.T) { originDomains := []string{"c", "d", "e", "f", "g"} mergedDomains := mergeSearchDomains(searchDomains, originDomains) if len(mergedDomains) != 6 { - t.Errorf("invalid len of result Domains: %d, want: %d", len(mergedDomains), 6) + t.Errorf("invalid len of result domains: %d, want: %d", len(mergedDomains), 6) } } @@ -37,7 +37,7 @@ func Test_mergeSearchTooLongDomain(t *testing.T) { originDomains := []string{"b"} mergedDomains := mergeSearchDomains(searchDomains, originDomains) if len(mergedDomains) != 1 { - t.Errorf("invalid len of result Domains: %d, want: %d", len(mergedDomains), 1) + t.Errorf("invalid len of result domains: %d, want: %d", len(mergedDomains), 1) } searchDomains = []string{"b"} @@ -45,7 +45,7 @@ func Test_mergeSearchTooLongDomain(t *testing.T) { mergedDomains = mergeSearchDomains(searchDomains, originDomains) if len(mergedDomains) != 1 { - t.Errorf("invalid len of result Domains: %d, want: %d", len(mergedDomains), 1) + t.Errorf("invalid len of result domains: %d, want: %d", len(mergedDomains), 1) } } diff --git a/client/internal/dns/host_darwin.go b/client/internal/dns/host_darwin.go index 303deb5e4a5..0f16b7828f2 100644 --- a/client/internal/dns/host_darwin.go +++ b/client/internal/dns/host_darwin.go @@ -81,7 +81,7 @@ func (s *systemConfigurator) applyDNSConfig(config HostDNSConfig) error { if len(matchDomains) != 0 { err = s.addMatchDomains(matchKey, strings.Join(matchDomains, " "), config.ServerIP, config.ServerPort) } else { - log.Infof("removing match Domains from the system") + log.Infof("removing match domains from the system") err = s.removeKeyFromSystemConfig(matchKey) } if err != nil { @@ -92,7 +92,7 @@ func (s *systemConfigurator) applyDNSConfig(config HostDNSConfig) error { if len(searchDomains) != 0 { err = s.addSearchDomains(searchKey, strings.Join(searchDomains, " "), config.ServerIP, config.ServerPort) } else { - log.Infof("removing search Domains from the system") + log.Infof("removing search domains from the system") err = s.removeKeyFromSystemConfig(searchKey) } if err != nil { @@ -110,7 +110,7 @@ func (s *systemConfigurator) restoreHostDNS() error { if strings.Contains(key, matchSuffix) { keyType = "match" } - log.Infof("removing %s Domains from system", keyType) + log.Infof("removing %s domains from system", keyType) } if s.primaryServiceID != "" { lines += buildRemoveKeyOperation(getKeyWithInput(primaryServiceSetupKeyFormat, s.primaryServiceID)) @@ -143,7 +143,7 @@ func (s *systemConfigurator) addSearchDomains(key, domains string, ip string, po return err } - log.Infof("added %d search Domains to the state. Domain list: %s", len(strings.Split(domains, " ")), domains) + log.Infof("added %d search domains to the state. Domain list: %s", len(strings.Split(domains, " ")), domains) s.createdKeys[key] = struct{}{} @@ -156,7 +156,7 @@ func (s *systemConfigurator) addMatchDomains(key, domains, dnsServer string, por return err } - log.Infof("added %d match Domains to the state. Domain list: %s", len(strings.Split(domains, " ")), domains) + log.Infof("added %d match domains to the state. Domain list: %s", len(strings.Split(domains, " ")), domains) s.createdKeys[key] = struct{}{} @@ -178,7 +178,7 @@ func (s *systemConfigurator) addDNSState(state, domains, dnsServer string, port _, err := runSystemConfigCommand(stdinCommands) if err != nil { - return fmt.Errorf("got error while applying state for Domains %s, error: %s", domains, err) + return fmt.Errorf("got error while applying state for domains %s, error: %s", domains, err) } return nil } diff --git a/client/internal/dns/host_windows.go b/client/internal/dns/host_windows.go index 7a8f8e6166e..3a574c4eefd 100644 --- a/client/internal/dns/host_windows.go +++ b/client/internal/dns/host_windows.go @@ -135,7 +135,7 @@ func (r *registryConfigurator) addDNSMatchPolicy(domains []string, ip string) er return fmt.Errorf("unable to set registry value for %s, error: %s", dnsPolicyConfigConfigOptionsKey, err) } - log.Infof("added %d match Domains to the state. Domain list: %s", len(domains), domains) + log.Infof("added %d match domains to the state. Domain list: %s", len(domains), domains) return nil } @@ -152,10 +152,10 @@ func (r *registryConfigurator) restoreHostDNS() error { func (r *registryConfigurator) updateSearchDomains(domains []string) error { err := r.setInterfaceRegistryKeyStringValue(interfaceConfigSearchListKey, strings.Join(domains, ",")) if err != nil { - return fmt.Errorf("adding search Domain failed with error: %s", err) + return fmt.Errorf("adding search domain failed with error: %s", err) } - log.Infof("updated the search Domains in the registry with %d Domains. Domain list: %s", len(domains), domains) + log.Infof("updated the search domains in the registry with %d domains. Domain list: %s", len(domains), domains) return nil } diff --git a/client/internal/dns/local_test.go b/client/internal/dns/local_test.go index 2110c63e76c..b62cd66a9bf 100644 --- a/client/internal/dns/local_test.go +++ b/client/internal/dns/local_test.go @@ -75,7 +75,7 @@ func TestLocalResolver_ServeDNS(t *testing.T) { answerString := responseMSG.Answer[0].String() if !strings.Contains(answerString, testCase.inputRecord.Name) { - t.Fatalf("answer doesn't contain the same Domain name: \nWant: %s\nGot:%s", testCase.name, answerString) + t.Fatalf("answer doesn't contain the same domain name: \nWant: %s\nGot:%s", testCase.name, answerString) } if !strings.Contains(answerString, dns.Type(testCase.inputRecord.Type).String()) { t.Fatalf("answer doesn't contain the correct type: \nWant: %s\nGot:%s", dns.Type(testCase.inputRecord.Type).String(), answerString) diff --git a/client/internal/dns/network_manager_linux.go b/client/internal/dns/network_manager_linux.go index 6b190143916..b4a7a2514b6 100644 --- a/client/internal/dns/network_manager_linux.go +++ b/client/internal/dns/network_manager_linux.go @@ -145,7 +145,7 @@ func (n *networkManagerDbusConfigurator) applyDNSConfig(config HostDNSConfig) er connSettings[networkManagerDbusIPv4Key][networkManagerDbusDNSPriorityKey] = dbus.MakeVariant(priority) connSettings[networkManagerDbusIPv4Key][networkManagerDbusDNSSearchKey] = dbus.MakeVariant(newDomainList) - log.Infof("adding %d search Domains and %d match Domains. Search list: %s , Match list: %s", len(searchDomains), len(matchDomains), searchDomains, matchDomains) + log.Infof("adding %d search domains and %d match domains. Search list: %s , Match list: %s", len(searchDomains), len(matchDomains), searchDomains, matchDomains) err = n.reApplyConnectionSettings(connSettings, configVersion) if err != nil { return fmt.Errorf("got an error while reapplying the connection with new settings, error: %s", err) diff --git a/client/internal/dns/resolvconf_linux.go b/client/internal/dns/resolvconf_linux.go index dfe4c00f7be..54bdeae128b 100644 --- a/client/internal/dns/resolvconf_linux.go +++ b/client/internal/dns/resolvconf_linux.go @@ -46,7 +46,7 @@ func (r *resolvconf) applyDNSConfig(config HostDNSConfig) error { if err != nil { log.Error(err) } - return fmt.Errorf("unable to configure DNS for this peer using resolvconf manager without a nameserver group with all Domains configured") + return fmt.Errorf("unable to configure DNS for this peer using resolvconf manager without a nameserver group with all domains configured") } searchDomainList := searchDomains(config) @@ -62,7 +62,7 @@ func (r *resolvconf) applyDNSConfig(config HostDNSConfig) error { return err } - log.Infof("added %d search Domains. Search list: %s", len(searchDomainList), searchDomainList) + log.Infof("added %d search domains. Search list: %s", len(searchDomainList), searchDomainList) return nil } diff --git a/client/internal/dns/server.go b/client/internal/dns/server.go index 436bddac0b2..439c27a2785 100644 --- a/client/internal/dns/server.go +++ b/client/internal/dns/server.go @@ -344,7 +344,7 @@ func (s *DefaultServer) buildUpstreamHandlerUpdate(nameServerGroups []*nbdns.Nam continue } - // when upstream fails to resolve Domain several times over all it servers + // when upstream fails to resolve domain several times over all it servers // it will calls this hook to exclude self from the configuration and // reapply DNS settings, but it not touch the original configuration and serial number // because it is temporal deactivation until next try @@ -364,13 +364,13 @@ func (s *DefaultServer) buildUpstreamHandlerUpdate(nameServerGroups []*nbdns.Nam if len(nsGroup.Domains) == 0 { handler.stop() - return nil, fmt.Errorf("received a non primary nameserver group with an empty Domain list") + return nil, fmt.Errorf("received a non primary nameserver group with an empty domain list") } for _, domain := range nsGroup.Domains { if domain == "" { handler.stop() - return nil, fmt.Errorf("received a nameserver group with an empty Domain element") + return nil, fmt.Errorf("received a nameserver group with an empty domain element") } muxUpdates = append(muxUpdates, muxUpdate{ domain: domain, diff --git a/client/internal/dns/server_test.go b/client/internal/dns/server_test.go index 49ec105bb55..67d411df5ac 100644 --- a/client/internal/dns/server_test.go +++ b/client/internal/dns/server_test.go @@ -567,7 +567,7 @@ func TestDNSServerUpstreamDeactivateCallback(t *testing.T) { } got := strings.Join(domains, ",") if expected != got { - t.Errorf("expected Domains list: %q, got %q", expected, got) + t.Errorf("expected domains list: %q, got %q", expected, got) } reactivate() @@ -581,7 +581,7 @@ func TestDNSServerUpstreamDeactivateCallback(t *testing.T) { } got = strings.Join(domains, ",") if expected != got { - t.Errorf("expected Domains list: %q, got %q", expected, domainsUpdate) + t.Errorf("expected domains list: %q, got %q", expected, domainsUpdate) } } diff --git a/client/internal/dns/service_listener.go b/client/internal/dns/service_listener.go index aad1cf4f1d4..232f6ebc257 100644 --- a/client/internal/dns/service_listener.go +++ b/client/internal/dns/service_listener.go @@ -173,7 +173,7 @@ func (s *serviceViaListener) evalListenAddress() (string, int, error) { } // shouldApplyPortFwd decides whether to apply eBPF program to capture DNS traffic on port 53. -// This is needed because on some operating systems if we start a DNS server not on a default port 53, the Domain name +// This is needed because on some operating systems if we start a DNS server not on a default port 53, the domain name // resolution won't work. // So, in case we are running on Linux and picked a non-default port (53) we should fall back to the eBPF solution that will capture // traffic on port 53 and forward it to a local DNS server running on 5053. diff --git a/client/internal/dns/systemd_linux.go b/client/internal/dns/systemd_linux.go index 715d96f602c..3cd4342ad3c 100644 --- a/client/internal/dns/systemd_linux.go +++ b/client/internal/dns/systemd_linux.go @@ -132,7 +132,7 @@ func (s *systemdDbusConfigurator) applyDNSConfig(config HostDNSConfig) error { log.Infof("removing %s:%d as main DNS forwarder for this peer", config.ServerIP, config.ServerPort) } - log.Infof("adding %d search Domains and %d match Domains. Search list: %s , Match list: %s", len(searchDomains), len(matchDomains), searchDomains, matchDomains) + log.Infof("adding %d search domains and %d match domains. Search list: %s , Match list: %s", len(searchDomains), len(matchDomains), searchDomains, matchDomains) err = s.setDomainsForInterface(domainsInput) if err != nil { log.Error(err) @@ -143,7 +143,7 @@ func (s *systemdDbusConfigurator) applyDNSConfig(config HostDNSConfig) error { func (s *systemdDbusConfigurator) setDomainsForInterface(domainsInput []systemdDbusLinkDomainsInput) error { err := s.callLinkMethod(systemdDbusSetDomainsMethodSuffix, domainsInput) if err != nil { - return fmt.Errorf("setting Domains configuration failed with error: %s", err) + return fmt.Errorf("setting domains configuration failed with error: %s", err) } return s.flushCaches() }