diff --git a/client/internal/dns/server_privileged_test.go b/client/internal/dns/server_privileged_test.go index 81f9b76cb..a57e4b40c 100644 --- a/client/internal/dns/server_privileged_test.go +++ b/client/internal/dns/server_privileged_test.go @@ -22,8 +22,22 @@ import ( "github.com/netbirdio/netbird/client/internal/peer" "github.com/netbirdio/netbird/client/internal/stdnet" nbdns "github.com/netbirdio/netbird/dns" + "github.com/netbirdio/netbird/shared/management/domain" ) +func generateDummyHandler(d string, servers []nbdns.NameServer) *upstreamResolverBase { + var srvs []netip.AddrPort + for _, srv := range servers { + srvs = append(srvs, srv.AddrPort()) + } + u := &upstreamResolverBase{ + domain: domain.Domain(d), + cancel: func() {}, + } + u.addRace(srvs) + return u +} + func TestUpdateDNSServer(t *testing.T) { nameServers := []nbdns.NameServer{ diff --git a/client/internal/dns/server_test.go b/client/internal/dns/server_test.go index 7d050fa67..b2b76f5ad 100644 --- a/client/internal/dns/server_test.go +++ b/client/internal/dns/server_test.go @@ -102,19 +102,6 @@ func init() { formatter.SetTextFormatter(log.StandardLogger()) } -func generateDummyHandler(d string, servers []nbdns.NameServer) *upstreamResolverBase { - var srvs []netip.AddrPort - for _, srv := range servers { - srvs = append(srvs, srv.AddrPort()) - } - u := &upstreamResolverBase{ - domain: domain.Domain(d), - cancel: func() {}, - } - u.addRace(srvs) - return u -} - func TestDNSServerStartStop(t *testing.T) { testCases := []struct { name string diff --git a/client/internal/engine_privileged_test.go b/client/internal/engine_privileged_test.go index 1773ed721..28ce6efdc 100644 --- a/client/internal/engine_privileged_test.go +++ b/client/internal/engine_privileged_test.go @@ -5,16 +5,22 @@ package internal import ( "context" "fmt" + "net" + "runtime" "strings" "sync" "testing" "time" + "github.com/golang/mock/gomock" "github.com/google/uuid" log "github.com/sirupsen/logrus" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "go.opentelemetry.io/otel" "golang.zx2c4.com/wireguard/wgctrl/wgtypes" + "google.golang.org/grpc" + "google.golang.org/grpc/keepalive" "github.com/netbirdio/netbird/client/iface" "github.com/netbirdio/netbird/client/iface/device" @@ -24,10 +30,31 @@ import ( nbssh "github.com/netbirdio/netbird/client/ssh" "github.com/netbirdio/netbird/client/system" nbdns "github.com/netbirdio/netbird/dns" + "github.com/netbirdio/netbird/management/internals/controllers/network_map/controller" + "github.com/netbirdio/netbird/management/internals/controllers/network_map/update_channel" + "github.com/netbirdio/netbird/management/internals/modules/peers" + "github.com/netbirdio/netbird/management/internals/modules/peers/ephemeral/manager" + "github.com/netbirdio/netbird/management/internals/server/config" + nbgrpc "github.com/netbirdio/netbird/management/internals/shared/grpc" + "github.com/netbirdio/netbird/management/server" + "github.com/netbirdio/netbird/management/server/activity" + nbcache "github.com/netbirdio/netbird/management/server/cache" + "github.com/netbirdio/netbird/management/server/groups" + "github.com/netbirdio/netbird/management/server/integrations/integrated_validator/validator" + "github.com/netbirdio/netbird/management/server/integrations/port_forwarding" + "github.com/netbirdio/netbird/management/server/job" + "github.com/netbirdio/netbird/management/server/permissions" + "github.com/netbirdio/netbird/management/server/settings" + "github.com/netbirdio/netbird/management/server/store" + "github.com/netbirdio/netbird/management/server/telemetry" + "github.com/netbirdio/netbird/management/server/types" mgmt "github.com/netbirdio/netbird/shared/management/client" mgmtProto "github.com/netbirdio/netbird/shared/management/proto" relayClient "github.com/netbirdio/netbird/shared/relay/client" signal "github.com/netbirdio/netbird/shared/signal/client" + "github.com/netbirdio/netbird/shared/signal/proto" + signalServer "github.com/netbirdio/netbird/signal/server" + "github.com/netbirdio/netbird/util" ) func TestEngine_SSH(t *testing.T) { @@ -341,3 +368,198 @@ loop: } } } + +var ( + kaep = keepalive.EnforcementPolicy{ + MinTime: 15 * time.Second, + PermitWithoutStream: true, + } + + kasp = keepalive.ServerParameters{ + MaxConnectionIdle: 15 * time.Second, + MaxConnectionAgeGrace: 5 * time.Second, + Time: 5 * time.Second, + Timeout: 2 * time.Second, + } +) + +func createEngine(ctx context.Context, cancel context.CancelFunc, setupKey string, i int, mgmtAddr string, signalAddr string) (*Engine, error) { + key, err := wgtypes.GeneratePrivateKey() + if err != nil { + return nil, err + } + mgmtClient, err := mgmt.NewClient(ctx, mgmtAddr, key, false) + if err != nil { + return nil, err + } + signalClient, err := signal.NewClient(ctx, signalAddr, key, false) + if err != nil { + return nil, err + } + + info := system.GetInfo(ctx) + resp, err := mgmtClient.Register(setupKey, "", info, nil, nil) + if err != nil { + return nil, err + } + + var ifaceName string + if runtime.GOOS == "darwin" { + ifaceName = fmt.Sprintf("utun1%d", i) + } else { + ifaceName = fmt.Sprintf("wt%d", i) + } + + wgPort := 33100 + i + conf := &EngineConfig{ + WgIfaceName: ifaceName, + WgAddr: wgaddr.MustParseWGAddress(resp.PeerConfig.Address), + WgPrivateKey: key, + WgPort: wgPort, + MTU: iface.DefaultMTU, + } + + relayMgr := relayClient.NewManager(ctx, nil, key.PublicKey().String(), iface.DefaultMTU) + e, err := NewEngine(ctx, cancel, conf, EngineServices{ + SignalClient: signalClient, + MgmClient: mgmtClient, + RelayManager: relayMgr, + StatusRecorder: peer.NewRecorder("https://mgm"), + }, MobileDependency{}), nil + e.ctx = ctx + return e, err +} + +func startSignal(t *testing.T) (*grpc.Server, string, error) { + t.Helper() + + s := grpc.NewServer(grpc.KeepaliveEnforcementPolicy(kaep), grpc.KeepaliveParams(kasp)) + + lis, err := net.Listen("tcp", "localhost:0") + if err != nil { + log.Fatalf("failed to listen: %v", err) + } + + srv, err := signalServer.NewServer(context.Background(), otel.Meter("")) + require.NoError(t, err) + proto.RegisterSignalExchangeServer(s, srv) + + go func() { + if err = s.Serve(lis); err != nil { + log.Fatalf("failed to serve: %v", err) + } + }() + + return s, lis.Addr().String(), nil +} + +func startManagement(t *testing.T, dataDir, testFile string) (*grpc.Server, string, error) { + t.Helper() + + config := &config.Config{ + Stuns: []*config.Host{}, + TURNConfig: &config.TURNConfig{}, + Relay: &config.Relay{ + Addresses: []string{"127.0.0.1:1234"}, + CredentialsTTL: util.Duration{Duration: time.Hour}, + Secret: "222222222222222222", + }, + Signal: &config.Host{ + Proto: "http", + URI: "localhost:10000", + }, + Datadir: dataDir, + HttpConfig: nil, + } + + lis, err := net.Listen("tcp", "localhost:0") + if err != nil { + return nil, "", err + } + s := grpc.NewServer(grpc.KeepaliveEnforcementPolicy(kaep), grpc.KeepaliveParams(kasp)) + + store, cleanUp, err := store.NewTestStoreFromSQL(context.Background(), testFile, config.Datadir) + if err != nil { + return nil, "", err + } + t.Cleanup(cleanUp) + + eventStore := &activity.InMemoryEventStore{} + if err != nil { + return nil, "", err + } + + permissionsManager := permissions.NewManager(store) + peersManager := peers.NewManager(store, permissionsManager) + jobManager := job.NewJobManager(nil, store, peersManager) + + cacheStore, err := nbcache.NewStore(context.Background(), 100*time.Millisecond, 300*time.Millisecond, 100) + if err != nil { + return nil, "", err + } + + ia, _ := validator.NewIntegratedValidator(context.Background(), peersManager, nil, eventStore, cacheStore) + + metrics, err := telemetry.NewDefaultAppMetrics(context.Background()) + require.NoError(t, err) + + ctrl := gomock.NewController(t) + t.Cleanup(ctrl.Finish) + settingsMockManager := settings.NewMockManager(ctrl) + settingsMockManager.EXPECT(). + GetSettings(gomock.Any(), gomock.Any(), gomock.Any()). + Return(&types.Settings{}, nil). + AnyTimes() + settingsMockManager.EXPECT(). + GetExtraSettings(gomock.Any(), gomock.Any()). + Return(&types.ExtraSettings{}, nil). + AnyTimes() + + groupsManager := groups.NewManagerMock() + + updateManager := update_channel.NewPeersUpdateManager(metrics) + requestBuffer := server.NewAccountRequestBuffer(context.Background(), store) + networkMapController := controller.NewController(context.Background(), store, metrics, updateManager, requestBuffer, server.MockIntegratedValidator{}, settingsMockManager, "netbird.selfhosted", port_forwarding.NewControllerMock(), manager.NewEphemeralManager(store, peersManager), config) + accountManager, err := server.BuildManager(context.Background(), config, store, networkMapController, jobManager, nil, "", eventStore, nil, false, ia, metrics, port_forwarding.NewControllerMock(), settingsMockManager, permissionsManager, false, cacheStore) + if err != nil { + return nil, "", err + } + + secretsManager, err := nbgrpc.NewTimeBasedAuthSecretsManager(updateManager, config.TURNConfig, config.Relay, settingsMockManager, groupsManager) + if err != nil { + return nil, "", err + } + mgmtServer, err := nbgrpc.NewServer(config, accountManager, settingsMockManager, jobManager, secretsManager, nil, nil, &server.MockIntegratedValidator{}, networkMapController, nil, nil) + if err != nil { + return nil, "", err + } + mgmtProto.RegisterManagementServiceServer(s, mgmtServer) + go func() { + if err = s.Serve(lis); err != nil { + log.Fatalf("failed to serve: %v", err) + } + }() + + return s, lis.Addr().String(), nil +} + +// getConnectedPeers returns a connection Status or nil if peer connection wasn't found +func getConnectedPeers(e *Engine) int { + e.syncMsgMux.Lock() + defer e.syncMsgMux.Unlock() + i := 0 + for _, id := range e.peerStore.PeersPubKey() { + conn, _ := e.peerStore.PeerConn(id) + if conn.IsConnected() { + i++ + } + } + return i +} + +func getPeers(e *Engine) int { + e.syncMsgMux.Lock() + defer e.syncMsgMux.Unlock() + + return len(e.peerStore.PeersPubKey()) +} diff --git a/client/internal/engine_test.go b/client/internal/engine_test.go index b74edc3e4..2511438a3 100644 --- a/client/internal/engine_test.go +++ b/client/internal/engine_test.go @@ -6,36 +6,18 @@ import ( "net" "net/netip" "os" - "runtime" "strings" "sync" "testing" "time" - "github.com/golang/mock/gomock" - log "github.com/sirupsen/logrus" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "go.opentelemetry.io/otel" wgdevice "golang.zx2c4.com/wireguard/device" "golang.zx2c4.com/wireguard/tun/netstack" "golang.zx2c4.com/wireguard/wgctrl/wgtypes" - "google.golang.org/grpc" - "google.golang.org/grpc/keepalive" "github.com/netbirdio/netbird/client/internal/stdnet" - "github.com/netbirdio/netbird/management/server/job" - - "github.com/netbirdio/netbird/management/server/integrations/integrated_validator/validator" - - "github.com/netbirdio/netbird/management/internals/controllers/network_map/controller" - "github.com/netbirdio/netbird/management/internals/controllers/network_map/update_channel" - "github.com/netbirdio/netbird/management/internals/modules/peers" - "github.com/netbirdio/netbird/management/internals/modules/peers/ephemeral/manager" - nbgrpc "github.com/netbirdio/netbird/management/internals/shared/grpc" - - "github.com/netbirdio/netbird/management/internals/server/config" - "github.com/netbirdio/netbird/management/server/groups" "github.com/netbirdio/netbird/client/iface" "github.com/netbirdio/netbird/client/iface/configurer" @@ -49,17 +31,7 @@ import ( icemaker "github.com/netbirdio/netbird/client/internal/peer/ice" "github.com/netbirdio/netbird/client/internal/profilemanager" "github.com/netbirdio/netbird/client/internal/routemanager" - "github.com/netbirdio/netbird/client/system" nbdns "github.com/netbirdio/netbird/dns" - "github.com/netbirdio/netbird/management/server" - "github.com/netbirdio/netbird/management/server/activity" - nbcache "github.com/netbirdio/netbird/management/server/cache" - "github.com/netbirdio/netbird/management/server/integrations/port_forwarding" - "github.com/netbirdio/netbird/management/server/permissions" - "github.com/netbirdio/netbird/management/server/settings" - "github.com/netbirdio/netbird/management/server/store" - "github.com/netbirdio/netbird/management/server/telemetry" - "github.com/netbirdio/netbird/management/server/types" "github.com/netbirdio/netbird/monotime" "github.com/netbirdio/netbird/route" mgmt "github.com/netbirdio/netbird/shared/management/client" @@ -67,25 +39,9 @@ import ( "github.com/netbirdio/netbird/shared/netiputil" relayClient "github.com/netbirdio/netbird/shared/relay/client" signal "github.com/netbirdio/netbird/shared/signal/client" - "github.com/netbirdio/netbird/shared/signal/proto" - signalServer "github.com/netbirdio/netbird/signal/server" "github.com/netbirdio/netbird/util" ) -var ( - kaep = keepalive.EnforcementPolicy{ - MinTime: 15 * time.Second, - PermitWithoutStream: true, - } - - kasp = keepalive.ServerParameters{ - MaxConnectionIdle: 15 * time.Second, - MaxConnectionAgeGrace: 5 * time.Second, - Time: 5 * time.Second, - Timeout: 2 * time.Second, - } -) - type MockWGIface struct { CreateFunc func() error CreateOnAndroidFunc func(routeRange []string, ip string, domains []string) error @@ -1212,187 +1168,6 @@ func TestCompareNetIPLists(t *testing.T) { } } -func createEngine(ctx context.Context, cancel context.CancelFunc, setupKey string, i int, mgmtAddr string, signalAddr string) (*Engine, error) { - key, err := wgtypes.GeneratePrivateKey() - if err != nil { - return nil, err - } - mgmtClient, err := mgmt.NewClient(ctx, mgmtAddr, key, false) - if err != nil { - return nil, err - } - signalClient, err := signal.NewClient(ctx, signalAddr, key, false) - if err != nil { - return nil, err - } - - info := system.GetInfo(ctx) - resp, err := mgmtClient.Register(setupKey, "", info, nil, nil) - if err != nil { - return nil, err - } - - var ifaceName string - if runtime.GOOS == "darwin" { - ifaceName = fmt.Sprintf("utun1%d", i) - } else { - ifaceName = fmt.Sprintf("wt%d", i) - } - - wgPort := 33100 + i - conf := &EngineConfig{ - WgIfaceName: ifaceName, - WgAddr: wgaddr.MustParseWGAddress(resp.PeerConfig.Address), - WgPrivateKey: key, - WgPort: wgPort, - MTU: iface.DefaultMTU, - } - - relayMgr := relayClient.NewManager(ctx, nil, key.PublicKey().String(), iface.DefaultMTU) - e, err := NewEngine(ctx, cancel, conf, EngineServices{ - SignalClient: signalClient, - MgmClient: mgmtClient, - RelayManager: relayMgr, - StatusRecorder: peer.NewRecorder("https://mgm"), - }, MobileDependency{}), nil - e.ctx = ctx - return e, err -} - -func startSignal(t *testing.T) (*grpc.Server, string, error) { - t.Helper() - - s := grpc.NewServer(grpc.KeepaliveEnforcementPolicy(kaep), grpc.KeepaliveParams(kasp)) - - lis, err := net.Listen("tcp", "localhost:0") - if err != nil { - log.Fatalf("failed to listen: %v", err) - } - - srv, err := signalServer.NewServer(context.Background(), otel.Meter("")) - require.NoError(t, err) - proto.RegisterSignalExchangeServer(s, srv) - - go func() { - if err = s.Serve(lis); err != nil { - log.Fatalf("failed to serve: %v", err) - } - }() - - return s, lis.Addr().String(), nil -} - -func startManagement(t *testing.T, dataDir, testFile string) (*grpc.Server, string, error) { - t.Helper() - - config := &config.Config{ - Stuns: []*config.Host{}, - TURNConfig: &config.TURNConfig{}, - Relay: &config.Relay{ - Addresses: []string{"127.0.0.1:1234"}, - CredentialsTTL: util.Duration{Duration: time.Hour}, - Secret: "222222222222222222", - }, - Signal: &config.Host{ - Proto: "http", - URI: "localhost:10000", - }, - Datadir: dataDir, - HttpConfig: nil, - } - - lis, err := net.Listen("tcp", "localhost:0") - if err != nil { - return nil, "", err - } - s := grpc.NewServer(grpc.KeepaliveEnforcementPolicy(kaep), grpc.KeepaliveParams(kasp)) - - store, cleanUp, err := store.NewTestStoreFromSQL(context.Background(), testFile, config.Datadir) - if err != nil { - return nil, "", err - } - t.Cleanup(cleanUp) - - eventStore := &activity.InMemoryEventStore{} - if err != nil { - return nil, "", err - } - - permissionsManager := permissions.NewManager(store) - peersManager := peers.NewManager(store, permissionsManager) - jobManager := job.NewJobManager(nil, store, peersManager) - - cacheStore, err := nbcache.NewStore(context.Background(), 100*time.Millisecond, 300*time.Millisecond, 100) - if err != nil { - return nil, "", err - } - - ia, _ := validator.NewIntegratedValidator(context.Background(), peersManager, nil, eventStore, cacheStore) - - metrics, err := telemetry.NewDefaultAppMetrics(context.Background()) - require.NoError(t, err) - - ctrl := gomock.NewController(t) - t.Cleanup(ctrl.Finish) - settingsMockManager := settings.NewMockManager(ctrl) - settingsMockManager.EXPECT(). - GetSettings(gomock.Any(), gomock.Any(), gomock.Any()). - Return(&types.Settings{}, nil). - AnyTimes() - settingsMockManager.EXPECT(). - GetExtraSettings(gomock.Any(), gomock.Any()). - Return(&types.ExtraSettings{}, nil). - AnyTimes() - - groupsManager := groups.NewManagerMock() - - updateManager := update_channel.NewPeersUpdateManager(metrics) - requestBuffer := server.NewAccountRequestBuffer(context.Background(), store) - networkMapController := controller.NewController(context.Background(), store, metrics, updateManager, requestBuffer, server.MockIntegratedValidator{}, settingsMockManager, "netbird.selfhosted", port_forwarding.NewControllerMock(), manager.NewEphemeralManager(store, peersManager), config) - accountManager, err := server.BuildManager(context.Background(), config, store, networkMapController, jobManager, nil, "", eventStore, nil, false, ia, metrics, port_forwarding.NewControllerMock(), settingsMockManager, permissionsManager, false, cacheStore) - if err != nil { - return nil, "", err - } - - secretsManager, err := nbgrpc.NewTimeBasedAuthSecretsManager(updateManager, config.TURNConfig, config.Relay, settingsMockManager, groupsManager) - if err != nil { - return nil, "", err - } - mgmtServer, err := nbgrpc.NewServer(config, accountManager, settingsMockManager, jobManager, secretsManager, nil, nil, &server.MockIntegratedValidator{}, networkMapController, nil, nil) - if err != nil { - return nil, "", err - } - mgmtProto.RegisterManagementServiceServer(s, mgmtServer) - go func() { - if err = s.Serve(lis); err != nil { - log.Fatalf("failed to serve: %v", err) - } - }() - - return s, lis.Addr().String(), nil -} - -// getConnectedPeers returns a connection Status or nil if peer connection wasn't found -func getConnectedPeers(e *Engine) int { - e.syncMsgMux.Lock() - defer e.syncMsgMux.Unlock() - i := 0 - for _, id := range e.peerStore.PeersPubKey() { - conn, _ := e.peerStore.PeerConn(id) - if conn.IsConnected() { - i++ - } - } - return i -} - -func getPeers(e *Engine) int { - e.syncMsgMux.Lock() - defer e.syncMsgMux.Unlock() - - return len(e.peerStore.PeersPubKey()) -} - func mustEncodePrefix(t *testing.T, p netip.Prefix) []byte { t.Helper() b, err := netiputil.EncodePrefix(p) diff --git a/client/internal/routemanager/systemops/systemops_bsd_test.go b/client/internal/routemanager/systemops/systemops_bsd_test.go index f9d989812..9650945b3 100644 --- a/client/internal/routemanager/systemops/systemops_bsd_test.go +++ b/client/internal/routemanager/systemops/systemops_bsd_test.go @@ -9,8 +9,16 @@ import ( "golang.org/x/net/route" ) +// Interface names used by the shared routing test fixtures. Kept untagged (no +// privileged build tag) so the non-privileged test files in this package compile. +// +//nolint:unused // consumed by the privileged-tagged routing tests var expectedVPNint = "utun100" + +//nolint:unused // consumed by the privileged-tagged routing tests var expectedExternalInt = "lo0" + +//nolint:unused // consumed by the privileged-tagged routing tests var expectedInternalInt = "lo0" func TestBits(t *testing.T) { diff --git a/client/internal/routemanager/systemops/v6route_bsd_test.go b/client/internal/routemanager/systemops/v6route_bsd_test.go index 98ce29c6d..90e49f54e 100644 --- a/client/internal/routemanager/systemops/v6route_bsd_test.go +++ b/client/internal/routemanager/systemops/v6route_bsd_test.go @@ -11,6 +11,8 @@ import ( // ensureIPv6DefaultRoute installs an IPv6 default route via the loopback // interface so route lookups for global IPv6 prefixes resolve in environments // without v6 connectivity. If a default already exists it is left alone. +// +//nolint:unused // consumed by the privileged-tagged routing tests func ensureIPv6DefaultRoute(t *testing.T) { t.Helper() diff --git a/client/internal/routemanager/systemops/v6route_windows_test.go b/client/internal/routemanager/systemops/v6route_windows_test.go index f79277b87..2c813a790 100644 --- a/client/internal/routemanager/systemops/v6route_windows_test.go +++ b/client/internal/routemanager/systemops/v6route_windows_test.go @@ -8,11 +8,14 @@ import ( "testing" ) +//nolint:unused // consumed by the privileged-tagged routing tests const loopbackIfaceWindows = "Loopback Pseudo-Interface 1" // ensureIPv6DefaultRoute installs an IPv6 default route via the loopback // interface so route lookups for global IPv6 prefixes resolve in environments // without v6 connectivity. If a default already exists it is left alone. +// +//nolint:unused // consumed by the privileged-tagged routing tests func ensureIPv6DefaultRoute(t *testing.T) { t.Helper() diff --git a/client/ssh/proxy/proxy_privileged_test.go b/client/ssh/proxy/proxy_privileged_test.go index d76c40e8c..94495a3ae 100644 --- a/client/ssh/proxy/proxy_privileged_test.go +++ b/client/ssh/proxy/proxy_privileged_test.go @@ -33,6 +33,10 @@ import ( sshuserhash "github.com/netbirdio/netbird/shared/sshauth" ) +func (m *mockDaemon) setJWTToken(token string) { + m.impl.jwtToken = token +} + func TestSSHProxy_Connect(t *testing.T) { if testing.Short() { t.Skip("Skipping integration test in short mode") diff --git a/client/ssh/proxy/proxy_test.go b/client/ssh/proxy/proxy_test.go index bb11208b4..2795c786b 100644 --- a/client/ssh/proxy/proxy_test.go +++ b/client/ssh/proxy/proxy_test.go @@ -150,10 +150,6 @@ func (m *mockDaemon) setHostKey(addr string, pubKey []byte) { m.impl.hostKeys[addr] = pubKey } -func (m *mockDaemon) setJWTToken(token string) { - m.impl.jwtToken = token -} - func (m *mockDaemon) stop() { if m.server != nil { m.server.Stop()