Repository: netbirdio/netbird

Issue:
Sleep detection on macOS (how to turn it off?)
**Describe the problem**

Hello,

The new [sleep detection](https://github.com/netbirdio/netbird/commit/ddcd182859116b7ac30a7934fcc7e40fba818591) feature on macOS is quite useful, but NetBird needs a setting to disable it.

For instance, I need to disconnect from our NetBird network in certain situations.

Before the update 0.60.4, I could simply disconnect from the app. However, now, I need to quit the app itself, as it automatically logs in after I wake up my computer.

Could you please add this option to the Settings menu?

Or at least tracking the connection status before it goes into sleep. If connection was established, auto-connect after wake up. If not, no auto-connection.

Thanks.

**Steps to reproduce the issue**

1. Disconnect from the NetBird network.
2. Put the Mac into sleep mode.
3. Wake up the Mac.
4. NetBird automatically reconnects, even though the user had intended to disconnect it before going to sleep.

Hints from issue comments:
@mlsmaycon: Hey @pierrechapuis we just released a better management for OS lifecycles on macOS. Can you please check that? It should remove the need for a dedicated flag@pierrechapuis: > Hey [@pierrechapuis](https://github.com/pierrechapuis) we just released a better management for OS lifecycles on macOS. Can you please check that? It should remove the need for a dedicated flag

Hey,

I tried the newest version today. It seems that the issue has been fixed.

Thanks!@mlsmaycon: That's great. Thanks for the feedback.

Solution patch:
diff --git a/client/internal/sleep/service.go b/client/internal/sleep/service.go
index 35fc933c..196a33f5 100644
--- a/client/internal/sleep/service.go
+++ b/client/internal/sleep/service.go
@@ -1,8 +1,9 @@
 package sleep
 
 var (
-	EventTypeSleep  EventType = 0
-	EventTypeWakeUp EventType = 1
+	EventTypeUnknown EventType = 0
+	EventTypeSleep   EventType = 1
+	EventTypeWakeUp  EventType = 2
 )
 
 type EventType int
diff --git a/client/proto/daemon.pb.go b/client/proto/daemon.pb.go
index 6f825561..28e8b2d4 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.36.6
-// 	protoc        v3.21.12
+// 	protoc        v6.32.1
 // source: daemon.proto
 
 package proto
@@ -88,6 +88,56 @@ func (LogLevel) EnumDescriptor() ([]byte, []int) {
 	return file_daemon_proto_rawDescGZIP(), []int{0}
 }
 
+// avoid collision with loglevel enum
+type OSLifecycleRequest_CycleType int32
+
+const (
+	OSLifecycleRequest_UNKNOWN OSLifecycleRequest_CycleType = 0
+	OSLifecycleRequest_SLEEP   OSLifecycleRequest_CycleType = 1
+	OSLifecycleRequest_WAKEUP  OSLifecycleRequest_CycleType = 2
+)
+
+// Enum value maps for OSLifecycleRequest_CycleType.
+var (
+	OSLifecycleRequest_CycleType_name = map[int32]string{
+		0: "UNKNOWN",
+		1: "SLEEP",
+		2: "WAKEUP",
+	}
+	OSLifecycleRequest_CycleType_value = map[string]int32{
+		"UNKNOWN": 0,
+		"SLEEP":   1,
+		"WAKEUP":  2,
+	}
+)
+
+func (x OSLifecycleRequest_CycleType) Enum() *OSLifecycleRequest_CycleType {
+	p := new(OSLifecycleRequest_CycleType)
+	*p = x
+	return p
+}
+
+func (x OSLifecycleRequest_CycleType) String() string {
+	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (OSLifecycleRequest_CycleType) Descriptor() protoreflect.EnumDescriptor {
+	return file_daemon_proto_enumTypes[1].Descriptor()
+}
+
+func (OSLifecycleRequest_CycleType) Type() protoreflect.EnumType {
+	return &file_daemon_proto_enumTypes[1]
+}
+
+func (x OSLifecycleRequest_CycleType) Number() protoreflect.EnumNumber {
+	return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Use OSLifecycleRequest_CycleType.Descriptor instead.
+func (OSLifecycleRequest_CycleType) EnumDescriptor() ([]byte, []int) {
+	return file_daemon_proto_rawDescGZIP(), []int{1, 0}
+}
+
 type SystemEvent_Severity int32
 
 const (
@@ -124,11 +174,11 @@ func (x SystemEvent_Severity) String() string {
 }
 
 func (SystemEvent_Severity) Descriptor() protoreflect.EnumDescriptor {
-	return file_daemon_proto_enumTypes[1].Descriptor()
+	return file_daemon_proto_enumTypes[2].Descriptor()
 }
 
 func (SystemEvent_Severity) Type() protoreflect.EnumType {
-	return &file_daemon_proto_enumTypes[1]
+	return &file_daemon_proto_enumTypes[2]
 }
 
 func (x SystemEvent_Severity) Number() protoreflect.EnumNumber {
@@ -137,7 +187,7 @@ func (x SystemEvent_Severity) Number() protoreflect.EnumNumber {
 
 // Deprecated: Use SystemEvent_Severity.Descriptor instead.
 func (SystemEvent_Severity) EnumDescriptor() ([]byte, []int) {
-	return file_daemon_proto_rawDescGZIP(), []int{51, 0}
+	return file_daemon_proto_rawDescGZIP(), []int{53, 0}
 }
 
 type SystemEvent_Category int32
@@ -179,11 +229,11 @@ func (x SystemEvent_Category) String() string {
 }
 
 func (SystemEvent_Category) Descriptor() protoreflect.EnumDescriptor {
-	return file_daemon_proto_enumTypes[2].Descriptor()
+	return file_daemon_proto_enumTypes[3].Descriptor()
 }
 
 func (SystemEvent_Category) Type() protoreflect.EnumType {
-	return &file_daemon_proto_enumTypes[2]
+	return &file_daemon_proto_enumTypes[3]
 }
 
 func (x SystemEvent_Category) Number() protoreflect.EnumNumber {
@@ -192,7 +242,7 @@ func (x SystemEvent_Category) Number() protoreflect.EnumNumber {
 
 // Deprecated: Use SystemEvent_Category.Descriptor instead.
 func (SystemEvent_Category) EnumDescriptor() ([]byte, []int) {
-	return file_daemon_proto_rawDescGZIP(), []int{51, 1}
+	return file_daemon_proto_rawDescGZIP(), []int{53, 1}
 }
 
 type EmptyRequest struct {
@@ -231,6 +281,86 @@ func (*EmptyRequest) Descriptor() ([]byte, []int) {
 	return file_daemon_proto_rawDescGZIP(), []int{0}
 }
 
+type OSLifecycleRequest struct {
+	state         protoimpl.MessageState       `protogen:"open.v1"`
+	Type          OSLifecycleRequest_CycleType `protobuf:"varint,1,opt,name=type,proto3,enum=daemon.OSLifecycleRequest_CycleType" json:"type,omitempty"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *OSLifecycleRequest) Reset() {
+	*x = OSLifecycleRequest{}
+	mi := &file_daemon_proto_msgTypes[1]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *OSLifecycleRequest) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*OSLifecycleRequest) ProtoMessage() {}
+
+func (x *OSLifecycleRequest) ProtoReflect() protoreflect.Message {
+	mi := &file_daemon_proto_msgTypes[1]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use OSLifecycleRequest.ProtoReflect.Descriptor instead.
+func (*OSLifecycleRequest) Descriptor() ([]byte, []int) {
+	return file_daemon_proto_rawDescGZIP(), []int{1}
+}
+
+func (x *OSLifecycleRequest) GetType() OSLifecycleRequest_CycleType {
+	if x != nil {
+		return x.Type
+	}
+	return OSLifecycleRequest_UNKNOWN
+}
+
+type OSLifecycleResponse struct {
+	state         protoimpl.MessageState `protogen:"open.v1"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *OSLifecycleResponse) Reset() {
+	*x = OSLifecycleResponse{}
+	mi := &file_daemon_proto_msgTypes[2]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *OSLifecycleResponse) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*OSLifecycleResponse) ProtoMessage() {}
+
+func (x *OSLifecycleResponse) ProtoReflect() protoreflect.Message {
+	mi := &file_daemon_proto_msgTypes[2]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use OSLifecycleResponse.ProtoReflect.Descriptor instead.
+func (*OSLifecycleResponse) Descriptor() ([]byte, []int) {
+	return file_daemon_proto_rawDescGZIP(), []int{2}
+}
+
 type LoginRequest struct {
 	state protoimpl.MessageState `protogen:"open.v1"`
 	// setupKey netbird setup key.
@@ -293,7 +423,7 @@ type LoginRequest struct {
 
 func (x *LoginRequest) Reset() {
 	*x = LoginRequest{}
-	mi := &file_daemon_proto_msgTypes[1]
+	mi := &file_daemon_proto_msgTypes[3]
 	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 	ms.StoreMessageInfo(mi)
 }
@@ -305,7 +435,7 @@ func (x *LoginRequest) String() string {
 func (*LoginRequest) ProtoMessage() {}
 
 func (x *LoginRequest) ProtoReflect() protoreflect.Message {
-	mi := &file_daemon_proto_msgTypes[1]
+	mi := &file_daemon_proto_msgTypes[3]
 	if x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -318,7 +448,7 @@ func (x *LoginRequest) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use LoginRequest.ProtoReflect.Descriptor instead.
 func (*LoginRequest) Descriptor() ([]byte, []int) {
-	return file_daemon_proto_rawDescGZIP(), []int{1}
+	return file_daemon_proto_rawDescGZIP(), []int{3}
 }
 
 func (x *LoginRequest) GetSetupKey() string {
@@ -607,7 +737,7 @@ type LoginResponse struct {
 
 func (x *LoginResponse) Reset() {
 	*x = LoginResponse{}
-	mi := &file_daemon_proto_msgTypes[2]
+	mi := &file_daemon_proto_msgTypes[4]
 	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 	ms.StoreMessageInfo(mi)
 }
@@ -619,7 +749,7 @@ func (x *LoginResponse) String() string {
 func (*LoginResponse) ProtoMessage() {}
 
 func (x *LoginResponse) ProtoReflect() protoreflect.Message {
-	mi := &file_daemon_proto_msgTypes[2]
+	mi := &file_daemon_proto_msgTypes[4]
 	if x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -632,7 +762,7 @@ func (x *LoginResponse) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use LoginResponse.ProtoReflect.Descriptor instead.
 func (*LoginResponse) Descriptor() ([]byte, []int) {
-	return file_daemon_proto_rawDescGZIP(), []int{2}
+	return file_daemon_proto_rawDescGZIP(), []int{4}
 }
 
 func (x *LoginResponse) GetNeedsSSOLogin() bool {
@@ -673,7 +803,7 @@ type WaitSSOLoginRequest struct {
 
 func (x *WaitSSOLoginRequest) Reset() {
 	*x = WaitSSOLoginRequest{}
-	mi := &file_daemon_proto_msgTypes[3]
+	mi := &file_daemon_proto_msgTypes[5]
 	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 	ms.StoreMessageInfo(mi)
 }
@@ -685,7 +815,7 @@ func (x *WaitSSOLoginRequest) String() string {
 func (*WaitSSOLoginRequest) ProtoMessage() {}
 
 func (x *WaitSSOLoginRequest) ProtoReflect() protoreflect.Message {
-	mi := &file_daemon_proto_msgTypes[3]
+	mi := &file_daemon_proto_msgTypes[5]
 	if x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -698,7 +828,7 @@ func (x *WaitSSOLoginRequest) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use WaitSSOLoginRequest.ProtoReflect.Descriptor instead.
 func (*WaitSSOLoginRequest) Descriptor() ([]byte, []int) {
-	return file_daemon_proto_rawDescGZIP(), []int{3}
+	return file_daemon_proto_rawDescGZIP(), []int{5}
 }
 
 func (x *WaitSSOLoginRequest) GetUserCode() string {
@@ -724,7 +854,7 @@ type WaitSSOLoginResponse struct {
 
 func (x *WaitSSOLoginResponse) Reset() {
 	*x = WaitSSOLoginResponse{}
-	mi := &file_daemon_proto_msgTypes[4]
+	mi := &file_daemon_proto_msgTypes[6]
 	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 	ms.StoreMessageInfo(mi)
 }
@@ -736,7 +866,7 @@ func (x *WaitSSOLoginResponse) String() string {
 func (*WaitSSOLoginResponse) ProtoMessage() {}
 
 func (x *WaitSSOLoginResponse) ProtoReflect() protoreflect.Message {
-	mi := &file_daemon_proto_msgTypes[4]
+	mi := &file_daemon_proto_msgTypes[6]
 	if x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -749,7 +879,7 @@ func (x *WaitSSOLoginResponse) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use WaitSSOLoginResponse.ProtoReflect.Descriptor instead.
 func (*WaitSSOLoginResponse) Descriptor() ([]byte, []int) {
-	return file_daemon_proto_rawDescGZIP(), []int{4}
+	return file_daemon_proto_rawDescGZIP(), []int{6}
 }
 
 func (x *WaitSSOLoginResponse) GetEmail() string {
@@ -769,7 +899,7 @@ type UpRequest struct {
 
 func (x *UpRequest) Reset() {
 	*x = UpRequest{}
-	mi := &file_daemon_proto_msgTypes[5]
+	mi := &file_daemon_proto_msgTypes[7]
 	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 	ms.StoreMessageInfo(mi)
 }
@@ -781,7 +911,7 @@ func (x *UpRequest) String() string {
 func (*UpRequest) ProtoMessage() {}
 
 func (x *UpRequest) ProtoReflect() protoreflect.Message {
-	mi := &file_daemon_proto_msgTypes[5]
+	mi := &file_daemon_proto_msgTypes[7]
 	if x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -794,7 +924,7 @@ func (x *UpRequest) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use UpRequest.ProtoReflect.Descriptor instead.
 func (*UpRequest) Descriptor() ([]byte, []int) {
-	return file_daemon_proto_rawDescGZIP(), []int{5}
+	return file_daemon_proto_rawDescGZIP(), []int{7}
 }
 
 func (x *UpRequest) GetProfileName() string {
@@ -819,7 +949,7 @@ type UpResponse struct {
 
 func (x *UpResponse) Reset() {
 	*x = UpResponse{}
-	mi := &file_daemon_proto_msgTypes[6]
+	mi := &file_daemon_proto_msgTypes[8]
 	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 	ms.StoreMessageInfo(mi)
 }
@@ -831,7 +961,7 @@ func (x *UpResponse) String() string {
 func (*UpResponse) ProtoMessage() {}
 
 func (x *UpResponse) ProtoReflect() protoreflect.Message {
-	mi := &file_daemon_proto_msgTypes[6]
+	mi := &file_daemon_proto_msgTypes[8]
 	if x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -844,7 +974,7 @@ func (x *UpResponse) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use UpResponse.ProtoReflect.Descriptor instead.
 func (*UpResponse) Descriptor() ([]byte, []int) {
-	return file_daemon_proto_rawDescGZIP(), []int{6}
+	return file_daemon_proto_rawDescGZIP(), []int{8}
 }
 
 type StatusRequest struct {
@@ -859,7 +989,7 @@ type StatusRequest struct {
 
 func (x *StatusRequest) Reset() {
 	*x = StatusRequest{}
-	mi := &file_daemon_proto_msgTypes[7]
+	mi := &file_daemon_proto_msgTypes[9]
 	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 	ms.StoreMessageInfo(mi)
 }
@@ -871,7 +1001,7 @@ func (x *StatusRequest) String() string {
 func (*StatusRequest) ProtoMessage() {}
 
 func (x *StatusRequest) ProtoReflect() protoreflect.Message {
-	mi := &file_daemon_proto_msgTypes[7]
+	mi := &file_daemon_proto_msgTypes[9]
 	if x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -884,7 +1014,7 @@ func (x *StatusRequest) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use StatusRequest.ProtoReflect.Descriptor instead.
 func (*StatusRequest) Descriptor() ([]byte, []int) {
-	return file_daemon_proto_rawDescGZIP(), []int{7}
+	return file_daemon_proto_rawDescGZIP(), []int{9}
 }
 
 func (x *StatusRequest) GetGetFullPeerStatus() bool {
@@ -921,7 +1051,7 @@ type StatusResponse struct {
 
 func (x *StatusResponse) Reset() {
 	*x = StatusResponse{}
-	mi := &file_daemon_proto_msgTypes[8]
+	mi := &file_daemon_proto_msgTypes[10]
 	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 	ms.StoreMessageInfo(mi)
 }
@@ -933,7 +1063,7 @@ func (x *StatusResponse) String() string {
 func (*StatusResponse) ProtoMessage() {}
 
 func (x *StatusResponse) ProtoReflect() protoreflect.Message {
-	mi := &file_daemon_proto_msgTypes[8]
+	mi := &file_daemon_proto_msgTypes[10]
 	if x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -946,7 +1076,7 @@ func (x *StatusResponse) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use StatusResponse.ProtoReflect.Descriptor instead.
 func (*StatusResponse) Descriptor() ([]byte, []int) {
-	return file_daemon_proto_rawDescGZIP(), []int{8}
+	return file_daemon_proto_rawDescGZIP(), []int{10}
 }
 
 func (x *StatusResponse) GetStatus() string {
@@ -978,7 +1108,7 @@ type DownRequest struct {
 
 func (x *DownRequest) Reset() {
 	*x = DownRequest{}
-	mi := &file_daemon_proto_msgTypes[9]
+	mi := &file_daemon_proto_msgTypes[11]
 	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 	ms.StoreMessageInfo(mi)
 }
@@ -990,7 +1120,7 @@ func (x *DownRequest) String() string {
 func (*DownRequest) ProtoMessage() {}
 
 func (x *DownRequest) ProtoReflect() protoreflect.Message {
-	mi := &file_daemon_proto_msgTypes[9]
+	mi := &file_daemon_proto_msgTypes[11]
 	if x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -1003,7 +1133,7 @@ func (x *DownRequest) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use DownRequest.ProtoReflect.Descriptor instead.
 func (*DownRequest) Descriptor() ([]byte, []int) {
-	return file_daemon_proto_rawDescGZIP(), []int{9}
+	return file_daemon_proto_rawDescGZIP(), []int{11}
 }
 
 type DownResponse struct {
@@ -1014,7 +1144,7 @@ type DownResponse struct {
 
 func (x *DownResponse) Reset() {
 	*x = DownResponse{}
-	mi := &file_daemon_proto_msgTypes[10]
+	mi := &file_daemon_proto_msgTypes[12]
 	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 	ms.StoreMessageInfo(mi)
 }
@@ -1026,7 +1156,7 @@ func (x *DownResponse) String() string {
 func (*DownResponse) ProtoMessage() {}
 
 func (x *DownResponse) ProtoReflect() protoreflect.Message {
-	mi := &file_daemon_proto_msgTypes[10]
+	mi := &file_daemon_proto_msgTypes[12]
 	if x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -1039,7 +1169,7 @@ func (x *DownResponse) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use DownResponse.ProtoReflect.Descriptor instead.
 func (*DownResponse) Descriptor() ([]byte, []int) {
-	return file_daemon_proto_rawDescGZIP(), []int{10}
+	return file_daemon_proto_rawDescGZIP(), []int{12}
 }
 
 type GetConfigRequest struct {
@@ -1052,7 +1182,7 @@ type GetConfigRequest struct {
 
 func (x *GetConfigRequest) Reset() {
 	*x = GetConfigRequest{}
-	mi := &file_daemon_proto_msgTypes[11]
+	mi := &file_daemon_proto_msgTypes[13]
 	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 	ms.StoreMessageInfo(mi)
 }
@@ -1064,7 +1194,7 @@ func (x *GetConfigRequest) String() string {
 func (*GetConfigRequest) ProtoMessage() {}
 
 func (x *GetConfigRequest) ProtoReflect() protoreflect.Message {
-	mi := &file_daemon_proto_msgTypes[11]
+	mi := &file_daemon_proto_msgTypes[13]
 	if x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -1077,7 +1207,7 @@ func (x *GetConfigRequest) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use GetConfigRequest.ProtoReflect.Descriptor instead.
 func (*GetConfigRequest) Descriptor() ([]byte, []int) {
-	return file_daemon_proto_rawDescGZIP(), []int{11}
+	return file_daemon_proto_rawDescGZIP(), []int{13}
 }
 
 func (x *GetConfigRequest) GetProfileName() string {
@@ -1133,7 +1263,7 @@ type GetConfigResponse struct {
 
 func (x *GetConfigResponse) Reset() {
 	*x = GetConfigResponse{}
-	mi := &file_daemon_proto_msgTypes[12]
+	mi := &file_daemon_proto_msgTypes[14]
 	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 	ms.StoreMessageInfo(mi)
 }
@@ -1145,7 +1275,7 @@ func (x *GetConfigResponse) String() string {
 func (*GetConfigResponse) ProtoMessage() {}
 
 func (x *GetConfigResponse) ProtoReflect() protoreflect.Message {
-	mi := &file_daemon_proto_msgTypes[12]
+	mi := &file_daemon_proto_msgTypes[14]
 	if x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -1158,7 +1288,7 @@ func (x *GetConfigResponse) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use GetConfigResponse.ProtoReflect.Descriptor instead.
 func (*GetConfigResponse) Descriptor() ([]byte, []int) {
-	return file_daemon_proto_rawDescGZIP(), []int{12}
+	return file_daemon_proto_rawDescGZIP(), []int{14}
 }
 
 func (x *GetConfigResponse) GetManagementUrl() string {
@@ -1370,7 +1500,7 @@ type PeerState struct {
 
 func (x *PeerState) Reset() {
 	*x = PeerState{}
-	mi := &file_daemon_proto_msgTypes[13]
+	mi := &file_daemon_proto_msgTypes[15]
 	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 	ms.StoreMessageInfo(mi)
 }
@@ -1382,7 +1512,7 @@ func (x *PeerState) String() string {
 func (*PeerState) ProtoMessage() {}
 
 func (x *PeerState) ProtoReflect() protoreflect.Message {
-	mi := &file_daemon_proto_msgTypes[13]
+	mi := &file_daemon_proto_msgTypes[15]
 	if x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -1395,7 +1525,7 @@ func (x *PeerState) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use PeerState.ProtoReflect.Descriptor instead.
 func (*PeerState) Descriptor() ([]byte, []int) {
-	return file_daemon_proto_rawDescGZIP(), []int{13}
+	return file_daemon_proto_rawDescGZIP(), []int{15}
 }
 
 func (x *PeerState) GetIP() string {
@@ -1540,7 +1670,7 @@ type LocalPeerState struct {
 
 func (x *LocalPeerState) Reset() {
 	*x = LocalPeerState{}
-	mi := &file_daemon_proto_msgTypes[14]
+	mi := &file_daemon_proto_msgTypes[16]
 	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 	ms.StoreMessageInfo(mi)
 }
@@ -1552,7 +1682,7 @@ func (x *LocalPeerState) String() string {
 func (*LocalPeerState) ProtoMessage() {}
 
 func (x *LocalPeerState) ProtoReflect() protoreflect.Message {
-	mi := &file_daemon_proto_msgTypes[14]
+	mi := &file_daemon_proto_msgTypes[16]
 	if x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -1565,7 +1695,7 @@ func (x *LocalPeerState) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use LocalPeerState.ProtoReflect.Descriptor instead.
 func (*LocalPeerState) Descriptor() ([]byte, []int) {
-	return file_daemon_proto_rawDescGZIP(), []int{14}
+	return file_daemon_proto_rawDescGZIP(), []int{16}
 }
 
 func (x *LocalPeerState) GetIP() string {
@@ -1629,7 +1759,7 @@ type SignalState struct {
 
 func (x *SignalState) Reset() {
 	*x = SignalState{}
-	mi := &file_daemon_proto_msgTypes[15]
+	mi := &file_daemon_proto_msgTypes[17]
 	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 	ms.StoreMessageInfo(mi)
 }
@@ -1641,7 +1771,7 @@ func (x *SignalState) String() string {
 func (*SignalState) ProtoMessage() {}
 
 func (x *SignalState) ProtoReflect() protoreflect.Message {
-	mi := &file_daemon_proto_msgTypes[15]
+	mi := &file_daemon_proto_msgTypes[17]
 	if x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -1654,7 +1784,7 @@ func (x *SignalState) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use SignalState.ProtoReflect.Descriptor instead.
 func (*SignalState) Descriptor() ([]byte, []int) {
-	return file_daemon_proto_rawDescGZIP(), []int{15}
+	return file_daemon_proto_rawDescGZIP(), []int{17}
 }
 
 func (x *SignalState) GetURL() string {
@@ -1690,7 +1820,7 @@ type ManagementState struct {
 
 func (x *ManagementState) Reset() {
 	*x = ManagementState{}
-	mi := &file_daemon_proto_msgTypes[16]
+	mi := &file_daemon_proto_msgTypes[18]
 	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 	ms.StoreMessageInfo(mi)
 }
@@ -1702,7 +1832,7 @@ func (x *ManagementState) String() string {
 func (*ManagementState) ProtoMessage() {}
 
 func (x *ManagementState) ProtoReflect() protoreflect.Message {
-	mi := &file_daemon_proto_msgTypes[16]
+	mi := &file_daemon_proto_msgTypes[18]
 	if x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -1715,7 +1845,7 @@ func (x *ManagementState) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use ManagementState.ProtoReflect.Descriptor instead.
 func (*ManagementState) Descriptor() ([]byte, []int) {
-	return file_daemon_proto_rawDescGZIP(), []int{16}
+	return file_daemon_proto_rawDescGZIP(), []int{18}
 }
 
 func (x *ManagementState) GetURL() string {
@@ -1751,7 +1881,7 @@ type RelayState struct {
 
 func (x *RelayState) Reset() {
 	*x = RelayState{}
-	mi := &file_daemon_proto_msgTypes[17]
+	mi := &file_daemon_proto_msgTypes[19]
 	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 	ms.StoreMessageInfo(mi)
 }
@@ -1763,7 +1893,7 @@ func (x *RelayState) String() string {
 func (*RelayState) ProtoMessage() {}
 
 func (x *RelayState) ProtoReflect() protoreflect.Message {
-	mi := &file_daemon_proto_msgTypes[17]
+	mi := &file_daemon_proto_msgTypes[19]
 	if x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -1776,7 +1906,7 @@ func (x *RelayState) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use RelayState.ProtoReflect.Descriptor instead.
 func (*RelayState) Descriptor() ([]byte, []int) {
-	return file_daemon_proto_rawDescGZIP(), []int{17}
+	return file_daemon_proto_rawDescGZIP(), []int{19}
 }
 
 func (x *RelayState) GetURI() string {
@@ -1812,7 +1942,7 @@ type NSGroupState struct {
 
 func (x *NSGroupState) Reset() {
 	*x = NSGroupState{}
-	mi := &file_daemon_proto_msgTypes[18]
+	mi := &file_daemon_proto_msgTypes[20]
 	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 	ms.StoreMessageInfo(mi)
 }
@@ -1824,7 +1954,7 @@ func (x *NSGroupState) String() string {
 func (*NSGroupState) ProtoMessage() {}
 
 func (x *NSGroupState) ProtoReflect() protoreflect.Message {
-	mi := &file_daemon_proto_msgTypes[18]
+	mi := &file_daemon_proto_msgTypes[20]
 	if x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -1837,7 +1967,7 @@ func (x *NSGroupState) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use NSGroupState.ProtoReflect.Descriptor instead.
 func (*NSGroupState) Descriptor() ([]byte, []int) {
-	return file_daemon_proto_rawDescGZIP(), []int{18}
+	return file_daemon_proto_rawDescGZIP(), []int{20}
 }
 
 func (x *NSGroupState) GetServers() []string {
@@ -1881,7 +2011,7 @@ type SSHSessionInfo struct {
 
 func (x *SSHSessionInfo) Reset() {
 	*x = SSHSessionInfo{}
-	mi := &file_daemon_proto_msgTypes[19]
+	mi := &file_daemon_proto_msgTypes[21]
 	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 	ms.StoreMessageInfo(mi)
 }
@@ -1893,7 +2023,7 @@ func (x *SSHSessionInfo) String() string {
 func (*SSHSessionInfo) ProtoMessage() {}
 
 func (x *SSHSessionInfo) ProtoReflect() protoreflect.Message {
-	mi := &file_daemon_proto_msgTypes[19]
+	mi := &file_daemon_proto_msgTypes[21]
 	if x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -1906,7 +2036,7 @@ func (x *SSHSessionInfo) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use SSHSessionInfo.ProtoReflect.Descriptor instead.
 func (*SSHSessionInfo) Descriptor() ([]byte, []int) {
-	return file_daemon_proto_rawDescGZIP(), []int{19}
+	return file_daemon_proto_rawDescGZIP(), []int{21}
 }
 
 func (x *SSHSessionInfo) GetUsername() string {
@@ -1948,7 +2078,7 @@ type SSHServerState struct {
 
 func (x *SSHServerState) Reset() {
 	*x = SSHServerState{}
-	mi := &file_daemon_proto_msgTypes[20]
+	mi := &file_daemon_proto_msgTypes[22]
 	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 	ms.StoreMessageInfo(mi)
 }
@@ -1960,7 +2090,7 @@ func (x *SSHServerState) String() string {
 func (*SSHServerState) ProtoMessage() {}
 
 func (x *SSHServerState) ProtoReflect() protoreflect.Message {
-	mi := &file_daemon_proto_msgTypes[20]
+	mi := &file_daemon_proto_msgTypes[22]
 	if x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -1973,7 +2103,7 @@ func (x *SSHServerState) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use SSHServerState.ProtoReflect.Descriptor instead.
 func (*SSHServerState) Descriptor() ([]byte, []int) {
-	return file_daemon_proto_rawDescGZIP(), []int{20}
+	return file_daemon_proto_rawDescGZIP(), []int{22}
 }
 
 func (x *SSHServerState) GetEnabled() bool {
@@ -2009,7 +2139,7 @@ type FullStatus struct {
 
 func (x *FullStatus) Reset() {
 	*x = FullStatus{}
-	mi := &file_daemon_proto_msgTypes[21]
+	mi := &file_daemon_proto_msgTypes[23]
 	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 	ms.StoreMessageInfo(mi)
 }
@@ -2021,7 +2151,7 @@ func (x *FullStatus) String() string {
 func (*FullStatus) ProtoMessage() {}
 
 func (x *FullStatus) ProtoReflect() protoreflect.Message {
-	mi := &file_daemon_proto_msgTypes[21]
+	mi := &file_daemon_proto_msgTypes[23]
 	if x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -2034,7 +2164,7 @@ func (x *FullStatus) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use FullStatus.ProtoReflect.Descriptor instead.
 func (*FullStatus) Descriptor() ([]byte, []int) {
-	return file_daemon_proto_rawDescGZIP(), []int{21}
+	return file_daemon_proto_rawDescGZIP(), []int{23}
 }
 
 func (x *FullStatus) GetManagementState() *ManagementState {
@@ -2116,7 +2246,7 @@ type ListNetworksRequest struct {
 
 func (x *ListNetworksRequest) Reset() {
 	*x = ListNetworksRequest{}
-	mi := &file_daemon_proto_msgTypes[22]
+	mi := &file_daemon_proto_msgTypes[24]
 	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 	ms.StoreMessageInfo(mi)
 }
@@ -2128,7 +2258,7 @@ func (x *ListNetworksRequest) String() string {
 func (*ListNetworksRequest) ProtoMessage() {}
 
 func (x *ListNetworksRequest) ProtoReflect() protoreflect.Message {
-	mi := &file_daemon_proto_msgTypes[22]
+	mi := &file_daemon_proto_msgTypes[24]
 	if x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -2141,7 +2271,7 @@ func (x *ListNetworksRequest) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use ListNetworksRequest.ProtoReflect.Descriptor instead.
 func (*ListNetworksRequest) Descriptor() ([]byte, []int) {
-	return file_daemon_proto_rawDescGZIP(), []int{22}
+	return file_daemon_proto_rawDescGZIP(), []int{24}
 }
 
 type ListNetworksResponse struct {
@@ -2153,7 +2283,7 @@ type ListNetworksResponse struct {
 
 func (x *ListNetworksResponse) Reset() {
 	*x = ListNetworksResponse{}
-	mi := &file_daemon_proto_msgTypes[23]
+	mi := &file_daemon_proto_msgTypes[25]
 	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 	ms.StoreMessageInfo(mi)
 }
@@ -2165,7 +2295,7 @@ func (x *ListNetworksResponse) String() string {
 func (*ListNetworksResponse) ProtoMessage() {}
 
 func (x *ListNetworksResponse) ProtoReflect() protoreflect.Message {
-	mi := &file_daemon_proto_msgTypes[23]
+	mi := &file_daemon_proto_msgTypes[25]
 	if x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -2178,7 +2308,7 @@ func (x *ListNetworksResponse) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use ListNetworksResponse.ProtoReflect.Descriptor instead.
 func (*ListNetworksResponse) Descriptor() ([]byte, []int) {
-	return file_daemon_proto_rawDescGZIP(), []int{23}
+	return file_daemon_proto_rawDescGZIP(), []int{25}
 }
 
 func (x *ListNetworksResponse) GetRoutes() []*Network {
@@ -2199,7 +2329,7 @@ type SelectNetworksRequest struct {
 
 func (x *SelectNetworksRequest) Reset() {
 	*x = SelectNetworksRequest{}
-	mi := &file_daemon_proto_msgTypes[24]
+	mi := &file_daemon_proto_msgTypes[26]
 	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 	ms.StoreMessageInfo(mi)
 }
@@ -2211,7 +2341,7 @@ func (x *SelectNetworksRequest) String() string {
 func (*SelectNetworksRequest) ProtoMessage() {}
 
 func (x *SelectNetworksRequest) ProtoReflect() protoreflect.Message {
-	mi := &file_daemon_proto_msgTypes[24]
+	mi := &file_daemon_proto_msgTypes[26]
 	if x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -2224,7 +2354,7 @@ func (x *SelectNetworksRequest) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use SelectNetworksRequest.ProtoReflect.Descriptor instead.
 func (*SelectNetworksRequest) Descriptor() ([]byte, []int) {
-	return file_daemon_proto_rawDescGZIP(), []int{24}
+	return file_daemon_proto_rawDescGZIP(), []int{26}
 }
 
 func (x *SelectNetworksRequest) GetNetworkIDs() []string {
@@ -2256,7 +2386,7 @@ type SelectNetworksResponse struct {
 
 func (x *SelectNetworksResponse) Reset() {
 	*x = SelectNetworksResponse{}
-	mi := &file_daemon_proto_msgTypes[25]
+	mi := &file_daemon_proto_msgTypes[27]
 	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 	ms.StoreMessageInfo(mi)
 }
@@ -2268,7 +2398,7 @@ func (x *SelectNetworksResponse) String() string {
 func (*SelectNetworksResponse) ProtoMessage() {}
 
 func (x *SelectNetworksResponse) ProtoReflect() protoreflect.Message {
-	mi := &file_daemon_proto_msgTypes[25]
+	mi := &file_daemon_proto_msgTypes[27]
 	if x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -2281,7 +2411,7 @@ func (x *SelectNetworksResponse) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use SelectNetworksResponse.ProtoReflect.Descriptor instead.
 func (*SelectNetworksResponse) Descriptor() ([]byte, []int) {
-	return file_daemon_proto_rawDescGZIP(), []int{25}
+	return file_daemon_proto_rawDescGZIP(), []int{27}
 }
 
 type IPList struct {
@@ -2293,7 +2423,7 @@ type IPList struct {
 
 func (x *IPList) Reset() {
 	*x = IPList{}
-	mi := &file_daemon_proto_msgTypes[26]
+	mi := &file_daemon_proto_msgTypes[28]
 	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 	ms.StoreMessageInfo(mi)
 }
@@ -2305,7 +2435,7 @@ func (x *IPList) String() string {
 func (*IPList) ProtoMessage() {}
 
 func (x *IPList) ProtoReflect() protoreflect.Message {
-	mi := &file_daemon_proto_msgTypes[26]
+	mi := &file_daemon_proto_msgTypes[28]
 	if x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -2318,7 +2448,7 @@ func (x *IPList) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use IPList.ProtoReflect.Descriptor instead.
 func (*IPList) Descriptor() ([]byte, []int) {
-	return file_daemon_proto_rawDescGZIP(), []int{26}
+	return file_daemon_proto_rawDescGZIP(), []int{28}
 }
 
 func (x *IPList) GetIps() []string {
@@ -2341,7 +2471,7 @@ type Network struct {
 
 func (x *Network) Reset() {
 	*x = Network{}
-	mi := &file_daemon_proto_msgTypes[27]
+	mi := &file_daemon_proto_msgTypes[29]
 	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 	ms.StoreMessageInfo(mi)
 }
@@ -2353,7 +2483,7 @@ func (x *Network) String() string {
 func (*Network) ProtoMessage() {}
 
 func (x *Network) ProtoReflect() protoreflect.Message {
-	mi := &file_daemon_proto_msgTypes[27]
+	mi := &file_daemon_proto_msgTypes[29]
 	if x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -2366,7 +2496,7 @@ func (x *Network) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use Network.ProtoReflect.Descriptor instead.
 func (*Network) Descriptor() ([]byte, []int) {
-	return file_daemon_proto_rawDescGZIP(), []int{27}
+	return file_daemon_proto_rawDescGZIP(), []int{29}
 }
 
 func (x *Network) GetID() string {
@@ -2418,7 +2548,7 @@ type PortInfo struct {
 
 func (x *PortInfo) Reset() {
 	*x = PortInfo{}
-	mi := &file_daemon_proto_msgTypes[28]
+	mi := &file_daemon_proto_msgTypes[30]
 	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 	ms.StoreMessageInfo(mi)
 }
@@ -2430,7 +2560,7 @@ func (x *PortInfo) String() string {
 func (*PortInfo) ProtoMessage() {}
 
 func (x *PortInfo) ProtoReflect() protoreflect.Message {
-	mi := &file_daemon_proto_msgTypes[28]
+	mi := &file_daemon_proto_msgTypes[30]
 	if x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -2443,7 +2573,7 @@ func (x *PortInfo) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use PortInfo.ProtoReflect.Descriptor instead.
 func (*PortInfo) Descriptor() ([]byte, []int) {
-	return file_daemon_proto_rawDescGZIP(), []int{28}
+	return file_daemon_proto_rawDescGZIP(), []int{30}
 }
 
 func (x *PortInfo) GetPortSelection() isPortInfo_PortSelection {
@@ -2500,7 +2630,7 @@ type ForwardingRule struct {
 
 func (x *ForwardingRule) Reset() {
 	*x = ForwardingRule{}
-	mi := &file_daemon_proto_msgTypes[29]
+	mi := &file_daemon_proto_msgTypes[31]
 	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 	ms.StoreMessageInfo(mi)
 }
@@ -2512,7 +2642,7 @@ func (x *ForwardingRule) String() string {
 func (*ForwardingRule) ProtoMessage() {}
 
 func (x *ForwardingRule) ProtoReflect() protoreflect.Message {
-	mi := &file_daemon_proto_msgTypes[29]
+	mi := &file_daemon_proto_msgTypes[31]
 	if x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -2525,7 +2655,7 @@ func (x *ForwardingRule) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use ForwardingRule.ProtoReflect.Descriptor instead.
 func (*ForwardingRule) Descriptor() ([]byte, []int) {
-	return file_daemon_proto_rawDescGZIP(), []int{29}
+	return file_daemon_proto_rawDescGZIP(), []int{31}
 }
 
 func (x *ForwardingRule) GetProtocol() string {
@@ -2572,7 +2702,7 @@ type ForwardingRulesResponse struct {
 
 func (x *ForwardingRulesResponse) Reset() {
 	*x = ForwardingRulesResponse{}
-	mi := &file_daemon_proto_msgTypes[30]
+	mi := &file_daemon_proto_msgTypes[32]
 	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 	ms.StoreMessageInfo(mi)
 }
@@ -2584,7 +2714,7 @@ func (x *ForwardingRulesResponse) String() string {
 func (*ForwardingRulesResponse) ProtoMessage() {}
 
 func (x *ForwardingRulesResponse) ProtoReflect() protoreflect.Message {
-	mi := &file_daemon_proto_msgTypes[30]
+	mi := &file_daemon_proto_msgTypes[32]
 	if x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -2597,7 +2727,7 @@ func (x *ForwardingRulesResponse) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use ForwardingRulesResponse.ProtoReflect.Descriptor instead.
 func (*ForwardingRulesResponse) Descriptor() ([]byte, []int) {
-	return file_daemon_proto_rawDescGZIP(), []int{30}
+	return file_daemon_proto_rawDescGZIP(), []int{32}
 }
 
 func (x *ForwardingRulesResponse) GetRules() []*ForwardingRule {
@@ -2621,7 +2751,7 @@ type DebugBundleRequest struct {
 
 func (x *DebugBundleRequest) Reset() {
 	*x = DebugBundleRequest{}
-	mi := &file_daemon_proto_msgTypes[31]
+	mi := &file_daemon_proto_msgTypes[33]
 	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 	ms.StoreMessageInfo(mi)
 }
@@ -2633,7 +2763,7 @@ func (x *DebugBundleRequest) String() string {
 func (*DebugBundleRequest) ProtoMessage() {}
 
 func (x *DebugBundleRequest) ProtoReflect() protoreflect.Message {
-	mi := &file_daemon_proto_msgTypes[31]
+	mi := &file_daemon_proto_msgTypes[33]
 	if x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -2646,7 +2776,7 @@ func (x *DebugBundleRequest) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use DebugBundleRequest.ProtoReflect.Descriptor instead.
 func (*DebugBundleRequest) Descriptor() ([]byte, []int) {
-	return file_daemon_proto_rawDescGZIP(), []int{31}
+	return file_daemon_proto_rawDescGZIP(), []int{33}
 }
 
 func (x *DebugBundleRequest) GetAnonymize() bool {
@@ -2695,7 +2825,7 @@ type DebugBundleResponse struct {
 
 func (x *DebugBundleResponse) Reset() {
 	*x = DebugBundleResponse{}
-	mi := &file_daemon_proto_msgTypes[32]
+	mi := &file_daemon_proto_msgTypes[34]
 	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 	ms.StoreMessageInfo(mi)
 }
@@ -2707,7 +2837,7 @@ func (x *DebugBundleResponse) String() string {
 func (*DebugBundleResponse) ProtoMessage() {}
 
 func (x *DebugBundleResponse) ProtoReflect() protoreflect.Message {
-	mi := &file_daemon_proto_msgTypes[32]
+	mi := &file_daemon_proto_msgTypes[34]
 	if x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -2720,7 +2850,7 @@ func (x *DebugBundleResponse) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use DebugBundleResponse.ProtoReflect.Descriptor instead.
 func (*DebugBundleResponse) Descriptor() ([]byte, []int) {
-	return file_daemon_proto_rawDescGZIP(), []int{32}
+	return file_daemon_proto_rawDescGZIP(), []int{34}
 }
 
 func (x *DebugBundleResponse) GetPath() string {
@@ -2752,7 +2882,7 @@ type GetLogLevelRequest struct {
 
 func (x *GetLogLevelRequest) Reset() {
 	*x = GetLogLevelRequest{}
-	mi := &file_daemon_proto_msgTypes[33]
+	mi := &file_daemon_proto_msgTypes[35]
 	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 	ms.StoreMessageInfo(mi)
 }
@@ -2764,7 +2894,7 @@ func (x *GetLogLevelRequest) String() string {
 func (*GetLogLevelRequest) ProtoMessage() {}
 
 func (x *GetLogLevelRequest) ProtoReflect() protoreflect.Message {
-	mi := &file_daemon_proto_msgTypes[33]
+	mi := &file_daemon_proto_msgTypes[35]
 	if x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -2777,7 +2907,7 @@ func (x *GetLogLevelRequest) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use GetLogLevelRequest.ProtoReflect.Descriptor instead.
 func (*GetLogLevelRequest) Descriptor() ([]byte, []int) {
-	return file_daemon_proto_rawDescGZIP(), []int{33}
+	return file_daemon_proto_rawDescGZIP(), []int{35}
 }
 
 type GetLogLevelResponse struct {
@@ -2789,7 +2919,7 @@ type GetLogLevelResponse struct {
 
 func (x *GetLogLevelResponse) Reset() {
 	*x = GetLogLevelResponse{}
-	mi := &file_daemon_proto_msgTypes[34]
+	mi := &file_daemon_proto_msgTypes[36]
 	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 	ms.StoreMessageInfo(mi)
 }
@@ -2801,7 +2931,7 @@ func (x *GetLogLevelResponse) String() string {
 func (*GetLogLevelResponse) ProtoMessage() {}
 
 func (x *GetLogLevelResponse) ProtoReflect() protoreflect.Message {
-	mi := &file_daemon_proto_msgTypes[34]
+	mi := &file_daemon_proto_msgTypes[36]
 	if x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -2814,7 +2944,7 @@ func (x *GetLogLevelResponse) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use GetLogLevelResponse.ProtoReflect.Descriptor instead.
 func (*GetLogLevelResponse) Descriptor() ([]byte, []int) {
-	return file_daemon_proto_rawDescGZIP(), []int{34}
+	return file_daemon_proto_rawDescGZIP(), []int{36}
 }
 
 func (x *GetLogLevelResponse) GetLevel() LogLevel {
@@ -2833,7 +2963,7 @@ type SetLogLevelRequest struct {
 
 func (x *SetLogLevelRequest) Reset() {
 	*x = SetLogLevelRequest{}
-	mi := &file_daemon_proto_msgTypes[35]
+	mi := &file_daemon_proto_msgTypes[37]
 	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 	ms.StoreMessageInfo(mi)
 }
@@ -2845,7 +2975,7 @@ func (x *SetLogLevelRequest) String() string {
 func (*SetLogLevelRequest) ProtoMessage() {}
 
 func (x *SetLogLevelRequest) ProtoReflect() protoreflect.Message {
-	mi := &file_daemon_proto_msgTypes[35]
+	mi := &file_daemon_proto_msgTypes[37]
 	if x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -2858,7 +2988,7 @@ func (x *SetLogLevelRequest) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use SetLogLevelRequest.ProtoReflect.Descriptor instead.
 func (*SetLogLevelRequest) Descriptor() ([]byte, []int) {
-	return file_daemon_proto_rawDescGZIP(), []int{35}
+	return file_daemon_proto_rawDescGZIP(), []int{37}
 }
 
 func (x *SetLogLevelRequest) GetLevel() LogLevel {
@@ -2876,7 +3006,7 @@ type SetLogLevelResponse struct {
 
 func (x *SetLogLevelResponse) Reset() {
 	*x = SetLogLevelResponse{}
-	mi := &file_daemon_proto_msgTypes[36]
+	mi := &file_daemon_proto_msgTypes[38]
 	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 	ms.StoreMessageInfo(mi)
 }
@@ -2888,7 +3018,7 @@ func (x *SetLogLevelResponse) String() string {
 func (*SetLogLevelResponse) ProtoMessage() {}
 
 func (x *SetLogLevelResponse) ProtoReflect() protoreflect.Message {
-	mi := &file_daemon_proto_msgTypes[36]
+	mi := &file_daemon_proto_msgTypes[38]
 	if x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -2901,7 +3031,7 @@ func (x *SetLogLevelResponse) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use SetLogLevelResponse.ProtoReflect.Descriptor instead.
 func (*SetLogLevelResponse) Descriptor() ([]byte, []int) {
-	return file_daemon_proto_rawDescGZIP(), []int{36}
+	return file_daemon_proto_rawDescGZIP(), []int{38}
 }
 
 // State represents a daemon state entry
@@ -2914,7 +3044,7 @@ type State struct {
 
 func (x *State) Reset() {
 	*x = State{}
-	mi := &file_daemon_proto_msgTypes[37]
+	mi := &file_daemon_proto_msgTypes[39]
 	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 	ms.StoreMessageInfo(mi)
 }
@@ -2926,7 +3056,7 @@ func (x *State) String() string {
 func (*State) ProtoMessage() {}
 
 func (x *State) ProtoReflect() protoreflect.Message {
-	mi := &file_daemon_proto_msgTypes[37]
+	mi := &file_daemon_proto_msgTypes[39]
 	if x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -2939,7 +3069,7 @@ func (x *State) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use State.ProtoReflect.Descriptor instead.
 func (*State) Descriptor() ([]byte, []int) {
-	return file_daemon_proto_rawDescGZIP(), []int{37}
+	return file_daemon_proto_rawDescGZIP(), []int{39}
 }
 
 func (x *State) GetName() string {
@@ -2958,7 +3088,7 @@ type ListStatesRequest struct {
 
 func (x *ListStatesRequest) Reset() {
 	*x = ListStatesRequest{}
-	mi := &file_daemon_proto_msgTypes[38]
+	mi := &file_daemon_proto_msgTypes[40]
 	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 	ms.StoreMessageInfo(mi)
 }
@@ -2970,7 +3100,7 @@ func (x *ListStatesRequest) String() string {
 func (*ListStatesRequest) ProtoMessage() {}
 
 func (x *ListStatesRequest) ProtoReflect() protoreflect.Message {
-	mi := &file_daemon_proto_msgTypes[38]
+	mi := &file_daemon_proto_msgTypes[40]
 	if x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -2983,7 +3113,7 @@ func (x *ListStatesRequest) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use ListStatesRequest.ProtoReflect.Descriptor instead.
 func (*ListStatesRequest) Descriptor() ([]byte, []int) {
-	return file_daemon_proto_rawDescGZIP(), []int{38}
+	return file_daemon_proto_rawDescGZIP(), []int{40}
 }
 
 // ListStatesResponse contains a list of states
@@ -2996,7 +3126,7 @@ type ListStatesResponse struct {
 
 func (x *ListStatesResponse) Reset() {
 	*x = ListStatesResponse{}
-	mi := &file_daemon_proto_msgTypes[39]
+	mi := &file_daemon_proto_msgTypes[41]
 	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 	ms.StoreMessageInfo(mi)
 }
@@ -3008,7 +3138,7 @@ func (x *ListStatesResponse) String() string {
 func (*ListStatesResponse) ProtoMessage() {}
 
 func (x *ListStatesResponse) ProtoReflect() protoreflect.Message {
-	mi := &file_daemon_proto_msgTypes[39]
+	mi := &file_daemon_proto_msgTypes[41]
 	if x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -3021,7 +3151,7 @@ func (x *ListStatesResponse) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use ListStatesResponse.ProtoReflect.Descriptor instead.
 func (*ListStatesResponse) Descriptor() ([]byte, []int) {
-	return file_daemon_proto_rawDescGZIP(), []int{39}
+	return file_daemon_proto_rawDescGZIP(), []int{41}
 }
 
 func (x *ListStatesResponse) GetStates() []*State {
@@ -3042,7 +3172,7 @@ type CleanStateRequest struct {
 
 func (x *CleanStateRequest) Reset() {
 	*x = CleanStateRequest{}
-	mi := &file_daemon_proto_msgTypes[40]
+	mi := &file_daemon_proto_msgTypes[42]
 	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 	ms.StoreMessageInfo(mi)
 }
@@ -3054,7 +3184,7 @@ func (x *CleanStateRequest) String() string {
 func (*CleanStateRequest) ProtoMessage() {}
 
 func (x *CleanStateRequest) ProtoReflect() protoreflect.Message {
-	mi := &file_daemon_proto_msgTypes[40]
+	mi := &file_daemon_proto_msgTypes[42]
 	if x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -3067,7 +3197,7 @@ func (x *CleanStateRequest) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use CleanStateRequest.ProtoReflect.Descriptor instead.
 func (*CleanStateRequest) Descriptor() ([]byte, []int) {
-	return file_daemon_proto_rawDescGZIP(), []int{40}
+	return file_daemon_proto_rawDescGZIP(), []int{42}
 }
 
 func (x *CleanStateRequest) GetStateName() string {
@@ -3094,7 +3224,7 @@ type CleanStateResponse struct {
 
 func (x *CleanStateResponse) Reset() {
 	*x = CleanStateResponse{}
-	mi := &file_daemon_proto_msgTypes[41]
+	mi := &file_daemon_proto_msgTypes[43]
 	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 	ms.StoreMessageInfo(mi)
 }
@@ -3106,7 +3236,7 @@ func (x *CleanStateResponse) String() string {
 func (*CleanStateResponse) ProtoMessage() {}
 
 func (x *CleanStateResponse) ProtoReflect() protoreflect.Message {
-	mi := &file_daemon_proto_msgTypes[41]
+	mi := &file_daemon_proto_msgTypes[43]
 	if x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -3119,7 +3249,7 @@ func (x *CleanStateResponse) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use CleanStateResponse.ProtoReflect.Descriptor instead.
 func (*CleanStateResponse) Descriptor() ([]byte, []int) {
-	return file_daemon_proto_rawDescGZIP(), []int{41}
+	return file_daemon_proto_rawDescGZIP(), []int{43}
 }
 
 func (x *CleanStateResponse) GetCleanedStates() int32 {
@@ -3140,7 +3270,7 @@ type DeleteStateRequest struct {
 
 func (x *DeleteStateRequest) Reset() {
 	*x = DeleteStateRequest{}
-	mi := &file_daemon_proto_msgTypes[42]
+	mi := &file_daemon_proto_msgTypes[44]
 	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 	ms.StoreMessageInfo(mi)
 }
@@ -3152,7 +3282,7 @@ func (x *DeleteStateRequest) String() string {
 func (*DeleteStateRequest) ProtoMessage() {}
 
 func (x *DeleteStateRequest) ProtoReflect() protoreflect.Message {
-	mi := &file_daemon_proto_msgTypes[42]
+	mi := &file_daemon_proto_msgTypes[44]
 	if x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -3165,7 +3295,7 @@ func (x *DeleteStateRequest) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use DeleteStateRequest.ProtoReflect.Descriptor instead.
 func (*DeleteStateRequest) Descriptor() ([]byte, []int) {
-	return file_daemon_proto_rawDescGZIP(), []int{42}
+	return file_daemon_proto_rawDescGZIP(), []int{44}
 }
 
 func (x *DeleteStateRequest) GetStateName() string {
@@ -3192,7 +3322,7 @@ type DeleteStateResponse struct {
 
 func (x *DeleteStateResponse) Reset() {
 	*x = DeleteStateResponse{}
-	mi := &file_daemon_proto_msgTypes[43]
+	mi := &file_daemon_proto_msgTypes[45]
 	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 	ms.StoreMessageInfo(mi)
 }
@@ -3204,7 +3334,7 @@ func (x *DeleteStateResponse) String() string {
 func (*DeleteStateResponse) ProtoMessage() {}
 
 func (x *DeleteStateResponse) ProtoReflect() protoreflect.Message {
-	mi := &file_daemon_proto_msgTypes[43]
+	mi := &file_daemon_proto_msgTypes[45]
 	if x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -3217,7 +3347,7 @@ func (x *DeleteStateResponse) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use DeleteStateResponse.ProtoReflect.Descriptor instead.
 func (*DeleteStateResponse) Descriptor() ([]byte, []int) {
-	return file_daemon_proto_rawDescGZIP(), []int{43}
+	return file_daemon_proto_rawDescGZIP(), []int{45}
 }
 
 func (x *DeleteStateResponse) GetDeletedStates() int32 {
@@ -3236,7 +3366,7 @@ type SetSyncResponsePersistenceRequest struct {
 
 func (x *SetSyncResponsePersistenceRequest) Reset() {
 	*x = SetSyncResponsePersistenceRequest{}
-	mi := &file_daemon_proto_msgTypes[44]
+	mi := &file_daemon_proto_msgTypes[46]
 	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 	ms.StoreMessageInfo(mi)
 }
@@ -3248,7 +3378,7 @@ func (x *SetSyncResponsePersistenceRequest) String() string {
 func (*SetSyncResponsePersistenceRequest) ProtoMessage() {}
 
 func (x *SetSyncResponsePersistenceRequest) ProtoReflect() protoreflect.Message {
-	mi := &file_daemon_proto_msgTypes[44]
+	mi := &file_daemon_proto_msgTypes[46]
 	if x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -3261,7 +3391,7 @@ func (x *SetSyncResponsePersistenceRequest) ProtoReflect() protoreflect.Message
 
 // Deprecated: Use SetSyncResponsePersistenceRequest.ProtoReflect.Descriptor instead.
 func (*SetSyncResponsePersistenceRequest) Descriptor() ([]byte, []int) {
-	return file_daemon_proto_rawDescGZIP(), []int{44}
+	return file_daemon_proto_rawDescGZIP(), []int{46}
 }
 
 func (x *SetSyncResponsePersistenceRequest) GetEnabled() bool {
@@ -3279,7 +3409,7 @@ type SetSyncResponsePersistenceResponse struct {
 
 func (x *SetSyncResponsePersistenceResponse) Reset() {
 	*x = SetSyncResponsePersistenceResponse{}
-	mi := &file_daemon_proto_msgTypes[45]
+	mi := &file_daemon_proto_msgTypes[47]
 	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 	ms.StoreMessageInfo(mi)
 }
@@ -3291,7 +3421,7 @@ func (x *SetSyncResponsePersistenceResponse) String() string {
 func (*SetSyncResponsePersistenceResponse) ProtoMessage() {}
 
 func (x *SetSyncResponsePersistenceResponse) ProtoReflect() protoreflect.Message {
-	mi := &file_daemon_proto_msgTypes[45]
+	mi := &file_daemon_proto_msgTypes[47]
 	if x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -3304,7 +3434,7 @@ func (x *SetSyncResponsePersistenceResponse) ProtoReflect() protoreflect.Message
 
 // Deprecated: Use SetSyncResponsePersistenceResponse.ProtoReflect.Descriptor instead.
 func (*SetSyncResponsePersistenceResponse) Descriptor() ([]byte, []int) {
-	return file_daemon_proto_rawDescGZIP(), []int{45}
+	return file_daemon_proto_rawDescGZIP(), []int{47}
 }
 
 type TCPFlags struct {
@@ -3321,7 +3451,7 @@ type TCPFlags struct {
 
 func (x *TCPFlags) Reset() {
 	*x = TCPFlags{}
-	mi := &file_daemon_proto_msgTypes[46]
+	mi := &file_daemon_proto_msgTypes[48]
 	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 	ms.StoreMessageInfo(mi)
 }
@@ -3333,7 +3463,7 @@ func (x *TCPFlags) String() string {
 func (*TCPFlags) ProtoMessage() {}
 
 func (x *TCPFlags) ProtoReflect() protoreflect.Message {
-	mi := &file_daemon_proto_msgTypes[46]
+	mi := &file_daemon_proto_msgTypes[48]
 	if x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -3346,7 +3476,7 @@ func (x *TCPFlags) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use TCPFlags.ProtoReflect.Descriptor instead.
 func (*TCPFlags) Descriptor() ([]byte, []int) {
-	return file_daemon_proto_rawDescGZIP(), []int{46}
+	return file_daemon_proto_rawDescGZIP(), []int{48}
 }
 
 func (x *TCPFlags) GetSyn() bool {
@@ -3408,7 +3538,7 @@ type TracePacketRequest struct {
 
 func (x *TracePacketRequest) Reset() {
 	*x = TracePacketRequest{}
-	mi := &file_daemon_proto_msgTypes[47]
+	mi := &file_daemon_proto_msgTypes[49]
 	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 	ms.StoreMessageInfo(mi)
 }
@@ -3420,7 +3550,7 @@ func (x *TracePacketRequest) String() string {
 func (*TracePacketRequest) ProtoMessage() {}
 
 func (x *TracePacketRequest) ProtoReflect() protoreflect.Message {
-	mi := &file_daemon_proto_msgTypes[47]
+	mi := &file_daemon_proto_msgTypes[49]
 	if x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -3433,7 +3563,7 @@ func (x *TracePacketRequest) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use TracePacketRequest.ProtoReflect.Descriptor instead.
 func (*TracePacketRequest) Descriptor() ([]byte, []int) {
-	return file_daemon_proto_rawDescGZIP(), []int{47}
+	return file_daemon_proto_rawDescGZIP(), []int{49}
 }
 
 func (x *TracePacketRequest) GetSourceIp() string {
@@ -3511,7 +3641,7 @@ type TraceStage struct {
 
 func (x *TraceStage) Reset() {
 	*x = TraceStage{}
-	mi := &file_daemon_proto_msgTypes[48]
+	mi := &file_daemon_proto_msgTypes[50]
 	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 	ms.StoreMessageInfo(mi)
 }
@@ -3523,7 +3653,7 @@ func (x *TraceStage) String() string {
 func (*TraceStage) ProtoMessage() {}
 
 func (x *TraceStage) ProtoReflect() protoreflect.Message {
-	mi := &file_daemon_proto_msgTypes[48]
+	mi := &file_daemon_proto_msgTypes[50]
 	if x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -3536,7 +3666,7 @@ func (x *TraceStage) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use TraceStage.ProtoReflect.Descriptor instead.
 func (*TraceStage) Descriptor() ([]byte, []int) {
-	return file_daemon_proto_rawDescGZIP(), []int{48}
+	return file_daemon_proto_rawDescGZIP(), []int{50}
 }
 
 func (x *TraceStage) GetName() string {
@@ -3577,7 +3707,7 @@ type TracePacketResponse struct {
 
 func (x *TracePacketResponse) Reset() {
 	*x = TracePacketResponse{}
-	mi := &file_daemon_proto_msgTypes[49]
+	mi := &file_daemon_proto_msgTypes[51]
 	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 	ms.StoreMessageInfo(mi)
 }
@@ -3589,7 +3719,7 @@ func (x *TracePacketResponse) String() string {
 func (*TracePacketResponse) ProtoMessage() {}
 
 func (x *TracePacketResponse) ProtoReflect() protoreflect.Message {
-	mi := &file_daemon_proto_msgTypes[49]
+	mi := &file_daemon_proto_msgTypes[51]
 	if x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -3602,7 +3732,7 @@ func (x *TracePacketResponse) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use TracePacketResponse.ProtoReflect.Descriptor instead.
 func (*TracePacketResponse) Descriptor() ([]byte, []int) {
-	return file_daemon_proto_rawDescGZIP(), []int{49}
+	return file_daemon_proto_rawDescGZIP(), []int{51}
 }
 
 func (x *TracePacketResponse) GetStages() []*TraceStage {
@@ -3627,7 +3757,7 @@ type SubscribeRequest struct {
 
 func (x *SubscribeRequest) Reset() {
 	*x = SubscribeRequest{}
-	mi := &file_daemon_proto_msgTypes[50]
+	mi := &file_daemon_proto_msgTypes[52]
 	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 	ms.StoreMessageInfo(mi)
 }
@@ -3639,7 +3769,7 @@ func (x *SubscribeRequest) String() string {
 func (*SubscribeRequest) ProtoMessage() {}
 
 func (x *SubscribeRequest) ProtoReflect() protoreflect.Message {
-	mi := &file_daemon_proto_msgTypes[50]
+	mi := &file_daemon_proto_msgTypes[52]
 	if x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -3652,7 +3782,7 @@ func (x *SubscribeRequest) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use SubscribeRequest.ProtoReflect.Descriptor instead.
 func (*SubscribeRequest) Descriptor() ([]byte, []int) {
-	return file_daemon_proto_rawDescGZIP(), []int{50}
+	return file_daemon_proto_rawDescGZIP(), []int{52}
 }
 
 type SystemEvent struct {
@@ -3670,7 +3800,7 @@ type SystemEvent struct {
 
 func (x *SystemEvent) Reset() {
 	*x = SystemEvent{}
-	mi := &file_daemon_proto_msgTypes[51]
+	mi := &file_daemon_proto_msgTypes[53]
 	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 	ms.StoreMessageInfo(mi)
 }
@@ -3682,7 +3812,7 @@ func (x *SystemEvent) String() string {
 func (*SystemEvent) ProtoMessage() {}
 
 func (x *SystemEvent) ProtoReflect() protoreflect.Message {
-	mi := &file_daemon_proto_msgTypes[51]
+	mi := &file_daemon_proto_msgTypes[53]
 	if x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -3695,7 +3825,7 @@ func (x *SystemEvent) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use SystemEvent.ProtoReflect.Descriptor instead.
 func (*SystemEvent) Descriptor() ([]byte, []int) {
-	return file_daemon_proto_rawDescGZIP(), []int{51}
+	return file_daemon_proto_rawDescGZIP(), []int{53}
 }
 
 func (x *SystemEvent) GetId() string {
@@ -3755,7 +3885,7 @@ type GetEventsRequest struct {
 
 func (x *GetEventsRequest) Reset() {
 	*x = GetEventsRequest{}
-	mi := &file_daemon_proto_msgTypes[52]
+	mi := &file_daemon_proto_msgTypes[54]
 	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 	ms.StoreMessageInfo(mi)
 }
@@ -3767,7 +3897,7 @@ func (x *GetEventsRequest) String() string {
 func (*GetEventsRequest) ProtoMessage() {}
 
 func (x *GetEventsRequest) ProtoReflect() protoreflect.Message {
-	mi := &file_daemon_proto_msgTypes[52]
+	mi := &file_daemon_proto_msgTypes[54]
 	if x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -3780,7 +3910,7 @@ func (x *GetEventsRequest) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use GetEventsRequest.ProtoReflect.Descriptor instead.
 func (*GetEventsRequest) Descriptor() ([]byte, []int) {
-	return file_daemon_proto_rawDescGZIP(), []int{52}
+	return file_daemon_proto_rawDescGZIP(), []int{54}
 }
 
 type GetEventsResponse struct {
@@ -3792,7 +3922,7 @@ type GetEventsResponse struct {
 
 func (x *GetEventsResponse) Reset() {
 	*x = GetEventsResponse{}
-	mi := &file_daemon_proto_msgTypes[53]
+	mi := &file_daemon_proto_msgTypes[55]
 	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 	ms.StoreMessageInfo(mi)
 }
@@ -3804,7 +3934,7 @@ func (x *GetEventsResponse) String() string {
 func (*GetEventsResponse) ProtoMessage() {}
 
 func (x *GetEventsResponse) ProtoReflect() protoreflect.Message {
-	mi := &file_daemon_proto_msgTypes[53]
+	mi := &file_daemon_proto_msgTypes[55]
 	if x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -3817,7 +3947,7 @@ func (x *GetEventsResponse) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use GetEventsResponse.ProtoReflect.Descriptor instead.
 func (*GetEventsResponse) Descriptor() ([]byte, []int) {
-	return file_daemon_proto_rawDescGZIP(), []int{53}
+	return file_daemon_proto_rawDescGZIP(), []int{55}
 }
 
 func (x *GetEventsResponse) GetEvents() []*SystemEvent {
@@ -3837,7 +3967,7 @@ type SwitchProfileRequest struct {
 
 func (x *SwitchProfileRequest) Reset() {
 	*x = SwitchProfileRequest{}
-	mi := &file_daemon_proto_msgTypes[54]
+	mi := &file_daemon_proto_msgTypes[56]
 	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 	ms.StoreMessageInfo(mi)
 }
@@ -3849,7 +3979,7 @@ func (x *SwitchProfileRequest) String() string {
 func (*SwitchProfileRequest) ProtoMessage() {}
 
 func (x *SwitchProfileRequest) ProtoReflect() protoreflect.Message {
-	mi := &file_daemon_proto_msgTypes[54]
+	mi := &file_daemon_proto_msgTypes[56]
 	if x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -3862,7 +3992,7 @@ func (x *SwitchProfileRequest) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use SwitchProfileRequest.ProtoReflect.Descriptor instead.
 func (*SwitchProfileRequest) Descriptor() ([]byte, []int) {
-	return file_daemon_proto_rawDescGZIP(), []int{54}
+	return file_daemon_proto_rawDescGZIP(), []int{56}
 }
 
 func (x *SwitchProfileRequest) GetProfileName() string {
@@ -3887,7 +4017,7 @@ type SwitchProfileResponse struct {
 
 func (x *SwitchProfileResponse) Reset() {
 	*x = SwitchProfileResponse{}
-	mi := &file_daemon_proto_msgTypes[55]
+	mi := &file_daemon_proto_msgTypes[57]
 	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 	ms.StoreMessageInfo(mi)
 }
@@ -3899,7 +4029,7 @@ func (x *SwitchProfileResponse) String() string {
 func (*SwitchProfileResponse) ProtoMessage() {}
 
 func (x *SwitchProfileResponse) ProtoReflect() protoreflect.Message {
-	mi := &file_daemon_proto_msgTypes[55]
+	mi := &file_daemon_proto_msgTypes[57]
 	if x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -3912,7 +4042,7 @@ func (x *SwitchProfileResponse) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use SwitchProfileResponse.ProtoReflect.Descriptor instead.
 func (*SwitchProfileResponse) Descriptor() ([]byte, []int) {
-	return file_daemon_proto_rawDescGZIP(), []int{55}
+	return file_daemon_proto_rawDescGZIP(), []int{57}
 }
 
 type SetConfigRequest struct {
@@ -3960,7 +4090,7 @@ type SetConfigRequest struct {
 
 func (x *SetConfigRequest) Reset() {
 	*x = SetConfigRequest{}
-	mi := &file_daemon_proto_msgTypes[56]
+	mi := &file_daemon_proto_msgTypes[58]
 	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 	ms.StoreMessageInfo(mi)
 }
@@ -3972,7 +4102,7 @@ func (x *SetConfigRequest) String() string {
 func (*SetConfigRequest) ProtoMessage() {}
 
 func (x *SetConfigRequest) ProtoReflect() protoreflect.Message {
-	mi := &file_daemon_proto_msgTypes[56]
+	mi := &file_daemon_proto_msgTypes[58]
 	if x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -3985,7 +4115,7 @@ func (x *SetConfigRequest) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use SetConfigRequest.ProtoReflect.Descriptor instead.
 func (*SetConfigRequest) Descriptor() ([]byte, []int) {
-	return file_daemon_proto_rawDescGZIP(), []int{56}
+	return file_daemon_proto_rawDescGZIP(), []int{58}
 }
 
 func (x *SetConfigRequest) GetUsername() string {
@@ -4234,7 +4364,7 @@ type SetConfigResponse struct {
 
 func (x *SetConfigResponse) Reset() {
 	*x = SetConfigResponse{}
-	mi := &file_daemon_proto_msgTypes[57]
+	mi := &file_daemon_proto_msgTypes[59]
 	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 	ms.StoreMessageInfo(mi)
 }
@@ -4246,7 +4376,7 @@ func (x *SetConfigResponse) String() string {
 func (*SetConfigResponse) ProtoMessage() {}
 
 func (x *SetConfigResponse) ProtoReflect() protoreflect.Message {
-	mi := &file_daemon_proto_msgTypes[57]
+	mi := &file_daemon_proto_msgTypes[59]
 	if x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -4259,7 +4389,7 @@ func (x *SetConfigResponse) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use SetConfigResponse.ProtoReflect.Descriptor instead.
 func (*SetConfigResponse) Descriptor() ([]byte, []int) {
-	return file_daemon_proto_rawDescGZIP(), []int{57}
+	return file_daemon_proto_rawDescGZIP(), []int{59}
 }
 
 type AddProfileRequest struct {
@@ -4272,7 +4402,7 @@ type AddProfileRequest struct {
 
 func (x *AddProfileRequest) Reset() {
 	*x = AddProfileRequest{}
-	mi := &file_daemon_proto_msgTypes[58]
+	mi := &file_daemon_proto_msgTypes[60]
 	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 	ms.StoreMessageInfo(mi)
 }
@@ -4284,7 +4414,7 @@ func (x *AddProfileRequest) String() string {
 func (*AddProfileRequest) ProtoMessage() {}
 
 func (x *AddProfileRequest) ProtoReflect() protoreflect.Message {
-	mi := &file_daemon_proto_msgTypes[58]
+	mi := &file_daemon_proto_msgTypes[60]
 	if x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -4297,7 +4427,7 @@ func (x *AddProfileRequest) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use AddProfileRequest.ProtoReflect.Descriptor instead.
 func (*AddProfileRequest) Descriptor() ([]byte, []int) {
-	return file_daemon_proto_rawDescGZIP(), []int{58}
+	return file_daemon_proto_rawDescGZIP(), []int{60}
 }
 
 func (x *AddProfileRequest) GetUsername() string {
@@ -4322,7 +4452,7 @@ type AddProfileResponse struct {
 
 func (x *AddProfileResponse) Reset() {
 	*x = AddProfileResponse{}
-	mi := &file_daemon_proto_msgTypes[59]
+	mi := &file_daemon_proto_msgTypes[61]
 	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 	ms.StoreMessageInfo(mi)
 }
@@ -4334,7 +4464,7 @@ func (x *AddProfileResponse) String() string {
 func (*AddProfileResponse) ProtoMessage() {}
 
 func (x *AddProfileResponse) ProtoReflect() protoreflect.Message {
-	mi := &file_daemon_proto_msgTypes[59]
+	mi := &file_daemon_proto_msgTypes[61]
 	if x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -4347,7 +4477,7 @@ func (x *AddProfileResponse) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use AddProfileResponse.ProtoReflect.Descriptor instead.
 func (*AddProfileResponse) Descriptor() ([]byte, []int) {
-	return file_daemon_proto_rawDescGZIP(), []int{59}
+	return file_daemon_proto_rawDescGZIP(), []int{61}
 }
 
 type RemoveProfileRequest struct {
@@ -4360,7 +4490,7 @@ type RemoveProfileRequest struct {
 
 func (x *RemoveProfileRequest) Reset() {
 	*x = RemoveProfileRequest{}
-	mi := &file_daemon_proto_msgTypes[60]
+	mi := &file_daemon_proto_msgTypes[62]
 	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 	ms.StoreMessageInfo(mi)
 }
@@ -4372,7 +4502,7 @@ func (x *RemoveProfileRequest) String() string {
 func (*RemoveProfileRequest) ProtoMessage() {}
 
 func (x *RemoveProfileRequest) ProtoReflect() protoreflect.Message {
-	mi := &file_daemon_proto_msgTypes[60]
+	mi := &file_daemon_proto_msgTypes[62]
 	if x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -4385,7 +4515,7 @@ func (x *RemoveProfileRequest) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use RemoveProfileRequest.ProtoReflect.Descriptor instead.
 func (*RemoveProfileRequest) Descriptor() ([]byte, []int) {
-	return file_daemon_proto_rawDescGZIP(), []int{60}
+	return file_daemon_proto_rawDescGZIP(), []int{62}
 }
 
 func (x *RemoveProfileRequest) GetUsername() string {
@@ -4410,7 +4540,7 @@ type RemoveProfileResponse struct {
 
 func (x *RemoveProfileResponse) Reset() {
 	*x = RemoveProfileResponse{}
-	mi := &file_daemon_proto_msgTypes[61]
+	mi := &file_daemon_proto_msgTypes[63]
 	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 	ms.StoreMessageInfo(mi)
 }
@@ -4422,7 +4552,7 @@ func (x *RemoveProfileResponse) String() string {
 func (*RemoveProfileResponse) ProtoMessage() {}
 
 func (x *RemoveProfileResponse) ProtoReflect() protoreflect.Message {
-	mi := &file_daemon_proto_msgTypes[61]
+	mi := &file_daemon_proto_msgTypes[63]
 	if x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -4435,7 +4565,7 @@ func (x *RemoveProfileResponse) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use RemoveProfileResponse.ProtoReflect.Descriptor instead.
 func (*RemoveProfileResponse) Descriptor() ([]byte, []int) {
-	return file_daemon_proto_rawDescGZIP(), []int{61}
+	return file_daemon_proto_rawDescGZIP(), []int{63}
 }
 
 type ListProfilesRequest struct {
@@ -4447,7 +4577,7 @@ type ListProfilesRequest struct {
 
 func (x *ListProfilesRequest) Reset() {
 	*x = ListProfilesRequest{}
-	mi := &file_daemon_proto_msgTypes[62]
+	mi := &file_daemon_proto_msgTypes[64]
 	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 	ms.StoreMessageInfo(mi)
 }
@@ -4459,7 +4589,7 @@ func (x *ListProfilesRequest) String() string {
 func (*ListProfilesRequest) ProtoMessage() {}
 
 func (x *ListProfilesRequest) ProtoReflect() protoreflect.Message {
-	mi := &file_daemon_proto_msgTypes[62]
+	mi := &file_daemon_proto_msgTypes[64]
 	if x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -4472,7 +4602,7 @@ func (x *ListProfilesRequest) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use ListProfilesRequest.ProtoReflect.Descriptor instead.
 func (*ListProfilesRequest) Descriptor() ([]byte, []int) {
-	return file_daemon_proto_rawDescGZIP(), []int{62}
+	return file_daemon_proto_rawDescGZIP(), []int{64}
 }
 
 func (x *ListProfilesRequest) GetUsername() string {
@@ -4491,7 +4621,7 @@ type ListProfilesResponse struct {
 
 func (x *ListProfilesResponse) Reset() {
 	*x = ListProfilesResponse{}
-	mi := &file_daemon_proto_msgTypes[63]
+	mi := &file_daemon_proto_msgTypes[65]
 	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 	ms.StoreMessageInfo(mi)
 }
@@ -4503,7 +4633,7 @@ func (x *ListProfilesResponse) String() string {
 func (*ListProfilesResponse) ProtoMessage() {}
 
 func (x *ListProfilesResponse) ProtoReflect() protoreflect.Message {
-	mi := &file_daemon_proto_msgTypes[63]
+	mi := &file_daemon_proto_msgTypes[65]
 	if x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -4516,7 +4646,7 @@ func (x *ListProfilesResponse) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use ListProfilesResponse.ProtoReflect.Descriptor instead.
 func (*ListProfilesResponse) Descriptor() ([]byte, []int) {
-	return file_daemon_proto_rawDescGZIP(), []int{63}
+	return file_daemon_proto_rawDescGZIP(), []int{65}
 }
 
 func (x *ListProfilesResponse) GetProfiles() []*Profile {
@@ -4536,7 +4666,7 @@ type Profile struct {
 
 func (x *Profile) Reset() {
 	*x = Profile{}
-	mi := &file_daemon_proto_msgTypes[64]
+	mi := &file_daemon_proto_msgTypes[66]
 	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 	ms.StoreMessageInfo(mi)
 }
@@ -4548,7 +4678,7 @@ func (x *Profile) String() string {
 func (*Profile) ProtoMessage() {}
 
 func (x *Profile) ProtoReflect() protoreflect.Message {
-	mi := &file_daemon_proto_msgTypes[64]
+	mi := &file_daemon_proto_msgTypes[66]
 	if x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -4561,7 +4691,7 @@ func (x *Profile) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use Profile.ProtoReflect.Descriptor instead.
 func (*Profile) Descriptor() ([]byte, []int) {
-	return file_daemon_proto_rawDescGZIP(), []int{64}
+	return file_daemon_proto_rawDescGZIP(), []int{66}
 }
 
 func (x *Profile) GetName() string {
@@ -4586,7 +4716,7 @@ type GetActiveProfileRequest struct {
 
 func (x *GetActiveProfileRequest) Reset() {
 	*x = GetActiveProfileRequest{}
-	mi := &file_daemon_proto_msgTypes[65]
+	mi := &file_daemon_proto_msgTypes[67]
 	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 	ms.StoreMessageInfo(mi)
 }
@@ -4598,7 +4728,7 @@ func (x *GetActiveProfileRequest) String() string {
 func (*GetActiveProfileRequest) ProtoMessage() {}
 
 func (x *GetActiveProfileRequest) ProtoReflect() protoreflect.Message {
-	mi := &file_daemon_proto_msgTypes[65]
+	mi := &file_daemon_proto_msgTypes[67]
 	if x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -4611,7 +4741,7 @@ func (x *GetActiveProfileRequest) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use GetActiveProfileRequest.ProtoReflect.Descriptor instead.
 func (*GetActiveProfileRequest) Descriptor() ([]byte, []int) {
-	return file_daemon_proto_rawDescGZIP(), []int{65}
+	return file_daemon_proto_rawDescGZIP(), []int{67}
 }
 
 type GetActiveProfileResponse struct {
@@ -4624,7 +4754,7 @@ type GetActiveProfileResponse struct {
 
 func (x *GetActiveProfileResponse) Reset() {
 	*x = GetActiveProfileResponse{}
-	mi := &file_daemon_proto_msgTypes[66]
+	mi := &file_daemon_proto_msgTypes[68]
 	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 	ms.StoreMessageInfo(mi)
 }
@@ -4636,7 +4766,7 @@ func (x *GetActiveProfileResponse) String() string {
 func (*GetActiveProfileResponse) ProtoMessage() {}
 
 func (x *GetActiveProfileResponse) ProtoReflect() protoreflect.Message {
-	mi := &file_daemon_proto_msgTypes[66]
+	mi := &file_daemon_proto_msgTypes[68]
 	if x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -4649,7 +4779,7 @@ func (x *GetActiveProfileResponse) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use GetActiveProfileResponse.ProtoReflect.Descriptor instead.
 func (*GetActiveProfileResponse) Descriptor() ([]byte, []int) {
-	return file_daemon_proto_rawDescGZIP(), []int{66}
+	return file_daemon_proto_rawDescGZIP(), []int{68}
 }
 
 func (x *GetActiveProfileResponse) GetProfileName() string {
@@ -4676,7 +4806,7 @@ type LogoutRequest struct {
 
 func (x *LogoutRequest) Reset() {
 	*x = LogoutRequest{}
-	mi := &file_daemon_proto_msgTypes[67]
+	mi := &file_daemon_proto_msgTypes[69]
 	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 	ms.StoreMessageInfo(mi)
 }
@@ -4688,7 +4818,7 @@ func (x *LogoutRequest) String() string {
 func (*LogoutRequest) ProtoMessage() {}
 
 func (x *LogoutRequest) ProtoReflect() protoreflect.Message {
-	mi := &file_daemon_proto_msgTypes[67]
+	mi := &file_daemon_proto_msgTypes[69]
 	if x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -4701,7 +4831,7 @@ func (x *LogoutRequest) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use LogoutRequest.ProtoReflect.Descriptor instead.
 func (*LogoutRequest) Descriptor() ([]byte, []int) {
-	return file_daemon_proto_rawDescGZIP(), []int{67}
+	return file_daemon_proto_rawDescGZIP(), []int{69}
 }
 
 func (x *LogoutRequest) GetProfileName() string {
@@ -4726,7 +4856,7 @@ type LogoutResponse struct {
 
 func (x *LogoutResponse) Reset() {
 	*x = LogoutResponse{}
-	mi := &file_daemon_proto_msgTypes[68]
+	mi := &file_daemon_proto_msgTypes[70]
 	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 	ms.StoreMessageInfo(mi)
 }
@@ -4738,7 +4868,7 @@ func (x *LogoutResponse) String() string {
 func (*LogoutResponse) ProtoMessage() {}
 
 func (x *LogoutResponse) ProtoReflect() protoreflect.Message {
-	mi := &file_daemon_proto_msgTypes[68]
+	mi := &file_daemon_proto_msgTypes[70]
 	if x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -4751,7 +4881,7 @@ func (x *LogoutResponse) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use LogoutResponse.ProtoReflect.Descriptor instead.
 func (*LogoutResponse) Descriptor() ([]byte, []int) {
-	return file_daemon_proto_rawDescGZIP(), []int{68}
+	return file_daemon_proto_rawDescGZIP(), []int{70}
 }
 
 type GetFeaturesRequest struct {
@@ -4762,7 +4892,7 @@ type GetFeaturesRequest struct {
 
 func (x *GetFeaturesRequest) Reset() {
 	*x = GetFeaturesRequest{}
-	mi := &file_daemon_proto_msgTypes[69]
+	mi := &file_daemon_proto_msgTypes[71]
 	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 	ms.StoreMessageInfo(mi)
 }
@@ -4774,7 +4904,7 @@ func (x *GetFeaturesRequest) String() string {
 func (*GetFeaturesRequest) ProtoMessage() {}
 
 func (x *GetFeaturesRequest) ProtoReflect() protoreflect.Message {
-	mi := &file_daemon_proto_msgTypes[69]
+	mi := &file_daemon_proto_msgTypes[71]
 	if x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -4787,7 +4917,7 @@ func (x *GetFeaturesRequest) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use GetFeaturesRequest.ProtoReflect.Descriptor instead.
 func (*GetFeaturesRequest) Descriptor() ([]byte, []int) {
-	return file_daemon_proto_rawDescGZIP(), []int{69}
+	return file_daemon_proto_rawDescGZIP(), []int{71}
 }
 
 type GetFeaturesResponse struct {
@@ -4800,7 +4930,7 @@ type GetFeaturesResponse struct {
 
 func (x *GetFeaturesResponse) Reset() {
 	*x = GetFeaturesResponse{}
-	mi := &file_daemon_proto_msgTypes[70]
+	mi := &file_daemon_proto_msgTypes[72]
 	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 	ms.StoreMessageInfo(mi)
 }
@@ -4812,7 +4942,7 @@ func (x *GetFeaturesResponse) String() string {
 func (*GetFeaturesResponse) ProtoMessage() {}
 
 func (x *GetFeaturesResponse) ProtoReflect() protoreflect.Message {
-	mi := &file_daemon_proto_msgTypes[70]
+	mi := &file_daemon_proto_msgTypes[72]
 	if x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -4825,7 +4955,7 @@ func (x *GetFeaturesResponse) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use GetFeaturesResponse.ProtoReflect.Descriptor instead.
 func (*GetFeaturesResponse) Descriptor() ([]byte, []int) {
-	return file_daemon_proto_rawDescGZIP(), []int{70}
+	return file_daemon_proto_rawDescGZIP(), []int{72}
 }
 
 func (x *GetFeaturesResponse) GetDisableProfiles() bool {
@@ -4853,7 +4983,7 @@ type GetPeerSSHHostKeyRequest struct {
 
 func (x *GetPeerSSHHostKeyRequest) Reset() {
 	*x = GetPeerSSHHostKeyRequest{}
-	mi := &file_daemon_proto_msgTypes[71]
+	mi := &file_daemon_proto_msgTypes[73]
 	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 	ms.StoreMessageInfo(mi)
 }
@@ -4865,7 +4995,7 @@ func (x *GetPeerSSHHostKeyRequest) String() string {
 func (*GetPeerSSHHostKeyRequest) ProtoMessage() {}
 
 func (x *GetPeerSSHHostKeyRequest) ProtoReflect() protoreflect.Message {
-	mi := &file_daemon_proto_msgTypes[71]
+	mi := &file_daemon_proto_msgTypes[73]
 	if x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -4878,7 +5008,7 @@ func (x *GetPeerSSHHostKeyRequest) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use GetPeerSSHHostKeyRequest.ProtoReflect.Descriptor instead.
 func (*GetPeerSSHHostKeyRequest) Descriptor() ([]byte, []int) {
-	return file_daemon_proto_rawDescGZIP(), []int{71}
+	return file_daemon_proto_rawDescGZIP(), []int{73}
 }
 
 func (x *GetPeerSSHHostKeyRequest) GetPeerAddress() string {
@@ -4905,7 +5035,7 @@ type GetPeerSSHHostKeyResponse struct {
 
 func (x *GetPeerSSHHostKeyResponse) Reset() {
 	*x = GetPeerSSHHostKeyResponse{}
-	mi := &file_daemon_proto_msgTypes[72]
+	mi := &file_daemon_proto_msgTypes[74]
 	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 	ms.StoreMessageInfo(mi)
 }
@@ -4917,7 +5047,7 @@ func (x *GetPeerSSHHostKeyResponse) String() string {
 func (*GetPeerSSHHostKeyResponse) ProtoMessage() {}
 
 func (x *GetPeerSSHHostKeyResponse) ProtoReflect() protoreflect.Message {
-	mi := &file_daemon_proto_msgTypes[72]
+	mi := &file_daemon_proto_msgTypes[74]
 	if x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -4930,7 +5060,7 @@ func (x *GetPeerSSHHostKeyResponse) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use GetPeerSSHHostKeyResponse.ProtoReflect.Descriptor instead.
 func (*GetPeerSSHHostKeyResponse) Descriptor() ([]byte, []int) {
-	return file_daemon_proto_rawDescGZIP(), []int{72}
+	return file_daemon_proto_rawDescGZIP(), []int{74}
 }
 
 func (x *GetPeerSSHHostKeyResponse) GetSshHostKey() []byte {
@@ -4972,7 +5102,7 @@ type RequestJWTAuthRequest struct {
 
 func (x *RequestJWTAuthRequest) Reset() {
 	*x = RequestJWTAuthRequest{}
-	mi := &file_daemon_proto_msgTypes[73]
+	mi := &file_daemon_proto_msgTypes[75]
 	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 	ms.StoreMessageInfo(mi)
 }
@@ -4984,7 +5114,7 @@ func (x *RequestJWTAuthRequest) String() string {
 func (*RequestJWTAuthRequest) ProtoMessage() {}
 
 func (x *RequestJWTAuthRequest) ProtoReflect() protoreflect.Message {
-	mi := &file_daemon_proto_msgTypes[73]
+	mi := &file_daemon_proto_msgTypes[75]
 	if x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -4997,7 +5127,7 @@ func (x *RequestJWTAuthRequest) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use RequestJWTAuthRequest.ProtoReflect.Descriptor instead.
 func (*RequestJWTAuthRequest) Descriptor() ([]byte, []int) {
-	return file_daemon_proto_rawDescGZIP(), []int{73}
+	return file_daemon_proto_rawDescGZIP(), []int{75}
 }
 
 func (x *RequestJWTAuthRequest) GetHint() string {
@@ -5030,7 +5160,7 @@ type RequestJWTAuthResponse struct {
 
 func (x *RequestJWTAuthResponse) Reset() {
 	*x = RequestJWTAuthResponse{}
-	mi := &file_daemon_proto_msgTypes[74]
+	mi := &file_daemon_proto_msgTypes[76]
 	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 	ms.StoreMessageInfo(mi)
 }
@@ -5042,7 +5172,7 @@ func (x *RequestJWTAuthResponse) String() string {
 func (*RequestJWTAuthResponse) ProtoMessage() {}
 
 func (x *RequestJWTAuthResponse) ProtoReflect() protoreflect.Message {
-	mi := &file_daemon_proto_msgTypes[74]
+	mi := &file_daemon_proto_msgTypes[76]
 	if x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -5055,7 +5185,7 @@ func (x *RequestJWTAuthResponse) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use RequestJWTAuthResponse.ProtoReflect.Descriptor instead.
 func (*RequestJWTAuthResponse) Descriptor() ([]byte, []int) {
-	return file_daemon_proto_rawDescGZIP(), []int{74}
+	return file_daemon_proto_rawDescGZIP(), []int{76}
 }
 
 func (x *RequestJWTAuthResponse) GetVerificationURI() string {
@@ -5120,7 +5250,7 @@ type WaitJWTTokenRequest struct {
 
 func (x *WaitJWTTokenRequest) Reset() {
 	*x = WaitJWTTokenRequest{}
-	mi := &file_daemon_proto_msgTypes[75]
+	mi := &file_daemon_proto_msgTypes[77]
 	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 	ms.StoreMessageInfo(mi)
 }
@@ -5132,7 +5262,7 @@ func (x *WaitJWTTokenRequest) String() string {
 func (*WaitJWTTokenRequest) ProtoMessage() {}
 
 func (x *WaitJWTTokenRequest) ProtoReflect() protoreflect.Message {
-	mi := &file_daemon_proto_msgTypes[75]
+	mi := &file_daemon_proto_msgTypes[77]
 	if x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -5145,7 +5275,7 @@ func (x *WaitJWTTokenRequest) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use WaitJWTTokenRequest.ProtoReflect.Descriptor instead.
 func (*WaitJWTTokenRequest) Descriptor() ([]byte, []int) {
-	return file_daemon_proto_rawDescGZIP(), []int{75}
+	return file_daemon_proto_rawDescGZIP(), []int{77}
 }
 
 func (x *WaitJWTTokenRequest) GetDeviceCode() string {
@@ -5177,7 +5307,7 @@ type WaitJWTTokenResponse struct {
 
 func (x *WaitJWTTokenResponse) Reset() {
 	*x = WaitJWTTokenResponse{}
-	mi := &file_daemon_proto_msgTypes[76]
+	mi := &file_daemon_proto_msgTypes[78]
 	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 	ms.StoreMessageInfo(mi)
 }
@@ -5189,7 +5319,7 @@ func (x *WaitJWTTokenResponse) String() string {
 func (*WaitJWTTokenResponse) ProtoMessage() {}
 
 func (x *WaitJWTTokenResponse) ProtoReflect() protoreflect.Message {
-	mi := &file_daemon_proto_msgTypes[76]
+	mi := &file_daemon_proto_msgTypes[78]
 	if x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -5202,7 +5332,7 @@ func (x *WaitJWTTokenResponse) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use WaitJWTTokenResponse.ProtoReflect.Descriptor instead.
 func (*WaitJWTTokenResponse) Descriptor() ([]byte, []int) {
-	return file_daemon_proto_rawDescGZIP(), []int{76}
+	return file_daemon_proto_rawDescGZIP(), []int{78}
 }
 
 func (x *WaitJWTTokenResponse) GetToken() string {
@@ -5236,7 +5366,7 @@ type PortInfo_Range struct {
 
 func (x *PortInfo_Range) Reset() {
 	*x = PortInfo_Range{}
-	mi := &file_daemon_proto_msgTypes[78]
+	mi := &file_daemon_proto_msgTypes[80]
 	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 	ms.StoreMessageInfo(mi)
 }
@@ -5248,7 +5378,7 @@ func (x *PortInfo_Range) String() string {
 func (*PortInfo_Range) ProtoMessage() {}
 
 func (x *PortInfo_Range) ProtoReflect() protoreflect.Message {
-	mi := &file_daemon_proto_msgTypes[78]
+	mi := &file_daemon_proto_msgTypes[80]
 	if x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -5261,7 +5391,7 @@ func (x *PortInfo_Range) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use PortInfo_Range.ProtoReflect.Descriptor instead.
 func (*PortInfo_Range) Descriptor() ([]byte, []int) {
-	return file_daemon_proto_rawDescGZIP(), []int{28, 0}
+	return file_daemon_proto_rawDescGZIP(), []int{30, 0}
 }
 
 func (x *PortInfo_Range) GetStart() uint32 {
@@ -5283,7 +5413,15 @@ var File_daemon_proto protoreflect.FileDescriptor
 const file_daemon_proto_rawDesc = "" +
 	"\n" +
 	"\fdaemon.proto\x12\x06daemon\x1a google/protobuf/descriptor.proto\x1a\x1fgoogle/protobuf/timestamp.proto\x1a\x1egoogle/protobuf/duration.proto\"\x0e\n" +
-	"\fEmptyRequest\"\xb6\x12\n" +
+	"\fEmptyRequest\"\x7f\n" +
+	"\x12OSLifecycleRequest\x128\n" +
+	"\x04type\x18\x01 \x01(\x0e2$.daemon.OSLifecycleRequest.CycleTypeR\x04type\"/\n" +
+	"\tCycleType\x12\v\n" +
+	"\aUNKNOWN\x10\x00\x12\t\n" +
+	"\x05SLEEP\x10\x01\x12\n" +
+	"\n" +
+	"\x06WAKEUP\x10\x02\"\x15\n" +
+	"\x13OSLifecycleResponse\"\xb6\x12\n" +
 	"\fLoginRequest\x12\x1a\n" +
 	"\bsetupKey\x18\x01 \x01(\tR\bsetupKey\x12&\n" +
 	"\fpreSharedKey\x18\x02 \x01(\tB\x02\x18\x01R\fpreSharedKey\x12$\n" +
@@ -5764,7 +5902,7 @@ const file_daemon_proto_rawDesc = "" +
 	"\x04WARN\x10\x04\x12\b\n" +
 	"\x04INFO\x10\x05\x12\t\n" +
 	"\x05DEBUG\x10\x06\x12\t\n" +
-	"\x05TRACE\x10\a2\x8b\x12\n" +
+	"\x05TRACE\x10\a2\xdb\x12\n" +
 	"\rDaemonService\x126\n" +
 	"\x05Login\x12\x14.daemon.LoginRequest\x1a\x15.daemon.LoginResponse\"\x00\x12K\n" +
 	"\fWaitSSOLogin\x12\x1b.daemon.WaitSSOLoginRequest\x1a\x1c.daemon.WaitSSOLoginResponse\"\x00\x12-\n" +
@@ -5799,7 +5937,8 @@ const file_daemon_proto_rawDesc = "" +
 	"\vGetFeatures\x12\x1a.daemon.GetFeaturesRequest\x1a\x1b.daemon.GetFeaturesResponse\"\x00\x12Z\n" +
 	"\x11GetPeerSSHHostKey\x12 .daemon.GetPeerSSHHostKeyRequest\x1a!.daemon.GetPeerSSHHostKeyResponse\"\x00\x12Q\n" +
 	"\x0eRequestJWTAuth\x12\x1d.daemon.RequestJWTAuthRequest\x1a\x1e.daemon.RequestJWTAuthResponse\"\x00\x12K\n" +
-	"\fWaitJWTToken\x12\x1b.daemon.WaitJWTTokenRequest\x1a\x1c.daemon.WaitJWTTokenResponse\"\x00B\bZ\x06/protob\x06proto3"
+	"\fWaitJWTToken\x12\x1b.daemon.WaitJWTTokenRequest\x1a\x1c.daemon.WaitJWTTokenResponse\"\x00\x12N\n" +
+	"\x11NotifyOSLifecycle\x12\x1a.daemon.OSLifecycleRequest\x1a\x1b.daemon.OSLifecycleResponse\"\x00B\bZ\x06/protob\x06proto3"
 
 var (
 	file_daemon_proto_rawDescOnce sync.Once
@@ -5813,196 +5952,202 @@ func file_daemon_proto_rawDescGZIP() []byte {
 	return file_daemon_proto_rawDescData
 }
 
-var file_daemon_proto_enumTypes = make([]protoimpl.EnumInfo, 3)
-var file_daemon_proto_msgTypes = make([]protoimpl.MessageInfo, 80)
+var file_daemon_proto_enumTypes = make([]protoimpl.EnumInfo, 4)
+var file_daemon_proto_msgTypes = make([]protoimpl.MessageInfo, 82)
 var file_daemon_proto_goTypes = []any{
 	(LogLevel)(0),                              // 0: daemon.LogLevel
-	(SystemEvent_Severity)(0),                  // 1: daemon.SystemEvent.Severity
-	(SystemEvent_Category)(0),                  // 2: daemon.SystemEvent.Category
-	(*EmptyRequest)(nil),                       // 3: daemon.EmptyRequest
-	(*LoginRequest)(nil),                       // 4: daemon.LoginRequest
-	(*LoginResponse)(nil),                      // 5: daemon.LoginResponse
-	(*WaitSSOLoginRequest)(nil),                // 6: daemon.WaitSSOLoginRequest
-	(*WaitSSOLoginResponse)(nil),               // 7: daemon.WaitSSOLoginResponse
-	(*UpRequest)(nil),                          // 8: daemon.UpRequest
-	(*UpResponse)(nil),                         // 9: daemon.UpResponse
-	(*StatusRequest)(nil),                      // 10: daemon.StatusRequest
-	(*StatusResponse)(nil),                     // 11: daemon.StatusResponse
-	(*DownRequest)(nil),                        // 12: daemon.DownRequest
-	(*DownResponse)(nil),                       // 13: daemon.DownResponse
-	(*GetConfigRequest)(nil),                   // 14: daemon.GetConfigRequest
-	(*GetConfigResponse)(nil),                  // 15: daemon.GetConfigResponse
-	(*PeerState)(nil),                          // 16: daemon.PeerState
-	(*LocalPeerState)(nil),                     // 17: daemon.LocalPeerState
-	(*SignalState)(nil),                        // 18: daemon.SignalState
-	(*ManagementState)(nil),                    // 19: daemon.ManagementState
-	(*RelayState)(nil),                         // 20: daemon.RelayState
-	(*NSGroupState)(nil),                       // 21: daemon.NSGroupState
-	(*SSHSessionInfo)(nil),                     // 22: daemon.SSHSessionInfo
-	(*SSHServerState)(nil),                     // 23: daemon.SSHServerState
-	(*FullStatus)(nil),                         // 24: daemon.FullStatus
-	(*ListNetworksRequest)(nil),                // 25: daemon.ListNetworksRequest
-	(*ListNetworksResponse)(nil),               // 26: daemon.ListNetworksResponse
-	(*SelectNetworksRequest)(nil),              // 27: daemon.SelectNetworksRequest
-	(*SelectNetworksResponse)(nil),             // 28: daemon.SelectNetworksResponse
-	(*IPList)(nil),                             // 29: daemon.IPList
-	(*Network)(nil),                            // 30: daemon.Network
-	(*PortInfo)(nil),                           // 31: daemon.PortInfo
-	(*ForwardingRule)(nil),                     // 32: daemon.ForwardingRule
-	(*ForwardingRulesResponse)(nil),            // 33: daemon.ForwardingRulesResponse
-	(*DebugBundleRequest)(nil),                 // 34: daemon.DebugBundleRequest
-	(*DebugBundleResponse)(nil),                // 35: daemon.DebugBundleResponse
-	(*GetLogLevelRequest)(nil),                 // 36: daemon.GetLogLevelRequest
-	(*GetLogLevelResponse)(nil),                // 37: daemon.GetLogLevelResponse
-	(*SetLogLevelRequest)(nil),                 // 38: daemon.SetLogLevelRequest
-	(*SetLogLevelResponse)(nil),                // 39: daemon.SetLogLevelResponse
-	(*State)(nil),                              // 40: daemon.State
-	(*ListStatesRequest)(nil),                  // 41: daemon.ListStatesRequest
-	(*ListStatesResponse)(nil),                 // 42: daemon.ListStatesResponse
-	(*CleanStateRequest)(nil),                  // 43: daemon.CleanStateRequest
-	(*CleanStateResponse)(nil),                 // 44: daemon.CleanStateResponse
-	(*DeleteStateRequest)(nil),                 // 45: daemon.DeleteStateRequest
-	(*DeleteStateResponse)(nil),                // 46: daemon.DeleteStateResponse
-	(*SetSyncResponsePersistenceRequest)(nil),  // 47: daemon.SetSyncResponsePersistenceRequest
-	(*SetSyncResponsePersistenceResponse)(nil), // 48: daemon.SetSyncResponsePersistenceResponse
-	(*TCPFlags)(nil),                           // 49: daemon.TCPFlags
-	(*TracePacketRequest)(nil),                 // 50: daemon.TracePacketRequest
-	(*TraceStage)(nil),                         // 51: daemon.TraceStage
-	(*TracePacketResponse)(nil),                // 52: daemon.TracePacketResponse
-	(*SubscribeRequest)(nil),                   // 53: daemon.SubscribeRequest
-	(*SystemEvent)(nil),                        // 54: daemon.SystemEvent
-	(*GetEventsRequest)(nil),                   // 55: daemon.GetEventsRequest
-	(*GetEventsResponse)(nil),                  // 56: daemon.GetEventsResponse
-	(*SwitchProfileRequest)(nil),               // 57: daemon.SwitchProfileRequest
-	(*SwitchProfileResponse)(nil),              // 58: daemon.SwitchProfileResponse
-	(*SetConfigRequest)(nil),                   // 59: daemon.SetConfigRequest
-	(*SetConfigResponse)(nil),                  // 60: daemon.SetConfigResponse
-	(*AddProfileRequest)(nil),                  // 61: daemon.AddProfileRequest
-	(*AddProfileResponse)(nil),                 // 62: daemon.AddProfileResponse
-	(*RemoveProfileRequest)(nil),               // 63: daemon.RemoveProfileRequest
-	(*RemoveProfileResponse)(nil),              // 64: daemon.RemoveProfileResponse
-	(*ListProfilesRequest)(nil),                // 65: daemon.ListProfilesRequest
-	(*ListProfilesResponse)(nil),               // 66: daemon.ListProfilesResponse
-	(*Profile)(nil),                            // 67: daemon.Profile
-	(*GetActiveProfileRequest)(nil),            // 68: daemon.GetActiveProfileRequest
-	(*GetActiveProfileResponse)(nil),           // 69: daemon.GetActiveProfileResponse
-	(*LogoutRequest)(nil),                      // 70: daemon.LogoutRequest
-	(*LogoutResponse)(nil),                     // 71: daemon.LogoutResponse
-	(*GetFeaturesRequest)(nil),                 // 72: daemon.GetFeaturesRequest
-	(*GetFeaturesResponse)(nil),                // 73: daemon.GetFeaturesResponse
-	(*GetPeerSSHHostKeyRequest)(nil),           // 74: daemon.GetPeerSSHHostKeyRequest
-	(*GetPeerSSHHostKeyResponse)(nil),          // 75: daemon.GetPeerSSHHostKeyResponse
-	(*RequestJWTAuthRequest)(nil),              // 76: daemon.RequestJWTAuthRequest
-	(*RequestJWTAuthResponse)(nil),             // 77: daemon.RequestJWTAuthResponse
-	(*WaitJWTTokenRequest)(nil),                // 78: daemon.WaitJWTTokenRequest
-	(*WaitJWTTokenResponse)(nil),               // 79: daemon.WaitJWTTokenResponse
-	nil,                                        // 80: daemon.Network.ResolvedIPsEntry
-	(*PortInfo_Range)(nil),                     // 81: daemon.PortInfo.Range
-	nil,                                        // 82: daemon.SystemEvent.MetadataEntry
-	(*durationpb.Duration)(nil),                // 83: google.protobuf.Duration
-	(*timestamppb.Timestamp)(nil),              // 84: google.protobuf.Timestamp
+	(OSLifecycleRequest_CycleType)(0),          // 1: daemon.OSLifecycleRequest.CycleType
+	(SystemEvent_Severity)(0),                  // 2: daemon.SystemEvent.Severity
+	(SystemEvent_Category)(0),                  // 3: daemon.SystemEvent.Category
+	(*EmptyRequest)(nil),                       // 4: daemon.EmptyRequest
+	(*OSLifecycleRequest)(nil),                 // 5: daemon.OSLifecycleRequest
+	(*OSLifecycleResponse)(nil),                // 6: daemon.OSLifecycleResponse
+	(*LoginRequest)(nil),                       // 7: daemon.LoginRequest
+	(*LoginResponse)(nil),                      // 8: daemon.LoginResponse
+	(*WaitSSOLoginRequest)(nil),                // 9: daemon.WaitSSOLoginRequest
+	(*WaitSSOLoginResponse)(nil),               // 10: daemon.WaitSSOLoginResponse
+	(*UpRequest)(nil),                          // 11: daemon.UpRequest
+	(*UpResponse)(nil),                         // 12: daemon.UpResponse
+	(*StatusRequest)(nil),                      // 13: daemon.StatusRequest
+	(*StatusResponse)(nil),                     // 14: daemon.StatusResponse
+	(*DownRequest)(nil),                        // 15: daemon.DownRequest
+	(*DownResponse)(nil),                       // 16: daemon.DownResponse
+	(*GetConfigRequest)(nil),                   // 17: daemon.GetConfigRequest
+	(*GetConfigResponse)(nil),                  // 18: daemon.GetConfigResponse
+	(*PeerState)(nil),                          // 19: daemon.PeerState
+	(*LocalPeerState)(nil),                     // 20: daemon.LocalPeerState
+	(*SignalState)(nil),                        // 21: daemon.SignalState
+	(*ManagementState)(nil),                    // 22: daemon.ManagementState
+	(*RelayState)(nil),                         // 23: daemon.RelayState
+	(*NSGroupState)(nil),                       // 24: daemon.NSGroupState
+	(*SSHSessionInfo)(nil),                     // 25: daemon.SSHSessionInfo
+	(*SSHServerState)(nil),                     // 26: daemon.SSHServerState
+	(*FullStatus)(nil),                         // 27: daemon.FullStatus
+	(*ListNetworksRequest)(nil),                // 28: daemon.ListNetworksRequest
+	(*ListNetworksResponse)(nil),               // 29: daemon.ListNetworksResponse
+	(*SelectNetworksRequest)(nil),              // 30: daemon.SelectNetworksRequest
+	(*SelectNetworksResponse)(nil),             // 31: daemon.SelectNetworksResponse
+	(*IPList)(nil),                             // 32: daemon.IPList
+	(*Network)(nil),                            // 33: daemon.Network
+	(*PortInfo)(nil),                           // 34: daemon.PortInfo
+	(*ForwardingRule)(nil),                     // 35: daemon.ForwardingRule
+	(*ForwardingRulesResponse)(nil),            // 36: daemon.ForwardingRulesResponse
+	(*DebugBundleRequest)(nil),                 // 37: daemon.DebugBundleRequest
+	(*DebugBundleResponse)(nil),                // 38: daemon.DebugBundleResponse
+	(*GetLogLevelRequest)(nil),                 // 39: daemon.GetLogLevelRequest
+	(*GetLogLevelResponse)(nil),                // 40: daemon.GetLogLevelResponse
+	(*SetLogLevelRequest)(nil),                 // 41: daemon.SetLogLevelRequest
+	(*SetLogLevelResponse)(nil),                // 42: daemon.SetLogLevelResponse
+	(*State)(nil),                              // 43: daemon.State
+	(*ListStatesRequest)(nil),                  // 44: daemon.ListStatesRequest
+	(*ListStatesResponse)(nil),                 // 45: daemon.ListStatesResponse
+	(*CleanStateRequest)(nil),                  // 46: daemon.CleanStateRequest
+	(*CleanStateResponse)(nil),                 // 47: daemon.CleanStateResponse
+	(*DeleteStateRequest)(nil),                 // 48: daemon.DeleteStateRequest
+	(*DeleteStateResponse)(nil),                // 49: daemon.DeleteStateResponse
+	(*SetSyncResponsePersistenceRequest)(nil),  // 50: daemon.SetSyncResponsePersistenceRequest
+	(*SetSyncResponsePersistenceResponse)(nil), // 51: daemon.SetSyncResponsePersistenceResponse
+	(*TCPFlags)(nil),                           // 52: daemon.TCPFlags
+	(*TracePacketRequest)(nil),                 // 53: daemon.TracePacketRequest
+	(*TraceStage)(nil),                         // 54: daemon.TraceStage
+	(*TracePacketResponse)(nil),                // 55: daemon.TracePacketResponse
+	(*SubscribeRequest)(nil),                   // 56: daemon.SubscribeRequest
+	(*SystemEvent)(nil),                        // 57: daemon.SystemEvent
+	(*GetEventsRequest)(nil),                   // 58: daemon.GetEventsRequest
+	(*GetEventsResponse)(nil),                  // 59: daemon.GetEventsResponse
+	(*SwitchProfileRequest)(nil),               // 60: daemon.SwitchProfileRequest
+	(*SwitchProfileResponse)(nil),              // 61: daemon.SwitchProfileResponse
+	(*SetConfigRequest)(nil),                   // 62: daemon.SetConfigRequest
+	(*SetConfigResponse)(nil),                  // 63: daemon.SetConfigResponse
+	(*AddProfileRequest)(nil),                  // 64: daemon.AddProfileRequest
+	(*AddProfileResponse)(nil),                 // 65: daemon.AddProfileResponse
+	(*RemoveProfileRequest)(nil),               // 66: daemon.RemoveProfileRequest
+	(*RemoveProfileResponse)(nil),              // 67: daemon.RemoveProfileResponse
+	(*ListProfilesRequest)(nil),                // 68: daemon.ListProfilesRequest
+	(*ListProfilesResponse)(nil),               // 69: daemon.ListProfilesResponse
+	(*Profile)(nil),                            // 70: daemon.Profile
+	(*GetActiveProfileRequest)(nil),            // 71: daemon.GetActiveProfileRequest
+	(*GetActiveProfileResponse)(nil),           // 72: daemon.GetActiveProfileResponse
+	(*LogoutRequest)(nil),                      // 73: daemon.LogoutRequest
+	(*LogoutResponse)(nil),                     // 74: daemon.LogoutResponse
+	(*GetFeaturesRequest)(nil),                 // 75: daemon.GetFeaturesRequest
+	(*GetFeaturesResponse)(nil),                // 76: daemon.GetFeaturesResponse
+	(*GetPeerSSHHostKeyRequest)(nil),           // 77: daemon.GetPeerSSHHostKeyRequest
+	(*GetPeerSSHHostKeyResponse)(nil),          // 78: daemon.GetPeerSSHHostKeyResponse
+	(*RequestJWTAuthRequest)(nil),              // 79: daemon.RequestJWTAuthRequest
+	(*RequestJWTAuthResponse)(nil),             // 80: daemon.RequestJWTAuthResponse
+	(*WaitJWTTokenRequest)(nil),                // 81: daemon.WaitJWTTokenRequest
+	(*WaitJWTTokenResponse)(nil),               // 82: daemon.WaitJWTTokenResponse
+	nil,                                        // 83: daemon.Network.ResolvedIPsEntry
+	(*PortInfo_Range)(nil),                     // 84: daemon.PortInfo.Range
+	nil,                                        // 85: daemon.SystemEvent.MetadataEntry
+	(*durationpb.Duration)(nil),                // 86: google.protobuf.Duration
+	(*timestamppb.Timestamp)(nil),              // 87: google.protobuf.Timestamp
 }
 var file_daemon_proto_depIdxs = []int32{
-	83, // 0: daemon.LoginRequest.dnsRouteInterval:type_name -> google.protobuf.Duration
-	24, // 1: daemon.StatusResponse.fullStatus:type_name -> daemon.FullStatus
-	84, // 2: daemon.PeerState.connStatusUpdate:type_name -> google.protobuf.Timestamp
-	84, // 3: daemon.PeerState.lastWireguardHandshake:type_name -> google.protobuf.Timestamp
-	83, // 4: daemon.PeerState.latency:type_name -> google.protobuf.Duration
-	22, // 5: daemon.SSHServerState.sessions:type_name -> daemon.SSHSessionInfo
-	19, // 6: daemon.FullStatus.managementState:type_name -> daemon.ManagementState
-	18, // 7: daemon.FullStatus.signalState:type_name -> daemon.SignalState
-	17, // 8: daemon.FullStatus.localPeerState:type_name -> daemon.LocalPeerState
-	16, // 9: daemon.FullStatus.peers:type_name -> daemon.PeerState
-	20, // 10: daemon.FullStatus.relays:type_name -> daemon.RelayState
-	21, // 11: daemon.FullStatus.dns_servers:type_name -> daemon.NSGroupState
-	54, // 12: daemon.FullStatus.events:type_name -> daemon.SystemEvent
-	23, // 13: daemon.FullStatus.sshServerState:type_name -> daemon.SSHServerState
-	30, // 14: daemon.ListNetworksResponse.routes:type_name -> daemon.Network
-	80, // 15: daemon.Network.resolvedIPs:type_name -> daemon.Network.ResolvedIPsEntry
-	81, // 16: daemon.PortInfo.range:type_name -> daemon.PortInfo.Range
-	31, // 17: daemon.ForwardingRule.destinationPort:type_name -> daemon.PortInfo
-	31, // 18: daemon.ForwardingRule.translatedPort:type_name -> daemon.PortInfo
-	32, // 19: daemon.ForwardingRulesResponse.rules:type_name -> daemon.ForwardingRule
-	0,  // 20: daemon.GetLogLevelResponse.level:type_name -> daemon.LogLevel
-	0,  // 21: daemon.SetLogLevelRequest.level:type_name -> daemon.LogLevel
-	40, // 22: daemon.ListStatesResponse.states:type_name -> daemon.State
-	49, // 23: daemon.TracePacketRequest.tcp_flags:type_name -> daemon.TCPFlags
-	51, // 24: daemon.TracePacketResponse.stages:type_name -> daemon.TraceStage
-	1,  // 25: daemon.SystemEvent.severity:type_name -> daemon.SystemEvent.Severity
-	2,  // 26: daemon.SystemEvent.category:type_name -> daemon.SystemEvent.Category
-	84, // 27: daemon.SystemEvent.timestamp:type_name -> google.protobuf.Timestamp
-	82, // 28: daemon.SystemEvent.metadata:type_name -> daemon.SystemEvent.MetadataEntry
-	54, // 29: daemon.GetEventsResponse.events:type_name -> daemon.SystemEvent
-	83, // 30: daemon.SetConfigRequest.dnsRouteInterval:type_name -> google.protobuf.Duration
-	67, // 31: daemon.ListProfilesResponse.profiles:type_name -> daemon.Profile
-	29, // 32: daemon.Network.ResolvedIPsEntry.value:type_name -> daemon.IPList
-	4,  // 33: daemon.DaemonService.Login:input_type -> daemon.LoginRequest
-	6,  // 34: daemon.DaemonService.WaitSSOLogin:input_type -> daemon.WaitSSOLoginRequest
-	8,  // 35: daemon.DaemonService.Up:input_type -> daemon.UpRequest
-	10, // 36: daemon.DaemonService.Status:input_type -> daemon.StatusRequest
-	12, // 37: daemon.DaemonService.Down:input_type -> daemon.DownRequest
-	14, // 38: daemon.DaemonService.GetConfig:input_type -> daemon.GetConfigRequest
-	25, // 39: daemon.DaemonService.ListNetworks:input_type -> daemon.ListNetworksRequest
-	27, // 40: daemon.DaemonService.SelectNetworks:input_type -> daemon.SelectNetworksRequest
-	27, // 41: daemon.DaemonService.DeselectNetworks:input_type -> daemon.SelectNetworksRequest
-	3,  // 42: daemon.DaemonService.ForwardingRules:input_type -> daemon.EmptyRequest
-	34, // 43: daemon.DaemonService.DebugBundle:input_type -> daemon.DebugBundleRequest
-	36, // 44: daemon.DaemonService.GetLogLevel:input_type -> daemon.GetLogLevelRequest
-	38, // 45: daemon.DaemonService.SetLogLevel:input_type -> daemon.SetLogLevelRequest
-	41, // 46: daemon.DaemonService.ListStates:input_type -> daemon.ListStatesRequest
-	43, // 47: daemon.DaemonService.CleanState:input_type -> daemon.CleanStateRequest
-	45, // 48: daemon.DaemonService.DeleteState:input_type -> daemon.DeleteStateRequest
-	47, // 49: daemon.DaemonService.SetSyncResponsePersistence:input_type -> daemon.SetSyncResponsePersistenceRequest
-	50, // 50: daemon.DaemonService.TracePacket:input_type -> daemon.TracePacketRequest
-	53, // 51: daemon.DaemonService.SubscribeEvents:input_type -> daemon.SubscribeRequest
-	55, // 52: daemon.DaemonService.GetEvents:input_type -> daemon.GetEventsRequest
-	57, // 53: daemon.DaemonService.SwitchProfile:input_type -> daemon.SwitchProfileRequest
-	59, // 54: daemon.DaemonService.SetConfig:input_type -> daemon.SetConfigRequest
-	61, // 55: daemon.DaemonService.AddProfile:input_type -> daemon.AddProfileRequest
-	63, // 56: daemon.DaemonService.RemoveProfile:input_type -> daemon.RemoveProfileRequest
-	65, // 57: daemon.DaemonService.ListProfiles:input_type -> daemon.ListProfilesRequest
-	68, // 58: daemon.DaemonService.GetActiveProfile:input_type -> daemon.GetActiveProfileRequest
-	70, // 59: daemon.DaemonService.Logout:input_type -> daemon.LogoutRequest
-	72, // 60: daemon.DaemonService.GetFeatures:input_type -> daemon.GetFeaturesRequest
-	74, // 61: daemon.DaemonService.GetPeerSSHHostKey:input_type -> daemon.GetPeerSSHHostKeyRequest
-	76, // 62: daemon.DaemonService.RequestJWTAuth:input_type -> daemon.RequestJWTAuthRequest
-	78, // 63: daemon.DaemonService.WaitJWTToken:input_type -> daemon.WaitJWTTokenRequest
-	5,  // 64: daemon.DaemonService.Login:output_type -> daemon.LoginResponse
-	7,  // 65: daemon.DaemonService.WaitSSOLogin:output_type -> daemon.WaitSSOLoginResponse
-	9,  // 66: daemon.DaemonService.Up:output_type -> daemon.UpResponse
-	11, // 67: daemon.DaemonService.Status:output_type -> daemon.StatusResponse
-	13, // 68: daemon.DaemonService.Down:output_type -> daemon.DownResponse
-	15, // 69: daemon.DaemonService.GetConfig:output_type -> daemon.GetConfigResponse
-	26, // 70: daemon.DaemonService.ListNetworks:output_type -> daemon.ListNetworksResponse
-	28, // 71: daemon.DaemonService.SelectNetworks:output_type -> daemon.SelectNetworksResponse
-	28, // 72: daemon.DaemonService.DeselectNetworks:output_type -> daemon.SelectNetworksResponse
-	33, // 73: daemon.DaemonService.ForwardingRules:output_type -> daemon.ForwardingRulesResponse
-	35, // 74: daemon.DaemonService.DebugBundle:output_type -> daemon.DebugBundleResponse
-	37, // 75: daemon.DaemonService.GetLogLevel:output_type -> daemon.GetLogLevelResponse
-	39, // 76: daemon.DaemonService.SetLogLevel:output_type -> daemon.SetLogLevelResponse
-	42, // 77: daemon.DaemonService.ListStates:output_type -> daemon.ListStatesResponse
-	44, // 78: daemon.DaemonService.CleanState:output_type -> daemon.CleanStateResponse
-	46, // 79: daemon.DaemonService.DeleteState:output_type -> daemon.DeleteStateResponse
-	48, // 80: daemon.DaemonService.SetSyncResponsePersistence:output_type -> daemon.SetSyncResponsePersistenceResponse
-	52, // 81: daemon.DaemonService.TracePacket:output_type -> daemon.TracePacketResponse
-	54, // 82: daemon.DaemonService.SubscribeEvents:output_type -> daemon.SystemEvent
-	56, // 83: daemon.DaemonService.GetEvents:output_type -> daemon.GetEventsResponse
-	58, // 84: daemon.DaemonService.SwitchProfile:output_type -> daemon.SwitchProfileResponse
-	60, // 85: daemon.DaemonService.SetConfig:output_type -> daemon.SetConfigResponse
-	62, // 86: daemon.DaemonService.AddProfile:output_type -> daemon.AddProfileResponse
-	64, // 87: daemon.DaemonService.RemoveProfile:output_type -> daemon.RemoveProfileResponse
-	66, // 88: daemon.DaemonService.ListProfiles:output_type -> daemon.ListProfilesResponse
-	69, // 89: daemon.DaemonService.GetActiveProfile:output_type -> daemon.GetActiveProfileResponse
-	71, // 90: daemon.DaemonService.Logout:output_type -> daemon.LogoutResponse
-	73, // 91: daemon.DaemonService.GetFeatures:output_type -> daemon.GetFeaturesResponse
-	75, // 92: daemon.DaemonService.GetPeerSSHHostKey:output_type -> daemon.GetPeerSSHHostKeyResponse
-	77, // 93: daemon.DaemonService.RequestJWTAuth:output_type -> daemon.RequestJWTAuthResponse
-	79, // 94: daemon.DaemonService.WaitJWTToken:output_type -> daemon.WaitJWTTokenResponse
-	64, // [64:95] is the sub-list for method output_type
-	33, // [33:64] is the sub-list for method input_type
-	33, // [33:33] is the sub-list for extension type_name
-	33, // [33:33] is the sub-list for extension extendee
-	0,  // [0:33] is the sub-list for field type_name
+	1,  // 0: daemon.OSLifecycleRequest.type:type_name -> daemon.OSLifecycleRequest.CycleType
+	86, // 1: daemon.LoginRequest.dnsRouteInterval:type_name -> google.protobuf.Duration
+	27, // 2: daemon.StatusResponse.fullStatus:type_name -> daemon.FullStatus
+	87, // 3: daemon.PeerState.connStatusUpdate:type_name -> google.protobuf.Timestamp
+	87, // 4: daemon.PeerState.lastWireguardHandshake:type_name -> google.protobuf.Timestamp
+	86, // 5: daemon.PeerState.latency:type_name -> google.protobuf.Duration
+	25, // 6: daemon.SSHServerState.sessions:type_name -> daemon.SSHSessionInfo
+	22, // 7: daemon.FullStatus.managementState:type_name -> daemon.ManagementState
+	21, // 8: daemon.FullStatus.signalState:type_name -> daemon.SignalState
+	20, // 9: daemon.FullStatus.localPeerState:type_name -> daemon.LocalPeerState
+	19, // 10: daemon.FullStatus.peers:type_name -> daemon.PeerState
+	23, // 11: daemon.FullStatus.relays:type_name -> daemon.RelayState
+	24, // 12: daemon.FullStatus.dns_servers:type_name -> daemon.NSGroupState
+	57, // 13: daemon.FullStatus.events:type_name -> daemon.SystemEvent
+	26, // 14: daemon.FullStatus.sshServerState:type_name -> daemon.SSHServerState
+	33, // 15: daemon.ListNetworksResponse.routes:type_name -> daemon.Network
+	83, // 16: daemon.Network.resolvedIPs:type_name -> daemon.Network.ResolvedIPsEntry
+	84, // 17: daemon.PortInfo.range:type_name -> daemon.PortInfo.Range
+	34, // 18: daemon.ForwardingRule.destinationPort:type_name -> daemon.PortInfo
+	34, // 19: daemon.ForwardingRule.translatedPort:type_name -> daemon.PortInfo
+	35, // 20: daemon.ForwardingRulesResponse.rules:type_name -> daemon.ForwardingRule
+	0,  // 21: daemon.GetLogLevelResponse.level:type_name -> daemon.LogLevel
+	0,  // 22: daemon.SetLogLevelRequest.level:type_name -> daemon.LogLevel
+	43, // 23: daemon.ListStatesResponse.states:type_name -> daemon.State
+	52, // 24: daemon.TracePacketRequest.tcp_flags:type_name -> daemon.TCPFlags
+	54, // 25: daemon.TracePacketResponse.stages:type_name -> daemon.TraceStage
+	2,  // 26: daemon.SystemEvent.severity:type_name -> daemon.SystemEvent.Severity
+	3,  // 27: daemon.SystemEvent.category:type_name -> daemon.SystemEvent.Category
+	87, // 28: daemon.SystemEvent.timestamp:type_name -> google.protobuf.Timestamp
+	85, // 29: daemon.SystemEvent.metadata:type_name -> daemon.SystemEvent.MetadataEntry
+	57, // 30: daemon.GetEventsResponse.events:type_name -> daemon.SystemEvent
+	86, // 31: daemon.SetConfigRequest.dnsRouteInterval:type_name -> google.protobuf.Duration
+	70, // 32: daemon.ListProfilesResponse.profiles:type_name -> daemon.Profile
+	32, // 33: daemon.Network.ResolvedIPsEntry.value:type_name -> daemon.IPList
+	7,  // 34: daemon.DaemonService.Login:input_type -> daemon.LoginRequest
+	9,  // 35: daemon.DaemonService.WaitSSOLogin:input_type -> daemon.WaitSSOLoginRequest
+	11, // 36: daemon.DaemonService.Up:input_type -> daemon.UpRequest
+	13, // 37: daemon.DaemonService.Status:input_type -> daemon.StatusRequest
+	15, // 38: daemon.DaemonService.Down:input_type -> daemon.DownRequest
+	17, // 39: daemon.DaemonService.GetConfig:input_type -> daemon.GetConfigRequest
+	28, // 40: daemon.DaemonService.ListNetworks:input_type -> daemon.ListNetworksRequest
+	30, // 41: daemon.DaemonService.SelectNetworks:input_type -> daemon.SelectNetworksRequest
+	30, // 42: daemon.DaemonService.DeselectNetworks:input_type -> daemon.SelectNetworksRequest
+	4,  // 43: daemon.DaemonService.ForwardingRules:input_type -> daemon.EmptyRequest
+	37, // 44: daemon.DaemonService.DebugBundle:input_type -> daemon.DebugBundleRequest
+	39, // 45: daemon.DaemonService.GetLogLevel:input_type -> daemon.GetLogLevelRequest
+	41, // 46: daemon.DaemonService.SetLogLevel:input_type -> daemon.SetLogLevelRequest
+	44, // 47: daemon.DaemonService.ListStates:input_type -> daemon.ListStatesRequest
+	46, // 48: daemon.DaemonService.CleanState:input_type -> daemon.CleanStateRequest
+	48, // 49: daemon.DaemonService.DeleteState:input_type -> daemon.DeleteStateRequest
+	50, // 50: daemon.DaemonService.SetSyncResponsePersistence:input_type -> daemon.SetSyncResponsePersistenceRequest
+	53, // 51: daemon.DaemonService.TracePacket:input_type -> daemon.TracePacketRequest
+	56, // 52: daemon.DaemonService.SubscribeEvents:input_type -> daemon.SubscribeRequest
+	58, // 53: daemon.DaemonService.GetEvents:input_type -> daemon.GetEventsRequest
+	60, // 54: daemon.DaemonService.SwitchProfile:input_type -> daemon.SwitchProfileRequest
+	62, // 55: daemon.DaemonService.SetConfig:input_type -> daemon.SetConfigRequest
+	64, // 56: daemon.DaemonService.AddProfile:input_type -> daemon.AddProfileRequest
+	66, // 57: daemon.DaemonService.RemoveProfile:input_type -> daemon.RemoveProfileRequest
+	68, // 58: daemon.DaemonService.ListProfiles:input_type -> daemon.ListProfilesRequest
+	71, // 59: daemon.DaemonService.GetActiveProfile:input_type -> daemon.GetActiveProfileRequest
+	73, // 60: daemon.DaemonService.Logout:input_type -> daemon.LogoutRequest
+	75, // 61: daemon.DaemonService.GetFeatures:input_type -> daemon.GetFeaturesRequest
+	77, // 62: daemon.DaemonService.GetPeerSSHHostKey:input_type -> daemon.GetPeerSSHHostKeyRequest
+	79, // 63: daemon.DaemonService.RequestJWTAuth:input_type -> daemon.RequestJWTAuthRequest
+	81, // 64: daemon.DaemonService.WaitJWTToken:input_type -> daemon.WaitJWTTokenRequest
+	5,  // 65: daemon.DaemonService.NotifyOSLifecycle:input_type -> daemon.OSLifecycleRequest
+	8,  // 66: daemon.DaemonService.Login:output_type -> daemon.LoginResponse
+	10, // 67: daemon.DaemonService.WaitSSOLogin:output_type -> daemon.WaitSSOLoginResponse
+	12, // 68: daemon.DaemonService.Up:output_type -> daemon.UpResponse
+	14, // 69: daemon.DaemonService.Status:output_type -> daemon.StatusResponse
+	16, // 70: daemon.DaemonService.Down:output_type -> daemon.DownResponse
+	18, // 71: daemon.DaemonService.GetConfig:output_type -> daemon.GetConfigResponse
+	29, // 72: daemon.DaemonService.ListNetworks:output_type -> daemon.ListNetworksResponse
+	31, // 73: daemon.DaemonService.SelectNetworks:output_type -> daemon.SelectNetworksResponse
+	31, // 74: daemon.DaemonService.DeselectNetworks:output_type -> daemon.SelectNetworksResponse
+	36, // 75: daemon.DaemonService.ForwardingRules:output_type -> daemon.ForwardingRulesResponse
+	38, // 76: daemon.DaemonService.DebugBundle:output_type -> daemon.DebugBundleResponse
+	40, // 77: daemon.DaemonService.GetLogLevel:output_type -> daemon.GetLogLevelResponse
+	42, // 78: daemon.DaemonService.SetLogLevel:output_type -> daemon.SetLogLevelResponse
+	45, // 79: daemon.DaemonService.ListStates:output_type -> daemon.ListStatesResponse
+	47, // 80: daemon.DaemonService.CleanState:output_type -> daemon.CleanStateResponse
+	49, // 81: daemon.DaemonService.DeleteState:output_type -> daemon.DeleteStateResponse
+	51, // 82: daemon.DaemonService.SetSyncResponsePersistence:output_type -> daemon.SetSyncResponsePersistenceResponse
+	55, // 83: daemon.DaemonService.TracePacket:output_type -> daemon.TracePacketResponse
+	57, // 84: daemon.DaemonService.SubscribeEvents:output_type -> daemon.SystemEvent
+	59, // 85: daemon.DaemonService.GetEvents:output_type -> daemon.GetEventsResponse
+	61, // 86: daemon.DaemonService.SwitchProfile:output_type -> daemon.SwitchProfileResponse
+	63, // 87: daemon.DaemonService.SetConfig:output_type -> daemon.SetConfigResponse
+	65, // 88: daemon.DaemonService.AddProfile:output_type -> daemon.AddProfileResponse
+	67, // 89: daemon.DaemonService.RemoveProfile:output_type -> daemon.RemoveProfileResponse
+	69, // 90: daemon.DaemonService.ListProfiles:output_type -> daemon.ListProfilesResponse
+	72, // 91: daemon.DaemonService.GetActiveProfile:output_type -> daemon.GetActiveProfileResponse
+	74, // 92: daemon.DaemonService.Logout:output_type -> daemon.LogoutResponse
+	76, // 93: daemon.DaemonService.GetFeatures:output_type -> daemon.GetFeaturesResponse
+	78, // 94: daemon.DaemonService.GetPeerSSHHostKey:output_type -> daemon.GetPeerSSHHostKeyResponse
+	80, // 95: daemon.DaemonService.RequestJWTAuth:output_type -> daemon.RequestJWTAuthResponse
+	82, // 96: daemon.DaemonService.WaitJWTToken:output_type -> daemon.WaitJWTTokenResponse
+	6,  // 97: daemon.DaemonService.NotifyOSLifecycle:output_type -> daemon.OSLifecycleResponse
+	66, // [66:98] is the sub-list for method output_type
+	34, // [34:66] is the sub-list for method input_type
+	34, // [34:34] is the sub-list for extension type_name
+	34, // [34:34] is the sub-list for extension extendee
+	0,  // [0:34] is the sub-list for field type_name
 }
 
 func init() { file_daemon_proto_init() }
@@ -6010,26 +6155,26 @@ func file_daemon_proto_init() {
 	if File_daemon_proto != nil {
 		return
 	}
-	file_daemon_proto_msgTypes[1].OneofWrappers = []any{}
-	file_daemon_proto_msgTypes[5].OneofWrappers = []any{}
+	file_daemon_proto_msgTypes[3].OneofWrappers = []any{}
 	file_daemon_proto_msgTypes[7].OneofWrappers = []any{}
-	file_daemon_proto_msgTypes[28].OneofWrappers = []any{
+	file_daemon_proto_msgTypes[9].OneofWrappers = []any{}
+	file_daemon_proto_msgTypes[30].OneofWrappers = []any{
 		(*PortInfo_Port)(nil),
 		(*PortInfo_Range_)(nil),
 	}
-	file_daemon_proto_msgTypes[47].OneofWrappers = []any{}
-	file_daemon_proto_msgTypes[48].OneofWrappers = []any{}
-	file_daemon_proto_msgTypes[54].OneofWrappers = []any{}
+	file_daemon_proto_msgTypes[49].OneofWrappers = []any{}
+	file_daemon_proto_msgTypes[50].OneofWrappers = []any{}
 	file_daemon_proto_msgTypes[56].OneofWrappers = []any{}
-	file_daemon_proto_msgTypes[67].OneofWrappers = []any{}
-	file_daemon_proto_msgTypes[73].OneofWrappers = []any{}
+	file_daemon_proto_msgTypes[58].OneofWrappers = []any{}
+	file_daemon_proto_msgTypes[69].OneofWrappers = []any{}
+	file_daemon_proto_msgTypes[75].OneofWrappers = []any{}
 	type x struct{}
 	out := protoimpl.TypeBuilder{
 		File: protoimpl.DescBuilder{
 			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
 			RawDescriptor: unsafe.Slice(unsafe.StringData(file_daemon_proto_rawDesc), len(file_daemon_proto_rawDesc)),
-			NumEnums:      3,
-			NumMessages:   80,
+			NumEnums:      4,
+			NumMessages:   82,
 			NumExtensions: 0,
 			NumServices:   1,
 		},
diff --git a/client/proto/daemon.proto b/client/proto/daemon.proto
index bf855370..3dfd3da8 100644
--- a/client/proto/daemon.proto
+++ b/client/proto/daemon.proto
@@ -24,7 +24,7 @@ service DaemonService {
   // Status of the service.
   rpc Status(StatusRequest) returns (StatusResponse) {}
 
-  // Down engine work in the daemon.
+  // Down stops engine work in the daemon.
   rpc Down(DownRequest) returns (DownResponse) {}
 
   // GetConfig of the daemon.
@@ -93,8 +93,25 @@ service DaemonService {
 
   // WaitJWTToken waits for JWT authentication completion
   rpc WaitJWTToken(WaitJWTTokenRequest) returns (WaitJWTTokenResponse) {}
+
+  rpc NotifyOSLifecycle(OSLifecycleRequest) returns(OSLifecycleResponse) {}
+}
+
+
+
+message OSLifecycleRequest {
+  // avoid collision with loglevel enum
+  enum CycleType {
+    UNKNOWN = 0;
+    SLEEP = 1;
+    WAKEUP = 2;
+  }
+
+  CycleType type = 1;
 }
 
+message OSLifecycleResponse {}
+
 
 message LoginRequest {
   // setupKey netbird setup key.
diff --git a/client/proto/daemon_grpc.pb.go b/client/proto/daemon_grpc.pb.go
index b2bf716b..6b01309b 100644
--- a/client/proto/daemon_grpc.pb.go
+++ b/client/proto/daemon_grpc.pb.go
@@ -27,7 +27,7 @@ type DaemonServiceClient interface {
 	Up(ctx context.Context, in *UpRequest, opts ...grpc.CallOption) (*UpResponse, error)
 	// Status of the service.
 	Status(ctx context.Context, in *StatusRequest, opts ...grpc.CallOption) (*StatusResponse, error)
-	// Down engine work in the daemon.
+	// Down stops engine work in the daemon.
 	Down(ctx context.Context, in *DownRequest, opts ...grpc.CallOption) (*DownResponse, error)
 	// GetConfig of the daemon.
 	GetConfig(ctx context.Context, in *GetConfigRequest, opts ...grpc.CallOption) (*GetConfigResponse, error)
@@ -70,6 +70,7 @@ type DaemonServiceClient interface {
 	RequestJWTAuth(ctx context.Context, in *RequestJWTAuthRequest, opts ...grpc.CallOption) (*RequestJWTAuthResponse, error)
 	// WaitJWTToken waits for JWT authentication completion
 	WaitJWTToken(ctx context.Context, in *WaitJWTTokenRequest, opts ...grpc.CallOption) (*WaitJWTTokenResponse, error)
+	NotifyOSLifecycle(ctx context.Context, in *OSLifecycleRequest, opts ...grpc.CallOption) (*OSLifecycleResponse, error)
 }
 
 type daemonServiceClient struct {
@@ -382,6 +383,15 @@ func (c *daemonServiceClient) WaitJWTToken(ctx context.Context, in *WaitJWTToken
 	return out, nil
 }
 
+func (c *daemonServiceClient) NotifyOSLifecycle(ctx context.Context, in *OSLifecycleRequest, opts ...grpc.CallOption) (*OSLifecycleResponse, error) {
+	out := new(OSLifecycleResponse)
+	err := c.cc.Invoke(ctx, "/daemon.DaemonService/NotifyOSLifecycle", 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
@@ -395,7 +405,7 @@ type DaemonServiceServer interface {
 	Up(context.Context, *UpRequest) (*UpResponse, error)
 	// Status of the service.
 	Status(context.Context, *StatusRequest) (*StatusResponse, error)
-	// Down engine work in the daemon.
+	// Down stops engine work in the daemon.
 	Down(context.Context, *DownRequest) (*DownResponse, error)
 	// GetConfig of the daemon.
 	GetConfig(context.Context, *GetConfigRequest) (*GetConfigResponse, error)
@@ -438,6 +448,7 @@ type DaemonServiceServer interface {
 	RequestJWTAuth(context.Context, *RequestJWTAuthRequest) (*RequestJWTAuthResponse, error)
 	// WaitJWTToken waits for JWT authentication completion
 	WaitJWTToken(context.Context, *WaitJWTTokenRequest) (*WaitJWTTokenResponse, error)
+	NotifyOSLifecycle(context.Context, *OSLifecycleRequest) (*OSLifecycleResponse, error)
 	mustEmbedUnimplementedDaemonServiceServer()
 }
 
@@ -538,6 +549,9 @@ func (UnimplementedDaemonServiceServer) RequestJWTAuth(context.Context, *Request
 func (UnimplementedDaemonServiceServer) WaitJWTToken(context.Context, *WaitJWTTokenRequest) (*WaitJWTTokenResponse, error) {
 	return nil, status.Errorf(codes.Unimplemented, "method WaitJWTToken not implemented")
 }
+func (UnimplementedDaemonServiceServer) NotifyOSLifecycle(context.Context, *OSLifecycleRequest) (*OSLifecycleResponse, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method NotifyOSLifecycle not implemented")
+}
 func (UnimplementedDaemonServiceServer) mustEmbedUnimplementedDaemonServiceServer() {}
 
 // UnsafeDaemonServiceServer may be embedded to opt out of forward compatibility for this service.
@@ -1112,6 +1126,24 @@ func _DaemonService_WaitJWTToken_Handler(srv interface{}, ctx context.Context, d
 	return interceptor(ctx, in, info, handler)
 }
 
+func _DaemonService_NotifyOSLifecycle_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(OSLifecycleRequest)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(DaemonServiceServer).NotifyOSLifecycle(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: "/daemon.DaemonService/NotifyOSLifecycle",
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(DaemonServiceServer).NotifyOSLifecycle(ctx, req.(*OSLifecycleRequest))
+	}
+	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)
@@ -1239,6 +1271,10 @@ var DaemonService_ServiceDesc = grpc.ServiceDesc{
 			MethodName: "WaitJWTToken",
 			Handler:    _DaemonService_WaitJWTToken_Handler,
 		},
+		{
+			MethodName: "NotifyOSLifecycle",
+			Handler:    _DaemonService_NotifyOSLifecycle_Handler,
+		},
 	},
 	Streams: []grpc.StreamDesc{
 		{
diff --git a/client/server/lifecycle.go b/client/server/lifecycle.go
new file mode 100644
index 00000000..3722c027
--- /dev/null
+++ b/client/server/lifecycle.go
@@ -0,0 +1,77 @@
+package server
+
+import (
+	"context"
+
+	log "github.com/sirupsen/logrus"
+
+	"github.com/netbirdio/netbird/client/internal"
+	"github.com/netbirdio/netbird/client/proto"
+)
+
+// NotifyOSLifecycle handles operating system lifecycle events by executing appropriate logic based on the request type.
+func (s *Server) NotifyOSLifecycle(callerCtx context.Context, req *proto.OSLifecycleRequest) (*proto.OSLifecycleResponse, error) {
+	switch req.GetType() {
+	case proto.OSLifecycleRequest_WAKEUP:
+		return s.handleWakeUp(callerCtx)
+	case proto.OSLifecycleRequest_SLEEP:
+		return s.handleSleep(callerCtx)
+	default:
+		log.Errorf("unknown OSLifecycleRequest type: %v", req.GetType())
+	}
+	return &proto.OSLifecycleResponse{}, nil
+}
+
+// handleWakeUp processes a wake-up event by triggering the Up command if the system was previously put to sleep.
+// It resets the sleep state and logs the process. Returns a response or an error if the Up command fails.
+func (s *Server) handleWakeUp(callerCtx context.Context) (*proto.OSLifecycleResponse, error) {
+	if !s.sleepTriggeredDown.Load() {
+		log.Info("skipping up because wasn't sleep down")
+		return &proto.OSLifecycleResponse{}, nil
+	}
+
+	// avoid other wakeup runs if sleep didn't make the computer sleep
+	s.sleepTriggeredDown.Store(false)
+
+	log.Info("running up after wake up")
+	_, err := s.Up(callerCtx, &proto.UpRequest{})
+	if err != nil {
+		log.Errorf("running up failed: %v", err)
+		return &proto.OSLifecycleResponse{}, err
+	}
+
+	log.Info("running up command executed successfully")
+	return &proto.OSLifecycleResponse{}, nil
+}
+
+// handleSleep handles the sleep event by initiating a "down" sequence if the system is in a connected or connecting state.
+func (s *Server) handleSleep(callerCtx context.Context) (*proto.OSLifecycleResponse, error) {
+	s.mutex.Lock()
+
+	state := internal.CtxGetState(s.rootCtx)
+	status, err := state.Status()
+	if err != nil {
+		s.mutex.Unlock()
+		return &proto.OSLifecycleResponse{}, err
+	}
+
+	if status != internal.StatusConnecting && status != internal.StatusConnected {
+		log.Infof("skipping setting the agent down because status is %s", status)
+		s.mutex.Unlock()
+		return &proto.OSLifecycleResponse{}, nil
+	}
+	s.mutex.Unlock()
+
+	log.Info("running down after system started sleeping")
+
+	_, err = s.Down(callerCtx, &proto.DownRequest{})
+	if err != nil {
+		log.Errorf("running down failed: %v", err)
+		return &proto.OSLifecycleResponse{}, err
+	}
+
+	s.sleepTriggeredDown.Store(true)
+
+	log.Info("running down executed successfully")
+	return &proto.OSLifecycleResponse{}, nil
+}
diff --git a/client/server/server.go b/client/server/server.go
index 49000c09..cf79ec5e 100644
--- a/client/server/server.go
+++ b/client/server/server.go
@@ -85,6 +85,9 @@ type Server struct {
 	profilesDisabled       bool
 	updateSettingsDisabled bool
 
+	// sleepTriggeredDown holds a state indicated if the sleep handler triggered the last client down
+	sleepTriggeredDown atomic.Bool
+
 	jwtCache *jwtCache
 }
 
diff --git a/client/ui/client_ui.go b/client/ui/client_ui.go
index 57d0e74a..8f99608e 100644
--- a/client/ui/client_ui.go
+++ b/client/ui/client_ui.go
@@ -1196,25 +1196,27 @@ func (s *serviceClient) handleSleepEvents(event sleep.EventType) {
 		return
 	}
 
+	req := &proto.OSLifecycleRequest{}
+
 	switch event {
 	case sleep.EventTypeWakeUp:
 		log.Infof("handle wakeup event: %v", event)
-		_, err = conn.Up(s.ctx, &proto.UpRequest{})
-		if err != nil {
-			log.Errorf("up service: %v", err)
-			return
-		}
-		return
+		req.Type = proto.OSLifecycleRequest_WAKEUP
 	case sleep.EventTypeSleep:
 		log.Infof("handle sleep event: %v", event)
-		_, err = conn.Down(s.ctx, &proto.DownRequest{})
-		if err != nil {
-			log.Errorf("down service: %v", err)
-			return
-		}
+		req.Type = proto.OSLifecycleRequest_SLEEP
+	default:
+		log.Infof("unknown event: %v", event)
+		return
+	}
+
+	_, err = conn.NotifyOSLifecycle(s.ctx, req)
+	if err != nil {
+		log.Errorf("failed to notify daemon about os lifecycle notification: %v", err)
+		return
 	}
 
-	log.Info("successfully notified daemon about sleep/wakeup event")
+	log.Info("successfully notified daemon about os lifecycle")
 }
 
 // setSettingsEnabled enables or disables the settings menu based on the provided state



Test patch:
diff --git a/client/server/lifecycle_test.go b/client/server/lifecycle_test.go
new file mode 100644
index 00000000..a604c60a
--- /dev/null
+++ b/client/server/lifecycle_test.go
@@ -0,0 +1,219 @@
+package server
+
+import (
+	"context"
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/require"
+
+	"github.com/netbirdio/netbird/client/internal"
+	"github.com/netbirdio/netbird/client/internal/peer"
+	"github.com/netbirdio/netbird/client/proto"
+)
+
+func newTestServer() *Server {
+	ctx := internal.CtxInitState(context.Background())
+	return &Server{
+		rootCtx:        ctx,
+		statusRecorder: peer.NewRecorder(""),
+	}
+}
+
+func TestNotifyOSLifecycle_WakeUp_SkipsWhenNotSleepTriggered(t *testing.T) {
+	s := newTestServer()
+
+	// sleepTriggeredDown is false by default
+	assert.False(t, s.sleepTriggeredDown.Load())
+
+	resp, err := s.NotifyOSLifecycle(context.Background(), &proto.OSLifecycleRequest{
+		Type: proto.OSLifecycleRequest_WAKEUP,
+	})
+
+	require.NoError(t, err)
+	require.NotNil(t, resp)
+	assert.False(t, s.sleepTriggeredDown.Load(), "flag should remain false")
+}
+
+func TestNotifyOSLifecycle_Sleep_SkipsWhenStatusIdle(t *testing.T) {
+	s := newTestServer()
+
+	state := internal.CtxGetState(s.rootCtx)
+	state.Set(internal.StatusIdle)
+
+	resp, err := s.NotifyOSLifecycle(context.Background(), &proto.OSLifecycleRequest{
+		Type: proto.OSLifecycleRequest_SLEEP,
+	})
+
+	require.NoError(t, err)
+	require.NotNil(t, resp)
+	assert.False(t, s.sleepTriggeredDown.Load(), "flag should remain false when status is Idle")
+}
+
+func TestNotifyOSLifecycle_Sleep_SkipsWhenStatusNeedsLogin(t *testing.T) {
+	s := newTestServer()
+
+	state := internal.CtxGetState(s.rootCtx)
+	state.Set(internal.StatusNeedsLogin)
+
+	resp, err := s.NotifyOSLifecycle(context.Background(), &proto.OSLifecycleRequest{
+		Type: proto.OSLifecycleRequest_SLEEP,
+	})
+
+	require.NoError(t, err)
+	require.NotNil(t, resp)
+	assert.False(t, s.sleepTriggeredDown.Load(), "flag should remain false when status is NeedsLogin")
+}
+
+func TestNotifyOSLifecycle_Sleep_SetsFlag_WhenConnecting(t *testing.T) {
+	s := newTestServer()
+
+	state := internal.CtxGetState(s.rootCtx)
+	state.Set(internal.StatusConnecting)
+
+	ctx, cancel := context.WithCancel(context.Background())
+	defer cancel()
+	s.actCancel = cancel
+
+	resp, err := s.NotifyOSLifecycle(ctx, &proto.OSLifecycleRequest{
+		Type: proto.OSLifecycleRequest_SLEEP,
+	})
+
+	require.NoError(t, err)
+	assert.NotNil(t, resp, "handleSleep returns not nil response on success")
+	assert.True(t, s.sleepTriggeredDown.Load(), "flag should be set after sleep when connecting")
+}
+
+func TestNotifyOSLifecycle_Sleep_SetsFlag_WhenConnected(t *testing.T) {
+	s := newTestServer()
+
+	state := internal.CtxGetState(s.rootCtx)
+	state.Set(internal.StatusConnected)
+
+	ctx, cancel := context.WithCancel(context.Background())
+	defer cancel()
+	s.actCancel = cancel
+
+	resp, err := s.NotifyOSLifecycle(ctx, &proto.OSLifecycleRequest{
+		Type: proto.OSLifecycleRequest_SLEEP,
+	})
+
+	require.NoError(t, err)
+	assert.NotNil(t, resp, "handleSleep returns not nil response on success")
+	assert.True(t, s.sleepTriggeredDown.Load(), "flag should be set after sleep when connected")
+}
+
+func TestNotifyOSLifecycle_WakeUp_ResetsFlag(t *testing.T) {
+	s := newTestServer()
+
+	// Manually set the flag to simulate prior sleep down
+	s.sleepTriggeredDown.Store(true)
+
+	// WakeUp will try to call Up which fails without proper setup, but flag should reset first
+	_, _ = s.NotifyOSLifecycle(context.Background(), &proto.OSLifecycleRequest{
+		Type: proto.OSLifecycleRequest_WAKEUP,
+	})
+
+	assert.False(t, s.sleepTriggeredDown.Load(), "flag should be reset after WakeUp attempt")
+}
+
+func TestNotifyOSLifecycle_MultipleWakeUpCalls(t *testing.T) {
+	s := newTestServer()
+
+	// First wakeup without prior sleep - should be no-op
+	resp, err := s.NotifyOSLifecycle(context.Background(), &proto.OSLifecycleRequest{
+		Type: proto.OSLifecycleRequest_WAKEUP,
+	})
+	require.NoError(t, err)
+	require.NotNil(t, resp)
+	assert.False(t, s.sleepTriggeredDown.Load())
+
+	// Simulate prior sleep
+	s.sleepTriggeredDown.Store(true)
+
+	// First wakeup after sleep - should reset flag
+	_, _ = s.NotifyOSLifecycle(context.Background(), &proto.OSLifecycleRequest{
+		Type: proto.OSLifecycleRequest_WAKEUP,
+	})
+	assert.False(t, s.sleepTriggeredDown.Load())
+
+	// Second wakeup - should be no-op
+	resp, err = s.NotifyOSLifecycle(context.Background(), &proto.OSLifecycleRequest{
+		Type: proto.OSLifecycleRequest_WAKEUP,
+	})
+	require.NoError(t, err)
+	require.NotNil(t, resp)
+	assert.False(t, s.sleepTriggeredDown.Load())
+}
+
+func TestHandleWakeUp_SkipsWhenFlagFalse(t *testing.T) {
+	s := newTestServer()
+
+	resp, err := s.handleWakeUp(context.Background())
+
+	require.NoError(t, err)
+	require.NotNil(t, resp)
+}
+
+func TestHandleWakeUp_ResetsFlagBeforeUp(t *testing.T) {
+	s := newTestServer()
+	s.sleepTriggeredDown.Store(true)
+
+	// Even if Up fails, flag should be reset
+	_, _ = s.handleWakeUp(context.Background())
+
+	assert.False(t, s.sleepTriggeredDown.Load(), "flag must be reset before calling Up")
+}
+
+func TestHandleSleep_SkipsForNonActiveStates(t *testing.T) {
+	tests := []struct {
+		name   string
+		status internal.StatusType
+	}{
+		{"Idle", internal.StatusIdle},
+		{"NeedsLogin", internal.StatusNeedsLogin},
+		{"LoginFailed", internal.StatusLoginFailed},
+	}
+
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			s := newTestServer()
+			state := internal.CtxGetState(s.rootCtx)
+			state.Set(tt.status)
+
+			resp, err := s.handleSleep(context.Background())
+
+			require.NoError(t, err)
+			require.NotNil(t, resp)
+			assert.False(t, s.sleepTriggeredDown.Load())
+		})
+	}
+}
+
+func TestHandleSleep_ProceedsForActiveStates(t *testing.T) {
+	tests := []struct {
+		name   string
+		status internal.StatusType
+	}{
+		{"Connecting", internal.StatusConnecting},
+		{"Connected", internal.StatusConnected},
+	}
+
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			s := newTestServer()
+			state := internal.CtxGetState(s.rootCtx)
+			state.Set(tt.status)
+
+			ctx, cancel := context.WithCancel(context.Background())
+			defer cancel()
+			s.actCancel = cancel
+
+			resp, err := s.handleSleep(ctx)
+
+			require.NoError(t, err)
+			assert.NotNil(t, resp)
+			assert.True(t, s.sleepTriggeredDown.Load())
+		})
+	}
+}