diff --git a/client/internal/engine.go b/client/internal/engine.go index 828bc6e945f..16ffdb33aaf 100644 --- a/client/internal/engine.go +++ b/client/internal/engine.go @@ -453,8 +453,6 @@ func (e *Engine) Start(netbirdConfig *mgmProto.NetbirdConfig, mgmtURL *url.URL) return fmt.Errorf("up wg interface: %w", err) } - - // if inbound conns are blocked there is no need to create the ACL manager if e.firewall != nil && !e.config.BlockInbound { e.acl = acl.NewDefaultManager(e.firewall) @@ -760,7 +758,7 @@ func (e *Engine) handleSync(update *mgmProto.SyncResponse) error { } nm := update.GetNetworkMap() - if nm == nil { + if nm == nil || update.SkipNetworkMapUpdate { return nil } diff --git a/client/internal/engine_sync_test.go b/client/internal/engine_sync_test.go new file mode 100644 index 00000000000..ad2a97157c0 --- /dev/null +++ b/client/internal/engine_sync_test.go @@ -0,0 +1,79 @@ +package internal + +import ( + "context" + "testing" + + "golang.zx2c4.com/wireguard/wgctrl/wgtypes" + + "github.com/netbirdio/netbird/client/iface" + "github.com/netbirdio/netbird/client/internal/peer" + "github.com/netbirdio/netbird/shared/management/client" + mgmtProto "github.com/netbirdio/netbird/shared/management/proto" +) + +// Ensures handleSync exits early when SkipNetworkMapUpdate is true +func TestEngine_HandleSync_SkipNetworkMapUpdate(t *testing.T) { + key, err := wgtypes.GeneratePrivateKey() + if err != nil { + t.Fatal(err) + } + + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + engine := NewEngine(ctx, cancel, nil, &client.MockClient{}, nil, &EngineConfig{ + WgIfaceName: "utun199", + WgAddr: "100.70.0.1/24", + WgPrivateKey: key, + WgPort: 33100, + MTU: iface.DefaultMTU, + }, MobileDependency{}, peer.NewRecorder("https://mgm"), nil) + engine.ctx = ctx + + // Precondition + if engine.networkSerial != 0 { + t.Fatalf("unexpected initial serial: %d", engine.networkSerial) + } + + resp := &mgmtProto.SyncResponse{ + NetworkMap: &mgmtProto.NetworkMap{Serial: 42}, + SkipNetworkMapUpdate: true, + } + + if err := engine.handleSync(resp); err != nil { + t.Fatalf("handleSync returned error: %v", err) + } + + if engine.networkSerial != 0 { + t.Fatalf("networkSerial changed despite SkipNetworkMapUpdate; got %d, want 0", engine.networkSerial) + } +} + +// Ensures handleSync exits early when NetworkMap is nil +func TestEngine_HandleSync_NilNetworkMap(t *testing.T) { + key, err := wgtypes.GeneratePrivateKey() + if err != nil { + t.Fatal(err) + } + + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + engine := NewEngine(ctx, cancel, nil, &client.MockClient{}, nil, &EngineConfig{ + WgIfaceName: "utun198", + WgAddr: "100.70.0.2/24", + WgPrivateKey: key, + WgPort: 33101, + MTU: iface.DefaultMTU, + }, MobileDependency{}, peer.NewRecorder("https://mgm"), nil) + engine.ctx = ctx + + resp := &mgmtProto.SyncResponse{NetworkMap: nil} + + if err := engine.handleSync(resp); err != nil { + t.Fatalf("handleSync returned error: %v", err) + } +} + + diff --git a/client/system/info.go b/client/system/info.go index a180be4c0d6..fa954b44d9e 100644 --- a/client/system/info.go +++ b/client/system/info.go @@ -96,6 +96,21 @@ func (i *Info) SetFlags( i.LazyConnectionEnabled = lazyConnectionEnabled } +func (i *Info) CopyFlagsFrom(other *Info) { + i.SetFlags( + other.RosenpassEnabled, + other.RosenpassPermissive, + &other.ServerSSHAllowed, + other.DisableClientRoutes, + other.DisableServerRoutes, + other.DisableDNS, + other.DisableFirewall, + other.BlockLANAccess, + other.BlockInbound, + other.LazyConnectionEnabled, + ) +} + // extractUserAgent extracts Netbird's agent (client) name and version from the outgoing context func extractUserAgent(ctx context.Context) string { md, hasMeta := metadata.FromOutgoingContext(ctx) diff --git a/client/system/info_test.go b/client/system/info_test.go index 27821f3c53c..fdd2895ac34 100644 --- a/client/system/info_test.go +++ b/client/system/info_test.go @@ -1,13 +1,72 @@ package system import ( - "context" - "testing" + "context" + "testing" - "github.com/stretchr/testify/assert" - "google.golang.org/grpc/metadata" + "github.com/stretchr/testify/assert" + "google.golang.org/grpc/metadata" ) +func TestInfo_CopyFlagsFrom(t *testing.T) { + origin := &Info{} + serverSSHAllowed := true + origin.SetFlags( + true, // RosenpassEnabled + false, // RosenpassPermissive + &serverSSHAllowed, + true, // DisableClientRoutes + false, // DisableServerRoutes + true, // DisableDNS + false, // DisableFirewall + true, // BlockLANAccess + false, // BlockInbound + true, // LazyConnectionEnabled + ) + + got := &Info{} + got.CopyFlagsFrom(origin) + + if got.RosenpassEnabled != true { + t.Fatalf("RosenpassEnabled not copied: got %v", got.RosenpassEnabled) + } + if got.RosenpassPermissive != false { + t.Fatalf("RosenpassPermissive not copied: got %v", got.RosenpassPermissive) + } + if got.ServerSSHAllowed != true { + t.Fatalf("ServerSSHAllowed not copied: got %v", got.ServerSSHAllowed) + } + if got.DisableClientRoutes != true { + t.Fatalf("DisableClientRoutes not copied: got %v", got.DisableClientRoutes) + } + if got.DisableServerRoutes != false { + t.Fatalf("DisableServerRoutes not copied: got %v", got.DisableServerRoutes) + } + if got.DisableDNS != true { + t.Fatalf("DisableDNS not copied: got %v", got.DisableDNS) + } + if got.DisableFirewall != false { + t.Fatalf("DisableFirewall not copied: got %v", got.DisableFirewall) + } + if got.BlockLANAccess != true { + t.Fatalf("BlockLANAccess not copied: got %v", got.BlockLANAccess) + } + if got.BlockInbound != false { + t.Fatalf("BlockInbound not copied: got %v", got.BlockInbound) + } + if got.LazyConnectionEnabled != true { + t.Fatalf("LazyConnectionEnabled not copied: got %v", got.LazyConnectionEnabled) + } + + // ensure CopyFlagsFrom does not touch unrelated fields + origin.Hostname = "host-a" + got.Hostname = "host-b" + got.CopyFlagsFrom(origin) + if got.Hostname != "host-b" { + t.Fatalf("CopyFlagsFrom should not overwrite non-flag fields, got Hostname=%q", got.Hostname) + } +} + func Test_LocalWTVersion(t *testing.T) { got := GetInfo(context.TODO()) want := "development" diff --git a/shared/management/client/grpc.go b/shared/management/client/grpc.go index f30e965be85..2d6f4dbf974 100644 --- a/shared/management/client/grpc.go +++ b/shared/management/client/grpc.go @@ -44,6 +44,9 @@ type GrpcClient struct { conn *grpc.ClientConn connStateCallback ConnStateNotifier connStateCallbackLock sync.RWMutex + // lastNetworkMapSerial stores last seen network map serial to optimize sync + lastNetworkMapSerial uint64 + lastNetworkMapSerialMu sync.Mutex } // NewClient creates a new client to Management service @@ -216,11 +219,23 @@ func (c *GrpcClient) GetNetworkMap(sysInfo *system.Info) (*proto.NetworkMap, err return nil, fmt.Errorf("invalid msg, required network map") } + // update last seen serial + c.setLastNetworkMapSerial(decryptedResp.GetNetworkMap().GetSerial()) + return decryptedResp.GetNetworkMap(), nil } func (c *GrpcClient) connectToStream(ctx context.Context, serverPubKey wgtypes.Key, sysInfo *system.Info) (proto.ManagementService_SyncClient, error) { - req := &proto.SyncRequest{Meta: infoToMetaData(sysInfo)} + // Always compute latest system info to ensure up-to-date PeerSystemMeta on first and subsequent syncs + recomputed := system.GetInfo(c.ctx) + if sysInfo != nil { + recomputed.CopyFlagsFrom(sysInfo) + // carry over posture files if any were computed + if len(sysInfo.Files) > 0 { + recomputed.Files = sysInfo.Files + } + } + req := &proto.SyncRequest{Meta: infoToMetaData(recomputed), NetworkMapSerial: c.getLastNetworkMapSerial()} myPrivateKey := c.key myPublicKey := myPrivateKey.PublicKey() @@ -258,6 +273,11 @@ func (c *GrpcClient) receiveEvents(stream proto.ManagementService_SyncClient, se return err } + // track latest network map serial if present + if decryptedResp.GetNetworkMap() != nil { + c.setLastNetworkMapSerial(decryptedResp.GetNetworkMap().GetSerial()) + } + if err := msgHandler(decryptedResp); err != nil { log.Errorf("failed handling an update message received from Management Service: %v", err.Error()) } @@ -582,3 +602,18 @@ func infoToMetaData(info *system.Info) *proto.PeerSystemMeta { }, } } + +// setLastNetworkMapSerial updates the cached last seen network map serial in a 32-bit safe manner +func (c *GrpcClient) setLastNetworkMapSerial(serial uint64) { + c.lastNetworkMapSerialMu.Lock() + c.lastNetworkMapSerial = serial + c.lastNetworkMapSerialMu.Unlock() +} + +// getLastNetworkMapSerial returns the cached last seen network map serial in a 32-bit safe manner +func (c *GrpcClient) getLastNetworkMapSerial() uint64 { + c.lastNetworkMapSerialMu.Lock() + v := c.lastNetworkMapSerial + c.lastNetworkMapSerialMu.Unlock() + return v +} diff --git a/shared/management/client/grpc_test.go b/shared/management/client/grpc_test.go new file mode 100644 index 00000000000..fccd2179e8f --- /dev/null +++ b/shared/management/client/grpc_test.go @@ -0,0 +1,26 @@ +package client + +import ( + "testing" +) + +func TestGrpcClient_LastNetworkMapSerial_SetGet(t *testing.T) { + c := &GrpcClient{} + + if got := c.getLastNetworkMapSerial(); got != 0 { + t.Fatalf("initial serial should be 0, got %d", got) + } + + c.setLastNetworkMapSerial(123) + if got := c.getLastNetworkMapSerial(); got != 123 { + t.Fatalf("serial after set should be 123, got %d", got) + } + + // overwrite should work + c.setLastNetworkMapSerial(5) + if got := c.getLastNetworkMapSerial(); got != 5 { + t.Fatalf("serial after overwrite should be 5, got %d", got) + } +} + + diff --git a/shared/management/proto/management.pb.go b/shared/management/proto/management.pb.go index bf614e8aac1..1748e4a553d 100644 --- a/shared/management/proto/management.pb.go +++ b/shared/management/proto/management.pb.go @@ -7,12 +7,13 @@ package proto import ( + reflect "reflect" + sync "sync" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" durationpb "google.golang.org/protobuf/types/known/durationpb" timestamppb "google.golang.org/protobuf/types/known/timestamppb" - reflect "reflect" - sync "sync" ) const ( @@ -343,6 +344,8 @@ type SyncRequest struct { // Meta data of the peer Meta *PeerSystemMeta `protobuf:"bytes,1,opt,name=meta,proto3" json:"meta,omitempty"` + // Optional: last known NetworkMap serial number on the client + NetworkMapSerial uint64 `protobuf:"varint,2,opt,name=networkMapSerial,proto3" json:"networkMapSerial,omitempty"` } func (x *SyncRequest) Reset() { @@ -384,6 +387,13 @@ func (x *SyncRequest) GetMeta() *PeerSystemMeta { return nil } +func (x *SyncRequest) GetNetworkMapSerial() uint64 { + if x != nil { + return x.NetworkMapSerial + } + return 0 +} + // 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) type SyncResponse struct { state protoimpl.MessageState @@ -402,6 +412,8 @@ type SyncResponse struct { NetworkMap *NetworkMap `protobuf:"bytes,5,opt,name=NetworkMap,proto3" json:"NetworkMap,omitempty"` // Posture checks to be evaluated by client Checks []*Checks `protobuf:"bytes,6,rep,name=Checks,proto3" json:"Checks,omitempty"` + // Indicates whether the client should skip updating the network map + SkipNetworkMapUpdate bool `protobuf:"varint,7,opt,name=skipNetworkMapUpdate,proto3" json:"skipNetworkMapUpdate,omitempty"` } func (x *SyncResponse) Reset() { @@ -478,6 +490,13 @@ func (x *SyncResponse) GetChecks() []*Checks { return nil } +func (x *SyncResponse) GetSkipNetworkMapUpdate() bool { + if x != nil { + return x.SkipNetworkMapUpdate + } + return false +} + type SyncMetaRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -3372,33 +3391,39 @@ var file_management_proto_rawDesc = []byte{ 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x77, 0x67, 0x50, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x12, 0x12, 0x0a, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x3d, 0x0a, + 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x69, 0x0a, 0x0b, 0x53, 0x79, 0x6e, 0x63, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2e, 0x0a, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x53, 0x79, 0x73, 0x74, - 0x65, 0x6d, 0x4d, 0x65, 0x74, 0x61, 0x52, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x22, 0xdb, 0x02, 0x0a, - 0x0c, 0x53, 0x79, 0x6e, 0x63, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3f, 0x0a, - 0x0d, 0x6e, 0x65, 0x74, 0x62, 0x69, 0x72, 0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, - 0x74, 0x2e, 0x4e, 0x65, 0x74, 0x62, 0x69, 0x72, 0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, - 0x0d, 0x6e, 0x65, 0x74, 0x62, 0x69, 0x72, 0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x36, - 0x0a, 0x0a, 0x70, 0x65, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, - 0x50, 0x65, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x0a, 0x70, 0x65, 0x65, 0x72, - 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x3e, 0x0a, 0x0b, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, - 0x50, 0x65, 0x65, 0x72, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x6d, 0x61, - 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x50, - 0x65, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x0b, 0x72, 0x65, 0x6d, 0x6f, 0x74, - 0x65, 0x50, 0x65, 0x65, 0x72, 0x73, 0x12, 0x2e, 0x0a, 0x12, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, - 0x50, 0x65, 0x65, 0x72, 0x73, 0x49, 0x73, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x18, 0x04, 0x20, 0x01, - 0x28, 0x08, 0x52, 0x12, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x50, 0x65, 0x65, 0x72, 0x73, 0x49, - 0x73, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x36, 0x0a, 0x0a, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, - 0x6b, 0x4d, 0x61, 0x70, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x6d, 0x61, 0x6e, - 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x4d, - 0x61, 0x70, 0x52, 0x0a, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x4d, 0x61, 0x70, 0x12, 0x2a, - 0x0a, 0x06, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x12, - 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x43, 0x68, 0x65, 0x63, - 0x6b, 0x73, 0x52, 0x06, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x73, 0x22, 0x41, 0x0a, 0x0f, 0x53, 0x79, + 0x65, 0x6d, 0x4d, 0x65, 0x74, 0x61, 0x52, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x12, 0x2a, 0x0a, 0x10, + 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x4d, 0x61, 0x70, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x10, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x4d, + 0x61, 0x70, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x22, 0x8f, 0x03, 0x0a, 0x0c, 0x53, 0x79, 0x6e, + 0x63, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3f, 0x0a, 0x0d, 0x6e, 0x65, 0x74, + 0x62, 0x69, 0x72, 0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x19, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x4e, 0x65, + 0x74, 0x62, 0x69, 0x72, 0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x0d, 0x6e, 0x65, 0x74, + 0x62, 0x69, 0x72, 0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x36, 0x0a, 0x0a, 0x70, 0x65, + 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, + 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x50, 0x65, 0x65, 0x72, + 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x0a, 0x70, 0x65, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, + 0x69, 0x67, 0x12, 0x3e, 0x0a, 0x0b, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x50, 0x65, 0x65, 0x72, + 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, + 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x50, 0x65, 0x65, 0x72, 0x43, + 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x0b, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x50, 0x65, 0x65, + 0x72, 0x73, 0x12, 0x2e, 0x0a, 0x12, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x50, 0x65, 0x65, 0x72, + 0x73, 0x49, 0x73, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x12, + 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x50, 0x65, 0x65, 0x72, 0x73, 0x49, 0x73, 0x45, 0x6d, 0x70, + 0x74, 0x79, 0x12, 0x36, 0x0a, 0x0a, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x4d, 0x61, 0x70, + 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, + 0x65, 0x6e, 0x74, 0x2e, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x4d, 0x61, 0x70, 0x52, 0x0a, + 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x4d, 0x61, 0x70, 0x12, 0x2a, 0x0a, 0x06, 0x43, 0x68, + 0x65, 0x63, 0x6b, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x6d, 0x61, 0x6e, + 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x73, 0x52, 0x06, + 0x43, 0x68, 0x65, 0x63, 0x6b, 0x73, 0x12, 0x32, 0x0a, 0x14, 0x73, 0x6b, 0x69, 0x70, 0x4e, 0x65, + 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x4d, 0x61, 0x70, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x18, 0x07, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x14, 0x73, 0x6b, 0x69, 0x70, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, + 0x6b, 0x4d, 0x61, 0x70, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x22, 0x41, 0x0a, 0x0f, 0x53, 0x79, 0x6e, 0x63, 0x4d, 0x65, 0x74, 0x61, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2e, 0x0a, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x53, 0x79, 0x73, diff --git a/shared/management/proto/management.proto b/shared/management/proto/management.proto index dcdd387b4ca..613720797f1 100644 --- a/shared/management/proto/management.proto +++ b/shared/management/proto/management.proto @@ -63,6 +63,8 @@ message EncryptedMessage { message SyncRequest { // Meta data of the peer PeerSystemMeta meta = 1; + // Optional: last known NetworkMap serial number on the client + uint64 networkMapSerial = 2; } // 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) @@ -85,6 +87,9 @@ message SyncResponse { // Posture checks to be evaluated by client repeated Checks Checks = 6; + + // Indicates whether the client should skip updating the network map + bool skipNetworkMapUpdate = 7; } message SyncMetaRequest {