redid versioning

Signed-off-by: Dmitri Dolguikh <dmitri.external@netbird.io>
This commit is contained in:
Dmitri Dolguikh
2026-07-16 17:45:57 +02:00
parent cfb534af8f
commit 20243fcfee
23 changed files with 1570 additions and 1657 deletions

View File

@@ -351,7 +351,7 @@ func (a *Auth) setSystemInfoFlags(info *system.Info) {
a.config.BlockLANAccess,
a.config.BlockInbound,
a.config.DisableIPv6,
a.config.DisableComponentNetworkMap,
a.config.SyncMessageVersion,
a.config.EnableSSHRoot,
a.config.EnableSSHSFTP,
a.config.EnableSSHLocalPortForwarding,

View File

@@ -611,14 +611,14 @@ func createEngineConfig(key wgtypes.Key, config *profilemanager.Config, peerConf
DisableSSHAuth: config.DisableSSHAuth,
DNSRouteInterval: config.DNSRouteInterval,
DisableClientRoutes: config.DisableClientRoutes,
DisableServerRoutes: config.DisableServerRoutes || config.BlockInbound,
DisableDNS: config.DisableDNS,
DisableFirewall: config.DisableFirewall,
BlockLANAccess: config.BlockLANAccess,
BlockInbound: config.BlockInbound,
DisableIPv6: config.DisableIPv6,
DisableComponentNetworkMap: config.DisableComponentNetworkMap,
DisableClientRoutes: config.DisableClientRoutes,
DisableServerRoutes: config.DisableServerRoutes || config.BlockInbound,
DisableDNS: config.DisableDNS,
DisableFirewall: config.DisableFirewall,
BlockLANAccess: config.BlockLANAccess,
BlockInbound: config.BlockInbound,
DisableIPv6: config.DisableIPv6,
SyncMessageVersion: config.SyncMessageVersion,
LazyConnection: lazyconn.ParseState(config.LazyConnection),
@@ -694,7 +694,7 @@ func loginToManagement(ctx context.Context, client mgm.Client, pubSSHKey []byte,
config.BlockLANAccess,
config.BlockInbound,
config.DisableIPv6,
config.DisableComponentNetworkMap,
config.SyncMessageVersion,
config.EnableSSHRoot,
config.EnableSSHSFTP,
config.EnableSSHLocalPortForwarding,

View File

@@ -676,7 +676,7 @@ func (g *BundleGenerator) addCommonConfigFields(configContent *strings.Builder)
configContent.WriteString(fmt.Sprintf("BlockLANAccess: %v\n", g.internalConfig.BlockLANAccess))
configContent.WriteString(fmt.Sprintf("BlockInbound: %v\n", g.internalConfig.BlockInbound))
configContent.WriteString(fmt.Sprintf("DisableIPv6: %v\n", g.internalConfig.DisableIPv6))
configContent.WriteString(fmt.Sprintf("DisableComponentNetworkMap: %v\n", g.internalConfig.DisableComponentNetworkMap))
configContent.WriteString(fmt.Sprintf("SyncMessageVersion: %v\n", g.internalConfig.SyncMessageVersion))
if g.internalConfig.DisableNotifications != nil {
configContent.WriteString(fmt.Sprintf("DisableNotifications: %v\n", *g.internalConfig.DisableNotifications))

View File

@@ -888,7 +888,7 @@ func TestAddConfig_AllFieldsCovered(t *testing.T) {
LazyConnection: "on",
MTU: 1280,
DisableIPv6: true,
DisableComponentNetworkMap: true,
SyncMessageVersion: func(v int) *int { return &v }(1),
}
for _, anonymize := range []bool{false, true} {

View File

@@ -64,6 +64,7 @@ import (
"github.com/netbirdio/netbird/route"
mgm "github.com/netbirdio/netbird/shared/management/client"
"github.com/netbirdio/netbird/shared/management/domain"
sharedgrpc "github.com/netbirdio/netbird/shared/management/grpc"
nbnetworkmap "github.com/netbirdio/netbird/shared/management/networkmap"
mgmProto "github.com/netbirdio/netbird/shared/management/proto"
types "github.com/netbirdio/netbird/shared/management/types"
@@ -142,14 +143,14 @@ type EngineConfig struct {
DNSRouteInterval time.Duration
DisableClientRoutes bool
DisableServerRoutes bool
DisableDNS bool
DisableFirewall bool
BlockLANAccess bool
BlockInbound bool
DisableIPv6 bool
DisableComponentNetworkMap bool
DisableClientRoutes bool
DisableServerRoutes bool
DisableDNS bool
DisableFirewall bool
BlockLANAccess bool
BlockInbound bool
DisableIPv6 bool
SyncMessageVersion *int
// LazyConnection is the MDM-sourced lazy-connection override; StateUnset defers to
// the env var and management feature flag.
@@ -995,7 +996,7 @@ func (e *Engine) handleSync(update *mgmProto.SyncResponse) error {
nm *mgmProto.NetworkMap
components *types.NetworkMapComponents
)
if version := update.GetVersion(); version == mgmProto.SyncResponseVersion_VersionComponentNetworkMap {
if version := update.GetVersion(); version == int32(sharedgrpc.ComponentNetworkMap) {
// Components-format peer: decode the envelope back to typed
// components, run Calculate() locally, and convert to the wire
// NetworkMap shape the rest of the engine consumes. Components are
@@ -1234,7 +1235,7 @@ func (e *Engine) applyInfoFlags(info *system.Info) {
e.config.BlockLANAccess,
e.config.BlockInbound,
e.config.DisableIPv6,
e.config.DisableComponentNetworkMap,
e.config.SyncMessageVersion,
e.config.EnableSSHRoot,
e.config.EnableSSHSFTP,
e.config.EnableSSHLocalPortForwarding,
@@ -2103,7 +2104,7 @@ func (e *Engine) readInitialSettings() ([]*route.Route, *nbdns.Config, bool, err
e.config.BlockLANAccess,
e.config.BlockInbound,
e.config.DisableIPv6,
e.config.DisableComponentNetworkMap,
e.config.SyncMessageVersion,
e.config.EnableSSHRoot,
e.config.EnableSSHSFTP,
e.config.EnableSSHLocalPortForwarding,

View File

@@ -89,14 +89,14 @@ type ConfigInput struct {
ClientCertPath string
ClientCertKeyPath string
DisableClientRoutes *bool
DisableServerRoutes *bool
DisableDNS *bool
DisableFirewall *bool
BlockLANAccess *bool
BlockInbound *bool
DisableIPv6 *bool
DisableComponentNetworkMap *bool
DisableClientRoutes *bool
DisableServerRoutes *bool
DisableDNS *bool
DisableFirewall *bool
BlockLANAccess *bool
BlockInbound *bool
DisableIPv6 *bool
SyncMessageVersion *int
DisableNotifications *bool
@@ -131,14 +131,14 @@ type Config struct {
DisableSSHAuth *bool
SSHJWTCacheTTL *int
DisableClientRoutes bool
DisableServerRoutes bool
DisableDNS bool
DisableFirewall bool
BlockLANAccess bool
BlockInbound bool
DisableIPv6 bool
DisableComponentNetworkMap bool
DisableClientRoutes bool
DisableServerRoutes bool
DisableDNS bool
DisableFirewall bool
BlockLANAccess bool
BlockInbound bool
DisableIPv6 bool
SyncMessageVersion *int
DisableNotifications *bool
@@ -589,9 +589,9 @@ func (config *Config) apply(input ConfigInput) (updated bool, err error) {
updated = true
}
if input.DisableComponentNetworkMap != nil && *input.DisableComponentNetworkMap != config.DisableComponentNetworkMap {
log.Infof("setting ComponentNetworkMap disabled=%v", *input.DisableComponentNetworkMap)
config.DisableComponentNetworkMap = *input.DisableComponentNetworkMap
if input.SyncMessageVersion != nil && *input.SyncMessageVersion != *config.SyncMessageVersion {
log.Infof("setting SyncMessageVersion to %v", *input.SyncMessageVersion)
*config.SyncMessageVersion = *input.SyncMessageVersion
updated = true
}

View File

@@ -66,27 +66,28 @@ type Info struct {
RosenpassPermissive bool
ServerSSHAllowed bool
DisableClientRoutes bool
DisableServerRoutes bool
DisableDNS bool
DisableFirewall bool
BlockLANAccess bool
BlockInbound bool
DisableIPv6 bool
DisableComponentNetworkMap bool
DisableClientRoutes bool
DisableServerRoutes bool
DisableDNS bool
DisableFirewall bool
BlockLANAccess bool
BlockInbound bool
DisableIPv6 bool
EnableSSHRoot bool
EnableSSHSFTP bool
EnableSSHLocalPortForwarding bool
EnableSSHRemotePortForwarding bool
DisableSSHAuth bool
SyncMessageVersion *int
}
func (i *Info) SetFlags(
rosenpassEnabled, rosenpassPermissive bool,
serverSSHAllowed *bool,
disableClientRoutes, disableServerRoutes,
disableDNS, disableFirewall, blockLANAccess, blockInbound, disableIPv6, disableComponentNetworkMap bool,
disableDNS, disableFirewall, blockLANAccess, blockInbound, disableIPv6 bool, syncMessageVersion *int,
enableSSHRoot, enableSSHSFTP, enableSSHLocalPortForwarding, enableSSHRemotePortForwarding *bool,
disableSSHAuth *bool,
) {
@@ -103,7 +104,8 @@ func (i *Info) SetFlags(
i.BlockLANAccess = blockLANAccess
i.BlockInbound = blockInbound
i.DisableIPv6 = disableIPv6
i.DisableComponentNetworkMap = disableComponentNetworkMap
i.SyncMessageVersion = syncMessageVersion
if enableSSHRoot != nil {
i.EnableSSHRoot = *enableSSHRoot

View File

@@ -75,8 +75,8 @@ type ServerConfig struct {
AuthStore StoreConfig `yaml:"authStore"`
ReverseProxy ReverseProxyConfig `yaml:"reverseProxy"`
SupportedSyncMessageVersions []string `yaml:"supportedSyncMessageVersions"`
PerAccountSupportedSyncMessageVersions map[string][]string `yaml:"perAccountSupportedSyncMessageVersions"`
SupportedSyncMessageVersions *int `yaml:"supportedSyncMessageVersions,omitempty"`
PerAccountSupportedSyncMessageVersions map[string]int `yaml:"perAccountSupportedSyncMessageVersions,omitempty"`
}
// TLSConfig contains TLS/HTTPS settings
@@ -697,18 +697,18 @@ func (c *CombinedConfig) ToManagementConfig() (*nbconfig.Config, error) {
httpConfig.AuthCallbackURL = callbackURL + types.ProxyCallbackEndpointFull
return &nbconfig.Config{
Stuns: stuns,
Relay: relayConfig,
Signal: signalConfig,
Datadir: mgmt.DataDir,
DataStoreEncryptionKey: mgmt.Store.EncryptionKey,
HttpConfig: httpConfig,
StoreConfig: storeConfig,
ReverseProxy: reverseProxy,
DisableDefaultPolicy: mgmt.DisableDefaultPolicy,
EmbeddedIdP: embeddedIdP,
SupportedSyncMessageVersions: c.Server.SupportedSyncMessageVersions,
PerAccountSupportedSyncMessageVersions: c.Server.PerAccountSupportedSyncMessageVersions,
Stuns: stuns,
Relay: relayConfig,
Signal: signalConfig,
Datadir: mgmt.DataDir,
DataStoreEncryptionKey: mgmt.Store.EncryptionKey,
HttpConfig: httpConfig,
StoreConfig: storeConfig,
ReverseProxy: reverseProxy,
DisableDefaultPolicy: mgmt.DisableDefaultPolicy,
EmbeddedIdP: embeddedIdP,
HighestSupportedSyncMessageVersion: c.Server.SupportedSyncMessageVersions,
PerAccountHighestSupportedSyncMessageVersion: c.Server.PerAccountSupportedSyncMessageVersions,
}, nil
}

View File

@@ -506,12 +506,12 @@ func createManagementServer(cfg *CombinedConfig, mgmtConfig *nbconfig.Config) (m
}
mgmtPort, _ := strconv.Atoi(portStr)
if err := syncgrpc.ValidateSyncMessageVersions(mgmtConfig.SupportedSyncMessageVersions); err != nil {
if err := syncgrpc.ValidateSyncMessageVersion(mgmtConfig.HighestSupportedSyncMessageVersion); err != nil {
return nil, err
}
for accountId, versions := range mgmtConfig.PerAccountSupportedSyncMessageVersions {
if err := syncgrpc.ValidateSyncMessageVersions(versions); err != nil {
for accountId, version := range mgmtConfig.PerAccountHighestSupportedSyncMessageVersion {
if err := syncgrpc.ValidateSyncMessageVersion(&version); err != nil {
return nil, fmt.Errorf("unrecognized sync message version in perAccountSupportedSyncMessageVersions for account %s %w", accountId, err)
}
}

View File

@@ -24,8 +24,8 @@ import (
"github.com/netbirdio/netbird/formatter/hook"
"github.com/netbirdio/netbird/management/internals/server"
nbconfig "github.com/netbirdio/netbird/management/internals/server/config"
"github.com/netbirdio/netbird/management/internals/shared/grpc"
nbdomain "github.com/netbirdio/netbird/shared/management/domain"
"github.com/netbirdio/netbird/shared/management/grpc"
"github.com/netbirdio/netbird/util"
"github.com/netbirdio/netbird/util/crypt"
)
@@ -154,13 +154,13 @@ func LoadMgmtConfig(ctx context.Context, mgmtConfigPath string) (*nbconfig.Confi
ApplyCommandLineOverrides(loadedConfig)
err := grpc.ValidateSyncMessageVersions(loadedConfig.SupportedSyncMessageVersions)
err := grpc.ValidateSyncMessageVersion(loadedConfig.HighestSupportedSyncMessageVersion)
if err != nil {
return nil, err
}
for account, versions := range loadedConfig.PerAccountSupportedSyncMessageVersions {
err := grpc.ValidateSyncMessageVersions(versions)
for account, version := range loadedConfig.PerAccountHighestSupportedSyncMessageVersion {
err := grpc.ValidateSyncMessageVersion(&version)
if err != nil {
return nil, fmt.Errorf("unrecognized sync message version for account %s, %w", account, err)
}

View File

@@ -5,6 +5,7 @@ import (
"os"
"testing"
"github.com/netbirdio/netbird/shared/management/grpc"
"github.com/stretchr/testify/assert"
)
@@ -23,34 +24,48 @@ const (
"AuthIssuer": "https://something.eu.auth0.com/",
"OIDCConfigEndpoint": "https://something.eu.auth0.com/.well-known/openid-configuration"
},
"SupportedSyncMessageVersions": ["Base", "ComponentNetworkMap"],
"PerAccountSupportedSyncMessageVersions": {
"1": ["Base"],
"2": ["ComponentNetworkMap"],
"3": []
"HighestSupportedSyncMessageVersion": 1,
"PerAccountHighestSupportedSyncMessageVersion": {
"1": 0,
"2": 1
}
}`
)
func Test_loadMgmtConfig(t *testing.T) {
tmpFile, err := createConfig()
func Test_LoadMgmtConfig(t *testing.T) {
tmpFile, err := createConfig(exampleConfig)
assert.NoError(t, err)
cfg, err := LoadMgmtConfig(context.Background(), tmpFile)
assert.NoError(t, err)
assert.NotEmpty(t, cfg.Relay)
assert.NotEmpty(t, cfg.Relay.Addresses)
assert.Equal(t, []string{"Base", "ComponentNetworkMap"}, cfg.SupportedSyncMessageVersions)
assert.Equal(t, map[string][]string{
"1": {"Base"}, "2": {"ComponentNetworkMap"}, "3": {}}, cfg.PerAccountSupportedSyncMessageVersions)
assert.Equal(t, int(grpc.ComponentNetworkMap), *cfg.HighestSupportedSyncMessageVersion)
assert.Equal(t, map[string]int{"1": int(grpc.Base), "2": int(grpc.ComponentNetworkMap)}, cfg.PerAccountHighestSupportedSyncMessageVersion)
}
func createConfig() (string, error) {
func Test_LoadMgmtConfig_Empty(t *testing.T) {
tmpFile, err := createConfig(`{
"HttpConfig": {
"AuthAudience": "https://stageapp/",
"AuthIssuer": "https://something.eu.auth0.com/",
"OIDCConfigEndpoint": "https://something.eu.auth0.com/.well-known/openid-configuration"
}
}`)
assert.NoError(t, err)
cfg, err := LoadMgmtConfig(context.Background(), tmpFile)
assert.NoError(t, err)
assert.Nil(t, cfg.HighestSupportedSyncMessageVersion)
assert.Nil(t, cfg.PerAccountHighestSupportedSyncMessageVersion)
}
func createConfig(config string) (string, error) {
tmpfile, err := os.CreateTemp("", "config.json")
if err != nil {
return "", err
}
_, err = tmpfile.Write([]byte(exampleConfig))
_, err = tmpfile.Write([]byte(config))
if err != nil {
return "", err
}

View File

@@ -21,6 +21,7 @@ import (
"github.com/netbirdio/netbird/management/internals/server/config"
"github.com/netbirdio/netbird/management/internals/shared/grpc"
"github.com/netbirdio/netbird/management/server/account"
sharedgrpc "github.com/netbirdio/netbird/management/server/account"
"github.com/netbirdio/netbird/management/server/integrations/integrated_validator"
"github.com/netbirdio/netbird/management/server/integrations/port_forwarding"
nbpeer "github.com/netbirdio/netbird/management/server/peer"
@@ -57,9 +58,9 @@ type Controller struct {
integratedPeerValidator integrated_validator.IntegratedValidator
serverSupportedSyncMessageVersions []grpc.SyncMessageVersion
serverSupportedSyncMessageVersion sharedgrpc.SyncMessageVersion
perAccountServerSupportedSyncMessageVersions map[string][]grpc.SyncMessageVersion
perAccountServerSupportedSyncMessageVersions map[string]sharedgrpc.SyncMessageVersion
}
type bufferUpdate struct {
@@ -96,8 +97,8 @@ func NewController(ctx context.Context, store store.Store, metrics telemetry.App
proxyController: proxyController,
EphemeralPeersManager: ephemeralPeersManager,
serverSupportedSyncMessageVersions: grpc.SyncMessageVersionsFromString(config.SupportedSyncMessageVersions),
perAccountServerSupportedSyncMessageVersions: grpc.SyncMessageVersionsFromMap(config.PerAccountSupportedSyncMessageVersions),
serverSupportedSyncMessageVersion: sharedgrpc.SyncMessageVersionFromConfig(config.HighestSupportedSyncMessageVersion),
perAccountServerSupportedSyncMessageVersions: sharedgrpc.SyncMessageVersionsFromMap(config.PerAccountHighestSupportedSyncMessageVersion),
}
}
@@ -232,13 +233,13 @@ func (c *Controller) sendUpdateAccountPeers(ctx context.Context, accountID strin
proxyNetworkMap := proxyNetworkMaps[p.ID]
var update *proto.SyncResponse
commonSyncMessageVersions := grpc.CommonSyncMessageVersions(
commonSyncMessageVersion := sharedgrpc.HighestCommonSyncMessageVersions(
c.perAccountOrGlobalSupportedSyncMessageVersions(accountID),
grpc.SyncMessageVersionsFromProtoEnums(peer.Meta.Capabilities))
sharedgrpc.SyncMessageVersionFromConfig(&peer.Meta.SyncMessageVersion))
log.WithContext(ctx).WithField("sync_message_version", commonSyncMessageVersions[0]).Debug("common highest sync message version")
log.WithContext(ctx).WithField("sync_message_version", commonSyncMessageVersion).Debug("common highest sync message version")
if commonSyncMessageVersions[0] == grpc.ComponentNetworkMap {
if commonSyncMessageVersion == sharedgrpc.ComponentNetworkMap {
components := account.GetPeerNetworkMapComponents(
ctx, p.ID, peersCustomZone, accountZones, approvedPeersMap, resourcePolicies, routers, groupIDToUserIDs)
@@ -287,11 +288,11 @@ func (c *Controller) sendUpdateAccountPeers(ctx context.Context, accountID strin
return nil
}
func (c *Controller) perAccountOrGlobalSupportedSyncMessageVersions(accountId string) []grpc.SyncMessageVersion {
func (c *Controller) perAccountOrGlobalSupportedSyncMessageVersions(accountId string) sharedgrpc.SyncMessageVersion {
if perAccount, ok := c.perAccountServerSupportedSyncMessageVersions[accountId]; ok {
return perAccount
}
return c.serverSupportedSyncMessageVersions
return c.serverSupportedSyncMessageVersion
}
// UpdatePeers updates all peers that belong to an account.
@@ -399,13 +400,13 @@ func (c *Controller) sendUpdateForAffectedPeers(ctx context.Context, accountID s
proxyNetworkMap := proxyNetworkMaps[p.ID]
var update *proto.SyncResponse
commonSyncMessageVersions := grpc.CommonSyncMessageVersions(
commonSyncMessageVersion := sharedgrpc.HighestCommonSyncMessageVersions(
c.perAccountOrGlobalSupportedSyncMessageVersions(accountID),
grpc.SyncMessageVersionsFromProtoEnums(peer.Meta.Capabilities))
sharedgrpc.SyncMessageVersionFromConfig(&peer.Meta.SyncMessageVersion))
log.WithContext(ctx).WithField("sync_message_version", commonSyncMessageVersions[0]).Debug("common highest sync message version")
log.WithContext(ctx).WithField("sync_message_version", commonSyncMessageVersion).Debug("common highest sync message version")
if commonSyncMessageVersions[0] == grpc.ComponentNetworkMap {
if commonSyncMessageVersion == sharedgrpc.ComponentNetworkMap {
components := account.GetPeerNetworkMapComponents(
ctx, p.ID, peersCustomZone, accountZones, approvedPeersMap, resourcePolicies, routers, groupIDToUserIDs)
@@ -535,13 +536,13 @@ func (c *Controller) UpdateAccountPeer(ctx context.Context, accountId string, pe
var update *proto.SyncResponse
commonSyncMessageVersions := grpc.CommonSyncMessageVersions(
commonSyncMessageVersion := sharedgrpc.HighestCommonSyncMessageVersions(
c.perAccountOrGlobalSupportedSyncMessageVersions(accountId),
grpc.SyncMessageVersionsFromProtoEnums(peer.Meta.Capabilities))
sharedgrpc.SyncMessageVersionFromConfig(&peer.Meta.SyncMessageVersion))
log.WithContext(ctx).WithField("sync_message_version", commonSyncMessageVersions[0]).Debug("common highest sync message version")
log.WithContext(ctx).WithField("sync_message_version", commonSyncMessageVersion).Debug("common highest sync message version")
if commonSyncMessageVersions[0] == grpc.ComponentNetworkMap {
if commonSyncMessageVersion == sharedgrpc.ComponentNetworkMap {
components := account.GetPeerNetworkMapComponents(
ctx, peer.ID, peersCustomZone, accountZones, approvedPeersMap, resourcePolicies, routers, groupIDToUserIDs)

View File

@@ -62,9 +62,9 @@ type Config struct {
// When set, Dex will be embedded in the management server and serve requests at /oauth2/
EmbeddedIdP *idp.EmbeddedIdPConfig
SupportedSyncMessageVersions []string
HighestSupportedSyncMessageVersion *int
PerAccountSupportedSyncMessageVersions map[string][]string
PerAccountHighestSupportedSyncMessageVersion map[string]int
}
// GetAuthAudiences returns the audience from the http config and device authorization flow config

View File

@@ -10,6 +10,7 @@ import (
nbpeer "github.com/netbirdio/netbird/management/server/peer"
"github.com/netbirdio/netbird/management/server/posture"
"github.com/netbirdio/netbird/management/server/types"
sharedgrpc "github.com/netbirdio/netbird/shared/management/grpc"
"github.com/netbirdio/netbird/shared/management/networkmap"
"github.com/netbirdio/netbird/shared/management/proto"
)
@@ -72,7 +73,7 @@ func ToComponentSyncResponse(
PeerConfig: peerConfig,
NetworkMapEnvelope: envelope,
Checks: toProtocolChecks(ctx, checks),
Version: proto.SyncResponseVersion_VersionComponentNetworkMap,
Version: int32(sharedgrpc.ComponentNetworkMap),
}
nbConfig := toNetbirdConfig(config, turnCredentials, relayCredentials, extraSettings, settings)

View File

@@ -45,6 +45,7 @@ import (
"github.com/netbirdio/netbird/management/server/settings"
"github.com/netbirdio/netbird/management/server/telemetry"
"github.com/netbirdio/netbird/management/server/types"
sharedgrpc "github.com/netbirdio/netbird/shared/management/grpc"
"github.com/netbirdio/netbird/shared/management/proto"
internalStatus "github.com/netbirdio/netbird/shared/management/status"
)
@@ -684,8 +685,9 @@ func extractPeerMeta(ctx context.Context, meta *proto.PeerSystemMeta) nbpeer.Pee
LazyConnectionEnabled: meta.GetFlags().GetLazyConnectionEnabled(),
DisableIPv6: meta.GetFlags().GetDisableIPv6(),
},
Files: files,
Capabilities: capabilitiesToInt32(meta.GetCapabilities()),
Files: files,
Capabilities: capabilitiesToInt32(meta.GetCapabilities()),
SyncMessageVersion: int(meta.GetSyncMessageVersion()),
}
}
@@ -1021,13 +1023,13 @@ func (s *Server) sendInitialSync(ctx context.Context, peerKey wgtypes.Key, peer
var plainResp *proto.SyncResponse
commonSyncMessageVersions := CommonSyncMessageVersions(
SyncMessageVersionsFromString(s.perAccountOrGlobalSyncMessageVersions(peer.AccountID)),
SyncMessageVersionsFromProtoEnums(peer.Meta.Capabilities))
commonSyncMessageVersion := sharedgrpc.HighestCommonSyncMessageVersions(
s.perAccountOrGlobalSyncMessageVersions(peer.AccountID),
sharedgrpc.SyncMessageVersionFromConfig(&peer.Meta.SyncMessageVersion))
log.WithContext(ctx).WithField("sync_message_version", commonSyncMessageVersions[0]).Debug("common highest sync message version")
log.WithContext(ctx).WithField("sync_message_version", commonSyncMessageVersion).Debug("common highest sync message version")
if commonSyncMessageVersions[0] == ComponentNetworkMap {
if commonSyncMessageVersion == sharedgrpc.ComponentNetworkMap {
// Capable peer: discard the legacy NetworkMap that SyncAndMarkPeer
// computed and recompute the raw components instead. This wastes one
// Calculate() call per initial-sync — the component-based wire
@@ -1073,11 +1075,11 @@ func (s *Server) sendInitialSync(ctx context.Context, peerKey wgtypes.Key, peer
return nil
}
func (s *Server) perAccountOrGlobalSyncMessageVersions(accountId string) []string {
if versions, ok := s.config.PerAccountSupportedSyncMessageVersions[accountId]; ok {
return versions
func (s *Server) perAccountOrGlobalSyncMessageVersions(accountId string) sharedgrpc.SyncMessageVersion {
if version, ok := s.config.PerAccountHighestSupportedSyncMessageVersion[accountId]; ok {
return sharedgrpc.SyncMessageVersionFromConfig(&version)
}
return s.config.SupportedSyncMessageVersions
return sharedgrpc.SyncMessageVersionFromConfig(s.config.HighestSupportedSyncMessageVersion)
}
// GetDeviceAuthorizationFlow returns a device authorization flow information

View File

@@ -1,127 +0,0 @@
package grpc
import (
"cmp"
"errors"
"fmt"
"slices"
"github.com/netbirdio/netbird/shared/management/proto"
)
type SyncMessageVersion uint16
const (
Base SyncMessageVersion = iota
ComponentNetworkMap
)
var (
AllSyncMessageVersions = []SyncMessageVersion{Base, ComponentNetworkMap}
ProtoToMessageSyncVersion = map[proto.PeerCapability]SyncMessageVersion{
proto.PeerCapability_PeerCapabilityComponentNetworkMap: ComponentNetworkMap,
}
MessageSyncVersionToProto = map[SyncMessageVersion]proto.PeerCapability{
ComponentNetworkMap: proto.PeerCapability_PeerCapabilityComponentNetworkMap,
}
)
var ErrorUnrecognizedSyncMessageVersion = errors.New("unrecognized SyncMessageVersion")
func (sm SyncMessageVersion) String() string {
return [...]string{"Base", "ComponentNetworkMap"}[sm]
}
func AllSupportedSyncMessageVersions() []SyncMessageVersion {
return AllSyncMessageVersions
}
func ValidateSyncMessageVersions(tovalidate []string) error {
// empty list == we support all available versions
if len(tovalidate) == 0 {
return nil
}
allversions := make(map[string]SyncMessageVersion, len(AllSyncMessageVersions))
for _, v := range AllSyncMessageVersions {
allversions[v.String()] = v
}
for _, s := range tovalidate {
if _, ok := allversions[s]; !ok {
return fmt.Errorf("%s: %w", s, ErrorUnrecognizedSyncMessageVersion)
}
}
return nil
}
// convert human-readable versions to enums
// please note no validation on input strings is done, misses are silently discarded
// the assumption is ValidateSyncMessageVersions() has been called before using SyncMessageVersionsFromString()
func SyncMessageVersionsFromString(toconvert []string) []SyncMessageVersion {
// empty list == we support all available versions
if len(toconvert) == 0 {
return AllSyncMessageVersions
}
allversions := make(map[string]SyncMessageVersion, len(AllSyncMessageVersions))
for _, v := range AllSyncMessageVersions {
allversions[v.String()] = v
}
toret := make([]SyncMessageVersion, 0)
for _, s := range toconvert {
toret = append(toret, allversions[s])
}
return toret
}
// convert per-account human-readable versions to enums
// please note no validation on versions strings is done, misses are silently discarded
// the assumption is ValidateSyncMessageVersions() has been called before using SyncMessageVersionsFromMap()
func SyncMessageVersionsFromMap(toconvert map[string][]string) map[string][]SyncMessageVersion {
// no per-account overrides
if len(toconvert) == 0 {
return nil
}
allversions := make(map[string]SyncMessageVersion, len(AllSyncMessageVersions))
for _, v := range AllSyncMessageVersions {
allversions[v.String()] = v
}
toret := make(map[string][]SyncMessageVersion, len(toconvert))
for account, versions := range toconvert {
toret[account] = SyncMessageVersionsFromString(versions)
}
return toret
}
// these come from the client; peer capabilities are expected to contain all enabled sync message versions.
// an empty list is interpreted as all but the base version are disabled.
func SyncMessageVersionsFromProtoEnums(peerCapabilities []int32) []SyncMessageVersion {
toret := make([]SyncMessageVersion, 0)
for _, pc := range peerCapabilities {
if _, ok := ProtoToMessageSyncVersion[proto.PeerCapability(pc)]; ok {
toret = append(toret, ProtoToMessageSyncVersion[proto.PeerCapability(pc)])
}
}
return toret
}
// return highest common sync message version, or Default (which is always available)
func CommonSyncMessageVersions(a []SyncMessageVersion, b []SyncMessageVersion) []SyncMessageVersion {
toret := []SyncMessageVersion{Base}
aversions := make(map[SyncMessageVersion]struct{})
for _, va := range a {
aversions[va] = struct{}{}
}
for _, vb := range b {
if _, ok := aversions[vb]; ok && vb != Base { // we already added 'Base' version
toret = append(toret, vb)
}
}
slices.SortFunc(toret, func(a SyncMessageVersion, b SyncMessageVersion) int {
return -1 * cmp.Compare(a, b)
})
return toret
}

View File

@@ -1,45 +0,0 @@
package grpc
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestValidation(t *testing.T) {
assert.NoError(t, ValidateSyncMessageVersions([]string{"Base", "ComponentNetworkMap"}))
assert.NoError(t, ValidateSyncMessageVersions([]string{}))
assert.ErrorIs(t, ValidateSyncMessageVersions([]string{"Boom"}), ErrorUnrecognizedSyncMessageVersion)
assert.ErrorIs(t, ValidateSyncMessageVersions([]string{"Base", "Boom"}), ErrorUnrecognizedSyncMessageVersion)
}
func TestConversionStringToEnum(t *testing.T) {
assert.Equal(t, []SyncMessageVersion{0, 1}, SyncMessageVersionsFromString([]string{}))
assert.Equal(t, []SyncMessageVersion{0}, SyncMessageVersionsFromString([]string{"Base"}))
assert.Equal(t, []SyncMessageVersion{1}, SyncMessageVersionsFromString([]string{"ComponentNetworkMap"}))
}
func TestPerAccountConversionStringToEnum(t *testing.T) {
assert.Equal(t, map[string][]SyncMessageVersion{"1": {0, 1}}, SyncMessageVersionsFromMap(map[string][]string{"1": {}}))
assert.Equal(t, map[string][]SyncMessageVersion{"2": {0}}, SyncMessageVersionsFromMap(map[string][]string{"2": {"Base"}}))
assert.Equal(t, map[string][]SyncMessageVersion{"3": {1}, "4": {0, 1}},
SyncMessageVersionsFromMap(map[string][]string{
"3": {"ComponentNetworkMap"},
"4": {"Base", "ComponentNetworkMap"},
}))
}
func TestConversionFromProtoEnums(t *testing.T) {
assert.Equal(t, []SyncMessageVersion{}, SyncMessageVersionsFromProtoEnums([]int32{}))
assert.Equal(t, []SyncMessageVersion{}, SyncMessageVersionsFromProtoEnums([]int32{0}))
assert.Equal(t, []SyncMessageVersion{1}, SyncMessageVersionsFromProtoEnums([]int32{3}))
}
func TestCommonVersions(t *testing.T) {
assert.Equal(t, []SyncMessageVersion{0},
CommonSyncMessageVersions([]SyncMessageVersion{0, 1}, []SyncMessageVersion{}))
assert.Equal(t, []SyncMessageVersion{0},
CommonSyncMessageVersions([]SyncMessageVersion{0}, []SyncMessageVersion{0, 1, 2}))
assert.Equal(t, []SyncMessageVersion{5, 1, 0},
CommonSyncMessageVersions([]SyncMessageVersion{0, 1, 4, 5}, []SyncMessageVersion{1, 0, 5, 2}))
}

View File

@@ -173,6 +173,7 @@ type PeerSystemMeta struct { //nolint:revive
Flags Flags `gorm:"serializer:json"`
Files []File `gorm:"serializer:json"`
Capabilities []int32 `gorm:"serializer:json"`
SyncMessageVersion int
}
func (p PeerSystemMeta) isEqual(other PeerSystemMeta) bool {
@@ -415,6 +416,9 @@ func diffMeta(oldMeta, newMeta PeerSystemMeta, oldLocation, newLocation Location
if !sameMultiset(oldMeta.Files, newMeta.Files) {
add("files", fmt.Sprintf("%v", oldMeta.Files), fmt.Sprintf("%v", newMeta.Files))
}
if oldMeta.SyncMessageVersion != newMeta.SyncMessageVersion {
add("sync_meta_version", fmt.Sprintf("%d", oldMeta.SyncMessageVersion), fmt.Sprintf("%d", newMeta.SyncMessageVersion))
}
if !oldLocation.equal(newLocation) {
add("connection_ip", oldLocation.ConnectionIP, newLocation.ConnectionIP)

View File

@@ -24,6 +24,7 @@ import (
"github.com/netbirdio/netbird/client/system"
"github.com/netbirdio/netbird/encryption"
"github.com/netbirdio/netbird/shared/management/domain"
nbmgmtgrpc "github.com/netbirdio/netbird/shared/management/grpc"
"github.com/netbirdio/netbird/shared/management/proto"
"github.com/netbirdio/netbird/util/wsproxy"
)
@@ -1026,6 +1027,8 @@ func infoToMetaData(info *system.Info) *proto.PeerSystemMeta {
},
Capabilities: peerCapabilities(*info),
SyncMessageVersion: syncMessageVersion(*info),
}
}
@@ -1034,14 +1037,15 @@ func peerCapabilities(info system.Info) []proto.PeerCapability {
caps := []proto.PeerCapability{
proto.PeerCapability_PeerCapabilitySourcePrefixes,
}
// PeerCapabilityComponentNetworkMap signals that this client can
// decode the components-format SyncResponse.NetworkMapEnvelope and
// run Calculate() locally.
if !info.DisableComponentNetworkMap {
caps = append(caps, proto.PeerCapability_PeerCapabilityComponentNetworkMap)
}
if !info.DisableIPv6 {
caps = append(caps, proto.PeerCapability_PeerCapabilityIPv6Overlay)
}
return caps
}
func syncMessageVersion(info system.Info) int32 {
if info.SyncMessageVersion != nil {
return int32(*info.SyncMessageVersion)
}
return int32(nbmgmtgrpc.CurrentSyncMessageVersion)
}

View File

@@ -0,0 +1,66 @@
package grpc
import (
"errors"
"fmt"
)
type SyncMessageVersion uint16
const (
Base SyncMessageVersion = iota
ComponentNetworkMap
)
const CurrentSyncMessageVersion = ComponentNetworkMap
var ErrorUnrecognizedSyncMessageVersion = errors.New("unrecognized SyncMessageVersion")
func ValidateSyncMessageVersion(v *int) error {
// empty list == we support all available versions
if v == nil {
return nil
}
if *v < 0 || *v > int(CurrentSyncMessageVersion) {
return fmt.Errorf("sync message version must between 0 and %d, %w", CurrentSyncMessageVersion, ErrorUnrecognizedSyncMessageVersion)
}
return nil
}
// returns SyncMessage version from config, or highest available version if the config is missing or
// base if it is invalid
// the assumption is ValidateSyncMessageVersion() has been called before using SyncMessageVersionFromConfig()
func SyncMessageVersionFromConfig(v *int) SyncMessageVersion {
if v == nil {
return CurrentSyncMessageVersion
}
if *v < 0 || *v > int(CurrentSyncMessageVersion) {
return Base
}
return SyncMessageVersion(*v)
}
// convert per-account supprted versions to SyncMessageVersion
// the assumption is ValidateSyncMessageVersion() has been called before using SyncMessageVersionsFromMap()
func SyncMessageVersionsFromMap(toconvert map[string]int) map[string]SyncMessageVersion {
// no per-account overrides
if len(toconvert) == 0 {
return nil
}
toret := make(map[string]SyncMessageVersion)
for account, version := range toconvert {
toret[account] = SyncMessageVersionFromConfig(&version)
}
return toret
}
// return highest common sync message version, or Default (which is always available)
func HighestCommonSyncMessageVersions(a SyncMessageVersion, b SyncMessageVersion) SyncMessageVersion {
if a > b {
return b
}
return a
}

View File

@@ -0,0 +1,36 @@
package grpc
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestValidation(t *testing.T) {
assert.NoError(t, ValidateSyncMessageVersion(nil))
assert.NoError(t, ValidateSyncMessageVersion(toIntPtr(0)))
assert.ErrorIs(t, ValidateSyncMessageVersion(toIntPtr(int(^uint(0)>>1))), ErrorUnrecognizedSyncMessageVersion)
assert.ErrorIs(t, ValidateSyncMessageVersion(toIntPtr(-1)), ErrorUnrecognizedSyncMessageVersion)
}
func TestVersionFromConfig(t *testing.T) {
assert.Equal(t, CurrentSyncMessageVersion, SyncMessageVersionFromConfig(nil))
assert.Equal(t, CurrentSyncMessageVersion, SyncMessageVersionFromConfig(toIntPtr(1)))
assert.Equal(t, Base, SyncMessageVersionFromConfig(toIntPtr(-1)))
assert.Equal(t, Base, SyncMessageVersionFromConfig(toIntPtr(int(^uint(0)>>1))))
}
func TestPerAccountConversionStringToEnum(t *testing.T) {
assert.Equal(t, map[string]SyncMessageVersion{"1": CurrentSyncMessageVersion}, SyncMessageVersionsFromMap(map[string]int{"1": 1}))
assert.Equal(t, map[string]SyncMessageVersion{"2": Base}, SyncMessageVersionsFromMap(map[string]int{"2": -1}))
}
func TestCommonVersions(t *testing.T) {
assert.Equal(t, Base, HighestCommonSyncMessageVersions(Base, CurrentSyncMessageVersion))
assert.Equal(t, Base, HighestCommonSyncMessageVersions(CurrentSyncMessageVersion, Base))
assert.Equal(t, CurrentSyncMessageVersion, HighestCommonSyncMessageVersions(CurrentSyncMessageVersion, CurrentSyncMessageVersion))
}
func toIntPtr(v int) *int {
return &v
}

File diff suppressed because it is too large Load Diff

View File

@@ -121,11 +121,6 @@ message SyncRequest {
PeerSystemMeta meta = 1;
}
enum SyncResponseVersion {
VersionUnknown = 0;
VersionComponentNetworkMap = 1;
}
// SyncResponse represents a state that should be applied to the local peer (e.g. Netbird servers config as well as local peer and remote peers configs)
message SyncResponse {
@@ -162,7 +157,7 @@ message SyncResponse {
// locally instead of receiving an expanded NetworkMap.
NetworkMapEnvelope NetworkMapEnvelope = 8;
SyncResponseVersion Version = 9;
int32 Version = 9;
}
message SyncMetaRequest {
@@ -267,6 +262,7 @@ message PeerSystemMeta {
Flags flags = 17;
repeated PeerCapability capabilities = 18;
int32 syncMessageVersion = 19;
}
message LoginResponse {