From 3ef33874b1a11c8b668911333618686154b8e197 Mon Sep 17 00:00:00 2001 From: Pascal Fischer Date: Fri, 9 Jun 2023 12:35:57 +0200 Subject: [PATCH 01/23] change checks before route adding to not only check for default gateway (test missing) --- .../routemanager/systemops_nonandroid.go | 102 ++++++++++++++++-- .../routemanager/systemops_nonandroid_test.go | 12 ++- 2 files changed, 100 insertions(+), 14 deletions(-) diff --git a/client/internal/routemanager/systemops_nonandroid.go b/client/internal/routemanager/systemops_nonandroid.go index 4796a9a59..49108825b 100644 --- a/client/internal/routemanager/systemops_nonandroid.go +++ b/client/internal/routemanager/systemops_nonandroid.go @@ -6,27 +6,51 @@ import ( "fmt" "net" "net/netip" + "syscall" "github.com/libp2p/go-netroute" log "github.com/sirupsen/logrus" + "golang.org/x/net/route" +) + +// selected BSD Route flags. +const ( + RTF_UP = 0x1 + RTF_GATEWAY = 0x2 + RTF_HOST = 0x4 + RTF_REJECT = 0x8 + RTF_DYNAMIC = 0x10 + RTF_MODIFIED = 0x20 + RTF_STATIC = 0x800 + RTF_BLACKHOLE = 0x1000 + RTF_LOCAL = 0x200000 + RTF_BROADCAST = 0x400000 + RTF_MULTICAST = 0x800000 ) var errRouteNotFound = fmt.Errorf("route not found") func addToRouteTableIfNoExists(prefix netip.Prefix, addr string) error { - gateway, err := getExistingRIBRouteGateway(netip.MustParsePrefix("0.0.0.0/0")) - if err != nil && err != errRouteNotFound { - return err - } - prefixGateway, err := getExistingRIBRouteGateway(prefix) + defaultGateway, err := getExistingRIBRouteGateway(netip.MustParsePrefix("0.0.0.0/0")) if err != nil && err != errRouteNotFound { return err } - if prefixGateway != nil && !prefixGateway.Equal(gateway) { - log.Warnf("skipping adding a new route for network %s because it already exists and is pointing to the non default gateway: %s", prefix, prefixGateway) + gatewayIP := netip.MustParseAddr(defaultGateway.String()) + if prefix.Contains(gatewayIP) { + log.Warnf("skipping adding a new route for network %s because it overlaps with the default gateway: %s", prefix, gatewayIP) return nil } + + ok, err := existsInRouteTable(prefix) + if err != nil { + return err + } + if ok { + log.Warnf("skipping adding a new route for network %s because it already exists", prefix) + return nil + } + return addToRouteTable(prefix, addr) } @@ -48,14 +72,70 @@ func getExistingRIBRouteGateway(prefix netip.Prefix) (net.IP, error) { if err != nil { return nil, err } - _, gateway, preferredSrc, err := r.Route(prefix.Addr().AsSlice()) + _, gateway, _, err := r.Route(prefix.Addr().AsSlice()) if err != nil { log.Errorf("getting routes returned an error: %v", err) return nil, errRouteNotFound } - if gateway == nil { - return preferredSrc, nil - } return gateway, nil } + +func existsInRouteTable(prefix netip.Prefix) (bool, error) { + tab, err := route.FetchRIB(syscall.AF_UNSPEC, route.RIBTypeRoute, 0) + if err != nil { + return false, err + } + msgs, err := route.ParseRIB(route.RIBTypeRoute, tab) + if err != nil { + return false, err + } + + for _, msg := range msgs { + m := msg.(*route.RouteMessage) + + if m.Version < 3 || m.Version > 5 { + return false, fmt.Errorf("unexpected RIB message version: %d", m.Version) + } + if m.Type != 4 /* RTM_GET */ { + return true, fmt.Errorf("unexpected RIB message type: %d", m.Type) + } + + if m.Flags&RTF_UP == 0 || + m.Flags&(RTF_REJECT|RTF_BLACKHOLE) != 0 { + continue + } + + dst, err := toIPAddr(m.Addrs[0]) + log.Debugf("checking route: %s", dst) + if err != nil { + return true, fmt.Errorf("unexpected RIB destination: %v", err) + } + + mask, err := toIPAddr(m.Addrs[2]) + log.Debugf("checking route mask: %s", mask) + if err != nil { + return true, fmt.Errorf("unexpected RIB destination: %v", err) + } + cidr, _ := net.IPMask(mask.To4()).Size() + if dst.String() == prefix.Addr().String() && cidr == prefix.Bits() { + return true, nil + } + } + + return false, nil +} + +func toIPAddr(a route.Addr) (net.IP, error) { + switch t := a.(type) { + case *route.Inet4Addr: + ip := net.IPv4(t.IP[0], t.IP[1], t.IP[2], t.IP[3]) + return ip, nil + case *route.Inet6Addr: + ip := make(net.IP, net.IPv6len) + copy(ip, t.IP[:]) + return ip, nil + default: + return net.IP{}, fmt.Errorf("unknown family: %v", t) + } +} diff --git a/client/internal/routemanager/systemops_nonandroid_test.go b/client/internal/routemanager/systemops_nonandroid_test.go index 59d4cb72c..28f798a2d 100644 --- a/client/internal/routemanager/systemops_nonandroid_test.go +++ b/client/internal/routemanager/systemops_nonandroid_test.go @@ -2,14 +2,20 @@ package routemanager import ( "fmt" - "github.com/netbirdio/netbird/iface" - "github.com/pion/transport/v2/stdnet" - "github.com/stretchr/testify/require" "net" "net/netip" "testing" + + "github.com/pion/transport/v2/stdnet" + "github.com/stretchr/testify/require" + + "github.com/netbirdio/netbird/iface" ) +// func TestAddRoute(t *testing.T) { +// addToRouteTableIfNoExists() +// } + func TestAddRemoveRoutes(t *testing.T) { testCases := []struct { name string From 3724323f7604f842b73fe8a974d3725b2d517675 Mon Sep 17 00:00:00 2001 From: Pascal Fischer Date: Fri, 9 Jun 2023 15:33:22 +0200 Subject: [PATCH 02/23] test still failing --- .../routemanager/systemops_nonandroid_test.go | 79 ++++++++++++++++++- 1 file changed, 75 insertions(+), 4 deletions(-) diff --git a/client/internal/routemanager/systemops_nonandroid_test.go b/client/internal/routemanager/systemops_nonandroid_test.go index 28f798a2d..21f7a5601 100644 --- a/client/internal/routemanager/systemops_nonandroid_test.go +++ b/client/internal/routemanager/systemops_nonandroid_test.go @@ -12,10 +12,6 @@ import ( "github.com/netbirdio/netbird/iface" ) -// func TestAddRoute(t *testing.T) { -// addToRouteTableIfNoExists() -// } - func TestAddRemoveRoutes(t *testing.T) { testCases := []struct { name string @@ -79,6 +75,81 @@ func TestAddRemoveRoutes(t *testing.T) { } } +func TestAddExistAndRemoveRoute(t *testing.T) { + defaultGateway, err := getExistingRIBRouteGateway(netip.MustParsePrefix("0.0.0.0/0")) + fmt.Println("defaultGateway: ", defaultGateway) + if err != nil { + t.Fatal("shouldn't return error when fetching the gateway: ", err) + } + testCases := []struct { + name string + prefix netip.Prefix + preExistingPrefix netip.Prefix + shouldAddRoute bool + }{ + { + name: "Should Add And Remove random Route", + prefix: netip.MustParsePrefix("99.99.99.99/32"), + shouldAddRoute: true, + }, + { + name: "Should Not Add Route if overlaps with default gateway", + prefix: netip.MustParsePrefix(defaultGateway.String() + "/31"), + shouldAddRoute: false, + }, + { + name: "Should Add Route if bigger network exists", + prefix: netip.MustParsePrefix("100.100.100.0/24"), + preExistingPrefix: netip.MustParsePrefix("100.100.0.0/16"), + shouldAddRoute: true, + }, + { + name: "Should Add Route if smaller network exists", + prefix: netip.MustParsePrefix("100.100.0.0/16"), + preExistingPrefix: netip.MustParsePrefix("100.100.100.0/24"), + shouldAddRoute: true, + }, + { + name: "Should Not Add Route if same network exists", + prefix: netip.MustParsePrefix("100.100.0.0/16"), + preExistingPrefix: netip.MustParsePrefix("100.100.0.0/16"), + shouldAddRoute: false, + }, + } + + MOCK_ADDR := "127.0.0.1" + + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + // Prepare the environment + if testCase.preExistingPrefix.IsValid() { + err := addToRouteTableIfNoExists(testCase.preExistingPrefix, MOCK_ADDR) + require.NoError(t, err, "should not return err when adding pre-existing route") + } + + // Add the route + err = addToRouteTableIfNoExists(testCase.prefix, MOCK_ADDR) + require.NoError(t, err, "should not return err when adding pre-existing route") + + if testCase.shouldAddRoute { + // test if route exists after adding + ok, err := existsInRouteTable(testCase.prefix) + require.NoError(t, err, "should not return err") + require.True(t, ok, "route should exist") + + // remove route again if added + err = removeFromRouteTableIfNonSystem(testCase.prefix, MOCK_ADDR) + require.NoError(t, err, "should not return err") + } + + // route should either not have been added or should have been removed + ok, err := existsInRouteTable(testCase.prefix) + require.NoError(t, err, "should not return err") + require.False(t, ok, "route should not exist") + }) + } +} + func TestGetExistingRIBRouteGateway(t *testing.T) { gateway, err := getExistingRIBRouteGateway(netip.MustParsePrefix("0.0.0.0/0")) if err != nil { From bc8ee8fc3c6edee5837faa4d191a8884f2b0a991 Mon Sep 17 00:00:00 2001 From: Pascal Fischer Date: Fri, 9 Jun 2023 16:18:48 +0200 Subject: [PATCH 03/23] add tests --- .../internal/routemanager/systemops_nonandroid.go | 7 +------ .../routemanager/systemops_nonandroid_test.go | 15 ++++++++++++++- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/client/internal/routemanager/systemops_nonandroid.go b/client/internal/routemanager/systemops_nonandroid.go index 49108825b..c9efd7882 100644 --- a/client/internal/routemanager/systemops_nonandroid.go +++ b/client/internal/routemanager/systemops_nonandroid.go @@ -107,16 +107,11 @@ func existsInRouteTable(prefix netip.Prefix) (bool, error) { } dst, err := toIPAddr(m.Addrs[0]) - log.Debugf("checking route: %s", dst) if err != nil { return true, fmt.Errorf("unexpected RIB destination: %v", err) } - mask, err := toIPAddr(m.Addrs[2]) - log.Debugf("checking route mask: %s", mask) - if err != nil { - return true, fmt.Errorf("unexpected RIB destination: %v", err) - } + mask, _ := toIPAddr(m.Addrs[2]) cidr, _ := net.IPMask(mask.To4()).Size() if dst.String() == prefix.Addr().String() && cidr == prefix.Bits() { return true, nil diff --git a/client/internal/routemanager/systemops_nonandroid_test.go b/client/internal/routemanager/systemops_nonandroid_test.go index 21f7a5601..2020aa8d4 100644 --- a/client/internal/routemanager/systemops_nonandroid_test.go +++ b/client/internal/routemanager/systemops_nonandroid_test.go @@ -1,12 +1,16 @@ package routemanager import ( + "bytes" "fmt" "net" "net/netip" + "os" + "strings" "testing" "github.com/pion/transport/v2/stdnet" + log "github.com/sirupsen/logrus" "github.com/stretchr/testify/require" "github.com/netbirdio/netbird/iface" @@ -120,6 +124,11 @@ func TestAddExistAndRemoveRoute(t *testing.T) { MOCK_ADDR := "127.0.0.1" for _, testCase := range testCases { + var buf bytes.Buffer + log.SetOutput(&buf) + defer func() { + log.SetOutput(os.Stderr) + }() t.Run(testCase.name, func(t *testing.T) { // Prepare the environment if testCase.preExistingPrefix.IsValid() { @@ -143,9 +152,13 @@ func TestAddExistAndRemoveRoute(t *testing.T) { } // route should either not have been added or should have been removed + // In case of already existing route, it should not have been added (but still exist) ok, err := existsInRouteTable(testCase.prefix) + fmt.Println("Buffer string: ", buf.String()) require.NoError(t, err, "should not return err") - require.False(t, ok, "route should not exist") + if !strings.Contains(buf.String(), "because it already exists") { + require.False(t, ok, "route should not exist") + } }) } } From 75fac258e743f95f9f2187d1cf7670be18012ec7 Mon Sep 17 00:00:00 2001 From: Pascal Fischer Date: Fri, 9 Jun 2023 17:40:10 +0200 Subject: [PATCH 04/23] hacky all-operating-systems solution --- .../routemanager/systemops_nonandroid.go | 102 +++++++----------- .../routemanager/systemops_nonandroid_test.go | 62 +++++++---- 2 files changed, 80 insertions(+), 84 deletions(-) diff --git a/client/internal/routemanager/systemops_nonandroid.go b/client/internal/routemanager/systemops_nonandroid.go index c9efd7882..dd2d18ad8 100644 --- a/client/internal/routemanager/systemops_nonandroid.go +++ b/client/internal/routemanager/systemops_nonandroid.go @@ -6,26 +6,9 @@ import ( "fmt" "net" "net/netip" - "syscall" "github.com/libp2p/go-netroute" log "github.com/sirupsen/logrus" - "golang.org/x/net/route" -) - -// selected BSD Route flags. -const ( - RTF_UP = 0x1 - RTF_GATEWAY = 0x2 - RTF_HOST = 0x4 - RTF_REJECT = 0x8 - RTF_DYNAMIC = 0x10 - RTF_MODIFIED = 0x20 - RTF_STATIC = 0x800 - RTF_BLACKHOLE = 0x1000 - RTF_LOCAL = 0x200000 - RTF_BROADCAST = 0x400000 - RTF_MULTICAST = 0x800000 ) var errRouteNotFound = fmt.Errorf("route not found") @@ -42,7 +25,16 @@ func addToRouteTableIfNoExists(prefix netip.Prefix, addr string) error { return nil } - ok, err := existsInRouteTable(prefix) + ok, err := routeExistsWithDifferentGateway(prefix, addr) + if err != nil { + return err + } + if ok { + log.Warnf("skipping adding a new route for network %s because it already exists", prefix) + return nil + } + + ok, err = routeExistsWithSameGateway(prefix, addr) if err != nil { return err } @@ -72,65 +64,53 @@ func getExistingRIBRouteGateway(prefix netip.Prefix) (net.IP, error) { if err != nil { return nil, err } - _, gateway, _, err := r.Route(prefix.Addr().AsSlice()) + _, gateway, preferredSrc, err := r.Route(prefix.Addr().AsSlice()) if err != nil { log.Errorf("getting routes returned an error: %v", err) return nil, errRouteNotFound } + if gateway == nil { + return preferredSrc, nil + } + return gateway, nil } -func existsInRouteTable(prefix netip.Prefix) (bool, error) { - tab, err := route.FetchRIB(syscall.AF_UNSPEC, route.RIBTypeRoute, 0) +func routeExistsWithSameGateway(prefix netip.Prefix, addr string) (bool, error) { + r, err := netroute.New() if err != nil { - return false, err - } - msgs, err := route.ParseRIB(route.RIBTypeRoute, tab) - if err != nil { - return false, err + return true, err } - for _, msg := range msgs { - m := msg.(*route.RouteMessage) + _, gateway, preferredSrc, err := r.Route(prefix.Addr().AsSlice()) + if err != nil { + log.Errorf("getting routes returned an error: %v", err) + return true, errRouteNotFound + } - if m.Version < 3 || m.Version > 5 { - return false, fmt.Errorf("unexpected RIB message version: %d", m.Version) - } - if m.Type != 4 /* RTM_GET */ { - return true, fmt.Errorf("unexpected RIB message type: %d", m.Type) - } - - if m.Flags&RTF_UP == 0 || - m.Flags&(RTF_REJECT|RTF_BLACKHOLE) != 0 { - continue - } - - dst, err := toIPAddr(m.Addrs[0]) - if err != nil { - return true, fmt.Errorf("unexpected RIB destination: %v", err) - } - - mask, _ := toIPAddr(m.Addrs[2]) - cidr, _ := net.IPMask(mask.To4()).Size() - if dst.String() == prefix.Addr().String() && cidr == prefix.Bits() { - return true, nil - } + if gateway.String() == addr || preferredSrc.String() == addr { + return true, nil } return false, nil } -func toIPAddr(a route.Addr) (net.IP, error) { - switch t := a.(type) { - case *route.Inet4Addr: - ip := net.IPv4(t.IP[0], t.IP[1], t.IP[2], t.IP[3]) - return ip, nil - case *route.Inet6Addr: - ip := make(net.IP, net.IPv6len) - copy(ip, t.IP[:]) - return ip, nil - default: - return net.IP{}, fmt.Errorf("unknown family: %v", t) +func routeExistsWithDifferentGateway(prefix netip.Prefix, addr string) (bool, error) { + r, err := netroute.New() + if err != nil { + return true, err } + + _, gateway, preferredSrc, err := r.Route(prefix.Addr().AsSlice()) + if err != nil { + log.Errorf("getting routes returned an error: %v", err) + return true, errRouteNotFound + } + + if gateway.String() != addr && preferredSrc.String() != addr { + return false, nil + } + + return true, nil } diff --git a/client/internal/routemanager/systemops_nonandroid_test.go b/client/internal/routemanager/systemops_nonandroid_test.go index 2020aa8d4..1f086fe62 100644 --- a/client/internal/routemanager/systemops_nonandroid_test.go +++ b/client/internal/routemanager/systemops_nonandroid_test.go @@ -86,43 +86,59 @@ func TestAddExistAndRemoveRoute(t *testing.T) { t.Fatal("shouldn't return error when fetching the gateway: ", err) } testCases := []struct { - name string - prefix netip.Prefix - preExistingPrefix netip.Prefix - shouldAddRoute bool + name string + prefix netip.Prefix + gateway string + preExistingPrefix netip.Prefix + preExistingGateway string + shouldAddRoute bool }{ { name: "Should Add And Remove random Route", prefix: netip.MustParsePrefix("99.99.99.99/32"), + gateway: "127.0.0.1", shouldAddRoute: true, }, { name: "Should Not Add Route if overlaps with default gateway", prefix: netip.MustParsePrefix(defaultGateway.String() + "/31"), + gateway: "127.0.0.1", shouldAddRoute: false, }, { - name: "Should Add Route if bigger network exists", - prefix: netip.MustParsePrefix("100.100.100.0/24"), - preExistingPrefix: netip.MustParsePrefix("100.100.0.0/16"), - shouldAddRoute: true, + name: "Should Add Route if bigger network exists", + prefix: netip.MustParsePrefix("100.100.100.0/24"), + gateway: "127.0.0.1", + preExistingPrefix: netip.MustParsePrefix("100.100.0.0/16"), + preExistingGateway: "127.0.0.1", + shouldAddRoute: true, }, { - name: "Should Add Route if smaller network exists", - prefix: netip.MustParsePrefix("100.100.0.0/16"), - preExistingPrefix: netip.MustParsePrefix("100.100.100.0/24"), - shouldAddRoute: true, + name: "Should Add Route if smaller network exists", + prefix: netip.MustParsePrefix("100.100.0.0/16"), + gateway: "127.0.0.1", + preExistingPrefix: netip.MustParsePrefix("100.100.100.0/24"), + preExistingGateway: "127.0.0.1", + shouldAddRoute: true, }, { - name: "Should Not Add Route if same network exists", - prefix: netip.MustParsePrefix("100.100.0.0/16"), - preExistingPrefix: netip.MustParsePrefix("100.100.0.0/16"), - shouldAddRoute: false, + name: "Should Not Add Route if same network with same gateway exists", + prefix: netip.MustParsePrefix("100.100.0.0/16"), + gateway: "127.0.0.1", + preExistingPrefix: netip.MustParsePrefix("100.100.0.0/16"), + preExistingGateway: "127.0.0.1", + shouldAddRoute: false, + }, + { + name: "Should Not Add Route if same network with different gateway exists", + prefix: netip.MustParsePrefix("100.100.0.0/16"), + gateway: "127.0.0.1", + preExistingPrefix: netip.MustParsePrefix("100.100.0.0/16"), + preExistingGateway: "123.0.0.1", + shouldAddRoute: false, }, } - MOCK_ADDR := "127.0.0.1" - for _, testCase := range testCases { var buf bytes.Buffer log.SetOutput(&buf) @@ -132,28 +148,28 @@ func TestAddExistAndRemoveRoute(t *testing.T) { t.Run(testCase.name, func(t *testing.T) { // Prepare the environment if testCase.preExistingPrefix.IsValid() { - err := addToRouteTableIfNoExists(testCase.preExistingPrefix, MOCK_ADDR) + err := addToRouteTableIfNoExists(testCase.preExistingPrefix, testCase.preExistingGateway) require.NoError(t, err, "should not return err when adding pre-existing route") } // Add the route - err = addToRouteTableIfNoExists(testCase.prefix, MOCK_ADDR) + err = addToRouteTableIfNoExists(testCase.prefix, testCase.gateway) require.NoError(t, err, "should not return err when adding pre-existing route") if testCase.shouldAddRoute { // test if route exists after adding - ok, err := existsInRouteTable(testCase.prefix) + ok, err := routeExistsWithSameGateway(testCase.prefix, testCase.gateway) require.NoError(t, err, "should not return err") require.True(t, ok, "route should exist") // remove route again if added - err = removeFromRouteTableIfNonSystem(testCase.prefix, MOCK_ADDR) + err = removeFromRouteTableIfNonSystem(testCase.prefix, testCase.gateway) require.NoError(t, err, "should not return err") } // route should either not have been added or should have been removed // In case of already existing route, it should not have been added (but still exist) - ok, err := existsInRouteTable(testCase.prefix) + ok, err := routeExistsWithSameGateway(testCase.prefix, testCase.gateway) fmt.Println("Buffer string: ", buf.String()) require.NoError(t, err, "should not return err") if !strings.Contains(buf.String(), "because it already exists") { From 493ddb4fe3466d2e73fce2e5fc3e2e4f761f9e64 Mon Sep 17 00:00:00 2001 From: Pascal Fischer Date: Fri, 9 Jun 2023 17:59:06 +0200 Subject: [PATCH 05/23] Revert "hacky all-operating-systems solution" This reverts commit 75fac258e743f95f9f2187d1cf7670be18012ec7. --- .../routemanager/systemops_nonandroid.go | 102 +++++++++++------- .../routemanager/systemops_nonandroid_test.go | 62 ++++------- 2 files changed, 84 insertions(+), 80 deletions(-) diff --git a/client/internal/routemanager/systemops_nonandroid.go b/client/internal/routemanager/systemops_nonandroid.go index dd2d18ad8..c9efd7882 100644 --- a/client/internal/routemanager/systemops_nonandroid.go +++ b/client/internal/routemanager/systemops_nonandroid.go @@ -6,9 +6,26 @@ import ( "fmt" "net" "net/netip" + "syscall" "github.com/libp2p/go-netroute" log "github.com/sirupsen/logrus" + "golang.org/x/net/route" +) + +// selected BSD Route flags. +const ( + RTF_UP = 0x1 + RTF_GATEWAY = 0x2 + RTF_HOST = 0x4 + RTF_REJECT = 0x8 + RTF_DYNAMIC = 0x10 + RTF_MODIFIED = 0x20 + RTF_STATIC = 0x800 + RTF_BLACKHOLE = 0x1000 + RTF_LOCAL = 0x200000 + RTF_BROADCAST = 0x400000 + RTF_MULTICAST = 0x800000 ) var errRouteNotFound = fmt.Errorf("route not found") @@ -25,16 +42,7 @@ func addToRouteTableIfNoExists(prefix netip.Prefix, addr string) error { return nil } - ok, err := routeExistsWithDifferentGateway(prefix, addr) - if err != nil { - return err - } - if ok { - log.Warnf("skipping adding a new route for network %s because it already exists", prefix) - return nil - } - - ok, err = routeExistsWithSameGateway(prefix, addr) + ok, err := existsInRouteTable(prefix) if err != nil { return err } @@ -64,53 +72,65 @@ func getExistingRIBRouteGateway(prefix netip.Prefix) (net.IP, error) { if err != nil { return nil, err } - _, gateway, preferredSrc, err := r.Route(prefix.Addr().AsSlice()) + _, gateway, _, err := r.Route(prefix.Addr().AsSlice()) if err != nil { log.Errorf("getting routes returned an error: %v", err) return nil, errRouteNotFound } - if gateway == nil { - return preferredSrc, nil - } - return gateway, nil } -func routeExistsWithSameGateway(prefix netip.Prefix, addr string) (bool, error) { - r, err := netroute.New() +func existsInRouteTable(prefix netip.Prefix) (bool, error) { + tab, err := route.FetchRIB(syscall.AF_UNSPEC, route.RIBTypeRoute, 0) if err != nil { - return true, err + return false, err + } + msgs, err := route.ParseRIB(route.RIBTypeRoute, tab) + if err != nil { + return false, err } - _, gateway, preferredSrc, err := r.Route(prefix.Addr().AsSlice()) - if err != nil { - log.Errorf("getting routes returned an error: %v", err) - return true, errRouteNotFound - } + for _, msg := range msgs { + m := msg.(*route.RouteMessage) - if gateway.String() == addr || preferredSrc.String() == addr { - return true, nil + if m.Version < 3 || m.Version > 5 { + return false, fmt.Errorf("unexpected RIB message version: %d", m.Version) + } + if m.Type != 4 /* RTM_GET */ { + return true, fmt.Errorf("unexpected RIB message type: %d", m.Type) + } + + if m.Flags&RTF_UP == 0 || + m.Flags&(RTF_REJECT|RTF_BLACKHOLE) != 0 { + continue + } + + dst, err := toIPAddr(m.Addrs[0]) + if err != nil { + return true, fmt.Errorf("unexpected RIB destination: %v", err) + } + + mask, _ := toIPAddr(m.Addrs[2]) + cidr, _ := net.IPMask(mask.To4()).Size() + if dst.String() == prefix.Addr().String() && cidr == prefix.Bits() { + return true, nil + } } return false, nil } -func routeExistsWithDifferentGateway(prefix netip.Prefix, addr string) (bool, error) { - r, err := netroute.New() - if err != nil { - return true, err +func toIPAddr(a route.Addr) (net.IP, error) { + switch t := a.(type) { + case *route.Inet4Addr: + ip := net.IPv4(t.IP[0], t.IP[1], t.IP[2], t.IP[3]) + return ip, nil + case *route.Inet6Addr: + ip := make(net.IP, net.IPv6len) + copy(ip, t.IP[:]) + return ip, nil + default: + return net.IP{}, fmt.Errorf("unknown family: %v", t) } - - _, gateway, preferredSrc, err := r.Route(prefix.Addr().AsSlice()) - if err != nil { - log.Errorf("getting routes returned an error: %v", err) - return true, errRouteNotFound - } - - if gateway.String() != addr && preferredSrc.String() != addr { - return false, nil - } - - return true, nil } diff --git a/client/internal/routemanager/systemops_nonandroid_test.go b/client/internal/routemanager/systemops_nonandroid_test.go index 1f086fe62..2020aa8d4 100644 --- a/client/internal/routemanager/systemops_nonandroid_test.go +++ b/client/internal/routemanager/systemops_nonandroid_test.go @@ -86,59 +86,43 @@ func TestAddExistAndRemoveRoute(t *testing.T) { t.Fatal("shouldn't return error when fetching the gateway: ", err) } testCases := []struct { - name string - prefix netip.Prefix - gateway string - preExistingPrefix netip.Prefix - preExistingGateway string - shouldAddRoute bool + name string + prefix netip.Prefix + preExistingPrefix netip.Prefix + shouldAddRoute bool }{ { name: "Should Add And Remove random Route", prefix: netip.MustParsePrefix("99.99.99.99/32"), - gateway: "127.0.0.1", shouldAddRoute: true, }, { name: "Should Not Add Route if overlaps with default gateway", prefix: netip.MustParsePrefix(defaultGateway.String() + "/31"), - gateway: "127.0.0.1", shouldAddRoute: false, }, { - name: "Should Add Route if bigger network exists", - prefix: netip.MustParsePrefix("100.100.100.0/24"), - gateway: "127.0.0.1", - preExistingPrefix: netip.MustParsePrefix("100.100.0.0/16"), - preExistingGateway: "127.0.0.1", - shouldAddRoute: true, + name: "Should Add Route if bigger network exists", + prefix: netip.MustParsePrefix("100.100.100.0/24"), + preExistingPrefix: netip.MustParsePrefix("100.100.0.0/16"), + shouldAddRoute: true, }, { - name: "Should Add Route if smaller network exists", - prefix: netip.MustParsePrefix("100.100.0.0/16"), - gateway: "127.0.0.1", - preExistingPrefix: netip.MustParsePrefix("100.100.100.0/24"), - preExistingGateway: "127.0.0.1", - shouldAddRoute: true, + name: "Should Add Route if smaller network exists", + prefix: netip.MustParsePrefix("100.100.0.0/16"), + preExistingPrefix: netip.MustParsePrefix("100.100.100.0/24"), + shouldAddRoute: true, }, { - name: "Should Not Add Route if same network with same gateway exists", - prefix: netip.MustParsePrefix("100.100.0.0/16"), - gateway: "127.0.0.1", - preExistingPrefix: netip.MustParsePrefix("100.100.0.0/16"), - preExistingGateway: "127.0.0.1", - shouldAddRoute: false, - }, - { - name: "Should Not Add Route if same network with different gateway exists", - prefix: netip.MustParsePrefix("100.100.0.0/16"), - gateway: "127.0.0.1", - preExistingPrefix: netip.MustParsePrefix("100.100.0.0/16"), - preExistingGateway: "123.0.0.1", - shouldAddRoute: false, + name: "Should Not Add Route if same network exists", + prefix: netip.MustParsePrefix("100.100.0.0/16"), + preExistingPrefix: netip.MustParsePrefix("100.100.0.0/16"), + shouldAddRoute: false, }, } + MOCK_ADDR := "127.0.0.1" + for _, testCase := range testCases { var buf bytes.Buffer log.SetOutput(&buf) @@ -148,28 +132,28 @@ func TestAddExistAndRemoveRoute(t *testing.T) { t.Run(testCase.name, func(t *testing.T) { // Prepare the environment if testCase.preExistingPrefix.IsValid() { - err := addToRouteTableIfNoExists(testCase.preExistingPrefix, testCase.preExistingGateway) + err := addToRouteTableIfNoExists(testCase.preExistingPrefix, MOCK_ADDR) require.NoError(t, err, "should not return err when adding pre-existing route") } // Add the route - err = addToRouteTableIfNoExists(testCase.prefix, testCase.gateway) + err = addToRouteTableIfNoExists(testCase.prefix, MOCK_ADDR) require.NoError(t, err, "should not return err when adding pre-existing route") if testCase.shouldAddRoute { // test if route exists after adding - ok, err := routeExistsWithSameGateway(testCase.prefix, testCase.gateway) + ok, err := existsInRouteTable(testCase.prefix) require.NoError(t, err, "should not return err") require.True(t, ok, "route should exist") // remove route again if added - err = removeFromRouteTableIfNonSystem(testCase.prefix, testCase.gateway) + err = removeFromRouteTableIfNonSystem(testCase.prefix, MOCK_ADDR) require.NoError(t, err, "should not return err") } // route should either not have been added or should have been removed // In case of already existing route, it should not have been added (but still exist) - ok, err := routeExistsWithSameGateway(testCase.prefix, testCase.gateway) + ok, err := existsInRouteTable(testCase.prefix) fmt.Println("Buffer string: ", buf.String()) require.NoError(t, err, "should not return err") if !strings.Contains(buf.String(), "because it already exists") { From 6e26d03fb8c35927cbea71742e49e5c3507c9332 Mon Sep 17 00:00:00 2001 From: Pascal Fischer Date: Fri, 9 Jun 2023 18:27:09 +0200 Subject: [PATCH 06/23] split systemops for operating systems and add linux --- client/internal/routemanager/systemops_bsd.go | 82 ++++++++++++++++ .../internal/routemanager/systemops_linux.go | 39 ++++++++ .../routemanager/systemops_nonandroid.go | 71 -------------- .../routemanager/systemops_nonandroid_test.go | 88 ----------------- .../internal/routemanager/systemops_test.go | 97 +++++++++++++++++++ .../routemanager/systemops_windows.go | 4 + 6 files changed, 222 insertions(+), 159 deletions(-) create mode 100644 client/internal/routemanager/systemops_bsd.go create mode 100644 client/internal/routemanager/systemops_test.go create mode 100644 client/internal/routemanager/systemops_windows.go diff --git a/client/internal/routemanager/systemops_bsd.go b/client/internal/routemanager/systemops_bsd.go new file mode 100644 index 000000000..e777ec8ec --- /dev/null +++ b/client/internal/routemanager/systemops_bsd.go @@ -0,0 +1,82 @@ +//go:build darwin || dragonfly || freebsd || netbsd || openbsd +// +build darwin dragonfly freebsd netbsd openbsd + +package routemanager + +import ( + "fmt" + "net" + "net/netip" + "syscall" + + "golang.org/x/net/route" +) + +// selected BSD Route flags. +const ( + RTF_UP = 0x1 + RTF_GATEWAY = 0x2 + RTF_HOST = 0x4 + RTF_REJECT = 0x8 + RTF_DYNAMIC = 0x10 + RTF_MODIFIED = 0x20 + RTF_STATIC = 0x800 + RTF_BLACKHOLE = 0x1000 + RTF_LOCAL = 0x200000 + RTF_BROADCAST = 0x400000 + RTF_MULTICAST = 0x800000 +) + +func existsInRouteTable(prefix netip.Prefix) (bool, error) { + tab, err := route.FetchRIB(syscall.AF_UNSPEC, route.RIBTypeRoute, 0) + if err != nil { + return false, err + } + msgs, err := route.ParseRIB(route.RIBTypeRoute, tab) + if err != nil { + return false, err + } + + for _, msg := range msgs { + m := msg.(*route.RouteMessage) + + if m.Version < 3 || m.Version > 5 { + return false, fmt.Errorf("unexpected RIB message version: %d", m.Version) + } + if m.Type != 4 /* RTM_GET */ { + return true, fmt.Errorf("unexpected RIB message type: %d", m.Type) + } + + if m.Flags&RTF_UP == 0 || + m.Flags&(RTF_REJECT|RTF_BLACKHOLE) != 0 { + continue + } + + dst, err := toIPAddr(m.Addrs[0]) + if err != nil { + return true, fmt.Errorf("unexpected RIB destination: %v", err) + } + + mask, _ := toIPAddr(m.Addrs[2]) + cidr, _ := net.IPMask(mask.To4()).Size() + if dst.String() == prefix.Addr().String() && cidr == prefix.Bits() { + return true, nil + } + } + + return false, nil +} + +func toIPAddr(a route.Addr) (net.IP, error) { + switch t := a.(type) { + case *route.Inet4Addr: + ip := net.IPv4(t.IP[0], t.IP[1], t.IP[2], t.IP[3]) + return ip, nil + case *route.Inet6Addr: + ip := make(net.IP, net.IPv6len) + copy(ip, t.IP[:]) + return ip, nil + default: + return net.IP{}, fmt.Errorf("unknown family: %v", t) + } +} diff --git a/client/internal/routemanager/systemops_linux.go b/client/internal/routemanager/systemops_linux.go index 67c59be2d..368cb9075 100644 --- a/client/internal/routemanager/systemops_linux.go +++ b/client/internal/routemanager/systemops_linux.go @@ -61,6 +61,45 @@ func removeFromRouteTable(prefix netip.Prefix) error { return nil } +func existsInRouteTable(prefix netip.Prefix) (bool, error) { + tab, err := syscall.NetlinkRIB(syscall.RTM_GETROUTE, syscall.AF_UNSPEC) + if err != nil { + return nil, err + } + msgs, err := syscall.ParseNetlinkMessage(tab) + if err != nil { + return nil, err + } +loop: + for _, m := range msgs { + switch m.Header.Type { + case syscall.NLMSG_DONE: + break loop + case syscall.RTM_NEWROUTE: + rt := (*routeInfoInMemory)(unsafe.Pointer(&m.Data[0])) + attrs, err := syscall.ParseNetlinkRouteAttr(&m) + if err != nil { + return nil, err + } + if rt.Family != syscall.AF_INET { + continue loop + } + + for _, attr := range attrs { + if attr.Attr.Type == syscall.RTA_DST { + ip := net.IP(attr.Value) + mask := net.CIDRMask(int(rt.DstLen), len(attr.Value)*8) + cidr, _ := mask.Size() + if ip.String() == prefix.Addr().String() && cidr == prefix.Bits() { + return true, nil + } + } + } + } + } + return false, nil +} + func enableIPForwarding() error { bytes, err := os.ReadFile(ipv4ForwardingPath) if err != nil { diff --git a/client/internal/routemanager/systemops_nonandroid.go b/client/internal/routemanager/systemops_nonandroid.go index c9efd7882..3958e0e05 100644 --- a/client/internal/routemanager/systemops_nonandroid.go +++ b/client/internal/routemanager/systemops_nonandroid.go @@ -6,26 +6,9 @@ import ( "fmt" "net" "net/netip" - "syscall" "github.com/libp2p/go-netroute" log "github.com/sirupsen/logrus" - "golang.org/x/net/route" -) - -// selected BSD Route flags. -const ( - RTF_UP = 0x1 - RTF_GATEWAY = 0x2 - RTF_HOST = 0x4 - RTF_REJECT = 0x8 - RTF_DYNAMIC = 0x10 - RTF_MODIFIED = 0x20 - RTF_STATIC = 0x800 - RTF_BLACKHOLE = 0x1000 - RTF_LOCAL = 0x200000 - RTF_BROADCAST = 0x400000 - RTF_MULTICAST = 0x800000 ) var errRouteNotFound = fmt.Errorf("route not found") @@ -80,57 +63,3 @@ func getExistingRIBRouteGateway(prefix netip.Prefix) (net.IP, error) { return gateway, nil } - -func existsInRouteTable(prefix netip.Prefix) (bool, error) { - tab, err := route.FetchRIB(syscall.AF_UNSPEC, route.RIBTypeRoute, 0) - if err != nil { - return false, err - } - msgs, err := route.ParseRIB(route.RIBTypeRoute, tab) - if err != nil { - return false, err - } - - for _, msg := range msgs { - m := msg.(*route.RouteMessage) - - if m.Version < 3 || m.Version > 5 { - return false, fmt.Errorf("unexpected RIB message version: %d", m.Version) - } - if m.Type != 4 /* RTM_GET */ { - return true, fmt.Errorf("unexpected RIB message type: %d", m.Type) - } - - if m.Flags&RTF_UP == 0 || - m.Flags&(RTF_REJECT|RTF_BLACKHOLE) != 0 { - continue - } - - dst, err := toIPAddr(m.Addrs[0]) - if err != nil { - return true, fmt.Errorf("unexpected RIB destination: %v", err) - } - - mask, _ := toIPAddr(m.Addrs[2]) - cidr, _ := net.IPMask(mask.To4()).Size() - if dst.String() == prefix.Addr().String() && cidr == prefix.Bits() { - return true, nil - } - } - - return false, nil -} - -func toIPAddr(a route.Addr) (net.IP, error) { - switch t := a.(type) { - case *route.Inet4Addr: - ip := net.IPv4(t.IP[0], t.IP[1], t.IP[2], t.IP[3]) - return ip, nil - case *route.Inet6Addr: - ip := make(net.IP, net.IPv6len) - copy(ip, t.IP[:]) - return ip, nil - default: - return net.IP{}, fmt.Errorf("unknown family: %v", t) - } -} diff --git a/client/internal/routemanager/systemops_nonandroid_test.go b/client/internal/routemanager/systemops_nonandroid_test.go index 2020aa8d4..48e262adb 100644 --- a/client/internal/routemanager/systemops_nonandroid_test.go +++ b/client/internal/routemanager/systemops_nonandroid_test.go @@ -1,16 +1,12 @@ package routemanager import ( - "bytes" "fmt" "net" "net/netip" - "os" - "strings" "testing" "github.com/pion/transport/v2/stdnet" - log "github.com/sirupsen/logrus" "github.com/stretchr/testify/require" "github.com/netbirdio/netbird/iface" @@ -79,90 +75,6 @@ func TestAddRemoveRoutes(t *testing.T) { } } -func TestAddExistAndRemoveRoute(t *testing.T) { - defaultGateway, err := getExistingRIBRouteGateway(netip.MustParsePrefix("0.0.0.0/0")) - fmt.Println("defaultGateway: ", defaultGateway) - if err != nil { - t.Fatal("shouldn't return error when fetching the gateway: ", err) - } - testCases := []struct { - name string - prefix netip.Prefix - preExistingPrefix netip.Prefix - shouldAddRoute bool - }{ - { - name: "Should Add And Remove random Route", - prefix: netip.MustParsePrefix("99.99.99.99/32"), - shouldAddRoute: true, - }, - { - name: "Should Not Add Route if overlaps with default gateway", - prefix: netip.MustParsePrefix(defaultGateway.String() + "/31"), - shouldAddRoute: false, - }, - { - name: "Should Add Route if bigger network exists", - prefix: netip.MustParsePrefix("100.100.100.0/24"), - preExistingPrefix: netip.MustParsePrefix("100.100.0.0/16"), - shouldAddRoute: true, - }, - { - name: "Should Add Route if smaller network exists", - prefix: netip.MustParsePrefix("100.100.0.0/16"), - preExistingPrefix: netip.MustParsePrefix("100.100.100.0/24"), - shouldAddRoute: true, - }, - { - name: "Should Not Add Route if same network exists", - prefix: netip.MustParsePrefix("100.100.0.0/16"), - preExistingPrefix: netip.MustParsePrefix("100.100.0.0/16"), - shouldAddRoute: false, - }, - } - - MOCK_ADDR := "127.0.0.1" - - for _, testCase := range testCases { - var buf bytes.Buffer - log.SetOutput(&buf) - defer func() { - log.SetOutput(os.Stderr) - }() - t.Run(testCase.name, func(t *testing.T) { - // Prepare the environment - if testCase.preExistingPrefix.IsValid() { - err := addToRouteTableIfNoExists(testCase.preExistingPrefix, MOCK_ADDR) - require.NoError(t, err, "should not return err when adding pre-existing route") - } - - // Add the route - err = addToRouteTableIfNoExists(testCase.prefix, MOCK_ADDR) - require.NoError(t, err, "should not return err when adding pre-existing route") - - if testCase.shouldAddRoute { - // test if route exists after adding - ok, err := existsInRouteTable(testCase.prefix) - require.NoError(t, err, "should not return err") - require.True(t, ok, "route should exist") - - // remove route again if added - err = removeFromRouteTableIfNonSystem(testCase.prefix, MOCK_ADDR) - require.NoError(t, err, "should not return err") - } - - // route should either not have been added or should have been removed - // In case of already existing route, it should not have been added (but still exist) - ok, err := existsInRouteTable(testCase.prefix) - fmt.Println("Buffer string: ", buf.String()) - require.NoError(t, err, "should not return err") - if !strings.Contains(buf.String(), "because it already exists") { - require.False(t, ok, "route should not exist") - } - }) - } -} - func TestGetExistingRIBRouteGateway(t *testing.T) { gateway, err := getExistingRIBRouteGateway(netip.MustParsePrefix("0.0.0.0/0")) if err != nil { diff --git a/client/internal/routemanager/systemops_test.go b/client/internal/routemanager/systemops_test.go new file mode 100644 index 000000000..d02b470f8 --- /dev/null +++ b/client/internal/routemanager/systemops_test.go @@ -0,0 +1,97 @@ +package routemanager + +import ( + "bytes" + "fmt" + "net/netip" + "os" + "strings" + "testing" + + log "github.com/sirupsen/logrus" + "github.com/stretchr/testify/require" +) + +func TestAddExistAndRemoveRoute(t *testing.T) { + defaultGateway, err := getExistingRIBRouteGateway(netip.MustParsePrefix("0.0.0.0/0")) + fmt.Println("defaultGateway: ", defaultGateway) + if err != nil { + t.Fatal("shouldn't return error when fetching the gateway: ", err) + } + testCases := []struct { + name string + prefix netip.Prefix + preExistingPrefix netip.Prefix + shouldAddRoute bool + }{ + { + name: "Should Add And Remove random Route", + prefix: netip.MustParsePrefix("99.99.99.99/32"), + shouldAddRoute: true, + }, + { + name: "Should Not Add Route if overlaps with default gateway", + prefix: netip.MustParsePrefix(defaultGateway.String() + "/31"), + shouldAddRoute: false, + }, + { + name: "Should Add Route if bigger network exists", + prefix: netip.MustParsePrefix("100.100.100.0/24"), + preExistingPrefix: netip.MustParsePrefix("100.100.0.0/16"), + shouldAddRoute: true, + }, + { + name: "Should Add Route if smaller network exists", + prefix: netip.MustParsePrefix("100.100.0.0/16"), + preExistingPrefix: netip.MustParsePrefix("100.100.100.0/24"), + shouldAddRoute: true, + }, + { + name: "Should Not Add Route if same network exists", + prefix: netip.MustParsePrefix("100.100.0.0/16"), + preExistingPrefix: netip.MustParsePrefix("100.100.0.0/16"), + shouldAddRoute: false, + }, + } + + MOCK_ADDR := "127.0.0.1" + + for _, testCase := range testCases { + var buf bytes.Buffer + log.SetOutput(&buf) + defer func() { + log.SetOutput(os.Stderr) + }() + t.Run(testCase.name, func(t *testing.T) { + // Prepare the environment + if testCase.preExistingPrefix.IsValid() { + err := addToRouteTableIfNoExists(testCase.preExistingPrefix, MOCK_ADDR) + require.NoError(t, err, "should not return err when adding pre-existing route") + } + + // Add the route + err = addToRouteTableIfNoExists(testCase.prefix, MOCK_ADDR) + require.NoError(t, err, "should not return err when adding pre-existing route") + + if testCase.shouldAddRoute { + // test if route exists after adding + ok, err := existsInRouteTable(testCase.prefix) + require.NoError(t, err, "should not return err") + require.True(t, ok, "route should exist") + + // remove route again if added + err = removeFromRouteTableIfNonSystem(testCase.prefix, MOCK_ADDR) + require.NoError(t, err, "should not return err") + } + + // route should either not have been added or should have been removed + // In case of already existing route, it should not have been added (but still exist) + ok, err := existsInRouteTable(testCase.prefix) + fmt.Println("Buffer string: ", buf.String()) + require.NoError(t, err, "should not return err") + if !strings.Contains(buf.String(), "because it already exists") { + require.False(t, ok, "route should not exist") + } + }) + } +} diff --git a/client/internal/routemanager/systemops_windows.go b/client/internal/routemanager/systemops_windows.go new file mode 100644 index 000000000..751b04846 --- /dev/null +++ b/client/internal/routemanager/systemops_windows.go @@ -0,0 +1,4 @@ +//go:build windows +// +build windows + +package routemanager From 64adaeb276f999d508358295192cb39c573897eb Mon Sep 17 00:00:00 2001 From: Pascal Fischer Date: Fri, 9 Jun 2023 18:30:36 +0200 Subject: [PATCH 07/23] split systemops for operating systems and add linux --- client/internal/routemanager/systemops_linux.go | 1 + 1 file changed, 1 insertion(+) diff --git a/client/internal/routemanager/systemops_linux.go b/client/internal/routemanager/systemops_linux.go index 368cb9075..ae8fe78b4 100644 --- a/client/internal/routemanager/systemops_linux.go +++ b/client/internal/routemanager/systemops_linux.go @@ -6,6 +6,7 @@ import ( "net" "net/netip" "os" + "syscall" "github.com/vishvananda/netlink" ) From 1ced2462c1da6344dd653cd2af37c10c7b589fcf Mon Sep 17 00:00:00 2001 From: Pascal Fischer Date: Fri, 9 Jun 2023 18:36:49 +0200 Subject: [PATCH 08/23] split systemops for operating systems and add linux --- .../internal/routemanager/systemops_linux.go | 21 +++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/client/internal/routemanager/systemops_linux.go b/client/internal/routemanager/systemops_linux.go index ae8fe78b4..d4491da8a 100644 --- a/client/internal/routemanager/systemops_linux.go +++ b/client/internal/routemanager/systemops_linux.go @@ -7,10 +7,27 @@ import ( "net/netip" "os" "syscall" + "unsafe" "github.com/vishvananda/netlink" ) +// Pulled from http://man7.org/linux/man-pages/man7/rtnetlink.7.html +// See the section on RTM_NEWROUTE, specifically 'struct rtmsg'. +type routeInfoInMemory struct { + Family byte + DstLen byte + SrcLen byte + TOS byte + + Table byte + Protocol byte + Scope byte + Type byte + + Flags uint32 +} + const ipv4ForwardingPath = "/proc/sys/net/ipv4/ip_forward" func addToRouteTable(prefix netip.Prefix, addr string) error { @@ -65,11 +82,11 @@ func removeFromRouteTable(prefix netip.Prefix) error { func existsInRouteTable(prefix netip.Prefix) (bool, error) { tab, err := syscall.NetlinkRIB(syscall.RTM_GETROUTE, syscall.AF_UNSPEC) if err != nil { - return nil, err + return true, err } msgs, err := syscall.ParseNetlinkMessage(tab) if err != nil { - return nil, err + return true, err } loop: for _, m := range msgs { From dad5501a44a65bee3e620aca524501f86c154d9e Mon Sep 17 00:00:00 2001 From: Pascal Fischer Date: Fri, 9 Jun 2023 18:40:35 +0200 Subject: [PATCH 09/23] split systemops for operating systems and add linux --- client/internal/routemanager/systemops_linux.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/internal/routemanager/systemops_linux.go b/client/internal/routemanager/systemops_linux.go index d4491da8a..fb2938d55 100644 --- a/client/internal/routemanager/systemops_linux.go +++ b/client/internal/routemanager/systemops_linux.go @@ -97,7 +97,7 @@ loop: rt := (*routeInfoInMemory)(unsafe.Pointer(&m.Data[0])) attrs, err := syscall.ParseNetlinkRouteAttr(&m) if err != nil { - return nil, err + return true, err } if rt.Family != syscall.AF_INET { continue loop From c8b4c08139d1e5973bedbdaf357683f1e0c0561d Mon Sep 17 00:00:00 2001 From: Pascal Fischer Date: Fri, 9 Jun 2023 18:48:21 +0200 Subject: [PATCH 10/23] split systemops for operating systems and add linux --- client/internal/routemanager/systemops_nonandroid.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/client/internal/routemanager/systemops_nonandroid.go b/client/internal/routemanager/systemops_nonandroid.go index 3958e0e05..3ddf72686 100644 --- a/client/internal/routemanager/systemops_nonandroid.go +++ b/client/internal/routemanager/systemops_nonandroid.go @@ -55,11 +55,15 @@ func getExistingRIBRouteGateway(prefix netip.Prefix) (net.IP, error) { if err != nil { return nil, err } - _, gateway, _, err := r.Route(prefix.Addr().AsSlice()) + _, gateway, preferredSrc, err := r.Route(prefix.Addr().AsSlice()) if err != nil { log.Errorf("getting routes returned an error: %v", err) return nil, errRouteNotFound } + if gateway == nil { + return preferredSrc, nil + } + return gateway, nil } From 9beaa91db915283a4580bcad5c61cb2081074519 Mon Sep 17 00:00:00 2001 From: Pascal Fischer Date: Fri, 9 Jun 2023 19:15:39 +0200 Subject: [PATCH 11/23] testing windows --- .../routemanager/systemops_windows.go | 36 +++++++++++++++++++ go.mod | 4 +++ go.sum | 8 +++++ 3 files changed, 48 insertions(+) diff --git a/client/internal/routemanager/systemops_windows.go b/client/internal/routemanager/systemops_windows.go index 751b04846..bc12a0389 100644 --- a/client/internal/routemanager/systemops_windows.go +++ b/client/internal/routemanager/systemops_windows.go @@ -2,3 +2,39 @@ // +build windows package routemanager + +import ( + "fmt" + "net/netip" + + "github.com/StackExchange/wmi" +) + +type Win32_IP4RouteTable struct { + Destination string + Mask string + NextHop string + InterfaceIdx int +} + +func existsInRouteTable(prefix netip.Prefix) (bool, error) { + var routes []Win32_IP4RouteTable + query := "SELECT Destination, Mask, NextHop, InterfaceIndex FROM Win32_IP4RouteTable" + + err := wmi.Query(query, &routes) + if err != nil { + return true, err + } + + fmt.Println("Destination Networks:") + for _, route := range routes { + fmt.Println("Destination :", route.Destination) + fmt.Println("Mask :", route.Mask) + // mask, _ := toIPAddr(m.Addrs[2]) + // cidr, _ := net.IPMask(mask.To4()).Size() + // if route.Destination == prefix.Addr().String() && cidr == prefix.Bits() { + // return true, nil + // } + } + return false, nil +} diff --git a/go.mod b/go.mod index 0f80479c1..a448850be 100644 --- a/go.mod +++ b/go.mod @@ -72,6 +72,7 @@ require ( require ( github.com/BurntSushi/toml v1.2.1 // indirect + github.com/StackExchange/wmi v1.2.1 // indirect github.com/XiaoMi/pegasus-go-client v0.0.0-20210427083443-f3b6b08bc4c2 // indirect github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be // indirect github.com/beorn7/perks v1.0.1 // indirect @@ -92,6 +93,7 @@ require ( github.com/go-gl/glfw/v3.3/glfw v0.0.0-20211024062804-40e447a793be // indirect github.com/go-logr/logr v1.2.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect + github.com/go-ole/go-ole v1.2.6 // indirect github.com/go-redis/redis/v8 v8.11.5 // indirect github.com/go-stack/stack v1.8.0 // indirect github.com/goki/freetype v0.0.0-20181231101311-fa8a33aabaff // indirect @@ -115,11 +117,13 @@ require ( github.com/prometheus/common v0.37.0 // indirect github.com/prometheus/procfs v0.8.0 // indirect github.com/rogpeppe/go-internal v1.8.0 // indirect + github.com/shirou/gopsutil v3.21.11+incompatible // indirect github.com/spf13/cast v1.5.0 // indirect github.com/srwiley/oksvg v0.0.0-20200311192757-870daf9aa564 // indirect github.com/srwiley/rasterx v0.0.0-20200120212402-85cb7272f5e9 // indirect github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 // indirect github.com/yuin/goldmark v1.4.13 // indirect + github.com/yusufpapurcu/wmi v1.2.3 // indirect go.opentelemetry.io/otel/sdk v1.11.1 // indirect go.opentelemetry.io/otel/trace v1.11.1 // indirect golang.org/x/image v0.5.0 // indirect diff --git a/go.sum b/go.sum index 0845147e3..9318f16d6 100644 --- a/go.sum +++ b/go.sum @@ -57,6 +57,8 @@ github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbt github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/StackExchange/wmi v1.2.1 h1:VIkavFPXSjcnS+O8yTq7NI32k0R5Aj+v39y29VYDOSA= +github.com/StackExchange/wmi v1.2.1/go.mod h1:rcmrprowKIVzvc+NUiLncP2uuArMWLCbu9SBzvHz7e8= github.com/XiaoMi/pegasus-go-client v0.0.0-20210427083443-f3b6b08bc4c2 h1:pami0oPhVosjOu/qRHepRmdjD6hGILF7DBr+qQZeP10= github.com/XiaoMi/pegasus-go-client v0.0.0-20210427083443-f3b6b08bc4c2/go.mod h1:jNIx5ykW1MroBuaTja9+VpglmaJOUzezumfhLlER3oY= github.com/akavel/rsrc v0.8.0/go.mod h1:uLoCtb9J+EyAqh+26kdrTgmzRBFPGOolLWKpdxkKq+c= @@ -219,6 +221,8 @@ github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/go-ole/go-ole v1.2.5/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= +github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0= github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= @@ -586,6 +590,8 @@ github.com/rs/xid v1.3.0 h1:6NjYksEUlhurdVehpc7S7dk6DAmcKv8V9gG0FsVN2U4= github.com/rs/xid v1.3.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI= +github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= @@ -661,6 +667,8 @@ github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1 github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.13 h1:fVcFKWvrslecOb/tg+Cc05dkeYx540o0FuFt3nUVDoE= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +github.com/yusufpapurcu/wmi v1.2.3 h1:E1ctvB7uKFMOJw3fdOW32DwGE9I7t++CRUEMKvFoFiw= +github.com/yusufpapurcu/wmi v1.2.3/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= From 0b5594f1453259d8f6e06d7fce34861c562343b4 Mon Sep 17 00:00:00 2001 From: Pascal Fischer Date: Fri, 9 Jun 2023 19:17:26 +0200 Subject: [PATCH 12/23] testing windows --- client/internal/routemanager/systemops_windows.go | 2 +- go.mod | 4 +--- go.sum | 5 ----- 3 files changed, 2 insertions(+), 9 deletions(-) diff --git a/client/internal/routemanager/systemops_windows.go b/client/internal/routemanager/systemops_windows.go index bc12a0389..567519d35 100644 --- a/client/internal/routemanager/systemops_windows.go +++ b/client/internal/routemanager/systemops_windows.go @@ -7,7 +7,7 @@ import ( "fmt" "net/netip" - "github.com/StackExchange/wmi" + "github.com/yusufpapurcu/wmi" ) type Win32_IP4RouteTable struct { diff --git a/go.mod b/go.mod index a448850be..d564f9b36 100644 --- a/go.mod +++ b/go.mod @@ -57,6 +57,7 @@ require ( github.com/rs/xid v1.3.0 github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 github.com/stretchr/testify v1.8.1 + github.com/yusufpapurcu/wmi v1.2.3 go.opentelemetry.io/otel v1.11.1 go.opentelemetry.io/otel/exporters/prometheus v0.33.0 go.opentelemetry.io/otel/metric v0.33.0 @@ -72,7 +73,6 @@ require ( require ( github.com/BurntSushi/toml v1.2.1 // indirect - github.com/StackExchange/wmi v1.2.1 // indirect github.com/XiaoMi/pegasus-go-client v0.0.0-20210427083443-f3b6b08bc4c2 // indirect github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be // indirect github.com/beorn7/perks v1.0.1 // indirect @@ -117,13 +117,11 @@ require ( github.com/prometheus/common v0.37.0 // indirect github.com/prometheus/procfs v0.8.0 // indirect github.com/rogpeppe/go-internal v1.8.0 // indirect - github.com/shirou/gopsutil v3.21.11+incompatible // indirect github.com/spf13/cast v1.5.0 // indirect github.com/srwiley/oksvg v0.0.0-20200311192757-870daf9aa564 // indirect github.com/srwiley/rasterx v0.0.0-20200120212402-85cb7272f5e9 // indirect github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 // indirect github.com/yuin/goldmark v1.4.13 // indirect - github.com/yusufpapurcu/wmi v1.2.3 // indirect go.opentelemetry.io/otel/sdk v1.11.1 // indirect go.opentelemetry.io/otel/trace v1.11.1 // indirect golang.org/x/image v0.5.0 // indirect diff --git a/go.sum b/go.sum index 9318f16d6..501866161 100644 --- a/go.sum +++ b/go.sum @@ -57,8 +57,6 @@ github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbt github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= -github.com/StackExchange/wmi v1.2.1 h1:VIkavFPXSjcnS+O8yTq7NI32k0R5Aj+v39y29VYDOSA= -github.com/StackExchange/wmi v1.2.1/go.mod h1:rcmrprowKIVzvc+NUiLncP2uuArMWLCbu9SBzvHz7e8= github.com/XiaoMi/pegasus-go-client v0.0.0-20210427083443-f3b6b08bc4c2 h1:pami0oPhVosjOu/qRHepRmdjD6hGILF7DBr+qQZeP10= github.com/XiaoMi/pegasus-go-client v0.0.0-20210427083443-f3b6b08bc4c2/go.mod h1:jNIx5ykW1MroBuaTja9+VpglmaJOUzezumfhLlER3oY= github.com/akavel/rsrc v0.8.0/go.mod h1:uLoCtb9J+EyAqh+26kdrTgmzRBFPGOolLWKpdxkKq+c= @@ -221,7 +219,6 @@ github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= -github.com/go-ole/go-ole v1.2.5/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0= @@ -590,8 +587,6 @@ github.com/rs/xid v1.3.0 h1:6NjYksEUlhurdVehpc7S7dk6DAmcKv8V9gG0FsVN2U4= github.com/rs/xid v1.3.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI= -github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= From d2fad1cfd929f491a712872dc7531aea4d58a27c Mon Sep 17 00:00:00 2001 From: Pascal Fischer Date: Mon, 12 Jun 2023 11:06:49 +0200 Subject: [PATCH 13/23] testing windows --- client/internal/routemanager/systemops_windows.go | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/client/internal/routemanager/systemops_windows.go b/client/internal/routemanager/systemops_windows.go index 567519d35..8be747222 100644 --- a/client/internal/routemanager/systemops_windows.go +++ b/client/internal/routemanager/systemops_windows.go @@ -11,15 +11,14 @@ import ( ) type Win32_IP4RouteTable struct { - Destination string - Mask string - NextHop string - InterfaceIdx int + Destination string + Mask string + NextHop string } func existsInRouteTable(prefix netip.Prefix) (bool, error) { var routes []Win32_IP4RouteTable - query := "SELECT Destination, Mask, NextHop, InterfaceIndex FROM Win32_IP4RouteTable" + query := "SELECT Destination, Mask, NextHop FROM Win32_IP4RouteTable" err := wmi.Query(query, &routes) if err != nil { From ce091ab42b91ea3a0fdb323e44b662f8ef618cb9 Mon Sep 17 00:00:00 2001 From: Pascal Fischer Date: Mon, 12 Jun 2023 11:43:18 +0200 Subject: [PATCH 14/23] test windows --- .../internal/routemanager/systemops_windows.go | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/client/internal/routemanager/systemops_windows.go b/client/internal/routemanager/systemops_windows.go index 8be747222..5df48fdf4 100644 --- a/client/internal/routemanager/systemops_windows.go +++ b/client/internal/routemanager/systemops_windows.go @@ -4,7 +4,7 @@ package routemanager import ( - "fmt" + "net" "net/netip" "github.com/yusufpapurcu/wmi" @@ -25,15 +25,13 @@ func existsInRouteTable(prefix netip.Prefix) (bool, error) { return true, err } - fmt.Println("Destination Networks:") for _, route := range routes { - fmt.Println("Destination :", route.Destination) - fmt.Println("Mask :", route.Mask) - // mask, _ := toIPAddr(m.Addrs[2]) - // cidr, _ := net.IPMask(mask.To4()).Size() - // if route.Destination == prefix.Addr().String() && cidr == prefix.Bits() { - // return true, nil - // } + ip := net.ParseIP(route.Mask) + mask := net.IPMask(ip) + cidr, _ := mask.Size() + if route.Destination == prefix.Addr().String() && cidr == prefix.Bits() { + return true, nil + } } return false, nil } From a5d14c92ff7f473ee88357c2339ff946cee83e2e Mon Sep 17 00:00:00 2001 From: Pascal Fischer Date: Mon, 12 Jun 2023 12:16:00 +0200 Subject: [PATCH 15/23] test windows --- client/internal/routemanager/systemops_windows.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/client/internal/routemanager/systemops_windows.go b/client/internal/routemanager/systemops_windows.go index 5df48fdf4..e91e03052 100644 --- a/client/internal/routemanager/systemops_windows.go +++ b/client/internal/routemanager/systemops_windows.go @@ -4,6 +4,7 @@ package routemanager import ( + "fmt" "net" "net/netip" @@ -29,6 +30,8 @@ func existsInRouteTable(prefix netip.Prefix) (bool, error) { ip := net.ParseIP(route.Mask) mask := net.IPMask(ip) cidr, _ := mask.Size() + fmt.Println(route.Destination, "<=>", prefix.Addr().String()) + fmt.Println(cidr, "<=>", prefix.Bits()) if route.Destination == prefix.Addr().String() && cidr == prefix.Bits() { return true, nil } From 7dfbb71f7a14bae8ce51e606198032496c6a5417 Mon Sep 17 00:00:00 2001 From: Pascal Fischer Date: Mon, 12 Jun 2023 12:49:21 +0200 Subject: [PATCH 16/23] test windows --- client/internal/routemanager/systemops_windows.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/client/internal/routemanager/systemops_windows.go b/client/internal/routemanager/systemops_windows.go index e91e03052..a6f20c59a 100644 --- a/client/internal/routemanager/systemops_windows.go +++ b/client/internal/routemanager/systemops_windows.go @@ -28,7 +28,8 @@ func existsInRouteTable(prefix netip.Prefix) (bool, error) { for _, route := range routes { ip := net.ParseIP(route.Mask) - mask := net.IPMask(ip) + ip = ip.To4() + mask := net.IPv4Mask(ip[0], ip[1], ip[2], ip[3]) cidr, _ := mask.Size() fmt.Println(route.Destination, "<=>", prefix.Addr().String()) fmt.Println(cidr, "<=>", prefix.Bits()) From 75d541f967b504d7eb2a65ccfcb459516a2cdd06 Mon Sep 17 00:00:00 2001 From: Pascal Fischer Date: Mon, 12 Jun 2023 14:56:30 +0200 Subject: [PATCH 17/23] test windows --- .../routemanager/systemops_nonandroid_test.go | 101 ++++++++++++++++++ .../internal/routemanager/systemops_test.go | 97 ----------------- .../routemanager/systemops_windows.go | 2 + 3 files changed, 103 insertions(+), 97 deletions(-) delete mode 100644 client/internal/routemanager/systemops_test.go diff --git a/client/internal/routemanager/systemops_nonandroid_test.go b/client/internal/routemanager/systemops_nonandroid_test.go index 48e262adb..d2d6998aa 100644 --- a/client/internal/routemanager/systemops_nonandroid_test.go +++ b/client/internal/routemanager/systemops_nonandroid_test.go @@ -1,12 +1,16 @@ package routemanager import ( + "bytes" "fmt" "net" "net/netip" + "os" + "strings" "testing" "github.com/pion/transport/v2/stdnet" + log "github.com/sirupsen/logrus" "github.com/stretchr/testify/require" "github.com/netbirdio/netbird/iface" @@ -116,3 +120,100 @@ func TestGetExistingRIBRouteGateway(t *testing.T) { t.Fatalf("local ip should match with testing IP: want %s got %s", testingIP, localIP.String()) } } + +func TestAddExistAndRemoveRoute(t *testing.T) { + defaultGateway, err := getExistingRIBRouteGateway(netip.MustParsePrefix("0.0.0.0/0")) + fmt.Println("defaultGateway: ", defaultGateway) + if err != nil { + t.Fatal("shouldn't return error when fetching the gateway: ", err) + } + testCases := []struct { + name string + prefix netip.Prefix + preExistingPrefix netip.Prefix + shouldAddRoute bool + }{ + { + name: "Should Add And Remove random Route", + prefix: netip.MustParsePrefix("99.99.99.99/32"), + shouldAddRoute: true, + }, + { + name: "Should Not Add Route if overlaps with default gateway", + prefix: netip.MustParsePrefix(defaultGateway.String() + "/31"), + shouldAddRoute: false, + }, + { + name: "Should Add Route if bigger network exists", + prefix: netip.MustParsePrefix("100.100.100.0/24"), + preExistingPrefix: netip.MustParsePrefix("100.100.0.0/16"), + shouldAddRoute: true, + }, + { + name: "Should Add Route if smaller network exists", + prefix: netip.MustParsePrefix("100.100.0.0/16"), + preExistingPrefix: netip.MustParsePrefix("100.100.100.0/24"), + shouldAddRoute: true, + }, + { + name: "Should Not Add Route if same network exists", + prefix: netip.MustParsePrefix("100.100.0.0/16"), + preExistingPrefix: netip.MustParsePrefix("100.100.0.0/16"), + shouldAddRoute: false, + }, + } + + // MOCK_ADDR := "127.0.0.1" + + for n, testCase := range testCases { + var buf bytes.Buffer + log.SetOutput(&buf) + defer func() { + log.SetOutput(os.Stderr) + }() + t.Run(testCase.name, func(t *testing.T) { + newNet, err := stdnet.NewNet() + if err != nil { + t.Fatal(err) + } + wgInterface, err := iface.NewWGIFace(fmt.Sprintf("utun53%d", n), "100.65.75.2/24", iface.DefaultMTU, nil, newNet) + require.NoError(t, err, "should create testing WGIface interface") + defer wgInterface.Close() + + err = wgInterface.Create() + require.NoError(t, err, "should create testing wireguard interface") + + MOCK_ADDR := wgInterface.Address().IP.String() + + // Prepare the environment + if testCase.preExistingPrefix.IsValid() { + err := addToRouteTableIfNoExists(testCase.preExistingPrefix, MOCK_ADDR) + require.NoError(t, err, "should not return err when adding pre-existing route") + } + + // Add the route + err = addToRouteTableIfNoExists(testCase.prefix, MOCK_ADDR) + require.NoError(t, err, "should not return err when adding pre-existing route") + + if testCase.shouldAddRoute { + // test if route exists after adding + ok, err := existsInRouteTable(testCase.prefix) + require.NoError(t, err, "should not return err") + require.True(t, ok, "route should exist") + + // remove route again if added + err = removeFromRouteTableIfNonSystem(testCase.prefix, MOCK_ADDR) + require.NoError(t, err, "should not return err") + } + + // route should either not have been added or should have been removed + // In case of already existing route, it should not have been added (but still exist) + ok, err := existsInRouteTable(testCase.prefix) + fmt.Println("Buffer string: ", buf.String()) + require.NoError(t, err, "should not return err") + if !strings.Contains(buf.String(), "because it already exists") { + require.False(t, ok, "route should not exist") + } + }) + } +} diff --git a/client/internal/routemanager/systemops_test.go b/client/internal/routemanager/systemops_test.go deleted file mode 100644 index d02b470f8..000000000 --- a/client/internal/routemanager/systemops_test.go +++ /dev/null @@ -1,97 +0,0 @@ -package routemanager - -import ( - "bytes" - "fmt" - "net/netip" - "os" - "strings" - "testing" - - log "github.com/sirupsen/logrus" - "github.com/stretchr/testify/require" -) - -func TestAddExistAndRemoveRoute(t *testing.T) { - defaultGateway, err := getExistingRIBRouteGateway(netip.MustParsePrefix("0.0.0.0/0")) - fmt.Println("defaultGateway: ", defaultGateway) - if err != nil { - t.Fatal("shouldn't return error when fetching the gateway: ", err) - } - testCases := []struct { - name string - prefix netip.Prefix - preExistingPrefix netip.Prefix - shouldAddRoute bool - }{ - { - name: "Should Add And Remove random Route", - prefix: netip.MustParsePrefix("99.99.99.99/32"), - shouldAddRoute: true, - }, - { - name: "Should Not Add Route if overlaps with default gateway", - prefix: netip.MustParsePrefix(defaultGateway.String() + "/31"), - shouldAddRoute: false, - }, - { - name: "Should Add Route if bigger network exists", - prefix: netip.MustParsePrefix("100.100.100.0/24"), - preExistingPrefix: netip.MustParsePrefix("100.100.0.0/16"), - shouldAddRoute: true, - }, - { - name: "Should Add Route if smaller network exists", - prefix: netip.MustParsePrefix("100.100.0.0/16"), - preExistingPrefix: netip.MustParsePrefix("100.100.100.0/24"), - shouldAddRoute: true, - }, - { - name: "Should Not Add Route if same network exists", - prefix: netip.MustParsePrefix("100.100.0.0/16"), - preExistingPrefix: netip.MustParsePrefix("100.100.0.0/16"), - shouldAddRoute: false, - }, - } - - MOCK_ADDR := "127.0.0.1" - - for _, testCase := range testCases { - var buf bytes.Buffer - log.SetOutput(&buf) - defer func() { - log.SetOutput(os.Stderr) - }() - t.Run(testCase.name, func(t *testing.T) { - // Prepare the environment - if testCase.preExistingPrefix.IsValid() { - err := addToRouteTableIfNoExists(testCase.preExistingPrefix, MOCK_ADDR) - require.NoError(t, err, "should not return err when adding pre-existing route") - } - - // Add the route - err = addToRouteTableIfNoExists(testCase.prefix, MOCK_ADDR) - require.NoError(t, err, "should not return err when adding pre-existing route") - - if testCase.shouldAddRoute { - // test if route exists after adding - ok, err := existsInRouteTable(testCase.prefix) - require.NoError(t, err, "should not return err") - require.True(t, ok, "route should exist") - - // remove route again if added - err = removeFromRouteTableIfNonSystem(testCase.prefix, MOCK_ADDR) - require.NoError(t, err, "should not return err") - } - - // route should either not have been added or should have been removed - // In case of already existing route, it should not have been added (but still exist) - ok, err := existsInRouteTable(testCase.prefix) - fmt.Println("Buffer string: ", buf.String()) - require.NoError(t, err, "should not return err") - if !strings.Contains(buf.String(), "because it already exists") { - require.False(t, ok, "route should not exist") - } - }) - } -} diff --git a/client/internal/routemanager/systemops_windows.go b/client/internal/routemanager/systemops_windows.go index a6f20c59a..48c803f60 100644 --- a/client/internal/routemanager/systemops_windows.go +++ b/client/internal/routemanager/systemops_windows.go @@ -27,6 +27,7 @@ func existsInRouteTable(prefix netip.Prefix) (bool, error) { } for _, route := range routes { + fmt.Println(routes) ip := net.ParseIP(route.Mask) ip = ip.To4() mask := net.IPv4Mask(ip[0], ip[1], ip[2], ip[3]) @@ -34,6 +35,7 @@ func existsInRouteTable(prefix netip.Prefix) (bool, error) { fmt.Println(route.Destination, "<=>", prefix.Addr().String()) fmt.Println(cidr, "<=>", prefix.Bits()) if route.Destination == prefix.Addr().String() && cidr == prefix.Bits() { + fmt.Println("Found route exists in table") return true, nil } } From 697d41c94e32349ae7e949736ba4f8b94e0e4cef Mon Sep 17 00:00:00 2001 From: Pascal Fischer Date: Mon, 12 Jun 2023 15:14:51 +0200 Subject: [PATCH 18/23] test windows --- .../routemanager/systemops_nonandroid_test.go | 101 ---------------- .../internal/routemanager/systemops_test.go | 113 ++++++++++++++++++ 2 files changed, 113 insertions(+), 101 deletions(-) create mode 100644 client/internal/routemanager/systemops_test.go diff --git a/client/internal/routemanager/systemops_nonandroid_test.go b/client/internal/routemanager/systemops_nonandroid_test.go index d2d6998aa..48e262adb 100644 --- a/client/internal/routemanager/systemops_nonandroid_test.go +++ b/client/internal/routemanager/systemops_nonandroid_test.go @@ -1,16 +1,12 @@ package routemanager import ( - "bytes" "fmt" "net" "net/netip" - "os" - "strings" "testing" "github.com/pion/transport/v2/stdnet" - log "github.com/sirupsen/logrus" "github.com/stretchr/testify/require" "github.com/netbirdio/netbird/iface" @@ -120,100 +116,3 @@ func TestGetExistingRIBRouteGateway(t *testing.T) { t.Fatalf("local ip should match with testing IP: want %s got %s", testingIP, localIP.String()) } } - -func TestAddExistAndRemoveRoute(t *testing.T) { - defaultGateway, err := getExistingRIBRouteGateway(netip.MustParsePrefix("0.0.0.0/0")) - fmt.Println("defaultGateway: ", defaultGateway) - if err != nil { - t.Fatal("shouldn't return error when fetching the gateway: ", err) - } - testCases := []struct { - name string - prefix netip.Prefix - preExistingPrefix netip.Prefix - shouldAddRoute bool - }{ - { - name: "Should Add And Remove random Route", - prefix: netip.MustParsePrefix("99.99.99.99/32"), - shouldAddRoute: true, - }, - { - name: "Should Not Add Route if overlaps with default gateway", - prefix: netip.MustParsePrefix(defaultGateway.String() + "/31"), - shouldAddRoute: false, - }, - { - name: "Should Add Route if bigger network exists", - prefix: netip.MustParsePrefix("100.100.100.0/24"), - preExistingPrefix: netip.MustParsePrefix("100.100.0.0/16"), - shouldAddRoute: true, - }, - { - name: "Should Add Route if smaller network exists", - prefix: netip.MustParsePrefix("100.100.0.0/16"), - preExistingPrefix: netip.MustParsePrefix("100.100.100.0/24"), - shouldAddRoute: true, - }, - { - name: "Should Not Add Route if same network exists", - prefix: netip.MustParsePrefix("100.100.0.0/16"), - preExistingPrefix: netip.MustParsePrefix("100.100.0.0/16"), - shouldAddRoute: false, - }, - } - - // MOCK_ADDR := "127.0.0.1" - - for n, testCase := range testCases { - var buf bytes.Buffer - log.SetOutput(&buf) - defer func() { - log.SetOutput(os.Stderr) - }() - t.Run(testCase.name, func(t *testing.T) { - newNet, err := stdnet.NewNet() - if err != nil { - t.Fatal(err) - } - wgInterface, err := iface.NewWGIFace(fmt.Sprintf("utun53%d", n), "100.65.75.2/24", iface.DefaultMTU, nil, newNet) - require.NoError(t, err, "should create testing WGIface interface") - defer wgInterface.Close() - - err = wgInterface.Create() - require.NoError(t, err, "should create testing wireguard interface") - - MOCK_ADDR := wgInterface.Address().IP.String() - - // Prepare the environment - if testCase.preExistingPrefix.IsValid() { - err := addToRouteTableIfNoExists(testCase.preExistingPrefix, MOCK_ADDR) - require.NoError(t, err, "should not return err when adding pre-existing route") - } - - // Add the route - err = addToRouteTableIfNoExists(testCase.prefix, MOCK_ADDR) - require.NoError(t, err, "should not return err when adding pre-existing route") - - if testCase.shouldAddRoute { - // test if route exists after adding - ok, err := existsInRouteTable(testCase.prefix) - require.NoError(t, err, "should not return err") - require.True(t, ok, "route should exist") - - // remove route again if added - err = removeFromRouteTableIfNonSystem(testCase.prefix, MOCK_ADDR) - require.NoError(t, err, "should not return err") - } - - // route should either not have been added or should have been removed - // In case of already existing route, it should not have been added (but still exist) - ok, err := existsInRouteTable(testCase.prefix) - fmt.Println("Buffer string: ", buf.String()) - require.NoError(t, err, "should not return err") - if !strings.Contains(buf.String(), "because it already exists") { - require.False(t, ok, "route should not exist") - } - }) - } -} diff --git a/client/internal/routemanager/systemops_test.go b/client/internal/routemanager/systemops_test.go new file mode 100644 index 000000000..41536f30c --- /dev/null +++ b/client/internal/routemanager/systemops_test.go @@ -0,0 +1,113 @@ +package routemanager + +import ( + "bytes" + "fmt" + "net/netip" + "os" + "strings" + "testing" + + "github.com/pion/transport/v2/stdnet" + log "github.com/sirupsen/logrus" + "github.com/stretchr/testify/require" + + "github.com/netbirdio/netbird/iface" +) + +func TestAddExistAndRemoveRoute(t *testing.T) { + defaultGateway, err := getExistingRIBRouteGateway(netip.MustParsePrefix("0.0.0.0/0")) + fmt.Println("defaultGateway: ", defaultGateway) + if err != nil { + t.Fatal("shouldn't return error when fetching the gateway: ", err) + } + testCases := []struct { + name string + prefix netip.Prefix + preExistingPrefix netip.Prefix + shouldAddRoute bool + }{ + { + name: "Should Add And Remove random Route", + prefix: netip.MustParsePrefix("99.99.99.99/32"), + shouldAddRoute: true, + }, + { + name: "Should Not Add Route if overlaps with default gateway", + prefix: netip.MustParsePrefix(defaultGateway.String() + "/31"), + shouldAddRoute: false, + }, + { + name: "Should Add Route if bigger network exists", + prefix: netip.MustParsePrefix("100.100.100.0/24"), + preExistingPrefix: netip.MustParsePrefix("100.100.0.0/16"), + shouldAddRoute: true, + }, + { + name: "Should Add Route if smaller network exists", + prefix: netip.MustParsePrefix("100.100.0.0/16"), + preExistingPrefix: netip.MustParsePrefix("100.100.100.0/24"), + shouldAddRoute: true, + }, + { + name: "Should Not Add Route if same network exists", + prefix: netip.MustParsePrefix("100.100.0.0/16"), + preExistingPrefix: netip.MustParsePrefix("100.100.0.0/16"), + shouldAddRoute: false, + }, + } + + // MOCK_ADDR := "127.0.0.1" + + for n, testCase := range testCases { + var buf bytes.Buffer + log.SetOutput(&buf) + defer func() { + log.SetOutput(os.Stderr) + }() + t.Run(testCase.name, func(t *testing.T) { + newNet, err := stdnet.NewNet() + if err != nil { + t.Fatal(err) + } + wgInterface, err := iface.NewWGIFace(fmt.Sprintf("utun53%d", n), "100.65.75.2/24", iface.DefaultMTU, nil, newNet) + require.NoError(t, err, "should create testing WGIface interface") + defer wgInterface.Close() + + err = wgInterface.Create() + require.NoError(t, err, "should create testing wireguard interface") + + MOCK_ADDR := wgInterface.Address().IP.String() + + // Prepare the environment + if testCase.preExistingPrefix.IsValid() { + err := addToRouteTableIfNoExists(testCase.preExistingPrefix, MOCK_ADDR) + require.NoError(t, err, "should not return err when adding pre-existing route") + } + + // Add the route + err = addToRouteTableIfNoExists(testCase.prefix, MOCK_ADDR) + require.NoError(t, err, "should not return err when adding route") + + if testCase.shouldAddRoute { + // test if route exists after adding + ok, err := existsInRouteTable(testCase.prefix) + require.NoError(t, err, "should not return err") + require.True(t, ok, "route should exist") + + // remove route again if added + err = removeFromRouteTableIfNonSystem(testCase.prefix, MOCK_ADDR) + require.NoError(t, err, "should not return err") + } + + // route should either not have been added or should have been removed + // In case of already existing route, it should not have been added (but still exist) + ok, err := existsInRouteTable(testCase.prefix) + fmt.Println("Buffer string: ", buf.String()) + require.NoError(t, err, "should not return err") + if !strings.Contains(buf.String(), "because it already exists") { + require.False(t, ok, "route should not exist") + } + }) + } +} From 5d19811331a40cb60b8b0841fe3f84d93d10ed79 Mon Sep 17 00:00:00 2001 From: Pascal Fischer Date: Mon, 12 Jun 2023 15:26:28 +0200 Subject: [PATCH 19/23] test windows --- .../internal/routemanager/systemops_test.go | 113 ------------------ .../routemanager/systemops_windows.go | 5 +- 2 files changed, 1 insertion(+), 117 deletions(-) delete mode 100644 client/internal/routemanager/systemops_test.go diff --git a/client/internal/routemanager/systemops_test.go b/client/internal/routemanager/systemops_test.go deleted file mode 100644 index 41536f30c..000000000 --- a/client/internal/routemanager/systemops_test.go +++ /dev/null @@ -1,113 +0,0 @@ -package routemanager - -import ( - "bytes" - "fmt" - "net/netip" - "os" - "strings" - "testing" - - "github.com/pion/transport/v2/stdnet" - log "github.com/sirupsen/logrus" - "github.com/stretchr/testify/require" - - "github.com/netbirdio/netbird/iface" -) - -func TestAddExistAndRemoveRoute(t *testing.T) { - defaultGateway, err := getExistingRIBRouteGateway(netip.MustParsePrefix("0.0.0.0/0")) - fmt.Println("defaultGateway: ", defaultGateway) - if err != nil { - t.Fatal("shouldn't return error when fetching the gateway: ", err) - } - testCases := []struct { - name string - prefix netip.Prefix - preExistingPrefix netip.Prefix - shouldAddRoute bool - }{ - { - name: "Should Add And Remove random Route", - prefix: netip.MustParsePrefix("99.99.99.99/32"), - shouldAddRoute: true, - }, - { - name: "Should Not Add Route if overlaps with default gateway", - prefix: netip.MustParsePrefix(defaultGateway.String() + "/31"), - shouldAddRoute: false, - }, - { - name: "Should Add Route if bigger network exists", - prefix: netip.MustParsePrefix("100.100.100.0/24"), - preExistingPrefix: netip.MustParsePrefix("100.100.0.0/16"), - shouldAddRoute: true, - }, - { - name: "Should Add Route if smaller network exists", - prefix: netip.MustParsePrefix("100.100.0.0/16"), - preExistingPrefix: netip.MustParsePrefix("100.100.100.0/24"), - shouldAddRoute: true, - }, - { - name: "Should Not Add Route if same network exists", - prefix: netip.MustParsePrefix("100.100.0.0/16"), - preExistingPrefix: netip.MustParsePrefix("100.100.0.0/16"), - shouldAddRoute: false, - }, - } - - // MOCK_ADDR := "127.0.0.1" - - for n, testCase := range testCases { - var buf bytes.Buffer - log.SetOutput(&buf) - defer func() { - log.SetOutput(os.Stderr) - }() - t.Run(testCase.name, func(t *testing.T) { - newNet, err := stdnet.NewNet() - if err != nil { - t.Fatal(err) - } - wgInterface, err := iface.NewWGIFace(fmt.Sprintf("utun53%d", n), "100.65.75.2/24", iface.DefaultMTU, nil, newNet) - require.NoError(t, err, "should create testing WGIface interface") - defer wgInterface.Close() - - err = wgInterface.Create() - require.NoError(t, err, "should create testing wireguard interface") - - MOCK_ADDR := wgInterface.Address().IP.String() - - // Prepare the environment - if testCase.preExistingPrefix.IsValid() { - err := addToRouteTableIfNoExists(testCase.preExistingPrefix, MOCK_ADDR) - require.NoError(t, err, "should not return err when adding pre-existing route") - } - - // Add the route - err = addToRouteTableIfNoExists(testCase.prefix, MOCK_ADDR) - require.NoError(t, err, "should not return err when adding route") - - if testCase.shouldAddRoute { - // test if route exists after adding - ok, err := existsInRouteTable(testCase.prefix) - require.NoError(t, err, "should not return err") - require.True(t, ok, "route should exist") - - // remove route again if added - err = removeFromRouteTableIfNonSystem(testCase.prefix, MOCK_ADDR) - require.NoError(t, err, "should not return err") - } - - // route should either not have been added or should have been removed - // In case of already existing route, it should not have been added (but still exist) - ok, err := existsInRouteTable(testCase.prefix) - fmt.Println("Buffer string: ", buf.String()) - require.NoError(t, err, "should not return err") - if !strings.Contains(buf.String(), "because it already exists") { - require.False(t, ok, "route should not exist") - } - }) - } -} diff --git a/client/internal/routemanager/systemops_windows.go b/client/internal/routemanager/systemops_windows.go index 48c803f60..d2c907b0a 100644 --- a/client/internal/routemanager/systemops_windows.go +++ b/client/internal/routemanager/systemops_windows.go @@ -32,10 +32,7 @@ func existsInRouteTable(prefix netip.Prefix) (bool, error) { ip = ip.To4() mask := net.IPv4Mask(ip[0], ip[1], ip[2], ip[3]) cidr, _ := mask.Size() - fmt.Println(route.Destination, "<=>", prefix.Addr().String()) - fmt.Println(cidr, "<=>", prefix.Bits()) - if route.Destination == prefix.Addr().String() && cidr == prefix.Bits() { - fmt.Println("Found route exists in table") + if route.Destination == prefix.Addr().String() && cidr == prefix.Bits() && false { return true, nil } } From b92107efc8bb44917b1c3740a7e3999fde1ef009 Mon Sep 17 00:00:00 2001 From: Pascal Fischer Date: Mon, 12 Jun 2023 15:38:47 +0200 Subject: [PATCH 20/23] test windows --- .../routemanager/systemops_windows.go | 106 ++++++++++++++++++ 1 file changed, 106 insertions(+) diff --git a/client/internal/routemanager/systemops_windows.go b/client/internal/routemanager/systemops_windows.go index d2c907b0a..4bc436b2d 100644 --- a/client/internal/routemanager/systemops_windows.go +++ b/client/internal/routemanager/systemops_windows.go @@ -4,11 +4,20 @@ package routemanager import ( + "bytes" "fmt" "net" "net/netip" + "os" + "strings" + "testing" + "github.com/pion/transport/v2/stdnet" + log "github.com/sirupsen/logrus" + "github.com/stretchr/testify/require" "github.com/yusufpapurcu/wmi" + + "github.com/netbirdio/netbird/iface" ) type Win32_IP4RouteTable struct { @@ -38,3 +47,100 @@ func existsInRouteTable(prefix netip.Prefix) (bool, error) { } return false, nil } + +func TestAddExistAndRemoveRoute(t *testing.T) { + defaultGateway, err := getExistingRIBRouteGateway(netip.MustParsePrefix("0.0.0.0/0")) + fmt.Println("defaultGateway: ", defaultGateway) + if err != nil { + t.Fatal("shouldn't return error when fetching the gateway: ", err) + } + testCases := []struct { + name string + prefix netip.Prefix + preExistingPrefix netip.Prefix + shouldAddRoute bool + }{ + { + name: "Should Add And Remove random Route", + prefix: netip.MustParsePrefix("99.99.99.99/32"), + shouldAddRoute: true, + }, + { + name: "Should Not Add Route if overlaps with default gateway", + prefix: netip.MustParsePrefix(defaultGateway.String() + "/31"), + shouldAddRoute: false, + }, + { + name: "Should Add Route if bigger network exists", + prefix: netip.MustParsePrefix("100.100.100.0/24"), + preExistingPrefix: netip.MustParsePrefix("100.100.0.0/16"), + shouldAddRoute: true, + }, + { + name: "Should Add Route if smaller network exists", + prefix: netip.MustParsePrefix("100.100.0.0/16"), + preExistingPrefix: netip.MustParsePrefix("100.100.100.0/24"), + shouldAddRoute: true, + }, + { + name: "Should Not Add Route if same network exists", + prefix: netip.MustParsePrefix("100.100.0.0/16"), + preExistingPrefix: netip.MustParsePrefix("100.100.0.0/16"), + shouldAddRoute: false, + }, + } + + // MOCK_ADDR := "127.0.0.1" + + for n, testCase := range testCases { + var buf bytes.Buffer + log.SetOutput(&buf) + defer func() { + log.SetOutput(os.Stderr) + }() + t.Run(testCase.name, func(t *testing.T) { + newNet, err := stdnet.NewNet() + if err != nil { + t.Fatal(err) + } + wgInterface, err := iface.NewWGIFace(fmt.Sprintf("utun53%d", n), "100.65.75.2/24", iface.DefaultMTU, nil, newNet) + require.NoError(t, err, "should create testing WGIface interface") + defer wgInterface.Close() + + err = wgInterface.Create() + require.NoError(t, err, "should create testing wireguard interface") + + MOCK_ADDR := wgInterface.Address().IP.String() + + // Prepare the environment + if testCase.preExistingPrefix.IsValid() { + err := addToRouteTableIfNoExists(testCase.preExistingPrefix, MOCK_ADDR) + require.NoError(t, err, "should not return err when adding pre-existing route") + } + + // Add the route + err = addToRouteTableIfNoExists(testCase.prefix, MOCK_ADDR) + require.NoError(t, err, "should not return err when adding pre-existing route") + + if testCase.shouldAddRoute { + // test if route exists after adding + ok, err := existsInRouteTable(testCase.prefix) + require.NoError(t, err, "should not return err") + require.True(t, ok, "route should exist") + + // remove route again if added + err = removeFromRouteTableIfNonSystem(testCase.prefix, MOCK_ADDR) + require.NoError(t, err, "should not return err") + } + + // route should either not have been added or should have been removed + // In case of already existing route, it should not have been added (but still exist) + ok, err := existsInRouteTable(testCase.prefix) + fmt.Println("Buffer string: ", buf.String()) + require.NoError(t, err, "should not return err") + if !strings.Contains(buf.String(), "because it already exists") { + require.False(t, ok, "route should not exist") + } + }) + } +} From 25670064120bbfb832a67bdd2280f59da7fa39b9 Mon Sep 17 00:00:00 2001 From: Pascal Fischer Date: Mon, 12 Jun 2023 16:01:06 +0200 Subject: [PATCH 21/23] test windows --- .../routemanager/systemops_nonandroid_test.go | 101 ++++++++++++++++ .../internal/routemanager/systemops_test.go | 113 ++++++++++++++++++ .../routemanager/systemops_windows.go | 106 ---------------- 3 files changed, 214 insertions(+), 106 deletions(-) create mode 100644 client/internal/routemanager/systemops_test.go diff --git a/client/internal/routemanager/systemops_nonandroid_test.go b/client/internal/routemanager/systemops_nonandroid_test.go index 48e262adb..48fc02562 100644 --- a/client/internal/routemanager/systemops_nonandroid_test.go +++ b/client/internal/routemanager/systemops_nonandroid_test.go @@ -1,12 +1,16 @@ package routemanager import ( + "bytes" "fmt" "net" "net/netip" + "os" + "strings" "testing" "github.com/pion/transport/v2/stdnet" + log "github.com/sirupsen/logrus" "github.com/stretchr/testify/require" "github.com/netbirdio/netbird/iface" @@ -116,3 +120,100 @@ func TestGetExistingRIBRouteGateway(t *testing.T) { t.Fatalf("local ip should match with testing IP: want %s got %s", testingIP, localIP.String()) } } + +func TestAddExistAndRemoveRouteNonAndroid(t *testing.T) { + defaultGateway, err := getExistingRIBRouteGateway(netip.MustParsePrefix("0.0.0.0/0")) + fmt.Println("defaultGateway: ", defaultGateway) + if err != nil { + t.Fatal("shouldn't return error when fetching the gateway: ", err) + } + testCases := []struct { + name string + prefix netip.Prefix + preExistingPrefix netip.Prefix + shouldAddRoute bool + }{ + { + name: "Should Add And Remove random Route", + prefix: netip.MustParsePrefix("99.99.99.99/32"), + shouldAddRoute: true, + }, + { + name: "Should Not Add Route if overlaps with default gateway", + prefix: netip.MustParsePrefix(defaultGateway.String() + "/31"), + shouldAddRoute: false, + }, + { + name: "Should Add Route if bigger network exists", + prefix: netip.MustParsePrefix("100.100.100.0/24"), + preExistingPrefix: netip.MustParsePrefix("100.100.0.0/16"), + shouldAddRoute: true, + }, + { + name: "Should Add Route if smaller network exists", + prefix: netip.MustParsePrefix("100.100.0.0/16"), + preExistingPrefix: netip.MustParsePrefix("100.100.100.0/24"), + shouldAddRoute: true, + }, + { + name: "Should Not Add Route if same network exists", + prefix: netip.MustParsePrefix("100.100.0.0/16"), + preExistingPrefix: netip.MustParsePrefix("100.100.0.0/16"), + shouldAddRoute: false, + }, + } + + // MOCK_ADDR := "127.0.0.1" + + for n, testCase := range testCases { + var buf bytes.Buffer + log.SetOutput(&buf) + defer func() { + log.SetOutput(os.Stderr) + }() + t.Run(testCase.name, func(t *testing.T) { + newNet, err := stdnet.NewNet() + if err != nil { + t.Fatal(err) + } + wgInterface, err := iface.NewWGIFace(fmt.Sprintf("utun53%d", n), "100.65.75.2/24", iface.DefaultMTU, nil, newNet) + require.NoError(t, err, "should create testing WGIface interface") + defer wgInterface.Close() + + err = wgInterface.Create() + require.NoError(t, err, "should create testing wireguard interface") + + MOCK_ADDR := wgInterface.Address().IP.String() + + // Prepare the environment + if testCase.preExistingPrefix.IsValid() { + err := addToRouteTableIfNoExists(testCase.preExistingPrefix, MOCK_ADDR) + require.NoError(t, err, "should not return err when adding pre-existing route") + } + + // Add the route + err = addToRouteTableIfNoExists(testCase.prefix, MOCK_ADDR) + require.NoError(t, err, "should not return err when adding route") + + if testCase.shouldAddRoute { + // test if route exists after adding + ok, err := existsInRouteTable(testCase.prefix) + require.NoError(t, err, "should not return err") + require.True(t, ok, "route should exist") + + // remove route again if added + err = removeFromRouteTableIfNonSystem(testCase.prefix, MOCK_ADDR) + require.NoError(t, err, "should not return err") + } + + // route should either not have been added or should have been removed + // In case of already existing route, it should not have been added (but still exist) + ok, err := existsInRouteTable(testCase.prefix) + fmt.Println("Buffer string: ", buf.String()) + require.NoError(t, err, "should not return err") + if !strings.Contains(buf.String(), "because it already exists") { + require.False(t, ok, "route should not exist") + } + }) + } +} diff --git a/client/internal/routemanager/systemops_test.go b/client/internal/routemanager/systemops_test.go new file mode 100644 index 000000000..41536f30c --- /dev/null +++ b/client/internal/routemanager/systemops_test.go @@ -0,0 +1,113 @@ +package routemanager + +import ( + "bytes" + "fmt" + "net/netip" + "os" + "strings" + "testing" + + "github.com/pion/transport/v2/stdnet" + log "github.com/sirupsen/logrus" + "github.com/stretchr/testify/require" + + "github.com/netbirdio/netbird/iface" +) + +func TestAddExistAndRemoveRoute(t *testing.T) { + defaultGateway, err := getExistingRIBRouteGateway(netip.MustParsePrefix("0.0.0.0/0")) + fmt.Println("defaultGateway: ", defaultGateway) + if err != nil { + t.Fatal("shouldn't return error when fetching the gateway: ", err) + } + testCases := []struct { + name string + prefix netip.Prefix + preExistingPrefix netip.Prefix + shouldAddRoute bool + }{ + { + name: "Should Add And Remove random Route", + prefix: netip.MustParsePrefix("99.99.99.99/32"), + shouldAddRoute: true, + }, + { + name: "Should Not Add Route if overlaps with default gateway", + prefix: netip.MustParsePrefix(defaultGateway.String() + "/31"), + shouldAddRoute: false, + }, + { + name: "Should Add Route if bigger network exists", + prefix: netip.MustParsePrefix("100.100.100.0/24"), + preExistingPrefix: netip.MustParsePrefix("100.100.0.0/16"), + shouldAddRoute: true, + }, + { + name: "Should Add Route if smaller network exists", + prefix: netip.MustParsePrefix("100.100.0.0/16"), + preExistingPrefix: netip.MustParsePrefix("100.100.100.0/24"), + shouldAddRoute: true, + }, + { + name: "Should Not Add Route if same network exists", + prefix: netip.MustParsePrefix("100.100.0.0/16"), + preExistingPrefix: netip.MustParsePrefix("100.100.0.0/16"), + shouldAddRoute: false, + }, + } + + // MOCK_ADDR := "127.0.0.1" + + for n, testCase := range testCases { + var buf bytes.Buffer + log.SetOutput(&buf) + defer func() { + log.SetOutput(os.Stderr) + }() + t.Run(testCase.name, func(t *testing.T) { + newNet, err := stdnet.NewNet() + if err != nil { + t.Fatal(err) + } + wgInterface, err := iface.NewWGIFace(fmt.Sprintf("utun53%d", n), "100.65.75.2/24", iface.DefaultMTU, nil, newNet) + require.NoError(t, err, "should create testing WGIface interface") + defer wgInterface.Close() + + err = wgInterface.Create() + require.NoError(t, err, "should create testing wireguard interface") + + MOCK_ADDR := wgInterface.Address().IP.String() + + // Prepare the environment + if testCase.preExistingPrefix.IsValid() { + err := addToRouteTableIfNoExists(testCase.preExistingPrefix, MOCK_ADDR) + require.NoError(t, err, "should not return err when adding pre-existing route") + } + + // Add the route + err = addToRouteTableIfNoExists(testCase.prefix, MOCK_ADDR) + require.NoError(t, err, "should not return err when adding route") + + if testCase.shouldAddRoute { + // test if route exists after adding + ok, err := existsInRouteTable(testCase.prefix) + require.NoError(t, err, "should not return err") + require.True(t, ok, "route should exist") + + // remove route again if added + err = removeFromRouteTableIfNonSystem(testCase.prefix, MOCK_ADDR) + require.NoError(t, err, "should not return err") + } + + // route should either not have been added or should have been removed + // In case of already existing route, it should not have been added (but still exist) + ok, err := existsInRouteTable(testCase.prefix) + fmt.Println("Buffer string: ", buf.String()) + require.NoError(t, err, "should not return err") + if !strings.Contains(buf.String(), "because it already exists") { + require.False(t, ok, "route should not exist") + } + }) + } +} diff --git a/client/internal/routemanager/systemops_windows.go b/client/internal/routemanager/systemops_windows.go index 4bc436b2d..d2c907b0a 100644 --- a/client/internal/routemanager/systemops_windows.go +++ b/client/internal/routemanager/systemops_windows.go @@ -4,20 +4,11 @@ package routemanager import ( - "bytes" "fmt" "net" "net/netip" - "os" - "strings" - "testing" - "github.com/pion/transport/v2/stdnet" - log "github.com/sirupsen/logrus" - "github.com/stretchr/testify/require" "github.com/yusufpapurcu/wmi" - - "github.com/netbirdio/netbird/iface" ) type Win32_IP4RouteTable struct { @@ -47,100 +38,3 @@ func existsInRouteTable(prefix netip.Prefix) (bool, error) { } return false, nil } - -func TestAddExistAndRemoveRoute(t *testing.T) { - defaultGateway, err := getExistingRIBRouteGateway(netip.MustParsePrefix("0.0.0.0/0")) - fmt.Println("defaultGateway: ", defaultGateway) - if err != nil { - t.Fatal("shouldn't return error when fetching the gateway: ", err) - } - testCases := []struct { - name string - prefix netip.Prefix - preExistingPrefix netip.Prefix - shouldAddRoute bool - }{ - { - name: "Should Add And Remove random Route", - prefix: netip.MustParsePrefix("99.99.99.99/32"), - shouldAddRoute: true, - }, - { - name: "Should Not Add Route if overlaps with default gateway", - prefix: netip.MustParsePrefix(defaultGateway.String() + "/31"), - shouldAddRoute: false, - }, - { - name: "Should Add Route if bigger network exists", - prefix: netip.MustParsePrefix("100.100.100.0/24"), - preExistingPrefix: netip.MustParsePrefix("100.100.0.0/16"), - shouldAddRoute: true, - }, - { - name: "Should Add Route if smaller network exists", - prefix: netip.MustParsePrefix("100.100.0.0/16"), - preExistingPrefix: netip.MustParsePrefix("100.100.100.0/24"), - shouldAddRoute: true, - }, - { - name: "Should Not Add Route if same network exists", - prefix: netip.MustParsePrefix("100.100.0.0/16"), - preExistingPrefix: netip.MustParsePrefix("100.100.0.0/16"), - shouldAddRoute: false, - }, - } - - // MOCK_ADDR := "127.0.0.1" - - for n, testCase := range testCases { - var buf bytes.Buffer - log.SetOutput(&buf) - defer func() { - log.SetOutput(os.Stderr) - }() - t.Run(testCase.name, func(t *testing.T) { - newNet, err := stdnet.NewNet() - if err != nil { - t.Fatal(err) - } - wgInterface, err := iface.NewWGIFace(fmt.Sprintf("utun53%d", n), "100.65.75.2/24", iface.DefaultMTU, nil, newNet) - require.NoError(t, err, "should create testing WGIface interface") - defer wgInterface.Close() - - err = wgInterface.Create() - require.NoError(t, err, "should create testing wireguard interface") - - MOCK_ADDR := wgInterface.Address().IP.String() - - // Prepare the environment - if testCase.preExistingPrefix.IsValid() { - err := addToRouteTableIfNoExists(testCase.preExistingPrefix, MOCK_ADDR) - require.NoError(t, err, "should not return err when adding pre-existing route") - } - - // Add the route - err = addToRouteTableIfNoExists(testCase.prefix, MOCK_ADDR) - require.NoError(t, err, "should not return err when adding pre-existing route") - - if testCase.shouldAddRoute { - // test if route exists after adding - ok, err := existsInRouteTable(testCase.prefix) - require.NoError(t, err, "should not return err") - require.True(t, ok, "route should exist") - - // remove route again if added - err = removeFromRouteTableIfNonSystem(testCase.prefix, MOCK_ADDR) - require.NoError(t, err, "should not return err") - } - - // route should either not have been added or should have been removed - // In case of already existing route, it should not have been added (but still exist) - ok, err := existsInRouteTable(testCase.prefix) - fmt.Println("Buffer string: ", buf.String()) - require.NoError(t, err, "should not return err") - if !strings.Contains(buf.String(), "because it already exists") { - require.False(t, ok, "route should not exist") - } - }) - } -} From f45eb1a1da4c9fab690cd62ac45ac046adb56d95 Mon Sep 17 00:00:00 2001 From: Pascal Fischer Date: Mon, 12 Jun 2023 16:12:24 +0200 Subject: [PATCH 22/23] test windows --- .../internal/routemanager/systemops_test.go | 113 ------------------ 1 file changed, 113 deletions(-) delete mode 100644 client/internal/routemanager/systemops_test.go diff --git a/client/internal/routemanager/systemops_test.go b/client/internal/routemanager/systemops_test.go deleted file mode 100644 index 41536f30c..000000000 --- a/client/internal/routemanager/systemops_test.go +++ /dev/null @@ -1,113 +0,0 @@ -package routemanager - -import ( - "bytes" - "fmt" - "net/netip" - "os" - "strings" - "testing" - - "github.com/pion/transport/v2/stdnet" - log "github.com/sirupsen/logrus" - "github.com/stretchr/testify/require" - - "github.com/netbirdio/netbird/iface" -) - -func TestAddExistAndRemoveRoute(t *testing.T) { - defaultGateway, err := getExistingRIBRouteGateway(netip.MustParsePrefix("0.0.0.0/0")) - fmt.Println("defaultGateway: ", defaultGateway) - if err != nil { - t.Fatal("shouldn't return error when fetching the gateway: ", err) - } - testCases := []struct { - name string - prefix netip.Prefix - preExistingPrefix netip.Prefix - shouldAddRoute bool - }{ - { - name: "Should Add And Remove random Route", - prefix: netip.MustParsePrefix("99.99.99.99/32"), - shouldAddRoute: true, - }, - { - name: "Should Not Add Route if overlaps with default gateway", - prefix: netip.MustParsePrefix(defaultGateway.String() + "/31"), - shouldAddRoute: false, - }, - { - name: "Should Add Route if bigger network exists", - prefix: netip.MustParsePrefix("100.100.100.0/24"), - preExistingPrefix: netip.MustParsePrefix("100.100.0.0/16"), - shouldAddRoute: true, - }, - { - name: "Should Add Route if smaller network exists", - prefix: netip.MustParsePrefix("100.100.0.0/16"), - preExistingPrefix: netip.MustParsePrefix("100.100.100.0/24"), - shouldAddRoute: true, - }, - { - name: "Should Not Add Route if same network exists", - prefix: netip.MustParsePrefix("100.100.0.0/16"), - preExistingPrefix: netip.MustParsePrefix("100.100.0.0/16"), - shouldAddRoute: false, - }, - } - - // MOCK_ADDR := "127.0.0.1" - - for n, testCase := range testCases { - var buf bytes.Buffer - log.SetOutput(&buf) - defer func() { - log.SetOutput(os.Stderr) - }() - t.Run(testCase.name, func(t *testing.T) { - newNet, err := stdnet.NewNet() - if err != nil { - t.Fatal(err) - } - wgInterface, err := iface.NewWGIFace(fmt.Sprintf("utun53%d", n), "100.65.75.2/24", iface.DefaultMTU, nil, newNet) - require.NoError(t, err, "should create testing WGIface interface") - defer wgInterface.Close() - - err = wgInterface.Create() - require.NoError(t, err, "should create testing wireguard interface") - - MOCK_ADDR := wgInterface.Address().IP.String() - - // Prepare the environment - if testCase.preExistingPrefix.IsValid() { - err := addToRouteTableIfNoExists(testCase.preExistingPrefix, MOCK_ADDR) - require.NoError(t, err, "should not return err when adding pre-existing route") - } - - // Add the route - err = addToRouteTableIfNoExists(testCase.prefix, MOCK_ADDR) - require.NoError(t, err, "should not return err when adding route") - - if testCase.shouldAddRoute { - // test if route exists after adding - ok, err := existsInRouteTable(testCase.prefix) - require.NoError(t, err, "should not return err") - require.True(t, ok, "route should exist") - - // remove route again if added - err = removeFromRouteTableIfNonSystem(testCase.prefix, MOCK_ADDR) - require.NoError(t, err, "should not return err") - } - - // route should either not have been added or should have been removed - // In case of already existing route, it should not have been added (but still exist) - ok, err := existsInRouteTable(testCase.prefix) - fmt.Println("Buffer string: ", buf.String()) - require.NoError(t, err, "should not return err") - if !strings.Contains(buf.String(), "because it already exists") { - require.False(t, ok, "route should not exist") - } - }) - } -} From b5d8142705e3240255120aa250c8830a5d13a4ca Mon Sep 17 00:00:00 2001 From: Pascal Fischer Date: Mon, 12 Jun 2023 16:22:53 +0200 Subject: [PATCH 23/23] test windows --- .../internal/routemanager/systemops_nonandroid_test.go | 10 ++++------ client/internal/routemanager/systemops_windows.go | 7 ++----- 2 files changed, 6 insertions(+), 11 deletions(-) diff --git a/client/internal/routemanager/systemops_nonandroid_test.go b/client/internal/routemanager/systemops_nonandroid_test.go index 48fc02562..68c0e1d26 100644 --- a/client/internal/routemanager/systemops_nonandroid_test.go +++ b/client/internal/routemanager/systemops_nonandroid_test.go @@ -163,8 +163,6 @@ func TestAddExistAndRemoveRouteNonAndroid(t *testing.T) { }, } - // MOCK_ADDR := "127.0.0.1" - for n, testCase := range testCases { var buf bytes.Buffer log.SetOutput(&buf) @@ -183,16 +181,16 @@ func TestAddExistAndRemoveRouteNonAndroid(t *testing.T) { err = wgInterface.Create() require.NoError(t, err, "should create testing wireguard interface") - MOCK_ADDR := wgInterface.Address().IP.String() + MockAddr := wgInterface.Address().IP.String() // Prepare the environment if testCase.preExistingPrefix.IsValid() { - err := addToRouteTableIfNoExists(testCase.preExistingPrefix, MOCK_ADDR) + err := addToRouteTableIfNoExists(testCase.preExistingPrefix, MockAddr) require.NoError(t, err, "should not return err when adding pre-existing route") } // Add the route - err = addToRouteTableIfNoExists(testCase.prefix, MOCK_ADDR) + err = addToRouteTableIfNoExists(testCase.prefix, MockAddr) require.NoError(t, err, "should not return err when adding route") if testCase.shouldAddRoute { @@ -202,7 +200,7 @@ func TestAddExistAndRemoveRouteNonAndroid(t *testing.T) { require.True(t, ok, "route should exist") // remove route again if added - err = removeFromRouteTableIfNonSystem(testCase.prefix, MOCK_ADDR) + err = removeFromRouteTableIfNonSystem(testCase.prefix, MockAddr) require.NoError(t, err, "should not return err") } diff --git a/client/internal/routemanager/systemops_windows.go b/client/internal/routemanager/systemops_windows.go index d2c907b0a..2233748bf 100644 --- a/client/internal/routemanager/systemops_windows.go +++ b/client/internal/routemanager/systemops_windows.go @@ -4,7 +4,6 @@ package routemanager import ( - "fmt" "net" "net/netip" @@ -14,12 +13,11 @@ import ( type Win32_IP4RouteTable struct { Destination string Mask string - NextHop string } func existsInRouteTable(prefix netip.Prefix) (bool, error) { var routes []Win32_IP4RouteTable - query := "SELECT Destination, Mask, NextHop FROM Win32_IP4RouteTable" + query := "SELECT Destination, Mask FROM Win32_IP4RouteTable" err := wmi.Query(query, &routes) if err != nil { @@ -27,12 +25,11 @@ func existsInRouteTable(prefix netip.Prefix) (bool, error) { } for _, route := range routes { - fmt.Println(routes) ip := net.ParseIP(route.Mask) ip = ip.To4() mask := net.IPv4Mask(ip[0], ip[1], ip[2], ip[3]) cidr, _ := mask.Size() - if route.Destination == prefix.Addr().String() && cidr == prefix.Bits() && false { + if route.Destination == prefix.Addr().String() && cidr == prefix.Bits() { return true, nil } }