From 5ac6f565941338f5c8a9ab8307670f83b4978ea0 Mon Sep 17 00:00:00 2001 From: Zoltan Papp Date: Thu, 29 Aug 2024 21:31:19 +0200 Subject: [PATCH] [relay] Replace the iface to interface (#2473) Replace the iface to interface --- client/internal/engine.go | 2 +- client/internal/engine_test.go | 13 +-- client/internal/peer/conn.go | 2 +- client/internal/routemanager/client.go | 6 +- client/internal/routemanager/dynamic/route.go | 4 +- client/internal/routemanager/manager.go | 4 +- .../internal/routemanager/server_android.go | 2 +- .../routemanager/server_nonandroid.go | 4 +- .../routemanager/sysctl/sysctl_linux.go | 2 +- .../routemanager/systemops/systemops.go | 4 +- .../systemops/systemops_generic.go | 2 +- iface/iface_moc.go | 103 ++++++++++++++++++ iface/iwginterface.go | 32 ++++++ iface/iwginterface_windows.go | 31 ++++++ 14 files changed, 188 insertions(+), 23 deletions(-) create mode 100644 iface/iface_moc.go create mode 100644 iface/iwginterface.go create mode 100644 iface/iwginterface_windows.go diff --git a/client/internal/engine.go b/client/internal/engine.go index d65322d6a..b3fc2b628 100644 --- a/client/internal/engine.go +++ b/client/internal/engine.go @@ -134,7 +134,7 @@ type Engine struct { ctx context.Context cancel context.CancelFunc - wgInterface *iface.WGIface + wgInterface iface.IWGIface wgProxyFactory *wgproxy.Factory udpMux *bind.UniversalUDPMuxDefault diff --git a/client/internal/engine_test.go b/client/internal/engine_test.go index 80b79a364..e024dd323 100644 --- a/client/internal/engine_test.go +++ b/client/internal/engine_test.go @@ -215,14 +215,13 @@ func TestEngine_UpdateNetworkMap(t *testing.T) { WgPrivateKey: key, WgPort: 33100, }, MobileDependency{}, peer.NewRecorder("https://mgm"), nil) - newNet, err := stdnet.NewNet() - if err != nil { - t.Fatal(err) - } - engine.wgInterface, err = iface.NewWGIFace("utun102", "100.64.0.1/24", engine.config.WgPort, key.String(), iface.DefaultMTU, newNet, nil, nil) - if err != nil { - t.Fatal(err) + + wgIface := &iface.MockWGIface{ + RemovePeerFunc: func(peerKey string) error { + return nil + }, } + engine.wgInterface = wgIface engine.routeManager = routemanager.NewManager(ctx, key.PublicKey().String(), time.Minute, engine.wgInterface, engine.statusRecorder, nil) engine.dnsServer = &dns.MockServer{ UpdateDNSServerFunc: func(serial uint64, update nbdns.Config) error { return nil }, diff --git a/client/internal/peer/conn.go b/client/internal/peer/conn.go index 0d8fd932c..d1fe0d419 100644 --- a/client/internal/peer/conn.go +++ b/client/internal/peer/conn.go @@ -36,7 +36,7 @@ const ( type WgConfig struct { WgListenPort int RemoteKey string - WgInterface *iface.WGIface + WgInterface iface.IWGIface AllowedIps string PreSharedKey *wgtypes.Key } diff --git a/client/internal/routemanager/client.go b/client/internal/routemanager/client.go index 1566d10dd..cebdd2b0f 100644 --- a/client/internal/routemanager/client.go +++ b/client/internal/routemanager/client.go @@ -44,7 +44,7 @@ type clientNetwork struct { ctx context.Context cancel context.CancelFunc statusRecorder *peer.Status - wgInterface *iface.WGIface + wgInterface iface.IWGIface routes map[route.ID]*route.Route routeUpdate chan routesUpdate peerStateUpdate chan struct{} @@ -54,7 +54,7 @@ type clientNetwork struct { updateSerial uint64 } -func newClientNetworkWatcher(ctx context.Context, dnsRouteInterval time.Duration, wgInterface *iface.WGIface, statusRecorder *peer.Status, rt *route.Route, routeRefCounter *refcounter.RouteRefCounter, allowedIPsRefCounter *refcounter.AllowedIPsRefCounter) *clientNetwork { +func newClientNetworkWatcher(ctx context.Context, dnsRouteInterval time.Duration, wgInterface iface.IWGIface, statusRecorder *peer.Status, rt *route.Route, routeRefCounter *refcounter.RouteRefCounter, allowedIPsRefCounter *refcounter.AllowedIPsRefCounter) *clientNetwork { ctx, cancel := context.WithCancel(ctx) client := &clientNetwork{ @@ -384,7 +384,7 @@ func (c *clientNetwork) peersStateAndUpdateWatcher() { } } -func handlerFromRoute(rt *route.Route, routeRefCounter *refcounter.RouteRefCounter, allowedIPsRefCounter *refcounter.AllowedIPsRefCounter, dnsRouterInteval time.Duration, statusRecorder *peer.Status, wgInterface *iface.WGIface) RouteHandler { +func handlerFromRoute(rt *route.Route, routeRefCounter *refcounter.RouteRefCounter, allowedIPsRefCounter *refcounter.AllowedIPsRefCounter, dnsRouterInteval time.Duration, statusRecorder *peer.Status, wgInterface iface.IWGIface) RouteHandler { if rt.IsDynamic() { dns := nbdns.NewServiceViaMemory(wgInterface) return dynamic.NewRoute(rt, routeRefCounter, allowedIPsRefCounter, dnsRouterInteval, statusRecorder, wgInterface, fmt.Sprintf("%s:%d", dns.RuntimeIP(), dns.RuntimePort())) diff --git a/client/internal/routemanager/dynamic/route.go b/client/internal/routemanager/dynamic/route.go index 3296f3ddf..5897031e7 100644 --- a/client/internal/routemanager/dynamic/route.go +++ b/client/internal/routemanager/dynamic/route.go @@ -48,7 +48,7 @@ type Route struct { currentPeerKey string cancel context.CancelFunc statusRecorder *peer.Status - wgInterface *iface.WGIface + wgInterface iface.IWGIface resolverAddr string } @@ -58,7 +58,7 @@ func NewRoute( allowedIPsRefCounter *refcounter.AllowedIPsRefCounter, interval time.Duration, statusRecorder *peer.Status, - wgInterface *iface.WGIface, + wgInterface iface.IWGIface, resolverAddr string, ) *Route { return &Route{ diff --git a/client/internal/routemanager/manager.go b/client/internal/routemanager/manager.go index 0b10dbe33..597eddd51 100644 --- a/client/internal/routemanager/manager.go +++ b/client/internal/routemanager/manager.go @@ -49,7 +49,7 @@ type DefaultManager struct { serverRouter serverRouter sysOps *systemops.SysOps statusRecorder *peer.Status - wgInterface *iface.WGIface + wgInterface iface.IWGIface pubKey string notifier *notifier.Notifier routeRefCounter *refcounter.RouteRefCounter @@ -61,7 +61,7 @@ func NewManager( ctx context.Context, pubKey string, dnsRouteInterval time.Duration, - wgInterface *iface.WGIface, + wgInterface iface.IWGIface, statusRecorder *peer.Status, initialRoutes []*route.Route, ) *DefaultManager { diff --git a/client/internal/routemanager/server_android.go b/client/internal/routemanager/server_android.go index b4065bca6..2057b9cc8 100644 --- a/client/internal/routemanager/server_android.go +++ b/client/internal/routemanager/server_android.go @@ -11,6 +11,6 @@ import ( "github.com/netbirdio/netbird/iface" ) -func newServerRouter(context.Context, *iface.WGIface, firewall.Manager, *peer.Status) (serverRouter, error) { +func newServerRouter(context.Context, iface.IWGIface, firewall.Manager, *peer.Status) (serverRouter, error) { return nil, fmt.Errorf("server route not supported on this os") } diff --git a/client/internal/routemanager/server_nonandroid.go b/client/internal/routemanager/server_nonandroid.go index 8470934c2..43a266cd2 100644 --- a/client/internal/routemanager/server_nonandroid.go +++ b/client/internal/routemanager/server_nonandroid.go @@ -22,11 +22,11 @@ type defaultServerRouter struct { ctx context.Context routes map[route.ID]*route.Route firewall firewall.Manager - wgInterface *iface.WGIface + wgInterface iface.IWGIface statusRecorder *peer.Status } -func newServerRouter(ctx context.Context, wgInterface *iface.WGIface, firewall firewall.Manager, statusRecorder *peer.Status) (serverRouter, error) { +func newServerRouter(ctx context.Context, wgInterface iface.IWGIface, firewall firewall.Manager, statusRecorder *peer.Status) (serverRouter, error) { return &defaultServerRouter{ ctx: ctx, routes: make(map[route.ID]*route.Route), diff --git a/client/internal/routemanager/sysctl/sysctl_linux.go b/client/internal/routemanager/sysctl/sysctl_linux.go index 43394a823..13e1229f8 100644 --- a/client/internal/routemanager/sysctl/sysctl_linux.go +++ b/client/internal/routemanager/sysctl/sysctl_linux.go @@ -23,7 +23,7 @@ const ( ) // Setup configures sysctl settings for RP filtering and source validation. -func Setup(wgIface *iface.WGIface) (map[string]int, error) { +func Setup(wgIface iface.IWGIface) (map[string]int, error) { keys := map[string]int{} var result *multierror.Error diff --git a/client/internal/routemanager/systemops/systemops.go b/client/internal/routemanager/systemops/systemops.go index cddd7e7e2..ae27b0123 100644 --- a/client/internal/routemanager/systemops/systemops.go +++ b/client/internal/routemanager/systemops/systemops.go @@ -19,7 +19,7 @@ type ExclusionCounter = refcounter.Counter[any, Nexthop] type SysOps struct { refCounter *ExclusionCounter - wgInterface *iface.WGIface + wgInterface iface.IWGIface // prefixes is tracking all the current added prefixes im memory // (this is used in iOS as all route updates require a full table update) //nolint @@ -30,7 +30,7 @@ type SysOps struct { notifier *notifier.Notifier } -func NewSysOps(wgInterface *iface.WGIface, notifier *notifier.Notifier) *SysOps { +func NewSysOps(wgInterface iface.IWGIface, notifier *notifier.Notifier) *SysOps { return &SysOps{ wgInterface: wgInterface, notifier: notifier, diff --git a/client/internal/routemanager/systemops/systemops_generic.go b/client/internal/routemanager/systemops/systemops_generic.go index 671545b86..d76824c10 100644 --- a/client/internal/routemanager/systemops/systemops_generic.go +++ b/client/internal/routemanager/systemops/systemops_generic.go @@ -122,7 +122,7 @@ func (r *SysOps) addRouteForCurrentDefaultGateway(prefix netip.Prefix) error { // addRouteToNonVPNIntf adds a new route to the routing table for the given prefix and returns the next hop and interface. // If the next hop or interface is pointing to the VPN interface, it will return the initial values. -func (r *SysOps) addRouteToNonVPNIntf(prefix netip.Prefix, vpnIntf *iface.WGIface, initialNextHop Nexthop) (Nexthop, error) { +func (r *SysOps) addRouteToNonVPNIntf(prefix netip.Prefix, vpnIntf iface.IWGIface, initialNextHop Nexthop) (Nexthop, error) { addr := prefix.Addr() switch { case addr.IsLoopback(), diff --git a/iface/iface_moc.go b/iface/iface_moc.go new file mode 100644 index 000000000..fab3054a0 --- /dev/null +++ b/iface/iface_moc.go @@ -0,0 +1,103 @@ +package iface + +import ( + "net" + "time" + + "golang.zx2c4.com/wireguard/wgctrl/wgtypes" + + "github.com/netbirdio/netbird/iface/bind" +) + +type MockWGIface struct { + CreateFunc func() error + CreateOnAndroidFunc func(routeRange []string, ip string, domains []string) error + IsUserspaceBindFunc func() bool + NameFunc func() string + AddressFunc func() WGAddress + ToInterfaceFunc func() *net.Interface + UpFunc func() (*bind.UniversalUDPMuxDefault, error) + UpdateAddrFunc func(newAddr string) error + UpdatePeerFunc func(peerKey string, allowedIps string, keepAlive time.Duration, endpoint *net.UDPAddr, preSharedKey *wgtypes.Key) error + RemovePeerFunc func(peerKey string) error + AddAllowedIPFunc func(peerKey string, allowedIP string) error + RemoveAllowedIPFunc func(peerKey string, allowedIP string) error + CloseFunc func() error + SetFilterFunc func(filter PacketFilter) error + GetFilterFunc func() PacketFilter + GetDeviceFunc func() *DeviceWrapper + GetStatsFunc func(peerKey string) (WGStats, error) + GetInterfaceGUIDStringFunc func() (string, error) +} + +func (m *MockWGIface) GetInterfaceGUIDString() (string, error) { + return m.GetInterfaceGUIDStringFunc() +} + +func (m *MockWGIface) Create() error { + return m.CreateFunc() +} + +func (m *MockWGIface) CreateOnAndroid(routeRange []string, ip string, domains []string) error { + return m.CreateOnAndroidFunc(routeRange, ip, domains) +} + +func (m *MockWGIface) IsUserspaceBind() bool { + return m.IsUserspaceBindFunc() +} + +func (m *MockWGIface) Name() string { + return m.NameFunc() +} + +func (m *MockWGIface) Address() WGAddress { + return m.AddressFunc() +} + +func (m *MockWGIface) ToInterface() *net.Interface { + return m.ToInterfaceFunc() +} + +func (m *MockWGIface) Up() (*bind.UniversalUDPMuxDefault, error) { + return m.UpFunc() +} + +func (m *MockWGIface) UpdateAddr(newAddr string) error { + return m.UpdateAddrFunc(newAddr) +} + +func (m *MockWGIface) UpdatePeer(peerKey string, allowedIps string, keepAlive time.Duration, endpoint *net.UDPAddr, preSharedKey *wgtypes.Key) error { + return m.UpdatePeerFunc(peerKey, allowedIps, keepAlive, endpoint, preSharedKey) +} + +func (m *MockWGIface) RemovePeer(peerKey string) error { + return m.RemovePeerFunc(peerKey) +} + +func (m *MockWGIface) AddAllowedIP(peerKey string, allowedIP string) error { + return m.AddAllowedIPFunc(peerKey, allowedIP) +} + +func (m *MockWGIface) RemoveAllowedIP(peerKey string, allowedIP string) error { + return m.RemoveAllowedIPFunc(peerKey, allowedIP) +} + +func (m *MockWGIface) Close() error { + return m.CloseFunc() +} + +func (m *MockWGIface) SetFilter(filter PacketFilter) error { + return m.SetFilterFunc(filter) +} + +func (m *MockWGIface) GetFilter() PacketFilter { + return m.GetFilterFunc() +} + +func (m *MockWGIface) GetDevice() *DeviceWrapper { + return m.GetDeviceFunc() +} + +func (m *MockWGIface) GetStats(peerKey string) (WGStats, error) { + return m.GetStatsFunc(peerKey) +} diff --git a/iface/iwginterface.go b/iface/iwginterface.go new file mode 100644 index 000000000..501f51d2b --- /dev/null +++ b/iface/iwginterface.go @@ -0,0 +1,32 @@ +//go:build !windows + +package iface + +import ( + "net" + "time" + + "golang.zx2c4.com/wireguard/wgctrl/wgtypes" + + "github.com/netbirdio/netbird/iface/bind" +) + +type IWGIface interface { + Create() error + CreateOnAndroid(routeRange []string, ip string, domains []string) error + IsUserspaceBind() bool + Name() string + Address() WGAddress + ToInterface() *net.Interface + Up() (*bind.UniversalUDPMuxDefault, error) + UpdateAddr(newAddr string) error + UpdatePeer(peerKey string, allowedIps string, keepAlive time.Duration, endpoint *net.UDPAddr, preSharedKey *wgtypes.Key) error + RemovePeer(peerKey string) error + AddAllowedIP(peerKey string, allowedIP string) error + RemoveAllowedIP(peerKey string, allowedIP string) error + Close() error + SetFilter(filter PacketFilter) error + GetFilter() PacketFilter + GetDevice() *DeviceWrapper + GetStats(peerKey string) (WGStats, error) +} diff --git a/iface/iwginterface_windows.go b/iface/iwginterface_windows.go new file mode 100644 index 000000000..b5053474e --- /dev/null +++ b/iface/iwginterface_windows.go @@ -0,0 +1,31 @@ +package iface + +import ( + "net" + "time" + + "golang.zx2c4.com/wireguard/wgctrl/wgtypes" + + "github.com/netbirdio/netbird/iface/bind" +) + +type IWGIface interface { + Create() error + CreateOnAndroid(routeRange []string, ip string, domains []string) error + IsUserspaceBind() bool + Name() string + Address() WGAddress + ToInterface() *net.Interface + Up() (*bind.UniversalUDPMuxDefault, error) + UpdateAddr(newAddr string) error + UpdatePeer(peerKey string, allowedIps string, keepAlive time.Duration, endpoint *net.UDPAddr, preSharedKey *wgtypes.Key) error + RemovePeer(peerKey string) error + AddAllowedIP(peerKey string, allowedIP string) error + RemoveAllowedIP(peerKey string, allowedIP string) error + Close() error + SetFilter(filter PacketFilter) error + GetFilter() PacketFilter + GetDevice() *DeviceWrapper + GetStats(peerKey string) (WGStats, error) + GetInterfaceGUIDString() (string, error) +}