diff --git a/client/internal/routemanager/firewall_linux.go b/client/internal/routemanager/firewall_linux.go index 8b27c8967..19a5a4cde 100644 --- a/client/internal/routemanager/firewall_linux.go +++ b/client/internal/routemanager/firewall_linux.go @@ -27,14 +27,19 @@ func genKey(format string, input string) string { } // NewFirewall if supported, returns an iptables manager, otherwise returns a nftables manager -func NewFirewall(parentCTX context.Context) firewallManager { +func NewFirewall(parentCTX context.Context) (firewallManager, error) { manager, err := newNFTablesManager(parentCTX) if err == nil { log.Debugf("nftables firewall manager will be used") - return manager + return manager, nil } - log.Debugf("fallback to iptables firewall manager: %s", err) - return newIptablesManager(parentCTX) + fMgr, err := newIptablesManager(parentCTX) + if err != nil { + log.Debugf("failed to initialize iptables for root mgr: %s", err) + return nil, err + } + log.Debugf("iptables firewall manager will be used") + return fMgr, nil } func getInPair(pair routerPair) routerPair { diff --git a/client/internal/routemanager/firewall_nonlinux.go b/client/internal/routemanager/firewall_nonlinux.go index 4691f15f8..1b52a1e85 100644 --- a/client/internal/routemanager/firewall_nonlinux.go +++ b/client/internal/routemanager/firewall_nonlinux.go @@ -3,24 +3,12 @@ package routemanager -import "context" +import ( + "context" + "fmt" +) -type unimplementedFirewall struct{} - -func (unimplementedFirewall) RestoreOrCreateContainers() error { - return nil -} -func (unimplementedFirewall) InsertRoutingRules(pair routerPair) error { - return nil -} -func (unimplementedFirewall) RemoveRoutingRules(pair routerPair) error { - return nil -} - -func (unimplementedFirewall) CleanRoutingRules() { -} - -// NewFirewall returns an unimplemented Firewall manager -func NewFirewall(parentCtx context.Context) firewallManager { - return unimplementedFirewall{} +// NewFirewall returns a nil manager +func NewFirewall(context.Context) (firewallManager, error) { + return nil, fmt.Errorf("firewall not supported on this OS") } diff --git a/client/internal/routemanager/iptables_linux.go b/client/internal/routemanager/iptables_linux.go index 3e3c16919..a87d4f4a3 100644 --- a/client/internal/routemanager/iptables_linux.go +++ b/client/internal/routemanager/iptables_linux.go @@ -49,14 +49,12 @@ type iptablesManager struct { mux sync.Mutex } -func newIptablesManager(parentCtx context.Context) *iptablesManager { - ctx, cancel := context.WithCancel(parentCtx) +func newIptablesManager(parentCtx context.Context) (*iptablesManager, error) { ipv4Client, err := iptables.NewWithProtocol(iptables.ProtocolIPv4) if err != nil { - log.Debugf("failed to initialize iptables for ipv4: %s", err) + return nil, err } else if !isIptablesClientAvailable(ipv4Client) { - log.Infof("iptables is missing for ipv4") - ipv4Client = nil + return nil, fmt.Errorf("iptables is missing for ipv4") } ipv6Client, err := iptables.NewWithProtocol(iptables.ProtocolIPv6) if err != nil { @@ -66,13 +64,14 @@ func newIptablesManager(parentCtx context.Context) *iptablesManager { ipv6Client = nil } + ctx, cancel := context.WithCancel(parentCtx) return &iptablesManager{ ctx: ctx, stop: cancel, ipv4Client: ipv4Client, ipv6Client: ipv6Client, rules: make(map[string]map[string][]string), - } + }, nil } // CleanRoutingRules cleans existing iptables resources that we created by the agent @@ -395,6 +394,10 @@ func (i *iptablesManager) insertRoutingRule(keyFormat, table, chain, jump string ipVersion = ipv6 } + if iptablesClient == nil { + return fmt.Errorf("unable to insert iptables routing rules. Iptables client is not initialized") + } + ruleKey := genKey(keyFormat, pair.ID) rule := genRuleSpec(jump, ruleKey, pair.source, pair.destination) existingRule, found := i.rules[ipVersion][ruleKey] @@ -459,6 +462,10 @@ func (i *iptablesManager) removeRoutingRule(keyFormat, table, chain string, pair ipVersion = ipv6 } + if iptablesClient == nil { + return fmt.Errorf("unable to remove iptables routing rules. Iptables client is not initialized") + } + ruleKey := genKey(keyFormat, pair.ID) existingRule, found := i.rules[ipVersion][ruleKey] if found { diff --git a/client/internal/routemanager/iptables_linux_test.go b/client/internal/routemanager/iptables_linux_test.go index c26355e56..dbe153f7b 100644 --- a/client/internal/routemanager/iptables_linux_test.go +++ b/client/internal/routemanager/iptables_linux_test.go @@ -16,7 +16,7 @@ func TestIptablesManager_RestoreOrCreateContainers(t *testing.T) { t.SkipNow() } - manager := newIptablesManager(context.TODO()) + manager, _ := newIptablesManager(context.TODO()) defer manager.CleanRoutingRules() diff --git a/client/internal/routemanager/manager.go b/client/internal/routemanager/manager.go index 7324759f9..13d9d1f38 100644 --- a/client/internal/routemanager/manager.go +++ b/client/internal/routemanager/manager.go @@ -27,7 +27,7 @@ type DefaultManager struct { stop context.CancelFunc mux sync.Mutex clientNetworks map[string]*clientNetwork - serverRouter *serverRouter + serverRouter serverRouter statusRecorder *peer.Status wgInterface *iface.WGIface pubKey string @@ -36,13 +36,17 @@ 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 { - mCTX, cancel := context.WithCancel(ctx) + serverRouter, err := newServerRouter(ctx, wgInterface) + if err != nil { + log.Errorf("server router is not supported: %s", err) + } + mCTX, cancel := context.WithCancel(ctx) dm := &DefaultManager{ ctx: mCTX, stop: cancel, clientNetworks: make(map[string]*clientNetwork), - serverRouter: newServerRouter(ctx, wgInterface), + serverRouter: serverRouter, statusRecorder: statusRecorder, wgInterface: wgInterface, pubKey: pubKey, @@ -59,7 +63,9 @@ func NewManager(ctx context.Context, pubKey string, wgInterface *iface.WGIface, // Stop stops the manager watchers and clean firewall rules func (m *DefaultManager) Stop() { m.stop() - m.serverRouter.cleanUp() + if m.serverRouter != nil { + m.serverRouter.cleanUp() + } m.ctx = nil } @@ -77,9 +83,12 @@ func (m *DefaultManager) UpdateRoutes(updateSerial uint64, newRoutes []*route.Ro m.updateClientNetworks(updateSerial, newClientRoutesIDMap) m.notifier.onNewRoutes(newClientRoutesIDMap) - err := m.serverRouter.updateRoutes(newServerRoutesMap) - if err != nil { - return err + + if m.serverRouter != nil { + err := m.serverRouter.updateRoutes(newServerRoutesMap) + if err != nil { + return err + } } return nil diff --git a/client/internal/routemanager/manager_test.go b/client/internal/routemanager/manager_test.go index 6291b4996..6f2ac294d 100644 --- a/client/internal/routemanager/manager_test.go +++ b/client/internal/routemanager/manager_test.go @@ -30,7 +30,6 @@ func TestManagerUpdateRoutes(t *testing.T) { inputInitRoutes []*route.Route inputRoutes []*route.Route inputSerial uint64 - shouldCheckServerRoutes bool serverRoutesExpected int clientNetworkWatchersExpected int }{ @@ -87,7 +86,6 @@ func TestManagerUpdateRoutes(t *testing.T) { }, }, inputSerial: 1, - shouldCheckServerRoutes: runtime.GOOS == "linux", serverRoutesExpected: 2, clientNetworkWatchersExpected: 0, }, @@ -116,7 +114,6 @@ func TestManagerUpdateRoutes(t *testing.T) { }, }, inputSerial: 1, - shouldCheckServerRoutes: runtime.GOOS == "linux", serverRoutesExpected: 1, clientNetworkWatchersExpected: 1, }, @@ -174,25 +171,6 @@ func TestManagerUpdateRoutes(t *testing.T) { inputSerial: 1, clientNetworkWatchersExpected: 0, }, - { - name: "No Server Routes Should Be Added To Non Linux", - inputRoutes: []*route.Route{ - { - ID: "a", - NetID: "routeA", - Peer: localPeerKey, - Network: netip.MustParsePrefix("1.2.3.4/32"), - NetworkType: route.IPv4Network, - Metric: 9999, - Masquerade: false, - Enabled: true, - }, - }, - inputSerial: 1, - shouldCheckServerRoutes: runtime.GOOS != "linux", - serverRoutesExpected: 0, - clientNetworkWatchersExpected: 0, - }, { name: "Remove 1 Client Route", inputInitRoutes: []*route.Route{ @@ -335,7 +313,6 @@ func TestManagerUpdateRoutes(t *testing.T) { }, inputRoutes: []*route.Route{}, inputSerial: 1, - shouldCheckServerRoutes: true, serverRoutesExpected: 0, clientNetworkWatchersExpected: 0, }, @@ -384,7 +361,6 @@ func TestManagerUpdateRoutes(t *testing.T) { }, }, inputSerial: 1, - shouldCheckServerRoutes: runtime.GOOS == "linux", serverRoutesExpected: 2, clientNetworkWatchersExpected: 1, }, @@ -419,8 +395,9 @@ func TestManagerUpdateRoutes(t *testing.T) { require.Len(t, routeManager.clientNetworks, testCase.clientNetworkWatchersExpected, "client networks size should match") - if testCase.shouldCheckServerRoutes { - require.Len(t, routeManager.serverRouter.routes, testCase.serverRoutesExpected, "server networks size should match") + if runtime.GOOS == "linux" { + sr := routeManager.serverRouter.(*defaultServerRouter) + require.Len(t, sr.routes, testCase.serverRoutesExpected, "server networks size should match") } }) } diff --git a/client/internal/routemanager/server.go b/client/internal/routemanager/server.go new file mode 100644 index 000000000..c9a13a904 --- /dev/null +++ b/client/internal/routemanager/server.go @@ -0,0 +1,9 @@ +package routemanager + +import "github.com/netbirdio/netbird/route" + +type serverRouter interface { + updateRoutes(map[string]*route.Route) error + removeFromServerNetwork(*route.Route) error + cleanUp() +} diff --git a/client/internal/routemanager/server_android.go b/client/internal/routemanager/server_android.go index c5e79a1a8..d130acc00 100644 --- a/client/internal/routemanager/server_android.go +++ b/client/internal/routemanager/server_android.go @@ -2,20 +2,11 @@ package routemanager import ( "context" + "fmt" "github.com/netbirdio/netbird/iface" - "github.com/netbirdio/netbird/route" ) -type serverRouter struct { +func newServerRouter(context.Context, *iface.WGIface) (serverRouter, error) { + return nil, fmt.Errorf("server route not supported on this os") } - -func newServerRouter(ctx context.Context, wgInterface *iface.WGIface) *serverRouter { - return &serverRouter{} -} - -func (r *serverRouter) updateRoutes(routesMap map[string]*route.Route) error { - return nil -} - -func (r *serverRouter) cleanUp() {} diff --git a/client/internal/routemanager/server_nonandroid.go b/client/internal/routemanager/server_nonandroid.go index 4b85149fa..bf7a1dfd4 100644 --- a/client/internal/routemanager/server_nonandroid.go +++ b/client/internal/routemanager/server_nonandroid.go @@ -13,7 +13,7 @@ import ( "github.com/netbirdio/netbird/route" ) -type serverRouter struct { +type defaultServerRouter struct { mux sync.Mutex ctx context.Context routes map[string]*route.Route @@ -21,16 +21,21 @@ type serverRouter struct { wgInterface *iface.WGIface } -func newServerRouter(ctx context.Context, wgInterface *iface.WGIface) *serverRouter { - return &serverRouter{ +func newServerRouter(ctx context.Context, wgInterface *iface.WGIface) (serverRouter, error) { + firewall, err := NewFirewall(ctx) + if err != nil { + return nil, err + } + + return &defaultServerRouter{ ctx: ctx, routes: make(map[string]*route.Route), - firewall: NewFirewall(ctx), + firewall: firewall, wgInterface: wgInterface, - } + }, nil } -func (m *serverRouter) updateRoutes(routesMap map[string]*route.Route) error { +func (m *defaultServerRouter) updateRoutes(routesMap map[string]*route.Route) error { serverRoutesToRemove := make([]string, 0) if len(routesMap) > 0 { @@ -81,7 +86,7 @@ func (m *serverRouter) updateRoutes(routesMap map[string]*route.Route) error { return nil } -func (m *serverRouter) removeFromServerNetwork(route *route.Route) error { +func (m *defaultServerRouter) removeFromServerNetwork(route *route.Route) error { select { case <-m.ctx.Done(): log.Infof("not removing from server network because context is done") @@ -98,7 +103,7 @@ func (m *serverRouter) removeFromServerNetwork(route *route.Route) error { } } -func (m *serverRouter) addToServerNetwork(route *route.Route) error { +func (m *defaultServerRouter) addToServerNetwork(route *route.Route) error { select { case <-m.ctx.Done(): log.Infof("not adding to server network because context is done") @@ -115,6 +120,6 @@ func (m *serverRouter) addToServerNetwork(route *route.Route) error { } } -func (m *serverRouter) cleanUp() { +func (m *defaultServerRouter) cleanUp() { m.firewall.CleanRoutingRules() } diff --git a/client/internal/stdnet/filter.go b/client/internal/stdnet/filter.go index da35a623f..8bbb93a25 100644 --- a/client/internal/stdnet/filter.go +++ b/client/internal/stdnet/filter.go @@ -20,7 +20,7 @@ func InterfaceFilter(disallowList []string) func(string) bool { for _, s := range disallowList { if strings.HasPrefix(iFace, s) { - log.Debugf("ignoring interface %s - it is not allowed", iFace) + log.Tracef("ignoring interface %s - it is not allowed", iFace) return false } } diff --git a/go.mod b/go.mod index 32e25c1a0..7ecf61584 100644 --- a/go.mod +++ b/go.mod @@ -31,7 +31,7 @@ require ( fyne.io/fyne/v2 v2.1.4 github.com/c-robinson/iplib v1.0.3 github.com/cilium/ebpf v0.10.0 - github.com/coreos/go-iptables v0.6.0 + github.com/coreos/go-iptables v0.7.0 github.com/creack/pty v1.1.18 github.com/eko/gocache/v3 v3.1.1 github.com/getlantern/systray v1.2.1 diff --git a/go.sum b/go.sum index da913db52..1eb9d243d 100644 --- a/go.sum +++ b/go.sum @@ -131,8 +131,8 @@ github.com/containerd/typeurl v1.0.2/go.mod h1:9trJWW2sRlGub4wZJRTW83VtbOLS6hwcD github.com/coocood/freecache v1.2.1 h1:/v1CqMq45NFH9mp/Pt142reundeBM0dVUD3osQBeu/U= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= -github.com/coreos/go-iptables v0.6.0 h1:is9qnZMPYjLd8LYqmm/qlE+wwEgJIkTYdhV3rfZo4jk= -github.com/coreos/go-iptables v0.6.0/go.mod h1:Qe8Bv2Xik5FyTXwgIbLAnv2sWSBmvWdFETJConOQ//Q= +github.com/coreos/go-iptables v0.7.0 h1:XWM3V+MPRr5/q51NuWSgU0fqMad64Zyxs8ZUoMsamr8= +github.com/coreos/go-iptables v0.7.0/go.mod h1:Qe8Bv2Xik5FyTXwgIbLAnv2sWSBmvWdFETJConOQ//Q= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd/v22 v22.0.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk=