[client] Check for fwmark support and use fallback routing if not supported (#3220)

This commit is contained in:
Viktor Liu
2025-02-11 13:09:17 +01:00
committed by GitHub
parent 44407a158a
commit 18f84f0df5
10 changed files with 163 additions and 56 deletions

View File

@@ -362,7 +362,7 @@ func toWgUserspaceString(wgCfg wgtypes.Config) string {
}
func getFwmark() int {
if runtime.GOOS == "linux" && !nbnet.CustomRoutingDisabled() {
if nbnet.AdvancedRouting() {
return nbnet.NetbirdFwmark
}
return 0

View File

@@ -31,6 +31,7 @@ import (
relayClient "github.com/netbirdio/netbird/relay/client"
signal "github.com/netbirdio/netbird/signal/client"
"github.com/netbirdio/netbird/util"
nbnet "github.com/netbirdio/netbird/util/net"
"github.com/netbirdio/netbird/version"
)
@@ -109,6 +110,8 @@ func (c *ConnectClient) run(mobileDependency MobileDependency, runningChan chan
log.Infof("starting NetBird client version %s on %s/%s", version.NetbirdVersion(), runtime.GOOS, runtime.GOARCH)
nbnet.Init()
backOff := &backoff.ExponentialBackOff{
InitialInterval: time.Second,
RandomizationFactor: 1,

View File

@@ -113,13 +113,14 @@ func NewManager(config ManagerConfig) *DefaultManager {
disableServerRoutes: config.DisableServerRoutes,
}
useNoop := netstack.IsEnabled() || config.DisableClientRoutes
dm.setupRefCounters(useNoop)
// don't proceed with client routes if it is disabled
if config.DisableClientRoutes {
return dm
}
dm.setupRefCounters()
if runtime.GOOS == "android" {
cr := dm.initialClientRoutes(config.InitialRoutes)
dm.notifier.SetInitialClientRoutes(cr)
@@ -127,7 +128,7 @@ func NewManager(config ManagerConfig) *DefaultManager {
return dm
}
func (m *DefaultManager) setupRefCounters() {
func (m *DefaultManager) setupRefCounters(useNoop bool) {
m.routeRefCounter = refcounter.New(
func(prefix netip.Prefix, _ struct{}) (struct{}, error) {
return struct{}{}, m.sysOps.AddVPNRoute(prefix, m.wgInterface.ToInterface())
@@ -137,7 +138,7 @@ func (m *DefaultManager) setupRefCounters() {
},
)
if netstack.IsEnabled() {
if useNoop {
m.routeRefCounter = refcounter.New(
func(netip.Prefix, struct{}) (struct{}, error) {
return struct{}{}, refcounter.ErrIgnore
@@ -449,7 +450,7 @@ func (m *DefaultManager) initialClientRoutes(initialRoutes []*route.Route) []*ro
}
func isRouteSupported(route *route.Route) bool {
if !nbnet.CustomRoutingDisabled() || route.IsDynamic() {
if netstack.IsEnabled() || !nbnet.CustomRoutingDisabled() || route.IsDynamic() {
return true
}

View File

@@ -53,20 +53,6 @@ type ruleParams struct {
description string
}
// isLegacy determines whether to use the legacy routing setup
func isLegacy() bool {
return os.Getenv("NB_USE_LEGACY_ROUTING") == "true" || nbnet.CustomRoutingDisabled() || nbnet.SkipSocketMark()
}
// setIsLegacy sets the legacy routing setup
func setIsLegacy(b bool) {
if b {
os.Setenv("NB_USE_LEGACY_ROUTING", "true")
} else {
os.Unsetenv("NB_USE_LEGACY_ROUTING")
}
}
func getSetupRules() []ruleParams {
return []ruleParams{
{100, -1, syscall.RT_TABLE_MAIN, netlink.FAMILY_V4, false, 0, "rule with suppress prefixlen v4"},
@@ -87,7 +73,7 @@ func getSetupRules() []ruleParams {
// This table is where a default route or other specific routes received from the management server are configured,
// enabling VPN connectivity.
func (r *SysOps) SetupRouting(initAddresses []net.IP, stateManager *statemanager.Manager) (_ nbnet.AddHookFunc, _ nbnet.RemoveHookFunc, err error) {
if isLegacy() {
if !nbnet.AdvancedRouting() {
log.Infof("Using legacy routing setup")
return r.setupRefCounter(initAddresses, stateManager)
}
@@ -103,11 +89,6 @@ func (r *SysOps) SetupRouting(initAddresses []net.IP, stateManager *statemanager
rules := getSetupRules()
for _, rule := range rules {
if err := addRule(rule); err != nil {
if errors.Is(err, syscall.EOPNOTSUPP) {
log.Warnf("Rule operations are not supported, falling back to the legacy routing setup")
setIsLegacy(true)
return r.setupRefCounter(initAddresses, stateManager)
}
return nil, nil, fmt.Errorf("%s: %w", rule.description, err)
}
}
@@ -130,7 +111,7 @@ func (r *SysOps) SetupRouting(initAddresses []net.IP, stateManager *statemanager
// It systematically removes the three rules and any associated routing table entries to ensure a clean state.
// The function uses error aggregation to report any errors encountered during the cleanup process.
func (r *SysOps) CleanupRouting(stateManager *statemanager.Manager) error {
if isLegacy() {
if !nbnet.AdvancedRouting() {
return r.cleanupRefCounter(stateManager)
}
@@ -168,7 +149,7 @@ func (r *SysOps) removeFromRouteTable(prefix netip.Prefix, nexthop Nexthop) erro
}
func (r *SysOps) AddVPNRoute(prefix netip.Prefix, intf *net.Interface) error {
if isLegacy() {
if !nbnet.AdvancedRouting() {
return r.genericAddVPNRoute(prefix, intf)
}
@@ -191,7 +172,7 @@ func (r *SysOps) AddVPNRoute(prefix netip.Prefix, intf *net.Interface) error {
}
func (r *SysOps) RemoveVPNRoute(prefix netip.Prefix, intf *net.Interface) error {
if isLegacy() {
if !nbnet.AdvancedRouting() {
return r.genericRemoveVPNRoute(prefix, intf)
}
@@ -504,7 +485,7 @@ func getAddressFamily(prefix netip.Prefix) int {
}
func hasSeparateRouting() ([]netip.Prefix, error) {
if isLegacy() {
if !nbnet.AdvancedRouting() {
return GetRoutesFromTable()
}
return nil, ErrRoutingIsSeparate

View File

@@ -85,6 +85,7 @@ var testCases = []testCase{
}
func TestRouting(t *testing.T) {
nbnet.Init()
for _, tc := range testCases {
// todo resolve test execution on freebsd
if runtime.GOOS == "freebsd" {