From dce457c6f82083442d9d60185a5135843ddc8c37 Mon Sep 17 00:00:00 2001 From: Viktor Liu Date: Fri, 29 Nov 2024 18:45:20 +0100 Subject: [PATCH 1/8] Add network map to debug bundle --- client/cmd/debug.go | 14 ++ client/internal/connect.go | 20 +- client/internal/engine.go | 63 +++++- client/proto/daemon.pb.go | 352 ++++++++++++++++++++++----------- client/proto/daemon.proto | 14 +- client/proto/daemon_grpc.pb.go | 38 ++++ client/server/debug.go | 292 +++++++++++++++++++++++++-- client/server/server.go | 3 + go.mod | 10 +- go.sum | 22 ++- 10 files changed, 688 insertions(+), 140 deletions(-) diff --git a/client/cmd/debug.go b/client/cmd/debug.go index 9abd2039dd5..16528fb0752 100644 --- a/client/cmd/debug.go +++ b/client/cmd/debug.go @@ -171,6 +171,13 @@ func runForDuration(cmd *cobra.Command, args []string) error { time.Sleep(1 * time.Second) + // Enable network map persistence before bringing the service up + if _, err := client.SetNetworkMapPersistence(cmd.Context(), &proto.SetNetworkMapPersistenceRequest{ + Enabled: true, + }); err != nil { + return fmt.Errorf("failed to enable network map persistence: %v", status.Convert(err).Message()) + } + if _, err := client.Up(cmd.Context(), &proto.UpRequest{}); err != nil { return fmt.Errorf("failed to up: %v", status.Convert(err).Message()) } @@ -200,6 +207,13 @@ func runForDuration(cmd *cobra.Command, args []string) error { return fmt.Errorf("failed to bundle debug: %v", status.Convert(err).Message()) } + // Disable network map persistence after creating the debug bundle + if _, err := client.SetNetworkMapPersistence(cmd.Context(), &proto.SetNetworkMapPersistenceRequest{ + Enabled: false, + }); err != nil { + return fmt.Errorf("failed to disable network map persistence: %v", status.Convert(err).Message()) + } + if stateWasDown { if _, err := client.Down(cmd.Context(), &proto.DownRequest{}); err != nil { return fmt.Errorf("failed to down: %v", status.Convert(err).Message()) diff --git a/client/internal/connect.go b/client/internal/connect.go index 8c2ad4aa1db..21f6d3ec869 100644 --- a/client/internal/connect.go +++ b/client/internal/connect.go @@ -40,6 +40,8 @@ type ConnectClient struct { statusRecorder *peer.Status engine *Engine engineMutex sync.Mutex + + persistNetworkMap bool } func NewConnectClient( @@ -258,7 +260,7 @@ func (c *ConnectClient) run(mobileDependency MobileDependency, probes *ProbeHold c.engineMutex.Lock() c.engine = NewEngineWithProbes(engineCtx, cancel, signalClient, mgmClient, relayManager, engineConfig, mobileDependency, c.statusRecorder, probes, checks) - + c.engine.SetNetworkMapPersistence(c.persistNetworkMap) c.engineMutex.Unlock() if err := c.engine.Start(); err != nil { @@ -362,6 +364,22 @@ func (c *ConnectClient) isContextCancelled() bool { } } +// SetNetworkMapPersistence enables or disables network map persistence. +// When enabled, the last received network map will be stored and can be retrieved +// through the Engine's getLatestNetworkMap method. When disabled, any stored +// network map will be cleared. This functionality is primarily used for debugging +// and should not be enabled during normal operation. +func (c *ConnectClient) SetNetworkMapPersistence(enabled bool) { + c.engineMutex.Lock() + c.persistNetworkMap = enabled + c.engineMutex.Unlock() + + engine := c.Engine() + if engine != nil { + engine.SetNetworkMapPersistence(enabled) + } +} + // createEngineConfig converts configuration received from Management Service to EngineConfig func createEngineConfig(key wgtypes.Key, config *Config, peerConfig *mgmProto.PeerConfig) (*EngineConfig, error) { nm := false diff --git a/client/internal/engine.go b/client/internal/engine.go index dc4499e17f3..fbbae671ccb 100644 --- a/client/internal/engine.go +++ b/client/internal/engine.go @@ -21,6 +21,7 @@ import ( "github.com/pion/stun/v2" log "github.com/sirupsen/logrus" "golang.zx2c4.com/wireguard/wgctrl/wgtypes" + "google.golang.org/protobuf/proto" "github.com/netbirdio/netbird/client/firewall" "github.com/netbirdio/netbird/client/firewall/manager" @@ -172,6 +173,10 @@ type Engine struct { relayManager *relayClient.Manager stateManager *statemanager.Manager srWatcher *guard.SRWatcher + + // Network map persistence + persistNetworkMap bool + latestNetworkMap *mgmProto.NetworkMap } // Peer is an instance of the Connection Peer @@ -564,13 +569,22 @@ func (e *Engine) handleSync(update *mgmProto.SyncResponse) error { return err } - if update.GetNetworkMap() != nil { - // only apply new changes and ignore old ones - err := e.updateNetworkMap(update.GetNetworkMap()) - if err != nil { - return err - } + nm := update.GetNetworkMap() + if nm == nil { + return nil + } + + // Store network map if persistence is enabled + if e.persistNetworkMap { + e.latestNetworkMap = nm + log.Debugf("network map persisted with serial %d", nm.GetSerial()) + } + + // only apply new changes and ignore old ones + if err := e.updateNetworkMap(nm); err != nil { + return err } + return nil } @@ -1491,6 +1505,43 @@ func (e *Engine) stopDNSServer() { e.statusRecorder.UpdateDNSStates(nsGroupStates) } +// SetNetworkMapPersistence enables or disables network map persistence +func (e *Engine) SetNetworkMapPersistence(enabled bool) { + e.syncMsgMux.Lock() + defer e.syncMsgMux.Unlock() + + if enabled == e.persistNetworkMap { + return + } + e.persistNetworkMap = enabled + log.Debugf("Network map persistence is set to %t", enabled) + + if !enabled { + e.latestNetworkMap = nil + } +} + +// GetLatestNetworkMap returns the stored network map if persistence is enabled +func (e *Engine) GetLatestNetworkMap() (*mgmProto.NetworkMap, error) { + e.syncMsgMux.Lock() + defer e.syncMsgMux.Unlock() + + if !e.persistNetworkMap { + return nil, errors.New("network map persistence is disabled") + } + + if e.latestNetworkMap == nil { + return nil, nil + } + + // Create a deep copy to avoid external modifications + if nm, ok := proto.Clone(e.latestNetworkMap).(*mgmProto.NetworkMap); ok { + return nm, nil + } + + return nil, nil +} + // isChecksEqual checks if two slices of checks are equal. func isChecksEqual(checks []*mgmProto.Checks, oChecks []*mgmProto.Checks) bool { for _, check := range checks { diff --git a/client/proto/daemon.pb.go b/client/proto/daemon.pb.go index b942d8b6e0a..0eae4e0d618 100644 --- a/client/proto/daemon.pb.go +++ b/client/proto/daemon.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.26.0 -// protoc v3.21.12 +// protoc v4.23.4 // source: daemon.proto package proto @@ -2103,6 +2103,91 @@ func (*SetLogLevelResponse) Descriptor() ([]byte, []int) { return file_daemon_proto_rawDescGZIP(), []int{30} } +type SetNetworkMapPersistenceRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Enabled bool `protobuf:"varint,1,opt,name=enabled,proto3" json:"enabled,omitempty"` +} + +func (x *SetNetworkMapPersistenceRequest) Reset() { + *x = SetNetworkMapPersistenceRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_daemon_proto_msgTypes[31] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SetNetworkMapPersistenceRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SetNetworkMapPersistenceRequest) ProtoMessage() {} + +func (x *SetNetworkMapPersistenceRequest) ProtoReflect() protoreflect.Message { + mi := &file_daemon_proto_msgTypes[31] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SetNetworkMapPersistenceRequest.ProtoReflect.Descriptor instead. +func (*SetNetworkMapPersistenceRequest) Descriptor() ([]byte, []int) { + return file_daemon_proto_rawDescGZIP(), []int{31} +} + +func (x *SetNetworkMapPersistenceRequest) GetEnabled() bool { + if x != nil { + return x.Enabled + } + return false +} + +type SetNetworkMapPersistenceResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *SetNetworkMapPersistenceResponse) Reset() { + *x = SetNetworkMapPersistenceResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_daemon_proto_msgTypes[32] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SetNetworkMapPersistenceResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SetNetworkMapPersistenceResponse) ProtoMessage() {} + +func (x *SetNetworkMapPersistenceResponse) ProtoReflect() protoreflect.Message { + mi := &file_daemon_proto_msgTypes[32] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SetNetworkMapPersistenceResponse.ProtoReflect.Descriptor instead. +func (*SetNetworkMapPersistenceResponse) Descriptor() ([]byte, []int) { + return file_daemon_proto_rawDescGZIP(), []int{32} +} + var File_daemon_proto protoreflect.FileDescriptor var file_daemon_proto_rawDesc = []byte{ @@ -2399,66 +2484,79 @@ var file_daemon_proto_rawDesc = []byte{ 0x32, 0x10, 0x2e, 0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x2e, 0x4c, 0x6f, 0x67, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x52, 0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x22, 0x15, 0x0a, 0x13, 0x53, 0x65, 0x74, 0x4c, 0x6f, 0x67, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x2a, 0x62, 0x0a, 0x08, 0x4c, 0x6f, 0x67, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x0b, 0x0a, 0x07, - 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x09, 0x0a, 0x05, 0x50, 0x41, 0x4e, - 0x49, 0x43, 0x10, 0x01, 0x12, 0x09, 0x0a, 0x05, 0x46, 0x41, 0x54, 0x41, 0x4c, 0x10, 0x02, 0x12, - 0x09, 0x0a, 0x05, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x03, 0x12, 0x08, 0x0a, 0x04, 0x57, 0x41, - 0x52, 0x4e, 0x10, 0x04, 0x12, 0x08, 0x0a, 0x04, 0x49, 0x4e, 0x46, 0x4f, 0x10, 0x05, 0x12, 0x09, - 0x0a, 0x05, 0x44, 0x45, 0x42, 0x55, 0x47, 0x10, 0x06, 0x12, 0x09, 0x0a, 0x05, 0x54, 0x52, 0x41, - 0x43, 0x45, 0x10, 0x07, 0x32, 0xb8, 0x06, 0x0a, 0x0d, 0x44, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x53, - 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x36, 0x0a, 0x05, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x12, - 0x14, 0x2e, 0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x2e, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x15, 0x2e, 0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x2e, 0x4c, - 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x4b, - 0x0a, 0x0c, 0x57, 0x61, 0x69, 0x74, 0x53, 0x53, 0x4f, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x12, 0x1b, - 0x2e, 0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x2e, 0x57, 0x61, 0x69, 0x74, 0x53, 0x53, 0x4f, 0x4c, - 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x64, 0x61, - 0x65, 0x6d, 0x6f, 0x6e, 0x2e, 0x57, 0x61, 0x69, 0x74, 0x53, 0x53, 0x4f, 0x4c, 0x6f, 0x67, 0x69, - 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x2d, 0x0a, 0x02, 0x55, - 0x70, 0x12, 0x11, 0x2e, 0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x2e, 0x55, 0x70, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x12, 0x2e, 0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x2e, 0x55, 0x70, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x39, 0x0a, 0x06, 0x53, 0x74, - 0x61, 0x74, 0x75, 0x73, 0x12, 0x15, 0x2e, 0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x2e, 0x53, 0x74, - 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x64, 0x61, - 0x65, 0x6d, 0x6f, 0x6e, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x33, 0x0a, 0x04, 0x44, 0x6f, 0x77, 0x6e, 0x12, 0x13, 0x2e, - 0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x2e, 0x44, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x14, 0x2e, 0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x2e, 0x44, 0x6f, 0x77, 0x6e, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x42, 0x0a, 0x09, 0x47, 0x65, - 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x18, 0x2e, 0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, - 0x2e, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x19, 0x2e, 0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x6f, - 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x45, - 0x0a, 0x0a, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x12, 0x19, 0x2e, 0x64, - 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x73, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, - 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x4b, 0x0a, 0x0c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x52, + 0x22, 0x3b, 0x0a, 0x1f, 0x53, 0x65, 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x4d, 0x61, + 0x70, 0x50, 0x65, 0x72, 0x73, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x22, 0x22, 0x0a, + 0x20, 0x53, 0x65, 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x4d, 0x61, 0x70, 0x50, 0x65, + 0x72, 0x73, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x2a, 0x62, 0x0a, 0x08, 0x4c, 0x6f, 0x67, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x0b, 0x0a, + 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x09, 0x0a, 0x05, 0x50, 0x41, + 0x4e, 0x49, 0x43, 0x10, 0x01, 0x12, 0x09, 0x0a, 0x05, 0x46, 0x41, 0x54, 0x41, 0x4c, 0x10, 0x02, + 0x12, 0x09, 0x0a, 0x05, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x03, 0x12, 0x08, 0x0a, 0x04, 0x57, + 0x41, 0x52, 0x4e, 0x10, 0x04, 0x12, 0x08, 0x0a, 0x04, 0x49, 0x4e, 0x46, 0x4f, 0x10, 0x05, 0x12, + 0x09, 0x0a, 0x05, 0x44, 0x45, 0x42, 0x55, 0x47, 0x10, 0x06, 0x12, 0x09, 0x0a, 0x05, 0x54, 0x52, + 0x41, 0x43, 0x45, 0x10, 0x07, 0x32, 0xa9, 0x07, 0x0a, 0x0d, 0x44, 0x61, 0x65, 0x6d, 0x6f, 0x6e, + 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x36, 0x0a, 0x05, 0x4c, 0x6f, 0x67, 0x69, 0x6e, + 0x12, 0x14, 0x2e, 0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x2e, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x15, 0x2e, 0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x2e, + 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, + 0x4b, 0x0a, 0x0c, 0x57, 0x61, 0x69, 0x74, 0x53, 0x53, 0x4f, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x12, + 0x1b, 0x2e, 0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x2e, 0x57, 0x61, 0x69, 0x74, 0x53, 0x53, 0x4f, + 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x64, + 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x2e, 0x57, 0x61, 0x69, 0x74, 0x53, 0x53, 0x4f, 0x4c, 0x6f, 0x67, + 0x69, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x2d, 0x0a, 0x02, + 0x55, 0x70, 0x12, 0x11, 0x2e, 0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x2e, 0x55, 0x70, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x12, 0x2e, 0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x2e, 0x55, + 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x39, 0x0a, 0x06, 0x53, + 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x15, 0x2e, 0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x2e, 0x53, + 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x64, + 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x33, 0x0a, 0x04, 0x44, 0x6f, 0x77, 0x6e, 0x12, 0x13, + 0x2e, 0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x2e, 0x44, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x14, 0x2e, 0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x2e, 0x44, 0x6f, 0x77, + 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x42, 0x0a, 0x09, 0x47, + 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x18, 0x2e, 0x64, 0x61, 0x65, 0x6d, 0x6f, + 0x6e, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x2e, 0x47, 0x65, 0x74, 0x43, + 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, + 0x45, 0x0a, 0x0a, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x12, 0x19, 0x2e, + 0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x6f, 0x75, 0x74, 0x65, + 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x64, 0x61, 0x65, 0x6d, 0x6f, + 0x6e, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x4b, 0x0a, 0x0c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, + 0x52, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x12, 0x1b, 0x2e, 0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x2e, + 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x2e, 0x53, 0x65, 0x6c, + 0x65, 0x63, 0x74, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x22, 0x00, 0x12, 0x4d, 0x0a, 0x0e, 0x44, 0x65, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x12, 0x1b, 0x2e, 0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x2e, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x2e, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x22, 0x00, 0x12, 0x4d, 0x0a, 0x0e, 0x44, 0x65, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x52, 0x6f, - 0x75, 0x74, 0x65, 0x73, 0x12, 0x1b, 0x2e, 0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x2e, 0x53, 0x65, - 0x6c, 0x65, 0x63, 0x74, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x1c, 0x2e, 0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x2e, 0x53, 0x65, 0x6c, 0x65, 0x63, - 0x74, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, - 0x00, 0x12, 0x48, 0x0a, 0x0b, 0x44, 0x65, 0x62, 0x75, 0x67, 0x42, 0x75, 0x6e, 0x64, 0x6c, 0x65, - 0x12, 0x1a, 0x2e, 0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x2e, 0x44, 0x65, 0x62, 0x75, 0x67, 0x42, - 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x64, - 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x2e, 0x44, 0x65, 0x62, 0x75, 0x67, 0x42, 0x75, 0x6e, 0x64, 0x6c, - 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x48, 0x0a, 0x0b, 0x47, - 0x65, 0x74, 0x4c, 0x6f, 0x67, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x1a, 0x2e, 0x64, 0x61, 0x65, - 0x6d, 0x6f, 0x6e, 0x2e, 0x47, 0x65, 0x74, 0x4c, 0x6f, 0x67, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x2e, - 0x47, 0x65, 0x74, 0x4c, 0x6f, 0x67, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x48, 0x0a, 0x0b, 0x53, 0x65, 0x74, 0x4c, 0x6f, 0x67, 0x4c, - 0x65, 0x76, 0x65, 0x6c, 0x12, 0x1a, 0x2e, 0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x2e, 0x53, 0x65, - 0x74, 0x4c, 0x6f, 0x67, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x1b, 0x2e, 0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x2e, 0x53, 0x65, 0x74, 0x4c, 0x6f, 0x67, - 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, - 0x08, 0x5a, 0x06, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x33, + 0x22, 0x00, 0x12, 0x48, 0x0a, 0x0b, 0x44, 0x65, 0x62, 0x75, 0x67, 0x42, 0x75, 0x6e, 0x64, 0x6c, + 0x65, 0x12, 0x1a, 0x2e, 0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x2e, 0x44, 0x65, 0x62, 0x75, 0x67, + 0x42, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, + 0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x2e, 0x44, 0x65, 0x62, 0x75, 0x67, 0x42, 0x75, 0x6e, 0x64, + 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x48, 0x0a, 0x0b, + 0x47, 0x65, 0x74, 0x4c, 0x6f, 0x67, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x1a, 0x2e, 0x64, 0x61, + 0x65, 0x6d, 0x6f, 0x6e, 0x2e, 0x47, 0x65, 0x74, 0x4c, 0x6f, 0x67, 0x4c, 0x65, 0x76, 0x65, 0x6c, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, + 0x2e, 0x47, 0x65, 0x74, 0x4c, 0x6f, 0x67, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x48, 0x0a, 0x0b, 0x53, 0x65, 0x74, 0x4c, 0x6f, 0x67, + 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x1a, 0x2e, 0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x2e, 0x53, + 0x65, 0x74, 0x4c, 0x6f, 0x67, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x1b, 0x2e, 0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x2e, 0x53, 0x65, 0x74, 0x4c, 0x6f, + 0x67, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, + 0x12, 0x6f, 0x0a, 0x18, 0x53, 0x65, 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x4d, 0x61, + 0x70, 0x50, 0x65, 0x72, 0x73, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x63, 0x65, 0x12, 0x27, 0x2e, 0x64, + 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x2e, 0x53, 0x65, 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, + 0x4d, 0x61, 0x70, 0x50, 0x65, 0x72, 0x73, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x63, 0x65, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x28, 0x2e, 0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x2e, 0x53, + 0x65, 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x4d, 0x61, 0x70, 0x50, 0x65, 0x72, 0x73, + 0x69, 0x73, 0x74, 0x65, 0x6e, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, + 0x00, 0x42, 0x08, 0x5a, 0x06, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x33, } var ( @@ -2474,50 +2572,52 @@ func file_daemon_proto_rawDescGZIP() []byte { } var file_daemon_proto_enumTypes = make([]protoimpl.EnumInfo, 1) -var file_daemon_proto_msgTypes = make([]protoimpl.MessageInfo, 32) +var file_daemon_proto_msgTypes = make([]protoimpl.MessageInfo, 34) var file_daemon_proto_goTypes = []interface{}{ - (LogLevel)(0), // 0: daemon.LogLevel - (*LoginRequest)(nil), // 1: daemon.LoginRequest - (*LoginResponse)(nil), // 2: daemon.LoginResponse - (*WaitSSOLoginRequest)(nil), // 3: daemon.WaitSSOLoginRequest - (*WaitSSOLoginResponse)(nil), // 4: daemon.WaitSSOLoginResponse - (*UpRequest)(nil), // 5: daemon.UpRequest - (*UpResponse)(nil), // 6: daemon.UpResponse - (*StatusRequest)(nil), // 7: daemon.StatusRequest - (*StatusResponse)(nil), // 8: daemon.StatusResponse - (*DownRequest)(nil), // 9: daemon.DownRequest - (*DownResponse)(nil), // 10: daemon.DownResponse - (*GetConfigRequest)(nil), // 11: daemon.GetConfigRequest - (*GetConfigResponse)(nil), // 12: daemon.GetConfigResponse - (*PeerState)(nil), // 13: daemon.PeerState - (*LocalPeerState)(nil), // 14: daemon.LocalPeerState - (*SignalState)(nil), // 15: daemon.SignalState - (*ManagementState)(nil), // 16: daemon.ManagementState - (*RelayState)(nil), // 17: daemon.RelayState - (*NSGroupState)(nil), // 18: daemon.NSGroupState - (*FullStatus)(nil), // 19: daemon.FullStatus - (*ListRoutesRequest)(nil), // 20: daemon.ListRoutesRequest - (*ListRoutesResponse)(nil), // 21: daemon.ListRoutesResponse - (*SelectRoutesRequest)(nil), // 22: daemon.SelectRoutesRequest - (*SelectRoutesResponse)(nil), // 23: daemon.SelectRoutesResponse - (*IPList)(nil), // 24: daemon.IPList - (*Route)(nil), // 25: daemon.Route - (*DebugBundleRequest)(nil), // 26: daemon.DebugBundleRequest - (*DebugBundleResponse)(nil), // 27: daemon.DebugBundleResponse - (*GetLogLevelRequest)(nil), // 28: daemon.GetLogLevelRequest - (*GetLogLevelResponse)(nil), // 29: daemon.GetLogLevelResponse - (*SetLogLevelRequest)(nil), // 30: daemon.SetLogLevelRequest - (*SetLogLevelResponse)(nil), // 31: daemon.SetLogLevelResponse - nil, // 32: daemon.Route.ResolvedIPsEntry - (*durationpb.Duration)(nil), // 33: google.protobuf.Duration - (*timestamppb.Timestamp)(nil), // 34: google.protobuf.Timestamp + (LogLevel)(0), // 0: daemon.LogLevel + (*LoginRequest)(nil), // 1: daemon.LoginRequest + (*LoginResponse)(nil), // 2: daemon.LoginResponse + (*WaitSSOLoginRequest)(nil), // 3: daemon.WaitSSOLoginRequest + (*WaitSSOLoginResponse)(nil), // 4: daemon.WaitSSOLoginResponse + (*UpRequest)(nil), // 5: daemon.UpRequest + (*UpResponse)(nil), // 6: daemon.UpResponse + (*StatusRequest)(nil), // 7: daemon.StatusRequest + (*StatusResponse)(nil), // 8: daemon.StatusResponse + (*DownRequest)(nil), // 9: daemon.DownRequest + (*DownResponse)(nil), // 10: daemon.DownResponse + (*GetConfigRequest)(nil), // 11: daemon.GetConfigRequest + (*GetConfigResponse)(nil), // 12: daemon.GetConfigResponse + (*PeerState)(nil), // 13: daemon.PeerState + (*LocalPeerState)(nil), // 14: daemon.LocalPeerState + (*SignalState)(nil), // 15: daemon.SignalState + (*ManagementState)(nil), // 16: daemon.ManagementState + (*RelayState)(nil), // 17: daemon.RelayState + (*NSGroupState)(nil), // 18: daemon.NSGroupState + (*FullStatus)(nil), // 19: daemon.FullStatus + (*ListRoutesRequest)(nil), // 20: daemon.ListRoutesRequest + (*ListRoutesResponse)(nil), // 21: daemon.ListRoutesResponse + (*SelectRoutesRequest)(nil), // 22: daemon.SelectRoutesRequest + (*SelectRoutesResponse)(nil), // 23: daemon.SelectRoutesResponse + (*IPList)(nil), // 24: daemon.IPList + (*Route)(nil), // 25: daemon.Route + (*DebugBundleRequest)(nil), // 26: daemon.DebugBundleRequest + (*DebugBundleResponse)(nil), // 27: daemon.DebugBundleResponse + (*GetLogLevelRequest)(nil), // 28: daemon.GetLogLevelRequest + (*GetLogLevelResponse)(nil), // 29: daemon.GetLogLevelResponse + (*SetLogLevelRequest)(nil), // 30: daemon.SetLogLevelRequest + (*SetLogLevelResponse)(nil), // 31: daemon.SetLogLevelResponse + (*SetNetworkMapPersistenceRequest)(nil), // 32: daemon.SetNetworkMapPersistenceRequest + (*SetNetworkMapPersistenceResponse)(nil), // 33: daemon.SetNetworkMapPersistenceResponse + nil, // 34: daemon.Route.ResolvedIPsEntry + (*durationpb.Duration)(nil), // 35: google.protobuf.Duration + (*timestamppb.Timestamp)(nil), // 36: google.protobuf.Timestamp } var file_daemon_proto_depIdxs = []int32{ - 33, // 0: daemon.LoginRequest.dnsRouteInterval:type_name -> google.protobuf.Duration + 35, // 0: daemon.LoginRequest.dnsRouteInterval:type_name -> google.protobuf.Duration 19, // 1: daemon.StatusResponse.fullStatus:type_name -> daemon.FullStatus - 34, // 2: daemon.PeerState.connStatusUpdate:type_name -> google.protobuf.Timestamp - 34, // 3: daemon.PeerState.lastWireguardHandshake:type_name -> google.protobuf.Timestamp - 33, // 4: daemon.PeerState.latency:type_name -> google.protobuf.Duration + 36, // 2: daemon.PeerState.connStatusUpdate:type_name -> google.protobuf.Timestamp + 36, // 3: daemon.PeerState.lastWireguardHandshake:type_name -> google.protobuf.Timestamp + 35, // 4: daemon.PeerState.latency:type_name -> google.protobuf.Duration 16, // 5: daemon.FullStatus.managementState:type_name -> daemon.ManagementState 15, // 6: daemon.FullStatus.signalState:type_name -> daemon.SignalState 14, // 7: daemon.FullStatus.localPeerState:type_name -> daemon.LocalPeerState @@ -2525,7 +2625,7 @@ var file_daemon_proto_depIdxs = []int32{ 17, // 9: daemon.FullStatus.relays:type_name -> daemon.RelayState 18, // 10: daemon.FullStatus.dns_servers:type_name -> daemon.NSGroupState 25, // 11: daemon.ListRoutesResponse.routes:type_name -> daemon.Route - 32, // 12: daemon.Route.resolvedIPs:type_name -> daemon.Route.ResolvedIPsEntry + 34, // 12: daemon.Route.resolvedIPs:type_name -> daemon.Route.ResolvedIPsEntry 0, // 13: daemon.GetLogLevelResponse.level:type_name -> daemon.LogLevel 0, // 14: daemon.SetLogLevelRequest.level:type_name -> daemon.LogLevel 24, // 15: daemon.Route.ResolvedIPsEntry.value:type_name -> daemon.IPList @@ -2541,20 +2641,22 @@ var file_daemon_proto_depIdxs = []int32{ 26, // 25: daemon.DaemonService.DebugBundle:input_type -> daemon.DebugBundleRequest 28, // 26: daemon.DaemonService.GetLogLevel:input_type -> daemon.GetLogLevelRequest 30, // 27: daemon.DaemonService.SetLogLevel:input_type -> daemon.SetLogLevelRequest - 2, // 28: daemon.DaemonService.Login:output_type -> daemon.LoginResponse - 4, // 29: daemon.DaemonService.WaitSSOLogin:output_type -> daemon.WaitSSOLoginResponse - 6, // 30: daemon.DaemonService.Up:output_type -> daemon.UpResponse - 8, // 31: daemon.DaemonService.Status:output_type -> daemon.StatusResponse - 10, // 32: daemon.DaemonService.Down:output_type -> daemon.DownResponse - 12, // 33: daemon.DaemonService.GetConfig:output_type -> daemon.GetConfigResponse - 21, // 34: daemon.DaemonService.ListRoutes:output_type -> daemon.ListRoutesResponse - 23, // 35: daemon.DaemonService.SelectRoutes:output_type -> daemon.SelectRoutesResponse - 23, // 36: daemon.DaemonService.DeselectRoutes:output_type -> daemon.SelectRoutesResponse - 27, // 37: daemon.DaemonService.DebugBundle:output_type -> daemon.DebugBundleResponse - 29, // 38: daemon.DaemonService.GetLogLevel:output_type -> daemon.GetLogLevelResponse - 31, // 39: daemon.DaemonService.SetLogLevel:output_type -> daemon.SetLogLevelResponse - 28, // [28:40] is the sub-list for method output_type - 16, // [16:28] is the sub-list for method input_type + 32, // 28: daemon.DaemonService.SetNetworkMapPersistence:input_type -> daemon.SetNetworkMapPersistenceRequest + 2, // 29: daemon.DaemonService.Login:output_type -> daemon.LoginResponse + 4, // 30: daemon.DaemonService.WaitSSOLogin:output_type -> daemon.WaitSSOLoginResponse + 6, // 31: daemon.DaemonService.Up:output_type -> daemon.UpResponse + 8, // 32: daemon.DaemonService.Status:output_type -> daemon.StatusResponse + 10, // 33: daemon.DaemonService.Down:output_type -> daemon.DownResponse + 12, // 34: daemon.DaemonService.GetConfig:output_type -> daemon.GetConfigResponse + 21, // 35: daemon.DaemonService.ListRoutes:output_type -> daemon.ListRoutesResponse + 23, // 36: daemon.DaemonService.SelectRoutes:output_type -> daemon.SelectRoutesResponse + 23, // 37: daemon.DaemonService.DeselectRoutes:output_type -> daemon.SelectRoutesResponse + 27, // 38: daemon.DaemonService.DebugBundle:output_type -> daemon.DebugBundleResponse + 29, // 39: daemon.DaemonService.GetLogLevel:output_type -> daemon.GetLogLevelResponse + 31, // 40: daemon.DaemonService.SetLogLevel:output_type -> daemon.SetLogLevelResponse + 33, // 41: daemon.DaemonService.SetNetworkMapPersistence:output_type -> daemon.SetNetworkMapPersistenceResponse + 29, // [29:42] is the sub-list for method output_type + 16, // [16:29] is the sub-list for method input_type 16, // [16:16] is the sub-list for extension type_name 16, // [16:16] is the sub-list for extension extendee 0, // [0:16] is the sub-list for field type_name @@ -2938,6 +3040,30 @@ func file_daemon_proto_init() { return nil } } + file_daemon_proto_msgTypes[31].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SetNetworkMapPersistenceRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_daemon_proto_msgTypes[32].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SetNetworkMapPersistenceResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } } file_daemon_proto_msgTypes[0].OneofWrappers = []interface{}{} type x struct{} @@ -2946,7 +3072,7 @@ func file_daemon_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_daemon_proto_rawDesc, NumEnums: 1, - NumMessages: 32, + NumMessages: 34, NumExtensions: 0, NumServices: 1, }, diff --git a/client/proto/daemon.proto b/client/proto/daemon.proto index 384bc0e6206..04aa6688262 100644 --- a/client/proto/daemon.proto +++ b/client/proto/daemon.proto @@ -45,7 +45,11 @@ service DaemonService { // SetLogLevel sets the log level of the daemon rpc SetLogLevel(SetLogLevelRequest) returns (SetLogLevelResponse) {} -}; + + // SetNetworkMapPersistence enables or disables network map persistence + rpc SetNetworkMapPersistence(SetNetworkMapPersistenceRequest) returns (SetNetworkMapPersistenceResponse) {} +} + message LoginRequest { // setupKey wiretrustee setup key. @@ -293,4 +297,10 @@ message SetLogLevelRequest { } message SetLogLevelResponse { -} \ No newline at end of file +} + +message SetNetworkMapPersistenceRequest { + bool enabled = 1; +} + +message SetNetworkMapPersistenceResponse {} diff --git a/client/proto/daemon_grpc.pb.go b/client/proto/daemon_grpc.pb.go index e0bc117e52d..31645763e0c 100644 --- a/client/proto/daemon_grpc.pb.go +++ b/client/proto/daemon_grpc.pb.go @@ -43,6 +43,8 @@ type DaemonServiceClient interface { GetLogLevel(ctx context.Context, in *GetLogLevelRequest, opts ...grpc.CallOption) (*GetLogLevelResponse, error) // SetLogLevel sets the log level of the daemon SetLogLevel(ctx context.Context, in *SetLogLevelRequest, opts ...grpc.CallOption) (*SetLogLevelResponse, error) + // SetNetworkMapPersistence enables or disables network map persistence + SetNetworkMapPersistence(ctx context.Context, in *SetNetworkMapPersistenceRequest, opts ...grpc.CallOption) (*SetNetworkMapPersistenceResponse, error) } type daemonServiceClient struct { @@ -161,6 +163,15 @@ func (c *daemonServiceClient) SetLogLevel(ctx context.Context, in *SetLogLevelRe return out, nil } +func (c *daemonServiceClient) SetNetworkMapPersistence(ctx context.Context, in *SetNetworkMapPersistenceRequest, opts ...grpc.CallOption) (*SetNetworkMapPersistenceResponse, error) { + out := new(SetNetworkMapPersistenceResponse) + err := c.cc.Invoke(ctx, "/daemon.DaemonService/SetNetworkMapPersistence", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // DaemonServiceServer is the server API for DaemonService service. // All implementations must embed UnimplementedDaemonServiceServer // for forward compatibility @@ -190,6 +201,8 @@ type DaemonServiceServer interface { GetLogLevel(context.Context, *GetLogLevelRequest) (*GetLogLevelResponse, error) // SetLogLevel sets the log level of the daemon SetLogLevel(context.Context, *SetLogLevelRequest) (*SetLogLevelResponse, error) + // SetNetworkMapPersistence enables or disables network map persistence + SetNetworkMapPersistence(context.Context, *SetNetworkMapPersistenceRequest) (*SetNetworkMapPersistenceResponse, error) mustEmbedUnimplementedDaemonServiceServer() } @@ -233,6 +246,9 @@ func (UnimplementedDaemonServiceServer) GetLogLevel(context.Context, *GetLogLeve func (UnimplementedDaemonServiceServer) SetLogLevel(context.Context, *SetLogLevelRequest) (*SetLogLevelResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method SetLogLevel not implemented") } +func (UnimplementedDaemonServiceServer) SetNetworkMapPersistence(context.Context, *SetNetworkMapPersistenceRequest) (*SetNetworkMapPersistenceResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method SetNetworkMapPersistence not implemented") +} func (UnimplementedDaemonServiceServer) mustEmbedUnimplementedDaemonServiceServer() {} // UnsafeDaemonServiceServer may be embedded to opt out of forward compatibility for this service. @@ -462,6 +478,24 @@ func _DaemonService_SetLogLevel_Handler(srv interface{}, ctx context.Context, de return interceptor(ctx, in, info, handler) } +func _DaemonService_SetNetworkMapPersistence_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(SetNetworkMapPersistenceRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(DaemonServiceServer).SetNetworkMapPersistence(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/daemon.DaemonService/SetNetworkMapPersistence", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(DaemonServiceServer).SetNetworkMapPersistence(ctx, req.(*SetNetworkMapPersistenceRequest)) + } + return interceptor(ctx, in, info, handler) +} + // DaemonService_ServiceDesc is the grpc.ServiceDesc for DaemonService service. // It's only intended for direct use with grpc.RegisterService, // and not to be introspected or modified (even as a copy) @@ -517,6 +551,10 @@ var DaemonService_ServiceDesc = grpc.ServiceDesc{ MethodName: "SetLogLevel", Handler: _DaemonService_SetLogLevel_Handler, }, + { + MethodName: "SetNetworkMapPersistence", + Handler: _DaemonService_SetNetworkMapPersistence_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "daemon.proto", diff --git a/client/server/debug.go b/client/server/debug.go index 5ed43293b4a..fc9add7f51f 100644 --- a/client/server/debug.go +++ b/client/server/debug.go @@ -5,7 +5,9 @@ package server import ( "archive/zip" "bufio" + "bytes" "context" + "errors" "fmt" "io" "net" @@ -15,12 +17,14 @@ import ( "strings" "time" + "buf.build/go/protoyaml" log "github.com/sirupsen/logrus" "github.com/netbirdio/netbird/client/anonymize" "github.com/netbirdio/netbird/client/internal/peer" "github.com/netbirdio/netbird/client/internal/routemanager/systemops" "github.com/netbirdio/netbird/client/proto" + mgmProto "github.com/netbirdio/netbird/management/proto" ) const readmeContent = `Netbird debug bundle @@ -31,6 +35,7 @@ client.log: Most recent, anonymized log file of the NetBird client. routes.txt: Anonymized system routes, if --system-info flag was provided. interfaces.txt: Anonymized network interface information, if --system-info flag was provided. config.txt: Anonymized configuration information of the NetBird client. +network_map.yaml: Anonymized network map containing peer configurations, routes, DNS settings, and firewall rules. Anonymization Process @@ -50,8 +55,19 @@ Domains All domain names (except for the netbird domains) are replaced with randomly generated strings ending in ".domain". Anonymized domains are consistent across all files in the bundle. Reoccuring domain names are replaced with the same anonymized domain. +Network Map +The network_map.json file contains the following anonymized information: +- Peer configurations (addresses, FQDNs, DNS settings) +- Remote and offline peer information (allowed IPs, FQDNs) +- Routes (network ranges, associated domains) +- DNS configuration (nameservers, domains, custom zones) +- Firewall rules (peer IPs, source/destination ranges) + +SSH keys in the network map are replaced with a placeholder value. All IP addresses and domains in the network map follow the same anonymization rules as described above. + Routes For anonymized routes, the IP addresses are replaced as described above. The prefix length remains unchanged. Note that for prefixes, the anonymized IP might not be a network address, but the prefix length is still correct. + Network Interfaces The interfaces.txt file contains information about network interfaces, including: - Interface name @@ -119,19 +135,23 @@ func (s *Server) createArchive(bundlePath *os.File, req *proto.DebugBundleReques seedFromStatus(anonymizer, &status) if err := s.addConfig(req, anonymizer, archive); err != nil { - return fmt.Errorf("add config: %w", err) + log.Errorf("Failed to add config to debug bundle: %v", err) } if req.GetSystemInfo() { if err := s.addRoutes(req, anonymizer, archive); err != nil { - return fmt.Errorf("add routes: %w", err) + log.Errorf("Failed to add routes to debug bundle: %v", err) } if err := s.addInterfaces(req, anonymizer, archive); err != nil { - return fmt.Errorf("add interfaces: %w", err) + log.Errorf("Failed to add interfaces to debug bundle: %v", err) } } + if err := s.addNetworkMap(req, anonymizer, archive); err != nil { + return fmt.Errorf("add network map: %w", err) + } + if err := s.addLogfile(req, anonymizer, archive); err != nil { return fmt.Errorf("add log file: %w", err) } @@ -220,15 +240,16 @@ func (s *Server) addCommonConfigFields(configContent *strings.Builder) { } func (s *Server) addRoutes(req *proto.DebugBundleRequest, anonymizer *anonymize.Anonymizer, archive *zip.Writer) error { - if routes, err := systemops.GetRoutesFromTable(); err != nil { - log.Errorf("Failed to get routes: %v", err) - } else { - // TODO: get routes including nexthop - routesContent := formatRoutes(routes, req.GetAnonymize(), anonymizer) - routesReader := strings.NewReader(routesContent) - if err := addFileToZip(archive, routesReader, "routes.txt"); err != nil { - return fmt.Errorf("add routes file to zip: %w", err) - } + routes, err := systemops.GetRoutesFromTable() + if err != nil { + return fmt.Errorf("get routes: %w", err) + } + + // TODO: get routes including nexthop + routesContent := formatRoutes(routes, req.GetAnonymize(), anonymizer) + routesReader := strings.NewReader(routesContent) + if err := addFileToZip(archive, routesReader, "routes.txt"); err != nil { + return fmt.Errorf("add routes file to zip: %w", err) } return nil } @@ -248,6 +269,39 @@ func (s *Server) addInterfaces(req *proto.DebugBundleRequest, anonymizer *anonym return nil } +func (s *Server) addNetworkMap(req *proto.DebugBundleRequest, anonymizer *anonymize.Anonymizer, archive *zip.Writer) error { + networkMap, err := s.getLatestNetworkMap() + if err != nil { + // Skip if network map is not available, but log it + log.Debugf("skipping empty network map in debug bundle: %v", err) + return nil + } + + if req.GetAnonymize() { + if err := anonymizeNetworkMap(networkMap, anonymizer); err != nil { + return fmt.Errorf("anonymize network map: %w", err) + } + } + + options := protoyaml.MarshalOptions{ + EmitUnpopulated: true, + UseProtoNames: true, + Indent: 2, + AllowPartial: true, + } + + yamlBytes, err := options.Marshal(networkMap) + if err != nil { + return fmt.Errorf("generate yaml: %w", err) + } + + if err := addFileToZip(archive, bytes.NewReader(yamlBytes), "network_map.yaml"); err != nil { + return fmt.Errorf("add network map to zip: %w", err) + } + + return nil +} + func (s *Server) addLogfile(req *proto.DebugBundleRequest, anonymizer *anonymize.Anonymizer, archive *zip.Writer) (err error) { logFile, err := os.Open(s.logFile) if err != nil { @@ -295,14 +349,43 @@ func (s *Server) anonymize(reader io.Reader, writer *io.PipeWriter, anonymizer * } } +// getLatestNetworkMap returns the latest network map from the engine if network map persistence is enabled +func (s *Server) getLatestNetworkMap() (*mgmProto.NetworkMap, error) { + if s.connectClient == nil { + return nil, errors.New("connect client is not initialized") + } + + engine := s.connectClient.Engine() + if engine == nil { + return nil, errors.New("engine is not initialized") + } + + networkMap, err := engine.GetLatestNetworkMap() + if err != nil { + return nil, fmt.Errorf("get latest network map: %w", err) + } + + if networkMap == nil { + return nil, errors.New("network map is not available") + } + + return networkMap, nil +} + // GetLogLevel gets the current logging level for the server. func (s *Server) GetLogLevel(_ context.Context, _ *proto.GetLogLevelRequest) (*proto.GetLogLevelResponse, error) { + s.mutex.Lock() + defer s.mutex.Unlock() + level := ParseLogLevel(log.GetLevel().String()) return &proto.GetLogLevelResponse{Level: level}, nil } // SetLogLevel sets the logging level for the server. func (s *Server) SetLogLevel(_ context.Context, req *proto.SetLogLevelRequest) (*proto.SetLogLevelResponse, error) { + s.mutex.Lock() + defer s.mutex.Unlock() + level, err := log.ParseLevel(req.Level.String()) if err != nil { return nil, fmt.Errorf("invalid log level: %w", err) @@ -313,6 +396,20 @@ func (s *Server) SetLogLevel(_ context.Context, req *proto.SetLogLevelRequest) ( return &proto.SetLogLevelResponse{}, nil } +// SetNetworkMapPersistence sets the network map persistence for the server. +func (s *Server) SetNetworkMapPersistence(_ context.Context, req *proto.SetNetworkMapPersistenceRequest) (*proto.SetNetworkMapPersistenceResponse, error) { + s.mutex.Lock() + defer s.mutex.Unlock() + + enabled := req.GetEnabled() + s.persistNetworkMap = enabled + if s.connectClient != nil { + s.connectClient.SetNetworkMapPersistence(enabled) + } + + return &proto.SetNetworkMapPersistenceResponse{}, nil +} + func addFileToZip(archive *zip.Writer, reader io.Reader, filename string) error { header := &zip.FileHeader{ Name: filename, @@ -484,3 +581,174 @@ func anonymizeNATExternalIPs(ips []string, anonymizer *anonymize.Anonymizer) []s } return anonymizedIPs } + +func anonymizeNetworkMap(networkMap *mgmProto.NetworkMap, anonymizer *anonymize.Anonymizer) error { + if networkMap.PeerConfig != nil { + anonymizePeerConfig(networkMap.PeerConfig, anonymizer) + } + + for _, peer := range networkMap.RemotePeers { + anonymizeRemotePeer(peer, anonymizer) + } + + for _, peer := range networkMap.OfflinePeers { + anonymizeRemotePeer(peer, anonymizer) + } + + for _, r := range networkMap.Routes { + anonymizeRoute(r, anonymizer) + } + + if networkMap.DNSConfig != nil { + anonymizeDNSConfig(networkMap.DNSConfig, anonymizer) + } + + for _, rule := range networkMap.FirewallRules { + anonymizeFirewallRule(rule, anonymizer) + } + + for _, rule := range networkMap.RoutesFirewallRules { + anonymizeRouteFirewallRule(rule, anonymizer) + } + + return nil +} + +func anonymizePeerConfig(config *mgmProto.PeerConfig, anonymizer *anonymize.Anonymizer) { + if config == nil { + return + } + + if addr, err := netip.ParseAddr(config.Address); err == nil { + config.Address = anonymizer.AnonymizeIP(addr).String() + } + + if config.SshConfig != nil && len(config.SshConfig.SshPubKey) > 0 { + config.SshConfig.SshPubKey = []byte("ssh-placeholder-key") + } + + config.Dns = anonymizer.AnonymizeString(config.Dns) + config.Fqdn = anonymizer.AnonymizeDomain(config.Fqdn) +} + +func anonymizeRemotePeer(peer *mgmProto.RemotePeerConfig, anonymizer *anonymize.Anonymizer) { + if peer == nil { + return + } + + for i, ip := range peer.AllowedIps { + // Try to parse as prefix first (CIDR) + if prefix, err := netip.ParsePrefix(ip); err == nil { + anonIP := anonymizer.AnonymizeIP(prefix.Addr()) + peer.AllowedIps[i] = fmt.Sprintf("%s/%d", anonIP, prefix.Bits()) + } else if addr, err := netip.ParseAddr(ip); err == nil { + peer.AllowedIps[i] = anonymizer.AnonymizeIP(addr).String() + } + } + + peer.Fqdn = anonymizer.AnonymizeDomain(peer.Fqdn) + + if peer.SshConfig != nil && len(peer.SshConfig.SshPubKey) > 0 { + peer.SshConfig.SshPubKey = []byte("ssh-placeholder-key") + } +} + +func anonymizeRoute(route *mgmProto.Route, anonymizer *anonymize.Anonymizer) { + if route == nil { + return + } + + if prefix, err := netip.ParsePrefix(route.Network); err == nil { + anonIP := anonymizer.AnonymizeIP(prefix.Addr()) + route.Network = fmt.Sprintf("%s/%d", anonIP, prefix.Bits()) + } + + for i, domain := range route.Domains { + route.Domains[i] = anonymizer.AnonymizeDomain(domain) + } + + route.NetID = anonymizer.AnonymizeString(route.NetID) +} + +func anonymizeDNSConfig(config *mgmProto.DNSConfig, anonymizer *anonymize.Anonymizer) { + if config == nil { + return + } + + anonymizeNameServerGroups(config.NameServerGroups, anonymizer) + anonymizeCustomZones(config.CustomZones, anonymizer) +} + +func anonymizeNameServerGroups(groups []*mgmProto.NameServerGroup, anonymizer *anonymize.Anonymizer) { + for _, group := range groups { + anonymizeServers(group.NameServers, anonymizer) + anonymizeDomains(group.Domains, anonymizer) + } +} + +func anonymizeServers(servers []*mgmProto.NameServer, anonymizer *anonymize.Anonymizer) { + for _, server := range servers { + if addr, err := netip.ParseAddr(server.IP); err == nil { + server.IP = anonymizer.AnonymizeIP(addr).String() + } + } +} + +func anonymizeDomains(domains []string, anonymizer *anonymize.Anonymizer) { + for i, domain := range domains { + domains[i] = anonymizer.AnonymizeDomain(domain) + } +} + +func anonymizeCustomZones(zones []*mgmProto.CustomZone, anonymizer *anonymize.Anonymizer) { + for _, zone := range zones { + zone.Domain = anonymizer.AnonymizeDomain(zone.Domain) + anonymizeRecords(zone.Records, anonymizer) + } +} + +func anonymizeRecords(records []*mgmProto.SimpleRecord, anonymizer *anonymize.Anonymizer) { + for _, record := range records { + record.Name = anonymizer.AnonymizeDomain(record.Name) + anonymizeRData(record, anonymizer) + } +} + +func anonymizeRData(record *mgmProto.SimpleRecord, anonymizer *anonymize.Anonymizer) { + switch record.Type { + case 1, 28: // A or AAAA record + if addr, err := netip.ParseAddr(record.RData); err == nil { + record.RData = anonymizer.AnonymizeIP(addr).String() + } + default: + record.RData = anonymizer.AnonymizeString(record.RData) + } +} + +func anonymizeFirewallRule(rule *mgmProto.FirewallRule, anonymizer *anonymize.Anonymizer) { + if rule == nil { + return + } + + if addr, err := netip.ParseAddr(rule.PeerIP); err == nil { + rule.PeerIP = anonymizer.AnonymizeIP(addr).String() + } +} + +func anonymizeRouteFirewallRule(rule *mgmProto.RouteFirewallRule, anonymizer *anonymize.Anonymizer) { + if rule == nil { + return + } + + for i, sourceRange := range rule.SourceRanges { + if prefix, err := netip.ParsePrefix(sourceRange); err == nil { + anonIP := anonymizer.AnonymizeIP(prefix.Addr()) + rule.SourceRanges[i] = fmt.Sprintf("%s/%d", anonIP, prefix.Bits()) + } + } + + if prefix, err := netip.ParsePrefix(rule.Destination); err == nil { + anonIP := anonymizer.AnonymizeIP(prefix.Addr()) + rule.Destination = fmt.Sprintf("%s/%d", anonIP, prefix.Bits()) + } +} diff --git a/client/server/server.go b/client/server/server.go index 106bdf32bbf..71eb58a66bc 100644 --- a/client/server/server.go +++ b/client/server/server.go @@ -68,6 +68,8 @@ type Server struct { relayProbe *internal.Probe wgProbe *internal.Probe lastProbe time.Time + + persistNetworkMap bool } type oauthAuthFlow struct { @@ -196,6 +198,7 @@ func (s *Server) connectWithRetryRuns(ctx context.Context, config *internal.Conf runOperation := func() error { log.Tracef("running client connection") s.connectClient = internal.NewConnectClient(ctx, config, statusRecorder) + s.connectClient.SetNetworkMapPersistence(s.persistNetworkMap) probes := internal.ProbeHolder{ MgmProbe: s.mgmProbe, diff --git a/go.mod b/go.mod index e8c65542280..66ad346ec8d 100644 --- a/go.mod +++ b/go.mod @@ -25,11 +25,12 @@ require ( golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6 golang.zx2c4.com/wireguard/windows v0.5.3 google.golang.org/grpc v1.64.1 - google.golang.org/protobuf v1.34.1 + google.golang.org/protobuf v1.34.2 gopkg.in/natefinch/lumberjack.v2 v2.0.0 ) require ( + buf.build/go/protoyaml v0.2.0 fyne.io/fyne/v2 v2.5.0 fyne.io/systray v1.11.0 github.com/TheJumpCloud/jcapi-go v3.0.0+incompatible @@ -103,6 +104,7 @@ require ( ) require ( + buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.34.2-20240717164558-a6c49f84cc0f.2 // indirect cloud.google.com/go/auth v0.3.0 // indirect cloud.google.com/go/auth/oauth2adapt v0.2.2 // indirect cloud.google.com/go/compute/metadata v0.3.0 // indirect @@ -113,6 +115,7 @@ require ( github.com/Microsoft/hcsshim v0.12.3 // 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/antlr4-go/antlr/v4 v4.13.0 // indirect github.com/aws/aws-sdk-go-v2 v1.30.3 // indirect github.com/aws/aws-sdk-go-v2/config v1.27.27 // indirect github.com/aws/aws-sdk-go-v2/credentials v1.17.27 // indirect @@ -129,6 +132,7 @@ require ( github.com/aws/smithy-go v1.20.3 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/bradfitz/gomemcache v0.0.0-20220106215444-fb4bf637b56d // indirect + github.com/bufbuild/protovalidate-go v0.6.3 // indirect github.com/caddyserver/zerossl v0.1.3 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/containerd/containerd v1.7.16 // indirect @@ -156,6 +160,7 @@ require ( github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/google/btree v1.1.2 // indirect + github.com/google/cel-go v0.21.0 // indirect github.com/google/s2a-go v0.1.7 // indirect github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect github.com/googleapis/gax-go/v2 v2.12.3 // indirect @@ -207,6 +212,7 @@ require ( github.com/spf13/cast v1.5.0 // indirect github.com/srwiley/oksvg v0.0.0-20221011165216-be6e8873101c // indirect github.com/srwiley/rasterx v0.0.0-20220730225603-2ab79fcdd4ef // indirect + github.com/stoewer/go-strcase v1.3.0 // indirect github.com/tklauser/go-sysconf v0.3.14 // indirect github.com/tklauser/numcpus v0.8.0 // indirect github.com/vishvananda/netns v0.0.4 // indirect @@ -224,7 +230,7 @@ require ( golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20240509183442-62759503f434 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240515191416-fc5f0ca64291 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 // indirect gopkg.in/square/go-jose.v2 v2.6.0 // indirect gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect gopkg.in/tomb.v2 v2.0.0-20161208151619-d5d1b5820637 // indirect diff --git a/go.sum b/go.sum index 47975d4eab4..b7da4f8bd6a 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,7 @@ +buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.34.2-20240717164558-a6c49f84cc0f.2 h1:SZRVx928rbYZ6hEKUIN+vtGDkl7uotABRWGY4OAg5gM= +buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.34.2-20240717164558-a6c49f84cc0f.2/go.mod h1:ylS4c28ACSI59oJrOdW4pHS4n0Hw4TgSPHn8rpHl4Yw= +buf.build/go/protoyaml v0.2.0 h1:2g3OHjtLDqXBREIOjpZGHmQ+U/4mkN1YiQjxNB68Ip8= +buf.build/go/protoyaml v0.2.0/go.mod h1:L/9QvTDkTWcDTzAL6HMfN+mYC6CmZRm2KnsUA054iL0= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= @@ -76,6 +80,8 @@ github.com/allegro/bigcache/v3 v3.0.2/go.mod h1:aPyh7jEvrog9zAwx5N7+JUQX5dZTSGpx github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8= github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= +github.com/antlr4-go/antlr/v4 v4.13.0 h1:lxCg3LAv+EUK6t1i0y1V6/SLeUi0eKEKdhQAlS8TVTI= +github.com/antlr4-go/antlr/v4 v4.13.0/go.mod h1:pfChB/xh/Unjila75QW7+VU4TSnWnnk9UTnmpPaOR2g= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= @@ -113,6 +119,8 @@ github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kB github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqOes/6LfM= github.com/bradfitz/gomemcache v0.0.0-20220106215444-fb4bf637b56d h1:pVrfxiGfwelyab6n21ZBkbkmbevaf+WvMIiR7sr97hw= github.com/bradfitz/gomemcache v0.0.0-20220106215444-fb4bf637b56d/go.mod h1:H0wQNHz2YrLsuXOZozoeDmnHXkNCRmMW0gwFWDfEZDA= +github.com/bufbuild/protovalidate-go v0.6.3 h1:wxQyzW035zM16Binbaz/nWAzS12dRIXhZdSUWRY7Fv0= +github.com/bufbuild/protovalidate-go v0.6.3/go.mod h1:J4PtwP9Z2YAGgB0+o+tTWEDtLtXvz/gfhFZD8pbzM/U= github.com/c-robinson/iplib v1.0.3 h1:NG0UF0GoEsrC1/vyfX1Lx2Ss7CySWl3KqqXh3q4DdPU= github.com/c-robinson/iplib v1.0.3/go.mod h1:i3LuuFL1hRT5gFpBRnEydzw8R6yhGkF4szNDIbF8pgo= github.com/caddyserver/certmagic v0.21.3 h1:pqRRry3yuB4CWBVq9+cUqu+Y6E2z8TswbhNx1AZeYm0= @@ -184,6 +192,8 @@ github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5y github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/envoyproxy/protoc-gen-validate v1.0.4 h1:gVPz/FMfvh57HdSJQyvBtF00j8JU4zdyUgIUNhlgg0A= +github.com/envoyproxy/protoc-gen-validate v1.0.4/go.mod h1:qys6tmnRsYrQqIhm2bvKZH4Blx/1gTIZ2UKVY1M+Yew= github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/felixge/fgprof v0.9.3 h1:VvyZxILNuCiUCSXtPtYmmtGvb65nqXh2QFWc0Wpf2/g= @@ -299,6 +309,8 @@ github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Z github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU= github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= +github.com/google/cel-go v0.21.0 h1:cl6uW/gxN+Hy50tNYvI691+sXxioCnstFzLp2WO4GCI= +github.com/google/cel-go v0.21.0/go.mod h1:rHUlWCcBKgyEk+eV03RPdZUekPp6YcJwV0FxuUksYxc= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= @@ -658,6 +670,8 @@ github.com/srwiley/oksvg v0.0.0-20221011165216-be6e8873101c h1:km8GpoQut05eY3GiY github.com/srwiley/oksvg v0.0.0-20221011165216-be6e8873101c/go.mod h1:cNQ3dwVJtS5Hmnjxy6AgTPd0Inb3pW05ftPSX7NZO7Q= github.com/srwiley/rasterx v0.0.0-20220730225603-2ab79fcdd4ef h1:Ch6Q+AZUxDBCVqdkI8FSpFyZDtCVBc2VmejdNrm5rRQ= github.com/srwiley/rasterx v0.0.0-20220730225603-2ab79fcdd4ef/go.mod h1:nXTWP6+gD5+LUJ8krVhhoeHjvHTutPxMYl5SvkcnJNE= +github.com/stoewer/go-strcase v1.3.0 h1:g0eASXYtp+yvN9fK8sH94oCIk0fau9uV1/ZdJ0AVEzs= +github.com/stoewer/go-strcase v1.3.0/go.mod h1:fAH5hQ5pehh+j3nZfvwdk2RgEgQjAoM8wodgtPmh1xo= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= @@ -1151,8 +1165,8 @@ google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaE google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= google.golang.org/genproto/googleapis/api v0.0.0-20240509183442-62759503f434 h1:OpXbo8JnN8+jZGPrL4SSfaDjSCjupr8lXyBAbexEm/U= google.golang.org/genproto/googleapis/api v0.0.0-20240509183442-62759503f434/go.mod h1:FfiGhwUm6CJviekPrc0oJ+7h29e+DmWU6UtjX0ZvI7Y= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240515191416-fc5f0ca64291 h1:AgADTJarZTBqgjiUzRgfaBchgYB3/WFTC80GPwsMcRI= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240515191416-fc5f0ca64291/go.mod h1:EfXuqaE1J41VCDicxHzUDm+8rk+7ZdXzHV0IhO/I6s0= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 h1:pPJltXNxVzT4pK9yD8vR9X75DaWYYmLGMsEvBfFQZzQ= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= @@ -1189,8 +1203,8 @@ google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp0 google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg= -google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= +google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= From 722744c2bdf01eb59b947f82f08ae68c4daab19f Mon Sep 17 00:00:00 2001 From: Viktor Liu Date: Fri, 29 Nov 2024 22:19:26 +0100 Subject: [PATCH 2/8] Handle domains with trailing dot --- client/anonymize/anonymize.go | 30 ++++++++++++++++++++---------- client/anonymize/anonymize_test.go | 18 ++++++++++++++++++ 2 files changed, 38 insertions(+), 10 deletions(-) diff --git a/client/anonymize/anonymize.go b/client/anonymize/anonymize.go index 7ebe0442dfa..b4e95adff80 100644 --- a/client/anonymize/anonymize.go +++ b/client/anonymize/anonymize.go @@ -83,29 +83,39 @@ func (a *Anonymizer) AnonymizeIPString(ip string) string { } func (a *Anonymizer) AnonymizeDomain(domain string) string { - if strings.HasSuffix(domain, "netbird.io") || - strings.HasSuffix(domain, "netbird.selfhosted") || - strings.HasSuffix(domain, "netbird.cloud") || - strings.HasSuffix(domain, "netbird.stage") || - strings.HasSuffix(domain, ".domain") { + baseDomain := domain + hasDot := strings.HasSuffix(domain, ".") + if hasDot { + baseDomain = domain[:len(domain)-1] + } + + if strings.HasSuffix(baseDomain, "netbird.io") || + strings.HasSuffix(baseDomain, "netbird.selfhosted") || + strings.HasSuffix(baseDomain, "netbird.cloud") || + strings.HasSuffix(baseDomain, "netbird.stage") || + strings.HasSuffix(baseDomain, ".domain") { return domain } - parts := strings.Split(domain, ".") + parts := strings.Split(baseDomain, ".") if len(parts) < 2 { return domain } - baseDomain := parts[len(parts)-2] + "." + parts[len(parts)-1] + baseForLookup := parts[len(parts)-2] + "." + parts[len(parts)-1] - anonymized, ok := a.domainAnonymizer[baseDomain] + anonymized, ok := a.domainAnonymizer[baseForLookup] if !ok { anonymizedBase := "anon-" + generateRandomString(5) + ".domain" - a.domainAnonymizer[baseDomain] = anonymizedBase + a.domainAnonymizer[baseForLookup] = anonymizedBase anonymized = anonymizedBase } - return strings.Replace(domain, baseDomain, anonymized, 1) + result := strings.Replace(baseDomain, baseForLookup, anonymized, 1) + if hasDot { + result += "." + } + return result } func (a *Anonymizer) AnonymizeURI(uri string) string { diff --git a/client/anonymize/anonymize_test.go b/client/anonymize/anonymize_test.go index e660749ec5d..445f3dce32d 100644 --- a/client/anonymize/anonymize_test.go +++ b/client/anonymize/anonymize_test.go @@ -67,18 +67,36 @@ func TestAnonymizeDomain(t *testing.T) { `^anon-[a-zA-Z0-9]+\.domain$`, true, }, + { + "Domain with Trailing Dot", + "example.com.", + `^anon-[a-zA-Z0-9]+\.domain.$`, + true, + }, { "Subdomain", "sub.example.com", `^sub\.anon-[a-zA-Z0-9]+\.domain$`, true, }, + { + "Subdomain with Trailing Dot", + "sub.example.com.", + `^sub\.anon-[a-zA-Z0-9]+\.domain.$`, + true, + }, { "Protected Domain", "netbird.io", `^netbird\.io$`, false, }, + { + "Protected Domain with Trailing Dot", + "netbird.io.", + `^netbird\.io.$`, + false, + }, } for _, tc := range tests { From 556a0f3f87051a567050e36301964cc7e3d55109 Mon Sep 17 00:00:00 2001 From: Viktor Liu Date: Fri, 29 Nov 2024 22:23:44 +0100 Subject: [PATCH 3/8] Use const --- client/anonymize/anonymize.go | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/client/anonymize/anonymize.go b/client/anonymize/anonymize.go index b4e95adff80..e6a17519b60 100644 --- a/client/anonymize/anonymize.go +++ b/client/anonymize/anonymize.go @@ -12,6 +12,8 @@ import ( "strings" ) +const anonTLD = ".domain" + type Anonymizer struct { ipAnonymizer map[netip.Addr]netip.Addr domainAnonymizer map[string]string @@ -93,7 +95,7 @@ func (a *Anonymizer) AnonymizeDomain(domain string) string { strings.HasSuffix(baseDomain, "netbird.selfhosted") || strings.HasSuffix(baseDomain, "netbird.cloud") || strings.HasSuffix(baseDomain, "netbird.stage") || - strings.HasSuffix(baseDomain, ".domain") { + strings.HasSuffix(baseDomain, anonTLD) { return domain } @@ -106,7 +108,7 @@ func (a *Anonymizer) AnonymizeDomain(domain string) string { anonymized, ok := a.domainAnonymizer[baseForLookup] if !ok { - anonymizedBase := "anon-" + generateRandomString(5) + ".domain" + anonymizedBase := "anon-" + generateRandomString(5) + anonTLD a.domainAnonymizer[baseForLookup] = anonymizedBase anonymized = anonymizedBase } @@ -178,10 +180,10 @@ func (a *Anonymizer) AnonymizeDNSLogLine(logEntry string) string { parts := strings.Split(match, `"`) if len(parts) >= 2 { domain := parts[1] - if strings.HasSuffix(domain, ".domain") { + if strings.HasSuffix(domain, anonTLD) { return match } - randomDomain := generateRandomString(10) + ".domain" + randomDomain := generateRandomString(10) + anonTLD return strings.Replace(match, domain, randomDomain, 1) } return match From b43fca9e40fdeb4406a7f1b1fa5c1fd6eb287954 Mon Sep 17 00:00:00 2001 From: Viktor Liu Date: Sat, 30 Nov 2024 13:19:09 +0100 Subject: [PATCH 4/8] Error out on type assertion --- client/internal/engine.go | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/client/internal/engine.go b/client/internal/engine.go index fbbae671ccb..64410114cee 100644 --- a/client/internal/engine.go +++ b/client/internal/engine.go @@ -1531,15 +1531,18 @@ func (e *Engine) GetLatestNetworkMap() (*mgmProto.NetworkMap, error) { } if e.latestNetworkMap == nil { + //nolint:nilnil return nil, nil } // Create a deep copy to avoid external modifications - if nm, ok := proto.Clone(e.latestNetworkMap).(*mgmProto.NetworkMap); ok { - return nm, nil + nm, ok := proto.Clone(e.latestNetworkMap).(*mgmProto.NetworkMap) + if !ok { + + return nil, fmt.Errorf("failed to clone network map") } - return nil, nil + return nm, nil } // isChecksEqual checks if two slices of checks are equal. From 4adf98458611edfe648393017e0629b84413baf2 Mon Sep 17 00:00:00 2001 From: Viktor Liu Date: Sat, 30 Nov 2024 16:16:19 +0100 Subject: [PATCH 5/8] Add network map persistence cli subcommand --- client/cmd/debug.go | 38 ++++++++++++++++++++++++++++++++++++++ client/cmd/root.go | 1 + 2 files changed, 39 insertions(+) diff --git a/client/cmd/debug.go b/client/cmd/debug.go index 16528fb0752..c7ab87b4766 100644 --- a/client/cmd/debug.go +++ b/client/cmd/debug.go @@ -3,6 +3,7 @@ package cmd import ( "context" "fmt" + "strings" "time" log "github.com/sirupsen/logrus" @@ -61,6 +62,15 @@ var forCmd = &cobra.Command{ RunE: runForDuration, } +var persistenceCmd = &cobra.Command{ + Use: "persistence [on|off]", + Short: "Set network map memory persistence", + Long: `Configure whether the latest network map should persist in memory. When enabled, the last known network map will be kept in memory.`, + Example: " netbird debug persistence on", + Args: cobra.ExactArgs(1), + RunE: setNetworkMapPersistence, +} + func debugBundle(cmd *cobra.Command, _ []string) error { conn, err := getClient(cmd) if err != nil { @@ -233,6 +243,34 @@ func runForDuration(cmd *cobra.Command, args []string) error { return nil } +func setNetworkMapPersistence(cmd *cobra.Command, args []string) error { + conn, err := getClient(cmd) + if err != nil { + return err + } + defer func() { + if err := conn.Close(); err != nil { + log.Errorf(errCloseConnection, err) + } + }() + + persistence := strings.ToLower(args[0]) + if persistence != "on" && persistence != "off" { + return fmt.Errorf("invalid persistence value: %s. Use 'on' or 'off'", args[0]) + } + + client := proto.NewDaemonServiceClient(conn) + _, err = client.SetNetworkMapPersistence(cmd.Context(), &proto.SetNetworkMapPersistenceRequest{ + Enabled: persistence == "on", + }) + if err != nil { + return fmt.Errorf("failed to set network map persistence: %v", status.Convert(err).Message()) + } + + cmd.Printf("Network map persistence set to: %s\n", persistence) + return nil +} + func getStatusOutput(cmd *cobra.Command) string { var statusOutputString string statusResp, err := getStatus(cmd.Context()) diff --git a/client/cmd/root.go b/client/cmd/root.go index 8dae6e27374..3f2d04ef304 100644 --- a/client/cmd/root.go +++ b/client/cmd/root.go @@ -155,6 +155,7 @@ func init() { debugCmd.AddCommand(logCmd) logCmd.AddCommand(logLevelCmd) debugCmd.AddCommand(forCmd) + debugCmd.AddCommand(persistenceCmd) upCmd.PersistentFlags().StringSliceVar(&natExternalIPs, externalIPMapFlag, nil, `Sets external IPs maps between local addresses and interfaces.`+ From b931c0c49c1b7aa11d40b369ff4ec3b55c4c51ea Mon Sep 17 00:00:00 2001 From: Viktor Liu Date: Mon, 2 Dec 2024 12:52:04 +0100 Subject: [PATCH 6/8] Replace yaml with json --- client/server/debug.go | 14 +++++++------- go.mod | 6 ------ go.sum | 14 -------------- 3 files changed, 7 insertions(+), 27 deletions(-) diff --git a/client/server/debug.go b/client/server/debug.go index fc9add7f51f..6d4546480f0 100644 --- a/client/server/debug.go +++ b/client/server/debug.go @@ -17,8 +17,8 @@ import ( "strings" "time" - "buf.build/go/protoyaml" log "github.com/sirupsen/logrus" + "google.golang.org/protobuf/encoding/protojson" "github.com/netbirdio/netbird/client/anonymize" "github.com/netbirdio/netbird/client/internal/peer" @@ -35,7 +35,7 @@ client.log: Most recent, anonymized log file of the NetBird client. routes.txt: Anonymized system routes, if --system-info flag was provided. interfaces.txt: Anonymized network interface information, if --system-info flag was provided. config.txt: Anonymized configuration information of the NetBird client. -network_map.yaml: Anonymized network map containing peer configurations, routes, DNS settings, and firewall rules. +network_map.json: Anonymized network map containing peer configurations, routes, DNS settings, and firewall rules. Anonymization Process @@ -283,19 +283,19 @@ func (s *Server) addNetworkMap(req *proto.DebugBundleRequest, anonymizer *anonym } } - options := protoyaml.MarshalOptions{ + options := protojson.MarshalOptions{ EmitUnpopulated: true, UseProtoNames: true, - Indent: 2, + Indent: " ", AllowPartial: true, } - yamlBytes, err := options.Marshal(networkMap) + jsonBytes, err := options.Marshal(networkMap) if err != nil { - return fmt.Errorf("generate yaml: %w", err) + return fmt.Errorf("generate json: %w", err) } - if err := addFileToZip(archive, bytes.NewReader(yamlBytes), "network_map.yaml"); err != nil { + if err := addFileToZip(archive, bytes.NewReader(jsonBytes), "network_map.json"); err != nil { return fmt.Errorf("add network map to zip: %w", err) } diff --git a/go.mod b/go.mod index 66ad346ec8d..c08713f2bd4 100644 --- a/go.mod +++ b/go.mod @@ -30,7 +30,6 @@ require ( ) require ( - buf.build/go/protoyaml v0.2.0 fyne.io/fyne/v2 v2.5.0 fyne.io/systray v1.11.0 github.com/TheJumpCloud/jcapi-go v3.0.0+incompatible @@ -104,7 +103,6 @@ require ( ) require ( - buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.34.2-20240717164558-a6c49f84cc0f.2 // indirect cloud.google.com/go/auth v0.3.0 // indirect cloud.google.com/go/auth/oauth2adapt v0.2.2 // indirect cloud.google.com/go/compute/metadata v0.3.0 // indirect @@ -115,7 +113,6 @@ require ( github.com/Microsoft/hcsshim v0.12.3 // 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/antlr4-go/antlr/v4 v4.13.0 // indirect github.com/aws/aws-sdk-go-v2 v1.30.3 // indirect github.com/aws/aws-sdk-go-v2/config v1.27.27 // indirect github.com/aws/aws-sdk-go-v2/credentials v1.17.27 // indirect @@ -132,7 +129,6 @@ require ( github.com/aws/smithy-go v1.20.3 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/bradfitz/gomemcache v0.0.0-20220106215444-fb4bf637b56d // indirect - github.com/bufbuild/protovalidate-go v0.6.3 // indirect github.com/caddyserver/zerossl v0.1.3 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/containerd/containerd v1.7.16 // indirect @@ -160,7 +156,6 @@ require ( github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/google/btree v1.1.2 // indirect - github.com/google/cel-go v0.21.0 // indirect github.com/google/s2a-go v0.1.7 // indirect github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect github.com/googleapis/gax-go/v2 v2.12.3 // indirect @@ -212,7 +207,6 @@ require ( github.com/spf13/cast v1.5.0 // indirect github.com/srwiley/oksvg v0.0.0-20221011165216-be6e8873101c // indirect github.com/srwiley/rasterx v0.0.0-20220730225603-2ab79fcdd4ef // indirect - github.com/stoewer/go-strcase v1.3.0 // indirect github.com/tklauser/go-sysconf v0.3.14 // indirect github.com/tklauser/numcpus v0.8.0 // indirect github.com/vishvananda/netns v0.0.4 // indirect diff --git a/go.sum b/go.sum index b7da4f8bd6a..5519d6ded99 100644 --- a/go.sum +++ b/go.sum @@ -1,7 +1,3 @@ -buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.34.2-20240717164558-a6c49f84cc0f.2 h1:SZRVx928rbYZ6hEKUIN+vtGDkl7uotABRWGY4OAg5gM= -buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.34.2-20240717164558-a6c49f84cc0f.2/go.mod h1:ylS4c28ACSI59oJrOdW4pHS4n0Hw4TgSPHn8rpHl4Yw= -buf.build/go/protoyaml v0.2.0 h1:2g3OHjtLDqXBREIOjpZGHmQ+U/4mkN1YiQjxNB68Ip8= -buf.build/go/protoyaml v0.2.0/go.mod h1:L/9QvTDkTWcDTzAL6HMfN+mYC6CmZRm2KnsUA054iL0= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= @@ -80,8 +76,6 @@ github.com/allegro/bigcache/v3 v3.0.2/go.mod h1:aPyh7jEvrog9zAwx5N7+JUQX5dZTSGpx github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8= github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= -github.com/antlr4-go/antlr/v4 v4.13.0 h1:lxCg3LAv+EUK6t1i0y1V6/SLeUi0eKEKdhQAlS8TVTI= -github.com/antlr4-go/antlr/v4 v4.13.0/go.mod h1:pfChB/xh/Unjila75QW7+VU4TSnWnnk9UTnmpPaOR2g= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= @@ -119,8 +113,6 @@ github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kB github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqOes/6LfM= github.com/bradfitz/gomemcache v0.0.0-20220106215444-fb4bf637b56d h1:pVrfxiGfwelyab6n21ZBkbkmbevaf+WvMIiR7sr97hw= github.com/bradfitz/gomemcache v0.0.0-20220106215444-fb4bf637b56d/go.mod h1:H0wQNHz2YrLsuXOZozoeDmnHXkNCRmMW0gwFWDfEZDA= -github.com/bufbuild/protovalidate-go v0.6.3 h1:wxQyzW035zM16Binbaz/nWAzS12dRIXhZdSUWRY7Fv0= -github.com/bufbuild/protovalidate-go v0.6.3/go.mod h1:J4PtwP9Z2YAGgB0+o+tTWEDtLtXvz/gfhFZD8pbzM/U= github.com/c-robinson/iplib v1.0.3 h1:NG0UF0GoEsrC1/vyfX1Lx2Ss7CySWl3KqqXh3q4DdPU= github.com/c-robinson/iplib v1.0.3/go.mod h1:i3LuuFL1hRT5gFpBRnEydzw8R6yhGkF4szNDIbF8pgo= github.com/caddyserver/certmagic v0.21.3 h1:pqRRry3yuB4CWBVq9+cUqu+Y6E2z8TswbhNx1AZeYm0= @@ -192,8 +184,6 @@ github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5y github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/envoyproxy/protoc-gen-validate v1.0.4 h1:gVPz/FMfvh57HdSJQyvBtF00j8JU4zdyUgIUNhlgg0A= -github.com/envoyproxy/protoc-gen-validate v1.0.4/go.mod h1:qys6tmnRsYrQqIhm2bvKZH4Blx/1gTIZ2UKVY1M+Yew= github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/felixge/fgprof v0.9.3 h1:VvyZxILNuCiUCSXtPtYmmtGvb65nqXh2QFWc0Wpf2/g= @@ -309,8 +299,6 @@ github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Z github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU= github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= -github.com/google/cel-go v0.21.0 h1:cl6uW/gxN+Hy50tNYvI691+sXxioCnstFzLp2WO4GCI= -github.com/google/cel-go v0.21.0/go.mod h1:rHUlWCcBKgyEk+eV03RPdZUekPp6YcJwV0FxuUksYxc= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= @@ -670,8 +658,6 @@ github.com/srwiley/oksvg v0.0.0-20221011165216-be6e8873101c h1:km8GpoQut05eY3GiY github.com/srwiley/oksvg v0.0.0-20221011165216-be6e8873101c/go.mod h1:cNQ3dwVJtS5Hmnjxy6AgTPd0Inb3pW05ftPSX7NZO7Q= github.com/srwiley/rasterx v0.0.0-20220730225603-2ab79fcdd4ef h1:Ch6Q+AZUxDBCVqdkI8FSpFyZDtCVBc2VmejdNrm5rRQ= github.com/srwiley/rasterx v0.0.0-20220730225603-2ab79fcdd4ef/go.mod h1:nXTWP6+gD5+LUJ8krVhhoeHjvHTutPxMYl5SvkcnJNE= -github.com/stoewer/go-strcase v1.3.0 h1:g0eASXYtp+yvN9fK8sH94oCIk0fau9uV1/ZdJ0AVEzs= -github.com/stoewer/go-strcase v1.3.0/go.mod h1:fAH5hQ5pehh+j3nZfvwdk2RgEgQjAoM8wodgtPmh1xo= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= From 50461c9bf8669cd6a4426d09c046f47e8ca06cde Mon Sep 17 00:00:00 2001 From: Viktor Liu Date: Mon, 2 Dec 2024 13:02:54 +0100 Subject: [PATCH 7/8] Add test --- client/server/debug_test.go | 175 ++++++++++++++++++++++++++++++++++++ 1 file changed, 175 insertions(+) create mode 100644 client/server/debug_test.go diff --git a/client/server/debug_test.go b/client/server/debug_test.go new file mode 100644 index 00000000000..1e3fff6ca65 --- /dev/null +++ b/client/server/debug_test.go @@ -0,0 +1,175 @@ +package server + +import ( + "net" + "strings" + "testing" + + "github.com/stretchr/testify/require" + + "github.com/netbirdio/netbird/client/anonymize" + mgmProto "github.com/netbirdio/netbird/management/proto" +) + +func TestAnonymizeNetworkMap(t *testing.T) { + networkMap := &mgmProto.NetworkMap{ + PeerConfig: &mgmProto.PeerConfig{ + Address: "203.0.113.5", + Dns: "1.2.3.4", + Fqdn: "peer1.corp.example.com", + SshConfig: &mgmProto.SSHConfig{ + SshPubKey: []byte("ssh-rsa AAAAB3NzaC1..."), + }, + }, + RemotePeers: []*mgmProto.RemotePeerConfig{ + { + AllowedIps: []string{ + "203.0.113.1/32", + "2001:db8:1234::1/128", + "192.168.1.1/32", + "100.64.0.1/32", + "10.0.0.1/32", + }, + Fqdn: "peer2.corp.example.com", + SshConfig: &mgmProto.SSHConfig{ + SshPubKey: []byte("ssh-rsa AAAAB3NzaC2..."), + }, + }, + }, + Routes: []*mgmProto.Route{ + { + Network: "197.51.100.0/24", + Domains: []string{"prod.example.com", "staging.example.com"}, + NetID: "net-123abc", + }, + }, + DNSConfig: &mgmProto.DNSConfig{ + NameServerGroups: []*mgmProto.NameServerGroup{ + { + NameServers: []*mgmProto.NameServer{ + {IP: "8.8.8.8"}, + {IP: "1.1.1.1"}, + {IP: "203.0.113.53"}, + }, + Domains: []string{"example.com", "internal.example.com"}, + }, + }, + CustomZones: []*mgmProto.CustomZone{ + { + Domain: "custom.example.com", + Records: []*mgmProto.SimpleRecord{ + { + Name: "www.custom.example.com", + Type: 1, + RData: "203.0.113.10", + }, + { + Name: "internal.custom.example.com", + Type: 1, + RData: "192.168.1.10", + }, + }, + }, + }, + }, + } + + // Create anonymizer with test addresses + anonymizer := anonymize.NewAnonymizer(anonymize.DefaultAddresses()) + + // Anonymize the network map + err := anonymizeNetworkMap(networkMap, anonymizer) + require.NoError(t, err) + + // Test PeerConfig anonymization + peerCfg := networkMap.PeerConfig + require.NotEqual(t, "203.0.113.5", peerCfg.Address) + + // Verify DNS and FQDN are properly anonymized + require.NotEqual(t, "1.2.3.4", peerCfg.Dns) + require.NotEqual(t, "peer1.corp.example.com", peerCfg.Fqdn) + require.True(t, strings.HasSuffix(peerCfg.Fqdn, ".domain")) + + // Verify SSH key is replaced + require.Equal(t, []byte("ssh-placeholder-key"), peerCfg.SshConfig.SshPubKey) + + // Test RemotePeers anonymization + remotePeer := networkMap.RemotePeers[0] + + // Verify FQDN is anonymized + require.NotEqual(t, "peer2.corp.example.com", remotePeer.Fqdn) + require.True(t, strings.HasSuffix(remotePeer.Fqdn, ".domain")) + + // Check that public IPs are anonymized but private IPs are preserved + for _, allowedIP := range remotePeer.AllowedIps { + ip, _, err := net.ParseCIDR(allowedIP) + require.NoError(t, err) + + if ip.IsPrivate() || isInCGNATRange(ip) { + require.Contains(t, []string{ + "192.168.1.1/32", + "100.64.0.1/32", + "10.0.0.1/32", + }, allowedIP) + } else { + require.NotContains(t, []string{ + "203.0.113.1/32", + "2001:db8:1234::1/128", + }, allowedIP) + } + } + + // Test Routes anonymization + route := networkMap.Routes[0] + require.NotEqual(t, "197.51.100.0/24", route.Network) + for _, domain := range route.Domains { + require.True(t, strings.HasSuffix(domain, ".domain")) + require.NotContains(t, domain, "example.com") + } + + // Test DNS config anonymization + dnsConfig := networkMap.DNSConfig + nameServerGroup := dnsConfig.NameServerGroups[0] + + // Verify well-known DNS servers are preserved + require.Equal(t, "8.8.8.8", nameServerGroup.NameServers[0].IP) + require.Equal(t, "1.1.1.1", nameServerGroup.NameServers[1].IP) + + // Verify public DNS server is anonymized + require.NotEqual(t, "203.0.113.53", nameServerGroup.NameServers[2].IP) + + // Verify domains are anonymized + for _, domain := range nameServerGroup.Domains { + require.True(t, strings.HasSuffix(domain, ".domain")) + require.NotContains(t, domain, "example.com") + } + + // Test CustomZones anonymization + customZone := dnsConfig.CustomZones[0] + require.True(t, strings.HasSuffix(customZone.Domain, ".domain")) + require.NotContains(t, customZone.Domain, "example.com") + + // Verify records are properly anonymized + for _, record := range customZone.Records { + require.True(t, strings.HasSuffix(record.Name, ".domain")) + require.NotContains(t, record.Name, "example.com") + + ip := net.ParseIP(record.RData) + if ip != nil { + if !ip.IsPrivate() { + require.NotEqual(t, "203.0.113.10", record.RData) + } else { + require.Equal(t, "192.168.1.10", record.RData) + } + } + } +} + +// Helper function to check if IP is in CGNAT range +func isInCGNATRange(ip net.IP) bool { + cgnat := net.IPNet{ + IP: net.ParseIP("100.64.0.0"), + Mask: net.CIDRMask(10, 32), + } + return cgnat.Contains(ip) +} From ba135488b4e885bc8618113b0d4db727e162182b Mon Sep 17 00:00:00 2001 From: Viktor Liu Date: Tue, 3 Dec 2024 13:24:01 +0100 Subject: [PATCH 8/8] Remove unused fn from merge --- client/server/debug.go | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/client/server/debug.go b/client/server/debug.go index bf997fe924c..c12fd99dbf2 100644 --- a/client/server/debug.go +++ b/client/server/debug.go @@ -419,26 +419,6 @@ func (s *Server) addSingleLogfile(logPath, targetName string, req *proto.DebugBu return nil } -func (s *Server) anonymize(reader io.Reader, writer *io.PipeWriter, anonymizer *anonymize.Anonymizer) { - defer func() { - // always nil - _ = writer.Close() - }() - - scanner := bufio.NewScanner(reader) - for scanner.Scan() { - line := anonymizer.AnonymizeString(scanner.Text()) - if _, err := writer.Write([]byte(line + "\n")); err != nil { - writer.CloseWithError(fmt.Errorf("anonymize write: %w", err)) - return - } - } - if err := scanner.Err(); err != nil { - writer.CloseWithError(fmt.Errorf("anonymize scan: %w", err)) - return - } -} - // getLatestNetworkMap returns the latest network map from the engine if network map persistence is enabled func (s *Server) getLatestNetworkMap() (*mgmProto.NetworkMap, error) { if s.connectClient == nil {