From 087a6df49059587b09e1ec3fefdc929bd25d83a5 Mon Sep 17 00:00:00 2001 From: hulto <7121375+hulto@users.noreply.github.com> Date: Mon, 29 Dec 2025 22:36:49 +0000 Subject: [PATCH 01/18] Manual updates --- docs/_docs/dev-guide/imix.md | 10 + tavern/internal/c2/c2pb/c2.pb.go | 633 +++++++++++------- .../c2pb/enum_beacon_active_transport_type.go | 64 ++ .../internal/c2/c2pb/enum_beacon_transport.go | 4 +- tavern/internal/c2/c2test/ent.go | 2 +- tavern/internal/c2/dnspb/dns.pb.go | 97 +-- tavern/internal/c2/proto/c2.proto | 23 +- tavern/internal/c2/reverse_shell_e2e_test.go | 2 +- tavern/internal/cdn/download_hostfile_test.go | 2 +- tavern/internal/ent/schema/beacon.go | 7 - tavern/internal/ent/schema/host_file_test.go | 2 +- tavern/internal/graphql/quest_test.go | 4 +- tavern/internal/http/stream/websocket_test.go | 2 +- tavern/test_data.go | 16 +- 14 files changed, 541 insertions(+), 327 deletions(-) create mode 100644 tavern/internal/c2/c2pb/enum_beacon_active_transport_type.go diff --git a/docs/_docs/dev-guide/imix.md b/docs/_docs/dev-guide/imix.md index bea5aa0a4..3824613c4 100644 --- a/docs/_docs/dev-guide/imix.md +++ b/docs/_docs/dev-guide/imix.md @@ -10,6 +10,16 @@ permalink: dev-guide/imix Imix in the main bot for Realm. +## Agent protobuf + +In order to communicate agent state and configuration during the claimTask request the agent sends a protobuf containing various configuration options. If any are updated agent side they're now syncronsized with the server ensuring operators can track the state of their agents. + +In order to keep these configuration options in sync realm uses protobuf and code generation to ensure agent and server agree. + +If you need to update these fields start with the `tavern/internal/c2/proto/c2.proto` file. + +Once you've finished making your changes apply these changes across the project. + ## Host Selector The host selector defined in `implants/lib/host_selector` allow imix to reliably identify which host it's running on. This is helpful for operators when creating tasking across multiple beacons as well as when searching for command results. Uniqueness is stored as a UUID4 value. diff --git a/tavern/internal/c2/c2pb/c2.pb.go b/tavern/internal/c2/c2pb/c2.pb.go index 21b96cf30..399b61185 100644 --- a/tavern/internal/c2/c2pb/c2.pb.go +++ b/tavern/internal/c2/c2pb/c2.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 -// protoc v6.32.0 +// protoc-gen-go v1.36.5 +// protoc v3.21.12 // source: c2.proto package c2pb @@ -72,24 +72,24 @@ func (ReverseShellMessageKind) EnumDescriptor() ([]byte, []int) { return file_c2_proto_rawDescGZIP(), []int{0} } -type Beacon_Transport int32 +type ActiveTransport_Type int32 const ( - Beacon_TRANSPORT_UNSPECIFIED Beacon_Transport = 0 - Beacon_TRANSPORT_GRPC Beacon_Transport = 1 - Beacon_TRANSPORT_HTTP1 Beacon_Transport = 2 - Beacon_TRANSPORT_DNS Beacon_Transport = 3 + ActiveTransport_TRANSPORT_UNSPECIFIED ActiveTransport_Type = 0 + ActiveTransport_TRANSPORT_GRPC ActiveTransport_Type = 1 + ActiveTransport_TRANSPORT_HTTP1 ActiveTransport_Type = 2 + ActiveTransport_TRANSPORT_DNS ActiveTransport_Type = 3 ) -// Enum value maps for Beacon_Transport. +// Enum value maps for ActiveTransport_Type. var ( - Beacon_Transport_name = map[int32]string{ + ActiveTransport_Type_name = map[int32]string{ 0: "TRANSPORT_UNSPECIFIED", 1: "TRANSPORT_GRPC", 2: "TRANSPORT_HTTP1", 3: "TRANSPORT_DNS", } - Beacon_Transport_value = map[string]int32{ + ActiveTransport_Type_value = map[string]int32{ "TRANSPORT_UNSPECIFIED": 0, "TRANSPORT_GRPC": 1, "TRANSPORT_HTTP1": 2, @@ -97,30 +97,30 @@ var ( } ) -func (x Beacon_Transport) Enum() *Beacon_Transport { - p := new(Beacon_Transport) +func (x ActiveTransport_Type) Enum() *ActiveTransport_Type { + p := new(ActiveTransport_Type) *p = x return p } -func (x Beacon_Transport) String() string { +func (x ActiveTransport_Type) String() string { return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) } -func (Beacon_Transport) Descriptor() protoreflect.EnumDescriptor { +func (ActiveTransport_Type) Descriptor() protoreflect.EnumDescriptor { return file_c2_proto_enumTypes[1].Descriptor() } -func (Beacon_Transport) Type() protoreflect.EnumType { +func (ActiveTransport_Type) Type() protoreflect.EnumType { return &file_c2_proto_enumTypes[1] } -func (x Beacon_Transport) Number() protoreflect.EnumNumber { +func (x ActiveTransport_Type) Number() protoreflect.EnumNumber { return protoreflect.EnumNumber(x) } -// Deprecated: Use Beacon_Transport.Descriptor instead. -func (Beacon_Transport) EnumDescriptor() ([]byte, []int) { +// Deprecated: Use ActiveTransport_Type.Descriptor instead. +func (ActiveTransport_Type) EnumDescriptor() ([]byte, []int) { return file_c2_proto_rawDescGZIP(), []int{1, 0} } @@ -176,7 +176,7 @@ func (x Host_Platform) Number() protoreflect.EnumNumber { // Deprecated: Use Host_Platform.Descriptor instead. func (Host_Platform) EnumDescriptor() ([]byte, []int) { - return file_c2_proto_rawDescGZIP(), []int{2, 0} + return file_c2_proto_rawDescGZIP(), []int{3, 0} } // Agent information to identify the type of beacon. @@ -224,22 +224,81 @@ func (x *Agent) GetIdentifier() string { return "" } -// Beacon information that is unique to the current running beacon. -type Beacon struct { +type ActiveTransport struct { state protoimpl.MessageState `protogen:"open.v1"` - Identifier string `protobuf:"bytes,1,opt,name=identifier,proto3" json:"identifier,omitempty"` - Principal string `protobuf:"bytes,2,opt,name=principal,proto3" json:"principal,omitempty"` - Host *Host `protobuf:"bytes,3,opt,name=host,proto3" json:"host,omitempty"` - Agent *Agent `protobuf:"bytes,4,opt,name=agent,proto3" json:"agent,omitempty"` - Interval uint64 `protobuf:"varint,5,opt,name=interval,proto3" json:"interval,omitempty"` // Duration until next callback, in seconds. - Transport Beacon_Transport `protobuf:"varint,6,opt,name=transport,proto3,enum=c2.Beacon_Transport" json:"transport,omitempty"` + Uri string `protobuf:"bytes,1,opt,name=uri,proto3" json:"uri,omitempty"` + Interval uint64 `protobuf:"varint,2,opt,name=interval,proto3" json:"interval,omitempty"` + Type ActiveTransport_Type `protobuf:"varint,3,opt,name=type,proto3,enum=c2.ActiveTransport_Type" json:"type,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } +func (x *ActiveTransport) Reset() { + *x = ActiveTransport{} + mi := &file_c2_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ActiveTransport) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ActiveTransport) ProtoMessage() {} + +func (x *ActiveTransport) ProtoReflect() protoreflect.Message { + mi := &file_c2_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 ActiveTransport.ProtoReflect.Descriptor instead. +func (*ActiveTransport) Descriptor() ([]byte, []int) { + return file_c2_proto_rawDescGZIP(), []int{1} +} + +func (x *ActiveTransport) GetUri() string { + if x != nil { + return x.Uri + } + return "" +} + +func (x *ActiveTransport) GetInterval() uint64 { + if x != nil { + return x.Interval + } + return 0 +} + +func (x *ActiveTransport) GetType() ActiveTransport_Type { + if x != nil { + return x.Type + } + return ActiveTransport_TRANSPORT_UNSPECIFIED +} + +// Beacon information that is unique to the current running beacon. +type Beacon struct { + state protoimpl.MessageState `protogen:"open.v1"` + Identifier string `protobuf:"bytes,1,opt,name=identifier,proto3" json:"identifier,omitempty"` + Principal string `protobuf:"bytes,2,opt,name=principal,proto3" json:"principal,omitempty"` + Host *Host `protobuf:"bytes,3,opt,name=host,proto3" json:"host,omitempty"` + Agent *Agent `protobuf:"bytes,4,opt,name=agent,proto3" json:"agent,omitempty"` + ActiveTransport *ActiveTransport `protobuf:"bytes,5,opt,name=active_transport,json=activeTransport,proto3" json:"active_transport,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + func (x *Beacon) Reset() { *x = Beacon{} - mi := &file_c2_proto_msgTypes[1] + mi := &file_c2_proto_msgTypes[2] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -251,7 +310,7 @@ func (x *Beacon) String() string { func (*Beacon) ProtoMessage() {} func (x *Beacon) ProtoReflect() protoreflect.Message { - mi := &file_c2_proto_msgTypes[1] + mi := &file_c2_proto_msgTypes[2] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -264,7 +323,7 @@ func (x *Beacon) ProtoReflect() protoreflect.Message { // Deprecated: Use Beacon.ProtoReflect.Descriptor instead. func (*Beacon) Descriptor() ([]byte, []int) { - return file_c2_proto_rawDescGZIP(), []int{1} + return file_c2_proto_rawDescGZIP(), []int{2} } func (x *Beacon) GetIdentifier() string { @@ -295,18 +354,11 @@ func (x *Beacon) GetAgent() *Agent { return nil } -func (x *Beacon) GetInterval() uint64 { +func (x *Beacon) GetActiveTransport() *ActiveTransport { if x != nil { - return x.Interval + return x.ActiveTransport } - return 0 -} - -func (x *Beacon) GetTransport() Beacon_Transport { - if x != nil { - return x.Transport - } - return Beacon_TRANSPORT_UNSPECIFIED + return nil } // Host information for the system a beacon is running on. @@ -322,7 +374,7 @@ type Host struct { func (x *Host) Reset() { *x = Host{} - mi := &file_c2_proto_msgTypes[2] + mi := &file_c2_proto_msgTypes[3] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -334,7 +386,7 @@ func (x *Host) String() string { func (*Host) ProtoMessage() {} func (x *Host) ProtoReflect() protoreflect.Message { - mi := &file_c2_proto_msgTypes[2] + mi := &file_c2_proto_msgTypes[3] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -347,7 +399,7 @@ func (x *Host) ProtoReflect() protoreflect.Message { // Deprecated: Use Host.ProtoReflect.Descriptor instead. func (*Host) Descriptor() ([]byte, []int) { - return file_c2_proto_rawDescGZIP(), []int{2} + return file_c2_proto_rawDescGZIP(), []int{3} } func (x *Host) GetIdentifier() string { @@ -390,7 +442,7 @@ type Task struct { func (x *Task) Reset() { *x = Task{} - mi := &file_c2_proto_msgTypes[3] + mi := &file_c2_proto_msgTypes[4] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -402,7 +454,7 @@ func (x *Task) String() string { func (*Task) ProtoMessage() {} func (x *Task) ProtoReflect() protoreflect.Message { - mi := &file_c2_proto_msgTypes[3] + mi := &file_c2_proto_msgTypes[4] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -415,7 +467,7 @@ func (x *Task) ProtoReflect() protoreflect.Message { // Deprecated: Use Task.ProtoReflect.Descriptor instead. func (*Task) Descriptor() ([]byte, []int) { - return file_c2_proto_rawDescGZIP(), []int{3} + return file_c2_proto_rawDescGZIP(), []int{4} } func (x *Task) GetId() int64 { @@ -449,7 +501,7 @@ type TaskError struct { func (x *TaskError) Reset() { *x = TaskError{} - mi := &file_c2_proto_msgTypes[4] + mi := &file_c2_proto_msgTypes[5] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -461,7 +513,7 @@ func (x *TaskError) String() string { func (*TaskError) ProtoMessage() {} func (x *TaskError) ProtoReflect() protoreflect.Message { - mi := &file_c2_proto_msgTypes[4] + mi := &file_c2_proto_msgTypes[5] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -474,7 +526,7 @@ func (x *TaskError) ProtoReflect() protoreflect.Message { // Deprecated: Use TaskError.ProtoReflect.Descriptor instead. func (*TaskError) Descriptor() ([]byte, []int) { - return file_c2_proto_rawDescGZIP(), []int{4} + return file_c2_proto_rawDescGZIP(), []int{5} } func (x *TaskError) GetMsg() string { @@ -500,7 +552,7 @@ type TaskOutput struct { func (x *TaskOutput) Reset() { *x = TaskOutput{} - mi := &file_c2_proto_msgTypes[5] + mi := &file_c2_proto_msgTypes[6] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -512,7 +564,7 @@ func (x *TaskOutput) String() string { func (*TaskOutput) ProtoMessage() {} func (x *TaskOutput) ProtoReflect() protoreflect.Message { - mi := &file_c2_proto_msgTypes[5] + mi := &file_c2_proto_msgTypes[6] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -525,7 +577,7 @@ func (x *TaskOutput) ProtoReflect() protoreflect.Message { // Deprecated: Use TaskOutput.ProtoReflect.Descriptor instead. func (*TaskOutput) Descriptor() ([]byte, []int) { - return file_c2_proto_rawDescGZIP(), []int{5} + return file_c2_proto_rawDescGZIP(), []int{6} } func (x *TaskOutput) GetId() int64 { @@ -573,7 +625,7 @@ type ClaimTasksRequest struct { func (x *ClaimTasksRequest) Reset() { *x = ClaimTasksRequest{} - mi := &file_c2_proto_msgTypes[6] + mi := &file_c2_proto_msgTypes[7] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -585,7 +637,7 @@ func (x *ClaimTasksRequest) String() string { func (*ClaimTasksRequest) ProtoMessage() {} func (x *ClaimTasksRequest) ProtoReflect() protoreflect.Message { - mi := &file_c2_proto_msgTypes[6] + mi := &file_c2_proto_msgTypes[7] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -598,7 +650,7 @@ func (x *ClaimTasksRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ClaimTasksRequest.ProtoReflect.Descriptor instead. func (*ClaimTasksRequest) Descriptor() ([]byte, []int) { - return file_c2_proto_rawDescGZIP(), []int{6} + return file_c2_proto_rawDescGZIP(), []int{7} } func (x *ClaimTasksRequest) GetBeacon() *Beacon { @@ -617,7 +669,7 @@ type ClaimTasksResponse struct { func (x *ClaimTasksResponse) Reset() { *x = ClaimTasksResponse{} - mi := &file_c2_proto_msgTypes[7] + mi := &file_c2_proto_msgTypes[8] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -629,7 +681,7 @@ func (x *ClaimTasksResponse) String() string { func (*ClaimTasksResponse) ProtoMessage() {} func (x *ClaimTasksResponse) ProtoReflect() protoreflect.Message { - mi := &file_c2_proto_msgTypes[7] + mi := &file_c2_proto_msgTypes[8] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -642,7 +694,7 @@ func (x *ClaimTasksResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ClaimTasksResponse.ProtoReflect.Descriptor instead. func (*ClaimTasksResponse) Descriptor() ([]byte, []int) { - return file_c2_proto_rawDescGZIP(), []int{7} + return file_c2_proto_rawDescGZIP(), []int{8} } func (x *ClaimTasksResponse) GetTasks() []*Task { @@ -661,7 +713,7 @@ type FetchAssetRequest struct { func (x *FetchAssetRequest) Reset() { *x = FetchAssetRequest{} - mi := &file_c2_proto_msgTypes[8] + mi := &file_c2_proto_msgTypes[9] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -673,7 +725,7 @@ func (x *FetchAssetRequest) String() string { func (*FetchAssetRequest) ProtoMessage() {} func (x *FetchAssetRequest) ProtoReflect() protoreflect.Message { - mi := &file_c2_proto_msgTypes[8] + mi := &file_c2_proto_msgTypes[9] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -686,7 +738,7 @@ func (x *FetchAssetRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use FetchAssetRequest.ProtoReflect.Descriptor instead. func (*FetchAssetRequest) Descriptor() ([]byte, []int) { - return file_c2_proto_rawDescGZIP(), []int{8} + return file_c2_proto_rawDescGZIP(), []int{9} } func (x *FetchAssetRequest) GetName() string { @@ -705,7 +757,7 @@ type FetchAssetResponse struct { func (x *FetchAssetResponse) Reset() { *x = FetchAssetResponse{} - mi := &file_c2_proto_msgTypes[9] + mi := &file_c2_proto_msgTypes[10] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -717,7 +769,7 @@ func (x *FetchAssetResponse) String() string { func (*FetchAssetResponse) ProtoMessage() {} func (x *FetchAssetResponse) ProtoReflect() protoreflect.Message { - mi := &file_c2_proto_msgTypes[9] + mi := &file_c2_proto_msgTypes[10] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -730,7 +782,7 @@ func (x *FetchAssetResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use FetchAssetResponse.ProtoReflect.Descriptor instead. func (*FetchAssetResponse) Descriptor() ([]byte, []int) { - return file_c2_proto_rawDescGZIP(), []int{9} + return file_c2_proto_rawDescGZIP(), []int{10} } func (x *FetchAssetResponse) GetChunk() []byte { @@ -750,7 +802,7 @@ type ReportCredentialRequest struct { func (x *ReportCredentialRequest) Reset() { *x = ReportCredentialRequest{} - mi := &file_c2_proto_msgTypes[10] + mi := &file_c2_proto_msgTypes[11] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -762,7 +814,7 @@ func (x *ReportCredentialRequest) String() string { func (*ReportCredentialRequest) ProtoMessage() {} func (x *ReportCredentialRequest) ProtoReflect() protoreflect.Message { - mi := &file_c2_proto_msgTypes[10] + mi := &file_c2_proto_msgTypes[11] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -775,7 +827,7 @@ func (x *ReportCredentialRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ReportCredentialRequest.ProtoReflect.Descriptor instead. func (*ReportCredentialRequest) Descriptor() ([]byte, []int) { - return file_c2_proto_rawDescGZIP(), []int{10} + return file_c2_proto_rawDescGZIP(), []int{11} } func (x *ReportCredentialRequest) GetTaskId() int64 { @@ -800,7 +852,7 @@ type ReportCredentialResponse struct { func (x *ReportCredentialResponse) Reset() { *x = ReportCredentialResponse{} - mi := &file_c2_proto_msgTypes[11] + mi := &file_c2_proto_msgTypes[12] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -812,7 +864,7 @@ func (x *ReportCredentialResponse) String() string { func (*ReportCredentialResponse) ProtoMessage() {} func (x *ReportCredentialResponse) ProtoReflect() protoreflect.Message { - mi := &file_c2_proto_msgTypes[11] + mi := &file_c2_proto_msgTypes[12] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -825,7 +877,7 @@ func (x *ReportCredentialResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ReportCredentialResponse.ProtoReflect.Descriptor instead. func (*ReportCredentialResponse) Descriptor() ([]byte, []int) { - return file_c2_proto_rawDescGZIP(), []int{11} + return file_c2_proto_rawDescGZIP(), []int{12} } type ReportFileRequest struct { @@ -838,7 +890,7 @@ type ReportFileRequest struct { func (x *ReportFileRequest) Reset() { *x = ReportFileRequest{} - mi := &file_c2_proto_msgTypes[12] + mi := &file_c2_proto_msgTypes[13] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -850,7 +902,7 @@ func (x *ReportFileRequest) String() string { func (*ReportFileRequest) ProtoMessage() {} func (x *ReportFileRequest) ProtoReflect() protoreflect.Message { - mi := &file_c2_proto_msgTypes[12] + mi := &file_c2_proto_msgTypes[13] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -863,7 +915,7 @@ func (x *ReportFileRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ReportFileRequest.ProtoReflect.Descriptor instead. func (*ReportFileRequest) Descriptor() ([]byte, []int) { - return file_c2_proto_rawDescGZIP(), []int{12} + return file_c2_proto_rawDescGZIP(), []int{13} } func (x *ReportFileRequest) GetTaskId() int64 { @@ -888,7 +940,7 @@ type ReportFileResponse struct { func (x *ReportFileResponse) Reset() { *x = ReportFileResponse{} - mi := &file_c2_proto_msgTypes[13] + mi := &file_c2_proto_msgTypes[14] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -900,7 +952,7 @@ func (x *ReportFileResponse) String() string { func (*ReportFileResponse) ProtoMessage() {} func (x *ReportFileResponse) ProtoReflect() protoreflect.Message { - mi := &file_c2_proto_msgTypes[13] + mi := &file_c2_proto_msgTypes[14] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -913,7 +965,7 @@ func (x *ReportFileResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ReportFileResponse.ProtoReflect.Descriptor instead. func (*ReportFileResponse) Descriptor() ([]byte, []int) { - return file_c2_proto_rawDescGZIP(), []int{13} + return file_c2_proto_rawDescGZIP(), []int{14} } type ReportProcessListRequest struct { @@ -926,7 +978,7 @@ type ReportProcessListRequest struct { func (x *ReportProcessListRequest) Reset() { *x = ReportProcessListRequest{} - mi := &file_c2_proto_msgTypes[14] + mi := &file_c2_proto_msgTypes[15] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -938,7 +990,7 @@ func (x *ReportProcessListRequest) String() string { func (*ReportProcessListRequest) ProtoMessage() {} func (x *ReportProcessListRequest) ProtoReflect() protoreflect.Message { - mi := &file_c2_proto_msgTypes[14] + mi := &file_c2_proto_msgTypes[15] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -951,7 +1003,7 @@ func (x *ReportProcessListRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ReportProcessListRequest.ProtoReflect.Descriptor instead. func (*ReportProcessListRequest) Descriptor() ([]byte, []int) { - return file_c2_proto_rawDescGZIP(), []int{14} + return file_c2_proto_rawDescGZIP(), []int{15} } func (x *ReportProcessListRequest) GetTaskId() int64 { @@ -976,7 +1028,7 @@ type ReportProcessListResponse struct { func (x *ReportProcessListResponse) Reset() { *x = ReportProcessListResponse{} - mi := &file_c2_proto_msgTypes[15] + mi := &file_c2_proto_msgTypes[16] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -988,7 +1040,7 @@ func (x *ReportProcessListResponse) String() string { func (*ReportProcessListResponse) ProtoMessage() {} func (x *ReportProcessListResponse) ProtoReflect() protoreflect.Message { - mi := &file_c2_proto_msgTypes[15] + mi := &file_c2_proto_msgTypes[16] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1001,7 +1053,7 @@ func (x *ReportProcessListResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ReportProcessListResponse.ProtoReflect.Descriptor instead. func (*ReportProcessListResponse) Descriptor() ([]byte, []int) { - return file_c2_proto_rawDescGZIP(), []int{15} + return file_c2_proto_rawDescGZIP(), []int{16} } type ReportTaskOutputRequest struct { @@ -1013,7 +1065,7 @@ type ReportTaskOutputRequest struct { func (x *ReportTaskOutputRequest) Reset() { *x = ReportTaskOutputRequest{} - mi := &file_c2_proto_msgTypes[16] + mi := &file_c2_proto_msgTypes[17] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1025,7 +1077,7 @@ func (x *ReportTaskOutputRequest) String() string { func (*ReportTaskOutputRequest) ProtoMessage() {} func (x *ReportTaskOutputRequest) ProtoReflect() protoreflect.Message { - mi := &file_c2_proto_msgTypes[16] + mi := &file_c2_proto_msgTypes[17] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1038,7 +1090,7 @@ func (x *ReportTaskOutputRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ReportTaskOutputRequest.ProtoReflect.Descriptor instead. func (*ReportTaskOutputRequest) Descriptor() ([]byte, []int) { - return file_c2_proto_rawDescGZIP(), []int{16} + return file_c2_proto_rawDescGZIP(), []int{17} } func (x *ReportTaskOutputRequest) GetOutput() *TaskOutput { @@ -1056,7 +1108,7 @@ type ReportTaskOutputResponse struct { func (x *ReportTaskOutputResponse) Reset() { *x = ReportTaskOutputResponse{} - mi := &file_c2_proto_msgTypes[17] + mi := &file_c2_proto_msgTypes[18] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1068,7 +1120,7 @@ func (x *ReportTaskOutputResponse) String() string { func (*ReportTaskOutputResponse) ProtoMessage() {} func (x *ReportTaskOutputResponse) ProtoReflect() protoreflect.Message { - mi := &file_c2_proto_msgTypes[17] + mi := &file_c2_proto_msgTypes[18] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1081,7 +1133,7 @@ func (x *ReportTaskOutputResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ReportTaskOutputResponse.ProtoReflect.Descriptor instead. func (*ReportTaskOutputResponse) Descriptor() ([]byte, []int) { - return file_c2_proto_rawDescGZIP(), []int{17} + return file_c2_proto_rawDescGZIP(), []int{18} } type ReverseShellRequest struct { @@ -1095,7 +1147,7 @@ type ReverseShellRequest struct { func (x *ReverseShellRequest) Reset() { *x = ReverseShellRequest{} - mi := &file_c2_proto_msgTypes[18] + mi := &file_c2_proto_msgTypes[19] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1107,7 +1159,7 @@ func (x *ReverseShellRequest) String() string { func (*ReverseShellRequest) ProtoMessage() {} func (x *ReverseShellRequest) ProtoReflect() protoreflect.Message { - mi := &file_c2_proto_msgTypes[18] + mi := &file_c2_proto_msgTypes[19] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1120,7 +1172,7 @@ func (x *ReverseShellRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ReverseShellRequest.ProtoReflect.Descriptor instead. func (*ReverseShellRequest) Descriptor() ([]byte, []int) { - return file_c2_proto_rawDescGZIP(), []int{18} + return file_c2_proto_rawDescGZIP(), []int{19} } func (x *ReverseShellRequest) GetKind() ReverseShellMessageKind { @@ -1154,7 +1206,7 @@ type ReverseShellResponse struct { func (x *ReverseShellResponse) Reset() { *x = ReverseShellResponse{} - mi := &file_c2_proto_msgTypes[19] + mi := &file_c2_proto_msgTypes[20] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1166,7 +1218,7 @@ func (x *ReverseShellResponse) String() string { func (*ReverseShellResponse) ProtoMessage() {} func (x *ReverseShellResponse) ProtoReflect() protoreflect.Message { - mi := &file_c2_proto_msgTypes[19] + mi := &file_c2_proto_msgTypes[20] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1179,7 +1231,7 @@ func (x *ReverseShellResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ReverseShellResponse.ProtoReflect.Descriptor instead. func (*ReverseShellResponse) Descriptor() ([]byte, []int) { - return file_c2_proto_rawDescGZIP(), []int{19} + return file_c2_proto_rawDescGZIP(), []int{20} } func (x *ReverseShellResponse) GetKind() ReverseShellMessageKind { @@ -1198,103 +1250,176 @@ func (x *ReverseShellResponse) GetData() []byte { var File_c2_proto protoreflect.FileDescriptor -const file_c2_proto_rawDesc = "" + - "\n" + - "\bc2.proto\x12\x02c2\x1a\x1fgoogle/protobuf/timestamp.proto\x1a\x0eeldritch.proto\"'\n" + - "\x05Agent\x12\x1e\n" + - "\n" + - "identifier\x18\x01 \x01(\tR\n" + - "identifier\"\xb9\x02\n" + - "\x06Beacon\x12\x1e\n" + - "\n" + - "identifier\x18\x01 \x01(\tR\n" + - "identifier\x12\x1c\n" + - "\tprincipal\x18\x02 \x01(\tR\tprincipal\x12\x1c\n" + - "\x04host\x18\x03 \x01(\v2\b.c2.HostR\x04host\x12\x1f\n" + - "\x05agent\x18\x04 \x01(\v2\t.c2.AgentR\x05agent\x12\x1a\n" + - "\binterval\x18\x05 \x01(\x04R\binterval\x122\n" + - "\ttransport\x18\x06 \x01(\x0e2\x14.c2.Beacon.TransportR\ttransport\"b\n" + - "\tTransport\x12\x19\n" + - "\x15TRANSPORT_UNSPECIFIED\x10\x00\x12\x12\n" + - "\x0eTRANSPORT_GRPC\x10\x01\x12\x13\n" + - "\x0fTRANSPORT_HTTP1\x10\x02\x12\x11\n" + - "\rTRANSPORT_DNS\x10\x03\"\xfe\x01\n" + - "\x04Host\x12\x1e\n" + - "\n" + - "identifier\x18\x01 \x01(\tR\n" + - "identifier\x12\x12\n" + - "\x04name\x18\x02 \x01(\tR\x04name\x12-\n" + - "\bplatform\x18\x03 \x01(\x0e2\x11.c2.Host.PlatformR\bplatform\x12\x1d\n" + - "\n" + - "primary_ip\x18\x04 \x01(\tR\tprimaryIp\"t\n" + - "\bPlatform\x12\x18\n" + - "\x14PLATFORM_UNSPECIFIED\x10\x00\x12\x14\n" + - "\x10PLATFORM_WINDOWS\x10\x01\x12\x12\n" + - "\x0ePLATFORM_LINUX\x10\x02\x12\x12\n" + - "\x0ePLATFORM_MACOS\x10\x03\x12\x10\n" + - "\fPLATFORM_BSD\x10\x04\"Y\n" + - "\x04Task\x12\x0e\n" + - "\x02id\x18\x01 \x01(\x03R\x02id\x12\"\n" + - "\x04tome\x18\x02 \x01(\v2\x0e.eldritch.TomeR\x04tome\x12\x1d\n" + - "\n" + - "quest_name\x18\x03 \x01(\tR\tquestName\"\x1d\n" + - "\tTaskError\x12\x10\n" + - "\x03msg\x18\x01 \x01(\tR\x03msg\"\xe3\x01\n" + - "\n" + - "TaskOutput\x12\x0e\n" + - "\x02id\x18\x01 \x01(\x03R\x02id\x12\x16\n" + - "\x06output\x18\x02 \x01(\tR\x06output\x12#\n" + - "\x05error\x18\x03 \x01(\v2\r.c2.TaskErrorR\x05error\x12B\n" + - "\x0fexec_started_at\x18\x04 \x01(\v2\x1a.google.protobuf.TimestampR\rexecStartedAt\x12D\n" + - "\x10exec_finished_at\x18\x05 \x01(\v2\x1a.google.protobuf.TimestampR\x0eexecFinishedAt\"7\n" + - "\x11ClaimTasksRequest\x12\"\n" + - "\x06beacon\x18\x01 \x01(\v2\n" + - ".c2.BeaconR\x06beacon\"4\n" + - "\x12ClaimTasksResponse\x12\x1e\n" + - "\x05tasks\x18\x01 \x03(\v2\b.c2.TaskR\x05tasks\"'\n" + - "\x11FetchAssetRequest\x12\x12\n" + - "\x04name\x18\x01 \x01(\tR\x04name\"*\n" + - "\x12FetchAssetResponse\x12\x14\n" + - "\x05chunk\x18\x01 \x01(\fR\x05chunk\"h\n" + - "\x17ReportCredentialRequest\x12\x17\n" + - "\atask_id\x18\x01 \x01(\x03R\x06taskId\x124\n" + - "\n" + - "credential\x18\x02 \x01(\v2\x14.eldritch.CredentialR\n" + - "credential\"\x1a\n" + - "\x18ReportCredentialResponse\"R\n" + - "\x11ReportFileRequest\x12\x17\n" + - "\atask_id\x18\x01 \x01(\x03R\x06taskId\x12$\n" + - "\x05chunk\x18\x02 \x01(\v2\x0e.eldritch.FileR\x05chunk\"\x14\n" + - "\x12ReportFileResponse\"^\n" + - "\x18ReportProcessListRequest\x12\x17\n" + - "\atask_id\x18\x01 \x01(\x03R\x06taskId\x12)\n" + - "\x04list\x18\x02 \x01(\v2\x15.eldritch.ProcessListR\x04list\"\x1b\n" + - "\x19ReportProcessListResponse\"A\n" + - "\x17ReportTaskOutputRequest\x12&\n" + - "\x06output\x18\x01 \x01(\v2\x0e.c2.TaskOutputR\x06output\"\x1a\n" + - "\x18ReportTaskOutputResponse\"s\n" + - "\x13ReverseShellRequest\x12/\n" + - "\x04kind\x18\x01 \x01(\x0e2\x1b.c2.ReverseShellMessageKindR\x04kind\x12\x12\n" + - "\x04data\x18\x02 \x01(\fR\x04data\x12\x17\n" + - "\atask_id\x18\x03 \x01(\x03R\x06taskId\"[\n" + - "\x14ReverseShellResponse\x12/\n" + - "\x04kind\x18\x01 \x01(\x0e2\x1b.c2.ReverseShellMessageKindR\x04kind\x12\x12\n" + - "\x04data\x18\x02 \x01(\fR\x04data*\x8f\x01\n" + - "\x17ReverseShellMessageKind\x12*\n" + - "&REVERSE_SHELL_MESSAGE_KIND_UNSPECIFIED\x10\x00\x12#\n" + - "\x1fREVERSE_SHELL_MESSAGE_KIND_DATA\x10\x01\x12#\n" + - "\x1fREVERSE_SHELL_MESSAGE_KIND_PING\x10\x022\xfc\x03\n" + - "\x02C2\x12=\n" + - "\n" + - "ClaimTasks\x12\x15.c2.ClaimTasksRequest\x1a\x16.c2.ClaimTasksResponse\"\x00\x12=\n" + - "\n" + - "FetchAsset\x12\x15.c2.FetchAssetRequest\x1a\x16.c2.FetchAssetResponse0\x01\x12M\n" + - "\x10ReportCredential\x12\x1b.c2.ReportCredentialRequest\x1a\x1c.c2.ReportCredentialResponse\x12=\n" + - "\n" + - "ReportFile\x12\x15.c2.ReportFileRequest\x1a\x16.c2.ReportFileResponse(\x01\x12P\n" + - "\x11ReportProcessList\x12\x1c.c2.ReportProcessListRequest\x1a\x1d.c2.ReportProcessListResponse\x12O\n" + - "\x10ReportTaskOutput\x12\x1b.c2.ReportTaskOutputRequest\x1a\x1c.c2.ReportTaskOutputResponse\"\x00\x12G\n" + - "\fReverseShell\x12\x17.c2.ReverseShellRequest\x1a\x18.c2.ReverseShellResponse\"\x00(\x010\x01B#Z!realm.pub/tavern/internal/c2/c2pbb\x06proto3" +var file_c2_proto_rawDesc = string([]byte{ + 0x0a, 0x08, 0x63, 0x32, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x02, 0x63, 0x32, 0x1a, 0x1f, + 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, + 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, + 0x0e, 0x65, 0x6c, 0x64, 0x72, 0x69, 0x74, 0x63, 0x68, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, + 0x27, 0x0a, 0x05, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x12, 0x1e, 0x0a, 0x0a, 0x69, 0x64, 0x65, 0x6e, + 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x69, 0x64, + 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x22, 0xcc, 0x01, 0x0a, 0x0f, 0x41, 0x63, 0x74, + 0x69, 0x76, 0x65, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x10, 0x0a, 0x03, + 0x75, 0x72, 0x69, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x69, 0x12, 0x1a, + 0x0a, 0x08, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, + 0x52, 0x08, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x12, 0x2c, 0x0a, 0x04, 0x74, 0x79, + 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x18, 0x2e, 0x63, 0x32, 0x2e, 0x41, 0x63, + 0x74, 0x69, 0x76, 0x65, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x54, 0x79, + 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x22, 0x5d, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, + 0x12, 0x19, 0x0a, 0x15, 0x54, 0x52, 0x41, 0x4e, 0x53, 0x50, 0x4f, 0x52, 0x54, 0x5f, 0x55, 0x4e, + 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x12, 0x0a, 0x0e, 0x54, + 0x52, 0x41, 0x4e, 0x53, 0x50, 0x4f, 0x52, 0x54, 0x5f, 0x47, 0x52, 0x50, 0x43, 0x10, 0x01, 0x12, + 0x13, 0x0a, 0x0f, 0x54, 0x52, 0x41, 0x4e, 0x53, 0x50, 0x4f, 0x52, 0x54, 0x5f, 0x48, 0x54, 0x54, + 0x50, 0x31, 0x10, 0x02, 0x12, 0x11, 0x0a, 0x0d, 0x54, 0x52, 0x41, 0x4e, 0x53, 0x50, 0x4f, 0x52, + 0x54, 0x5f, 0x44, 0x4e, 0x53, 0x10, 0x03, 0x22, 0xc5, 0x01, 0x0a, 0x06, 0x42, 0x65, 0x61, 0x63, + 0x6f, 0x6e, 0x12, 0x1e, 0x0a, 0x0a, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, + 0x65, 0x72, 0x12, 0x1c, 0x0a, 0x09, 0x70, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x70, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, + 0x12, 0x1c, 0x0a, 0x04, 0x68, 0x6f, 0x73, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x08, + 0x2e, 0x63, 0x32, 0x2e, 0x48, 0x6f, 0x73, 0x74, 0x52, 0x04, 0x68, 0x6f, 0x73, 0x74, 0x12, 0x1f, + 0x0a, 0x05, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x09, 0x2e, + 0x63, 0x32, 0x2e, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x52, 0x05, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x12, + 0x3e, 0x0a, 0x10, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, + 0x6f, 0x72, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x63, 0x32, 0x2e, 0x41, + 0x63, 0x74, 0x69, 0x76, 0x65, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x0f, + 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x22, + 0xfe, 0x01, 0x0a, 0x04, 0x48, 0x6f, 0x73, 0x74, 0x12, 0x1e, 0x0a, 0x0a, 0x69, 0x64, 0x65, 0x6e, + 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x69, 0x64, + 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x2d, 0x0a, 0x08, + 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x11, + 0x2e, 0x63, 0x32, 0x2e, 0x48, 0x6f, 0x73, 0x74, 0x2e, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, + 0x6d, 0x52, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x12, 0x1d, 0x0a, 0x0a, 0x70, + 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x5f, 0x69, 0x70, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x09, 0x70, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x49, 0x70, 0x22, 0x74, 0x0a, 0x08, 0x50, 0x6c, + 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x12, 0x18, 0x0a, 0x14, 0x50, 0x4c, 0x41, 0x54, 0x46, 0x4f, + 0x52, 0x4d, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, + 0x12, 0x14, 0x0a, 0x10, 0x50, 0x4c, 0x41, 0x54, 0x46, 0x4f, 0x52, 0x4d, 0x5f, 0x57, 0x49, 0x4e, + 0x44, 0x4f, 0x57, 0x53, 0x10, 0x01, 0x12, 0x12, 0x0a, 0x0e, 0x50, 0x4c, 0x41, 0x54, 0x46, 0x4f, + 0x52, 0x4d, 0x5f, 0x4c, 0x49, 0x4e, 0x55, 0x58, 0x10, 0x02, 0x12, 0x12, 0x0a, 0x0e, 0x50, 0x4c, + 0x41, 0x54, 0x46, 0x4f, 0x52, 0x4d, 0x5f, 0x4d, 0x41, 0x43, 0x4f, 0x53, 0x10, 0x03, 0x12, 0x10, + 0x0a, 0x0c, 0x50, 0x4c, 0x41, 0x54, 0x46, 0x4f, 0x52, 0x4d, 0x5f, 0x42, 0x53, 0x44, 0x10, 0x04, + 0x22, 0x59, 0x0a, 0x04, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x03, 0x52, 0x02, 0x69, 0x64, 0x12, 0x22, 0x0a, 0x04, 0x74, 0x6f, 0x6d, 0x65, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x65, 0x6c, 0x64, 0x72, 0x69, 0x74, 0x63, + 0x68, 0x2e, 0x54, 0x6f, 0x6d, 0x65, 0x52, 0x04, 0x74, 0x6f, 0x6d, 0x65, 0x12, 0x1d, 0x0a, 0x0a, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x09, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0x1d, 0x0a, 0x09, 0x54, + 0x61, 0x73, 0x6b, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x10, 0x0a, 0x03, 0x6d, 0x73, 0x67, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6d, 0x73, 0x67, 0x22, 0xe3, 0x01, 0x0a, 0x0a, 0x54, + 0x61, 0x73, 0x6b, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x02, 0x69, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x6f, 0x75, 0x74, + 0x70, 0x75, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6f, 0x75, 0x74, 0x70, 0x75, + 0x74, 0x12, 0x23, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x0d, 0x2e, 0x63, 0x32, 0x2e, 0x54, 0x61, 0x73, 0x6b, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, + 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x42, 0x0a, 0x0f, 0x65, 0x78, 0x65, 0x63, 0x5f, 0x73, + 0x74, 0x61, 0x72, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, + 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0d, 0x65, 0x78, 0x65, + 0x63, 0x53, 0x74, 0x61, 0x72, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x44, 0x0a, 0x10, 0x65, 0x78, + 0x65, 0x63, 0x5f, 0x66, 0x69, 0x6e, 0x69, 0x73, 0x68, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x05, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, + 0x52, 0x0e, 0x65, 0x78, 0x65, 0x63, 0x46, 0x69, 0x6e, 0x69, 0x73, 0x68, 0x65, 0x64, 0x41, 0x74, + 0x22, 0x37, 0x0a, 0x11, 0x43, 0x6c, 0x61, 0x69, 0x6d, 0x54, 0x61, 0x73, 0x6b, 0x73, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x22, 0x0a, 0x06, 0x62, 0x65, 0x61, 0x63, 0x6f, 0x6e, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0a, 0x2e, 0x63, 0x32, 0x2e, 0x42, 0x65, 0x61, 0x63, 0x6f, + 0x6e, 0x52, 0x06, 0x62, 0x65, 0x61, 0x63, 0x6f, 0x6e, 0x22, 0x34, 0x0a, 0x12, 0x43, 0x6c, 0x61, + 0x69, 0x6d, 0x54, 0x61, 0x73, 0x6b, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x1e, 0x0a, 0x05, 0x74, 0x61, 0x73, 0x6b, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x08, + 0x2e, 0x63, 0x32, 0x2e, 0x54, 0x61, 0x73, 0x6b, 0x52, 0x05, 0x74, 0x61, 0x73, 0x6b, 0x73, 0x22, + 0x27, 0x0a, 0x11, 0x46, 0x65, 0x74, 0x63, 0x68, 0x41, 0x73, 0x73, 0x65, 0x74, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x2a, 0x0a, 0x12, 0x46, 0x65, 0x74, 0x63, + 0x68, 0x41, 0x73, 0x73, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x14, + 0x0a, 0x05, 0x63, 0x68, 0x75, 0x6e, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x63, + 0x68, 0x75, 0x6e, 0x6b, 0x22, 0x68, 0x0a, 0x17, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x43, 0x72, + 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, + 0x17, 0x0a, 0x07, 0x74, 0x61, 0x73, 0x6b, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, + 0x52, 0x06, 0x74, 0x61, 0x73, 0x6b, 0x49, 0x64, 0x12, 0x34, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x64, + 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x65, + 0x6c, 0x64, 0x72, 0x69, 0x74, 0x63, 0x68, 0x2e, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, + 0x61, 0x6c, 0x52, 0x0a, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x22, 0x1a, + 0x0a, 0x18, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, + 0x61, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x52, 0x0a, 0x11, 0x52, 0x65, + 0x70, 0x6f, 0x72, 0x74, 0x46, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, + 0x17, 0x0a, 0x07, 0x74, 0x61, 0x73, 0x6b, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, + 0x52, 0x06, 0x74, 0x61, 0x73, 0x6b, 0x49, 0x64, 0x12, 0x24, 0x0a, 0x05, 0x63, 0x68, 0x75, 0x6e, + 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x65, 0x6c, 0x64, 0x72, 0x69, 0x74, + 0x63, 0x68, 0x2e, 0x46, 0x69, 0x6c, 0x65, 0x52, 0x05, 0x63, 0x68, 0x75, 0x6e, 0x6b, 0x22, 0x14, + 0x0a, 0x12, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x46, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x5e, 0x0a, 0x18, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x50, 0x72, + 0x6f, 0x63, 0x65, 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x12, 0x17, 0x0a, 0x07, 0x74, 0x61, 0x73, 0x6b, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x03, 0x52, 0x06, 0x74, 0x61, 0x73, 0x6b, 0x49, 0x64, 0x12, 0x29, 0x0a, 0x04, 0x6c, 0x69, 0x73, + 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x65, 0x6c, 0x64, 0x72, 0x69, 0x74, + 0x63, 0x68, 0x2e, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x04, + 0x6c, 0x69, 0x73, 0x74, 0x22, 0x1b, 0x0a, 0x19, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x50, 0x72, + 0x6f, 0x63, 0x65, 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x22, 0x41, 0x0a, 0x17, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x54, 0x61, 0x73, 0x6b, 0x4f, + 0x75, 0x74, 0x70, 0x75, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x26, 0x0a, 0x06, + 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x63, + 0x32, 0x2e, 0x54, 0x61, 0x73, 0x6b, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x52, 0x06, 0x6f, 0x75, + 0x74, 0x70, 0x75, 0x74, 0x22, 0x1a, 0x0a, 0x18, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x54, 0x61, + 0x73, 0x6b, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x22, 0x73, 0x0a, 0x13, 0x52, 0x65, 0x76, 0x65, 0x72, 0x73, 0x65, 0x53, 0x68, 0x65, 0x6c, 0x6c, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2f, 0x0a, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1b, 0x2e, 0x63, 0x32, 0x2e, 0x52, 0x65, 0x76, 0x65, 0x72, + 0x73, 0x65, 0x53, 0x68, 0x65, 0x6c, 0x6c, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x4b, 0x69, + 0x6e, 0x64, 0x52, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x12, 0x17, 0x0a, 0x07, + 0x74, 0x61, 0x73, 0x6b, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x74, + 0x61, 0x73, 0x6b, 0x49, 0x64, 0x22, 0x5b, 0x0a, 0x14, 0x52, 0x65, 0x76, 0x65, 0x72, 0x73, 0x65, + 0x53, 0x68, 0x65, 0x6c, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2f, 0x0a, + 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1b, 0x2e, 0x63, 0x32, + 0x2e, 0x52, 0x65, 0x76, 0x65, 0x72, 0x73, 0x65, 0x53, 0x68, 0x65, 0x6c, 0x6c, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x4b, 0x69, 0x6e, 0x64, 0x52, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x12, 0x12, + 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x64, 0x61, + 0x74, 0x61, 0x2a, 0x8f, 0x01, 0x0a, 0x17, 0x52, 0x65, 0x76, 0x65, 0x72, 0x73, 0x65, 0x53, 0x68, + 0x65, 0x6c, 0x6c, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x4b, 0x69, 0x6e, 0x64, 0x12, 0x2a, + 0x0a, 0x26, 0x52, 0x45, 0x56, 0x45, 0x52, 0x53, 0x45, 0x5f, 0x53, 0x48, 0x45, 0x4c, 0x4c, 0x5f, + 0x4d, 0x45, 0x53, 0x53, 0x41, 0x47, 0x45, 0x5f, 0x4b, 0x49, 0x4e, 0x44, 0x5f, 0x55, 0x4e, 0x53, + 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x23, 0x0a, 0x1f, 0x52, 0x45, + 0x56, 0x45, 0x52, 0x53, 0x45, 0x5f, 0x53, 0x48, 0x45, 0x4c, 0x4c, 0x5f, 0x4d, 0x45, 0x53, 0x53, + 0x41, 0x47, 0x45, 0x5f, 0x4b, 0x49, 0x4e, 0x44, 0x5f, 0x44, 0x41, 0x54, 0x41, 0x10, 0x01, 0x12, + 0x23, 0x0a, 0x1f, 0x52, 0x45, 0x56, 0x45, 0x52, 0x53, 0x45, 0x5f, 0x53, 0x48, 0x45, 0x4c, 0x4c, + 0x5f, 0x4d, 0x45, 0x53, 0x53, 0x41, 0x47, 0x45, 0x5f, 0x4b, 0x49, 0x4e, 0x44, 0x5f, 0x50, 0x49, + 0x4e, 0x47, 0x10, 0x02, 0x32, 0xfc, 0x03, 0x0a, 0x02, 0x43, 0x32, 0x12, 0x3d, 0x0a, 0x0a, 0x43, + 0x6c, 0x61, 0x69, 0x6d, 0x54, 0x61, 0x73, 0x6b, 0x73, 0x12, 0x15, 0x2e, 0x63, 0x32, 0x2e, 0x43, + 0x6c, 0x61, 0x69, 0x6d, 0x54, 0x61, 0x73, 0x6b, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x16, 0x2e, 0x63, 0x32, 0x2e, 0x43, 0x6c, 0x61, 0x69, 0x6d, 0x54, 0x61, 0x73, 0x6b, 0x73, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x3d, 0x0a, 0x0a, 0x46, 0x65, + 0x74, 0x63, 0x68, 0x41, 0x73, 0x73, 0x65, 0x74, 0x12, 0x15, 0x2e, 0x63, 0x32, 0x2e, 0x46, 0x65, + 0x74, 0x63, 0x68, 0x41, 0x73, 0x73, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x16, 0x2e, 0x63, 0x32, 0x2e, 0x46, 0x65, 0x74, 0x63, 0x68, 0x41, 0x73, 0x73, 0x65, 0x74, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x30, 0x01, 0x12, 0x4d, 0x0a, 0x10, 0x52, 0x65, 0x70, + 0x6f, 0x72, 0x74, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x12, 0x1b, 0x2e, + 0x63, 0x32, 0x2e, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, + 0x69, 0x61, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x63, 0x32, 0x2e, + 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3d, 0x0a, 0x0a, 0x52, 0x65, 0x70, 0x6f, + 0x72, 0x74, 0x46, 0x69, 0x6c, 0x65, 0x12, 0x15, 0x2e, 0x63, 0x32, 0x2e, 0x52, 0x65, 0x70, 0x6f, + 0x72, 0x74, 0x46, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, + 0x63, 0x32, 0x2e, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x46, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x28, 0x01, 0x12, 0x50, 0x0a, 0x11, 0x52, 0x65, 0x70, 0x6f, 0x72, + 0x74, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x1c, 0x2e, 0x63, + 0x32, 0x2e, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x4c, + 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x63, 0x32, 0x2e, + 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x4c, 0x69, 0x73, + 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4f, 0x0a, 0x10, 0x52, 0x65, 0x70, + 0x6f, 0x72, 0x74, 0x54, 0x61, 0x73, 0x6b, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x12, 0x1b, 0x2e, + 0x63, 0x32, 0x2e, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x54, 0x61, 0x73, 0x6b, 0x4f, 0x75, 0x74, + 0x70, 0x75, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x63, 0x32, 0x2e, + 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x54, 0x61, 0x73, 0x6b, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x47, 0x0a, 0x0c, 0x52, 0x65, + 0x76, 0x65, 0x72, 0x73, 0x65, 0x53, 0x68, 0x65, 0x6c, 0x6c, 0x12, 0x17, 0x2e, 0x63, 0x32, 0x2e, + 0x52, 0x65, 0x76, 0x65, 0x72, 0x73, 0x65, 0x53, 0x68, 0x65, 0x6c, 0x6c, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x63, 0x32, 0x2e, 0x52, 0x65, 0x76, 0x65, 0x72, 0x73, 0x65, + 0x53, 0x68, 0x65, 0x6c, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x28, + 0x01, 0x30, 0x01, 0x42, 0x23, 0x5a, 0x21, 0x72, 0x65, 0x61, 0x6c, 0x6d, 0x2e, 0x70, 0x75, 0x62, + 0x2f, 0x74, 0x61, 0x76, 0x65, 0x72, 0x6e, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, + 0x2f, 0x63, 0x32, 0x2f, 0x63, 0x32, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +}) var ( file_c2_proto_rawDescOnce sync.Once @@ -1309,73 +1434,75 @@ func file_c2_proto_rawDescGZIP() []byte { } var file_c2_proto_enumTypes = make([]protoimpl.EnumInfo, 3) -var file_c2_proto_msgTypes = make([]protoimpl.MessageInfo, 20) +var file_c2_proto_msgTypes = make([]protoimpl.MessageInfo, 21) var file_c2_proto_goTypes = []any{ (ReverseShellMessageKind)(0), // 0: c2.ReverseShellMessageKind - (Beacon_Transport)(0), // 1: c2.Beacon.Transport + (ActiveTransport_Type)(0), // 1: c2.ActiveTransport.Type (Host_Platform)(0), // 2: c2.Host.Platform (*Agent)(nil), // 3: c2.Agent - (*Beacon)(nil), // 4: c2.Beacon - (*Host)(nil), // 5: c2.Host - (*Task)(nil), // 6: c2.Task - (*TaskError)(nil), // 7: c2.TaskError - (*TaskOutput)(nil), // 8: c2.TaskOutput - (*ClaimTasksRequest)(nil), // 9: c2.ClaimTasksRequest - (*ClaimTasksResponse)(nil), // 10: c2.ClaimTasksResponse - (*FetchAssetRequest)(nil), // 11: c2.FetchAssetRequest - (*FetchAssetResponse)(nil), // 12: c2.FetchAssetResponse - (*ReportCredentialRequest)(nil), // 13: c2.ReportCredentialRequest - (*ReportCredentialResponse)(nil), // 14: c2.ReportCredentialResponse - (*ReportFileRequest)(nil), // 15: c2.ReportFileRequest - (*ReportFileResponse)(nil), // 16: c2.ReportFileResponse - (*ReportProcessListRequest)(nil), // 17: c2.ReportProcessListRequest - (*ReportProcessListResponse)(nil), // 18: c2.ReportProcessListResponse - (*ReportTaskOutputRequest)(nil), // 19: c2.ReportTaskOutputRequest - (*ReportTaskOutputResponse)(nil), // 20: c2.ReportTaskOutputResponse - (*ReverseShellRequest)(nil), // 21: c2.ReverseShellRequest - (*ReverseShellResponse)(nil), // 22: c2.ReverseShellResponse - (*epb.Tome)(nil), // 23: eldritch.Tome - (*timestamppb.Timestamp)(nil), // 24: google.protobuf.Timestamp - (*epb.Credential)(nil), // 25: eldritch.Credential - (*epb.File)(nil), // 26: eldritch.File - (*epb.ProcessList)(nil), // 27: eldritch.ProcessList + (*ActiveTransport)(nil), // 4: c2.ActiveTransport + (*Beacon)(nil), // 5: c2.Beacon + (*Host)(nil), // 6: c2.Host + (*Task)(nil), // 7: c2.Task + (*TaskError)(nil), // 8: c2.TaskError + (*TaskOutput)(nil), // 9: c2.TaskOutput + (*ClaimTasksRequest)(nil), // 10: c2.ClaimTasksRequest + (*ClaimTasksResponse)(nil), // 11: c2.ClaimTasksResponse + (*FetchAssetRequest)(nil), // 12: c2.FetchAssetRequest + (*FetchAssetResponse)(nil), // 13: c2.FetchAssetResponse + (*ReportCredentialRequest)(nil), // 14: c2.ReportCredentialRequest + (*ReportCredentialResponse)(nil), // 15: c2.ReportCredentialResponse + (*ReportFileRequest)(nil), // 16: c2.ReportFileRequest + (*ReportFileResponse)(nil), // 17: c2.ReportFileResponse + (*ReportProcessListRequest)(nil), // 18: c2.ReportProcessListRequest + (*ReportProcessListResponse)(nil), // 19: c2.ReportProcessListResponse + (*ReportTaskOutputRequest)(nil), // 20: c2.ReportTaskOutputRequest + (*ReportTaskOutputResponse)(nil), // 21: c2.ReportTaskOutputResponse + (*ReverseShellRequest)(nil), // 22: c2.ReverseShellRequest + (*ReverseShellResponse)(nil), // 23: c2.ReverseShellResponse + (*epb.Tome)(nil), // 24: eldritch.Tome + (*timestamppb.Timestamp)(nil), // 25: google.protobuf.Timestamp + (*epb.Credential)(nil), // 26: eldritch.Credential + (*epb.File)(nil), // 27: eldritch.File + (*epb.ProcessList)(nil), // 28: eldritch.ProcessList } var file_c2_proto_depIdxs = []int32{ - 5, // 0: c2.Beacon.host:type_name -> c2.Host - 3, // 1: c2.Beacon.agent:type_name -> c2.Agent - 1, // 2: c2.Beacon.transport:type_name -> c2.Beacon.Transport - 2, // 3: c2.Host.platform:type_name -> c2.Host.Platform - 23, // 4: c2.Task.tome:type_name -> eldritch.Tome - 7, // 5: c2.TaskOutput.error:type_name -> c2.TaskError - 24, // 6: c2.TaskOutput.exec_started_at:type_name -> google.protobuf.Timestamp - 24, // 7: c2.TaskOutput.exec_finished_at:type_name -> google.protobuf.Timestamp - 4, // 8: c2.ClaimTasksRequest.beacon:type_name -> c2.Beacon - 6, // 9: c2.ClaimTasksResponse.tasks:type_name -> c2.Task - 25, // 10: c2.ReportCredentialRequest.credential:type_name -> eldritch.Credential - 26, // 11: c2.ReportFileRequest.chunk:type_name -> eldritch.File - 27, // 12: c2.ReportProcessListRequest.list:type_name -> eldritch.ProcessList - 8, // 13: c2.ReportTaskOutputRequest.output:type_name -> c2.TaskOutput - 0, // 14: c2.ReverseShellRequest.kind:type_name -> c2.ReverseShellMessageKind - 0, // 15: c2.ReverseShellResponse.kind:type_name -> c2.ReverseShellMessageKind - 9, // 16: c2.C2.ClaimTasks:input_type -> c2.ClaimTasksRequest - 11, // 17: c2.C2.FetchAsset:input_type -> c2.FetchAssetRequest - 13, // 18: c2.C2.ReportCredential:input_type -> c2.ReportCredentialRequest - 15, // 19: c2.C2.ReportFile:input_type -> c2.ReportFileRequest - 17, // 20: c2.C2.ReportProcessList:input_type -> c2.ReportProcessListRequest - 19, // 21: c2.C2.ReportTaskOutput:input_type -> c2.ReportTaskOutputRequest - 21, // 22: c2.C2.ReverseShell:input_type -> c2.ReverseShellRequest - 10, // 23: c2.C2.ClaimTasks:output_type -> c2.ClaimTasksResponse - 12, // 24: c2.C2.FetchAsset:output_type -> c2.FetchAssetResponse - 14, // 25: c2.C2.ReportCredential:output_type -> c2.ReportCredentialResponse - 16, // 26: c2.C2.ReportFile:output_type -> c2.ReportFileResponse - 18, // 27: c2.C2.ReportProcessList:output_type -> c2.ReportProcessListResponse - 20, // 28: c2.C2.ReportTaskOutput:output_type -> c2.ReportTaskOutputResponse - 22, // 29: c2.C2.ReverseShell:output_type -> c2.ReverseShellResponse - 23, // [23:30] is the sub-list for method output_type - 16, // [16:23] is the sub-list for method input_type - 16, // [16:16] is the sub-list for extension type_name - 16, // [16:16] is the sub-list for extension extendee - 0, // [0:16] is the sub-list for field type_name + 1, // 0: c2.ActiveTransport.type:type_name -> c2.ActiveTransport.Type + 6, // 1: c2.Beacon.host:type_name -> c2.Host + 3, // 2: c2.Beacon.agent:type_name -> c2.Agent + 4, // 3: c2.Beacon.active_transport:type_name -> c2.ActiveTransport + 2, // 4: c2.Host.platform:type_name -> c2.Host.Platform + 24, // 5: c2.Task.tome:type_name -> eldritch.Tome + 8, // 6: c2.TaskOutput.error:type_name -> c2.TaskError + 25, // 7: c2.TaskOutput.exec_started_at:type_name -> google.protobuf.Timestamp + 25, // 8: c2.TaskOutput.exec_finished_at:type_name -> google.protobuf.Timestamp + 5, // 9: c2.ClaimTasksRequest.beacon:type_name -> c2.Beacon + 7, // 10: c2.ClaimTasksResponse.tasks:type_name -> c2.Task + 26, // 11: c2.ReportCredentialRequest.credential:type_name -> eldritch.Credential + 27, // 12: c2.ReportFileRequest.chunk:type_name -> eldritch.File + 28, // 13: c2.ReportProcessListRequest.list:type_name -> eldritch.ProcessList + 9, // 14: c2.ReportTaskOutputRequest.output:type_name -> c2.TaskOutput + 0, // 15: c2.ReverseShellRequest.kind:type_name -> c2.ReverseShellMessageKind + 0, // 16: c2.ReverseShellResponse.kind:type_name -> c2.ReverseShellMessageKind + 10, // 17: c2.C2.ClaimTasks:input_type -> c2.ClaimTasksRequest + 12, // 18: c2.C2.FetchAsset:input_type -> c2.FetchAssetRequest + 14, // 19: c2.C2.ReportCredential:input_type -> c2.ReportCredentialRequest + 16, // 20: c2.C2.ReportFile:input_type -> c2.ReportFileRequest + 18, // 21: c2.C2.ReportProcessList:input_type -> c2.ReportProcessListRequest + 20, // 22: c2.C2.ReportTaskOutput:input_type -> c2.ReportTaskOutputRequest + 22, // 23: c2.C2.ReverseShell:input_type -> c2.ReverseShellRequest + 11, // 24: c2.C2.ClaimTasks:output_type -> c2.ClaimTasksResponse + 13, // 25: c2.C2.FetchAsset:output_type -> c2.FetchAssetResponse + 15, // 26: c2.C2.ReportCredential:output_type -> c2.ReportCredentialResponse + 17, // 27: c2.C2.ReportFile:output_type -> c2.ReportFileResponse + 19, // 28: c2.C2.ReportProcessList:output_type -> c2.ReportProcessListResponse + 21, // 29: c2.C2.ReportTaskOutput:output_type -> c2.ReportTaskOutputResponse + 23, // 30: c2.C2.ReverseShell:output_type -> c2.ReverseShellResponse + 24, // [24:31] is the sub-list for method output_type + 17, // [17:24] is the sub-list for method input_type + 17, // [17:17] is the sub-list for extension type_name + 17, // [17:17] is the sub-list for extension extendee + 0, // [0:17] is the sub-list for field type_name } func init() { file_c2_proto_init() } @@ -1389,7 +1516,7 @@ func file_c2_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: unsafe.Slice(unsafe.StringData(file_c2_proto_rawDesc), len(file_c2_proto_rawDesc)), NumEnums: 3, - NumMessages: 20, + NumMessages: 21, NumExtensions: 0, NumServices: 1, }, diff --git a/tavern/internal/c2/c2pb/enum_beacon_active_transport_type.go b/tavern/internal/c2/c2pb/enum_beacon_active_transport_type.go new file mode 100644 index 000000000..692336ace --- /dev/null +++ b/tavern/internal/c2/c2pb/enum_beacon_active_transport_type.go @@ -0,0 +1,64 @@ +package c2pb + +import ( + "database/sql/driver" + "io" + "sort" + + "github.com/99designs/gqlgen/graphql" +) + +// Values provides list valid values for Enum. +func (ActiveTransport_Type) Values() []string { + values := make([]string, 0, len(ActiveTransport_Type_name)) + for _, name := range ActiveTransport_Type_name { + values = append(values, name) + } + sort.Strings(values) + return values +} + +// Value provides the DB a string from int. +func (p ActiveTransport_Type) Value() (driver.Value, error) { + return p.String(), nil +} + +// Scan tells our code how to read the enum into our type. +func (p *ActiveTransport_Type) Scan(val any) error { + var name string + switch v := val.(type) { + case nil: + return nil + case string: + name = v + case []uint8: + name = string(v) + default: + *p = ActiveTransport_TRANSPORT_UNSPECIFIED + return nil + } + + status, ok := ActiveTransport_Type_value[name] + if !ok { + *p = ActiveTransport_TRANSPORT_UNSPECIFIED + return nil + } + *p = ActiveTransport_Type(status) + + return nil +} + +// MarshalGQL writes a formatted string value for GraphQL. +func (p ActiveTransport_Type) MarshalGQL(w io.Writer) { + graphql.MarshalString(p.String()).MarshalGQL(w) +} + +// UnmarshalGQL parses a GraphQL string representation into the enum. +func (p *ActiveTransport_Type) UnmarshalGQL(v interface{}) error { + str, err := graphql.UnmarshalString(v) + if err != nil { + return err + } + + return p.Scan(str) +} diff --git a/tavern/internal/c2/c2pb/enum_beacon_transport.go b/tavern/internal/c2/c2pb/enum_beacon_transport.go index 51d62e104..0c89ef8c2 100644 --- a/tavern/internal/c2/c2pb/enum_beacon_transport.go +++ b/tavern/internal/c2/c2pb/enum_beacon_transport.go @@ -34,13 +34,13 @@ func (p *Beacon_Transport) Scan(val any) error { case []uint8: name = string(v) default: - *p = Beacon_TRANSPORT_UNSPECIFIED + *p = ActiveTransport_TRANSPORT_UNSPECIFIED return nil } status, ok := Beacon_Transport_value[name] if !ok { - *p = Beacon_TRANSPORT_UNSPECIFIED + *p = ActiveTransport_TRANSPORT_UNSPECIFIED return nil } *p = Beacon_Transport(status) diff --git a/tavern/internal/c2/c2test/ent.go b/tavern/internal/c2/c2test/ent.go index 13568f254..8324aac0f 100644 --- a/tavern/internal/c2/c2test/ent.go +++ b/tavern/internal/c2/c2test/ent.go @@ -26,7 +26,7 @@ func NewRandomBeacon(ctx context.Context, graph *ent.Client) *ent.Beacon { return graph.Beacon.Create(). SetIdentifier(namegen.NewComplex()). SetHost(host). - SetTransport(c2pb.Beacon_TRANSPORT_UNSPECIFIED). + SetTransport(c2pb.ActiveTransport_TRANSPORT_UNSPECIFIED). SaveX(ctx) } diff --git a/tavern/internal/c2/dnspb/dns.pb.go b/tavern/internal/c2/dnspb/dns.pb.go index 83c2ff9b3..12c484b81 100644 --- a/tavern/internal/c2/dnspb/dns.pb.go +++ b/tavern/internal/c2/dnspb/dns.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 -// protoc v6.32.0 +// protoc-gen-go v1.36.5 +// protoc v3.21.12 // source: dns.proto package dnspb @@ -412,45 +412,60 @@ func (x *ResponseMetadata) GetChunkSize() uint32 { var File_dns_proto protoreflect.FileDescriptor -const file_dns_proto_rawDesc = "" + - "\n" + - "\tdns.proto\x12\x03dns\"\xf9\x01\n" + - "\tDNSPacket\x12#\n" + - "\x04type\x18\x01 \x01(\x0e2\x0f.dns.PacketTypeR\x04type\x12\x1a\n" + - "\bsequence\x18\x02 \x01(\rR\bsequence\x12'\n" + - "\x0fconversation_id\x18\x03 \x01(\tR\x0econversationId\x12\x12\n" + - "\x04data\x18\x04 \x01(\fR\x04data\x12\x14\n" + - "\x05crc32\x18\x05 \x01(\rR\x05crc32\x12\x1f\n" + - "\vwindow_size\x18\x06 \x01(\rR\n" + - "windowSize\x12!\n" + - "\x04acks\x18\a \x03(\v2\r.dns.AckRangeR\x04acks\x12\x14\n" + - "\x05nacks\x18\b \x03(\rR\x05nacks\"@\n" + - "\bAckRange\x12\x1b\n" + - "\tstart_seq\x18\x01 \x01(\rR\bstartSeq\x12\x17\n" + - "\aend_seq\x18\x02 \x01(\rR\x06endSeq\"\x8d\x01\n" + - "\vInitPayload\x12\x1f\n" + - "\vmethod_code\x18\x01 \x01(\tR\n" + - "methodCode\x12!\n" + - "\ftotal_chunks\x18\x02 \x01(\rR\vtotalChunks\x12\x1d\n" + - "\n" + - "data_crc32\x18\x03 \x01(\rR\tdataCrc32\x12\x1b\n" + - "\tfile_size\x18\x04 \x01(\rR\bfileSize\"/\n" + - "\fFetchPayload\x12\x1f\n" + - "\vchunk_index\x18\x01 \x01(\rR\n" + - "chunkIndex\"s\n" + - "\x10ResponseMetadata\x12!\n" + - "\ftotal_chunks\x18\x01 \x01(\rR\vtotalChunks\x12\x1d\n" + - "\n" + - "data_crc32\x18\x02 \x01(\rR\tdataCrc32\x12\x1d\n" + - "\n" + - "chunk_size\x18\x03 \x01(\rR\tchunkSize*\x84\x01\n" + - "\n" + - "PacketType\x12\x1b\n" + - "\x17PACKET_TYPE_UNSPECIFIED\x10\x00\x12\x14\n" + - "\x10PACKET_TYPE_INIT\x10\x01\x12\x14\n" + - "\x10PACKET_TYPE_DATA\x10\x02\x12\x15\n" + - "\x11PACKET_TYPE_FETCH\x10\x03\x12\x16\n" + - "\x12PACKET_TYPE_STATUS\x10\x04B$Z\"realm.pub/tavern/internal/c2/dnspbb\x06proto3" +var file_dns_proto_rawDesc = string([]byte{ + 0x0a, 0x09, 0x64, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x03, 0x64, 0x6e, 0x73, + 0x22, 0xf9, 0x01, 0x0a, 0x09, 0x44, 0x4e, 0x53, 0x50, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x12, 0x23, + 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0f, 0x2e, 0x64, + 0x6e, 0x73, 0x2e, 0x50, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, + 0x79, 0x70, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x12, + 0x27, 0x0a, 0x0f, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, + 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, + 0x73, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, + 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x12, 0x14, 0x0a, 0x05, + 0x63, 0x72, 0x63, 0x33, 0x32, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x63, 0x72, 0x63, + 0x33, 0x32, 0x12, 0x1f, 0x0a, 0x0b, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x5f, 0x73, 0x69, 0x7a, + 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x53, + 0x69, 0x7a, 0x65, 0x12, 0x21, 0x0a, 0x04, 0x61, 0x63, 0x6b, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x0d, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x41, 0x63, 0x6b, 0x52, 0x61, 0x6e, 0x67, 0x65, + 0x52, 0x04, 0x61, 0x63, 0x6b, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x6e, 0x61, 0x63, 0x6b, 0x73, 0x18, + 0x08, 0x20, 0x03, 0x28, 0x0d, 0x52, 0x05, 0x6e, 0x61, 0x63, 0x6b, 0x73, 0x22, 0x40, 0x0a, 0x08, + 0x41, 0x63, 0x6b, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x73, 0x74, 0x61, 0x72, + 0x74, 0x5f, 0x73, 0x65, 0x71, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x73, 0x74, 0x61, + 0x72, 0x74, 0x53, 0x65, 0x71, 0x12, 0x17, 0x0a, 0x07, 0x65, 0x6e, 0x64, 0x5f, 0x73, 0x65, 0x71, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x06, 0x65, 0x6e, 0x64, 0x53, 0x65, 0x71, 0x22, 0x8d, + 0x01, 0x0a, 0x0b, 0x49, 0x6e, 0x69, 0x74, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x1f, + 0x0a, 0x0b, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x0a, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x43, 0x6f, 0x64, 0x65, 0x12, + 0x21, 0x0a, 0x0c, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x63, 0x68, 0x75, 0x6e, 0x6b, 0x73, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0b, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x43, 0x68, 0x75, 0x6e, + 0x6b, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x63, 0x72, 0x63, 0x33, 0x32, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x09, 0x64, 0x61, 0x74, 0x61, 0x43, 0x72, 0x63, 0x33, + 0x32, 0x12, 0x1b, 0x0a, 0x09, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x22, 0x2f, + 0x0a, 0x0c, 0x46, 0x65, 0x74, 0x63, 0x68, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x1f, + 0x0a, 0x0b, 0x63, 0x68, 0x75, 0x6e, 0x6b, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x63, 0x68, 0x75, 0x6e, 0x6b, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x22, + 0x73, 0x0a, 0x10, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, + 0x61, 0x74, 0x61, 0x12, 0x21, 0x0a, 0x0c, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x63, 0x68, 0x75, + 0x6e, 0x6b, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0b, 0x74, 0x6f, 0x74, 0x61, 0x6c, + 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x63, + 0x72, 0x63, 0x33, 0x32, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x09, 0x64, 0x61, 0x74, 0x61, + 0x43, 0x72, 0x63, 0x33, 0x32, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x68, 0x75, 0x6e, 0x6b, 0x5f, 0x73, + 0x69, 0x7a, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x09, 0x63, 0x68, 0x75, 0x6e, 0x6b, + 0x53, 0x69, 0x7a, 0x65, 0x2a, 0x84, 0x01, 0x0a, 0x0a, 0x50, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x54, + 0x79, 0x70, 0x65, 0x12, 0x1b, 0x0a, 0x17, 0x50, 0x41, 0x43, 0x4b, 0x45, 0x54, 0x5f, 0x54, 0x59, + 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, + 0x12, 0x14, 0x0a, 0x10, 0x50, 0x41, 0x43, 0x4b, 0x45, 0x54, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, + 0x49, 0x4e, 0x49, 0x54, 0x10, 0x01, 0x12, 0x14, 0x0a, 0x10, 0x50, 0x41, 0x43, 0x4b, 0x45, 0x54, + 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x44, 0x41, 0x54, 0x41, 0x10, 0x02, 0x12, 0x15, 0x0a, 0x11, + 0x50, 0x41, 0x43, 0x4b, 0x45, 0x54, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x46, 0x45, 0x54, 0x43, + 0x48, 0x10, 0x03, 0x12, 0x16, 0x0a, 0x12, 0x50, 0x41, 0x43, 0x4b, 0x45, 0x54, 0x5f, 0x54, 0x59, + 0x50, 0x45, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x10, 0x04, 0x42, 0x24, 0x5a, 0x22, 0x72, + 0x65, 0x61, 0x6c, 0x6d, 0x2e, 0x70, 0x75, 0x62, 0x2f, 0x74, 0x61, 0x76, 0x65, 0x72, 0x6e, 0x2f, + 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x63, 0x32, 0x2f, 0x64, 0x6e, 0x73, 0x70, + 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +}) var ( file_dns_proto_rawDescOnce sync.Once diff --git a/tavern/internal/c2/proto/c2.proto b/tavern/internal/c2/proto/c2.proto index 8ef213c85..8fced3156 100644 --- a/tavern/internal/c2/proto/c2.proto +++ b/tavern/internal/c2/proto/c2.proto @@ -17,22 +17,27 @@ message Agent { string identifier = 1; } -// Beacon information that is unique to the current running beacon. -message Beacon { - string identifier = 1; - string principal = 2; - Host host = 3; - Agent agent = 4; - uint64 interval = 5; // Duration until next callback, in seconds. +message ActiveTransport { + string uri = 1; + uint64 interval = 2; - enum Transport { + enum Type { TRANSPORT_UNSPECIFIED = 0; TRANSPORT_GRPC = 1; TRANSPORT_HTTP1 = 2; TRANSPORT_DNS = 3; } - Transport transport = 6; + Type type = 3; +} + +// Beacon information that is unique to the current running beacon. +message Beacon { + string identifier = 1; + string principal = 2; + Host host = 3; + Agent agent = 4; + ActiveTransport active_transport = 5; } // Host information for the system a beacon is running on. diff --git a/tavern/internal/c2/reverse_shell_e2e_test.go b/tavern/internal/c2/reverse_shell_e2e_test.go index 277f0358b..3d3b708f1 100644 --- a/tavern/internal/c2/reverse_shell_e2e_test.go +++ b/tavern/internal/c2/reverse_shell_e2e_test.go @@ -84,7 +84,7 @@ func TestReverseShell_E2E(t *testing.T) { require.NoError(t, err) host, err := graph.Host.Create().SetIdentifier("test-host").SetPlatform(c2pb.Host_PLATFORM_LINUX).Save(ctx) require.NoError(t, err) - beacon, err := graph.Beacon.Create().SetHost(host).SetTransport(c2pb.Beacon_TRANSPORT_UNSPECIFIED).Save(ctx) + beacon, err := graph.Beacon.Create().SetHost(host).SetTransport(c2pb.ActiveTransport_TRANSPORT_UNSPECIFIED).Save(ctx) require.NoError(t, err) tome, err := graph.Tome.Create().SetName("test-tome").SetDescription("test-desc").SetAuthor("test-author").SetEldritch("test-eldritch").SetUploader(user).Save(ctx) require.NoError(t, err) diff --git a/tavern/internal/cdn/download_hostfile_test.go b/tavern/internal/cdn/download_hostfile_test.go index 3835555b5..d6b015ae3 100644 --- a/tavern/internal/cdn/download_hostfile_test.go +++ b/tavern/internal/cdn/download_hostfile_test.go @@ -28,7 +28,7 @@ func TestDownloadHostFile(t *testing.T) { existingBeacon := graph.Beacon.Create(). SetHost(existingHost). SetIdentifier("ABCDEFG"). - SetTransport(c2pb.Beacon_TRANSPORT_UNSPECIFIED). + SetTransport(c2pb.ActiveTransport_TRANSPORT_UNSPECIFIED). SaveX(ctx) existingTome := graph.Tome.Create(). SetName("Wowza"). diff --git a/tavern/internal/ent/schema/beacon.go b/tavern/internal/ent/schema/beacon.go index 86574b1cd..9ddc10b57 100644 --- a/tavern/internal/ent/schema/beacon.go +++ b/tavern/internal/ent/schema/beacon.go @@ -12,7 +12,6 @@ import ( "entgo.io/ent/schema" "entgo.io/ent/schema/edge" "entgo.io/ent/schema/field" - "realm.pub/tavern/internal/c2/c2pb" "realm.pub/tavern/internal/namegen" ) @@ -74,12 +73,6 @@ func (Beacon) Fields() []ent.Field { entgql.Skip(entgql.SkipMutationUpdateInput), ). Comment("Duration until next callback, in seconds."), - field.Enum("transport"). - GoType(c2pb.Beacon_Transport(0)). - Annotations( - entgql.Skip(entgql.SkipMutationUpdateInput), - ). - Comment("Beacons current transport."), } } diff --git a/tavern/internal/ent/schema/host_file_test.go b/tavern/internal/ent/schema/host_file_test.go index dd257157f..7c2844ae6 100644 --- a/tavern/internal/ent/schema/host_file_test.go +++ b/tavern/internal/ent/schema/host_file_test.go @@ -45,7 +45,7 @@ func newHostFile(graph *ent.Client, path string, content []byte) *ent.HostFile { beacon := graph.Beacon.Create(). SetHost(host). SetIdentifier("ABCDEFG"). - SetTransport(c2pb.Beacon_TRANSPORT_UNSPECIFIED). + SetTransport(c2pb.ActiveTransport_TRANSPORT_UNSPECIFIED). SaveX(ctx) tome := graph.Tome.Create(). SetName("Wowza"). diff --git a/tavern/internal/graphql/quest_test.go b/tavern/internal/graphql/quest_test.go index d1206940a..08779ce49 100644 --- a/tavern/internal/graphql/quest_test.go +++ b/tavern/internal/graphql/quest_test.go @@ -47,11 +47,11 @@ func TestCreateQuest(t *testing.T) { testBeacons := []*ent.Beacon{ graph.Beacon.Create(). SetHost(testHost). - SetTransport(c2pb.Beacon_TRANSPORT_UNSPECIFIED). + SetTransport(c2pb.ActiveTransport_TRANSPORT_UNSPECIFIED). SaveX(ctx), graph.Beacon.Create(). SetHost(testHost). - SetTransport(c2pb.Beacon_TRANSPORT_UNSPECIFIED). + SetTransport(c2pb.ActiveTransport_TRANSPORT_UNSPECIFIED). SaveX(ctx), } testTome := graph.Tome.Create(). diff --git a/tavern/internal/http/stream/websocket_test.go b/tavern/internal/http/stream/websocket_test.go index 8e67d5421..670328052 100644 --- a/tavern/internal/http/stream/websocket_test.go +++ b/tavern/internal/http/stream/websocket_test.go @@ -53,7 +53,7 @@ func TestNewShellHandler(t *testing.T) { require.NoError(t, err) // Create a test beacon - beacon, err := graph.Beacon.Create().SetHost(host).SetTransport(c2pb.Beacon_TRANSPORT_UNSPECIFIED).Save(ctx) + beacon, err := graph.Beacon.Create().SetHost(host).SetTransport(c2pb.ActiveTransport_TRANSPORT_UNSPECIFIED).Save(ctx) require.NoError(t, err) // Create a test tome diff --git a/tavern/test_data.go b/tavern/test_data.go index e4a98d9a0..3caeeeeb2 100644 --- a/tavern/test_data.go +++ b/tavern/test_data.go @@ -94,7 +94,7 @@ func createTestData(ctx context.Context, client *ent.Client) { SetHost(testHost). SetInterval(60). SetPrincipal("root"). - SetTransport(c2pb.Beacon_TRANSPORT_UNSPECIFIED). + SetTransport(c2pb.ActiveTransport_TRANSPORT_UNSPECIFIED). SaveX(ctx), ) testBeacons = append(testBeacons, @@ -106,7 +106,7 @@ func createTestData(ctx context.Context, client *ent.Client) { SetHost(testHost). SetInterval(60). SetPrincipal("root"). - SetTransport(c2pb.Beacon_TRANSPORT_UNSPECIFIED). + SetTransport(c2pb.ActiveTransport_TRANSPORT_UNSPECIFIED). SaveX(ctx), ) testBeacons = append(testBeacons, @@ -118,7 +118,7 @@ func createTestData(ctx context.Context, client *ent.Client) { SetHost(testHost). SetInterval(60). SetPrincipal("root"). - SetTransport(c2pb.Beacon_TRANSPORT_UNSPECIFIED). + SetTransport(c2pb.ActiveTransport_TRANSPORT_UNSPECIFIED). SaveX(ctx), ) } else { @@ -131,7 +131,7 @@ func createTestData(ctx context.Context, client *ent.Client) { SetHost(testHost). SetInterval(600000). SetPrincipal("root"). - SetTransport(c2pb.Beacon_TRANSPORT_UNSPECIFIED). + SetTransport(c2pb.ActiveTransport_TRANSPORT_UNSPECIFIED). SaveX(ctx), ) if i == 3 { @@ -144,7 +144,7 @@ func createTestData(ctx context.Context, client *ent.Client) { SetHost(testHost). SetInterval(600). SetPrincipal("janet"). - SetTransport(c2pb.Beacon_TRANSPORT_UNSPECIFIED). + SetTransport(c2pb.ActiveTransport_TRANSPORT_UNSPECIFIED). SaveX(ctx), ) } @@ -158,7 +158,7 @@ func createTestData(ctx context.Context, client *ent.Client) { SetHost(testHost). SetInterval(600000). SetPrincipal("jane"). - SetTransport(c2pb.Beacon_TRANSPORT_UNSPECIFIED). + SetTransport(c2pb.ActiveTransport_TRANSPORT_UNSPECIFIED). SaveX(ctx), ) } @@ -172,7 +172,7 @@ func createTestData(ctx context.Context, client *ent.Client) { SetHost(testHost). SetInterval(1000). SetPrincipal("admin"). - SetTransport(c2pb.Beacon_TRANSPORT_UNSPECIFIED). + SetTransport(c2pb.ActiveTransport_TRANSPORT_UNSPECIFIED). SaveX(ctx), ) @@ -185,7 +185,7 @@ func createTestData(ctx context.Context, client *ent.Client) { SetHost(testHost). SetInterval(4). SetPrincipal("Administrator"). - SetTransport(c2pb.Beacon_TRANSPORT_UNSPECIFIED). + SetTransport(c2pb.ActiveTransport_TRANSPORT_UNSPECIFIED). SaveX(ctx), ) } From 53399d2fb2fbef68c70b0a3df469581df6c5b144 Mon Sep 17 00:00:00 2001 From: hulto <7121375+hulto@users.noreply.github.com> Date: Mon, 29 Dec 2025 22:36:53 +0000 Subject: [PATCH 02/18] go generated --- tavern/internal/c2/api_claim_tasks.go | 8 +- tavern/internal/c2/api_claim_tasks_test.go | 12 +- .../internal/c2/c2pb/enum_beacon_transport.go | 64 -------- tavern/internal/ent/beacon.go | 8 +- tavern/internal/ent/beacon/beacon.go | 12 +- tavern/internal/ent/beacon/where.go | 8 +- tavern/internal/ent/beacon_create.go | 10 +- tavern/internal/ent/beacon_update.go | 20 +-- tavern/internal/ent/gql_where_input.go | 8 +- tavern/internal/ent/migrate/schema.go | 2 +- tavern/internal/ent/mutation.go | 12 +- tavern/internal/ent/schema/beacon.go | 7 + .../graphql/generated/ent.generated.go | 146 +++++++++--------- .../graphql/generated/root_.generated.go | 29 ++-- tavern/internal/graphql/schema.graphql | 29 ++-- tavern/internal/graphql/schema/ent.graphql | 29 ++-- tavern/internal/www/schema.graphql | 29 ++-- 17 files changed, 193 insertions(+), 240 deletions(-) delete mode 100644 tavern/internal/c2/c2pb/enum_beacon_transport.go diff --git a/tavern/internal/c2/api_claim_tasks.go b/tavern/internal/c2/api_claim_tasks.go index 5c6f472df..bd63fa9ac 100644 --- a/tavern/internal/c2/api_claim_tasks.go +++ b/tavern/internal/c2/api_claim_tasks.go @@ -69,7 +69,7 @@ func (srv *Server) ClaimTasks(ctx context.Context, req *c2pb.ClaimTasksRequest) SetPrimaryIP(req.Beacon.Host.PrimaryIp). SetExternalIP(clientIP). SetLastSeenAt(now). - SetNextSeenAt(now.Add(time.Duration(req.Beacon.Interval) * time.Second)). + SetNextSeenAt(now.Add(time.Duration(req.Beacon.ActiveTransport.Interval) * time.Second)). OnConflict(). UpdateNewValues(). ID(ctx) @@ -162,9 +162,9 @@ func (srv *Server) ClaimTasks(ctx context.Context, req *c2pb.ClaimTasksRequest) SetNillableName(beaconNameAddr). SetHostID(hostID). SetLastSeenAt(now). - SetNextSeenAt(now.Add(time.Duration(req.Beacon.Interval) * time.Second)). - SetInterval(req.Beacon.Interval). - SetTransport(req.Beacon.Transport). + SetNextSeenAt(now.Add(time.Duration(req.Beacon.ActiveTransport.Interval) * time.Second)). + SetInterval(req.Beacon.ActiveTransport.Interval). + SetTransport(req.Beacon.ActiveTransport.Transport). OnConflict(). UpdateNewValues(). ID(ctx) diff --git a/tavern/internal/c2/api_claim_tasks_test.go b/tavern/internal/c2/api_claim_tasks_test.go index 59adf6c1d..b79bd583d 100644 --- a/tavern/internal/c2/api_claim_tasks_test.go +++ b/tavern/internal/c2/api_claim_tasks_test.go @@ -56,7 +56,9 @@ func TestClaimTasks(t *testing.T) { Platform: c2pb.Host_PLATFORM_LINUX, PrimaryIp: "127.0.0.1", }, - Interval: uint64(60), + ActiveTransport: &c2pb.ActiveTransport{ + Interval: uint64(60), + }, }, }, wantResp: &c2pb.ClaimTasksResponse{}, @@ -81,7 +83,9 @@ func TestClaimTasks(t *testing.T) { Platform: c2pb.Host_PLATFORM_LINUX, PrimaryIp: "127.0.0.1", }, - Interval: uint64(100), + ActiveTransport: &c2pb.ActiveTransport{ + Interval: uint64(100), + }, }, }, wantResp: &c2pb.ClaimTasksResponse{}, @@ -106,7 +110,9 @@ func TestClaimTasks(t *testing.T) { Platform: c2pb.Host_PLATFORM_LINUX, PrimaryIp: "127.0.0.1", }, - Interval: uint64(100), + ActiveTransport: &c2pb.ActiveTransport{ + Interval: uint64(100), + }, }, }, wantResp: &c2pb.ClaimTasksResponse{ diff --git a/tavern/internal/c2/c2pb/enum_beacon_transport.go b/tavern/internal/c2/c2pb/enum_beacon_transport.go deleted file mode 100644 index 0c89ef8c2..000000000 --- a/tavern/internal/c2/c2pb/enum_beacon_transport.go +++ /dev/null @@ -1,64 +0,0 @@ -package c2pb - -import ( - "database/sql/driver" - "io" - "sort" - - "github.com/99designs/gqlgen/graphql" -) - -// Values provides list valid values for Enum. -func (Beacon_Transport) Values() []string { - values := make([]string, 0, len(Beacon_Transport_name)) - for _, name := range Beacon_Transport_name { - values = append(values, name) - } - sort.Strings(values) - return values -} - -// Value provides the DB a string from int. -func (p Beacon_Transport) Value() (driver.Value, error) { - return p.String(), nil -} - -// Scan tells our code how to read the enum into our type. -func (p *Beacon_Transport) Scan(val any) error { - var name string - switch v := val.(type) { - case nil: - return nil - case string: - name = v - case []uint8: - name = string(v) - default: - *p = ActiveTransport_TRANSPORT_UNSPECIFIED - return nil - } - - status, ok := Beacon_Transport_value[name] - if !ok { - *p = ActiveTransport_TRANSPORT_UNSPECIFIED - return nil - } - *p = Beacon_Transport(status) - - return nil -} - -// MarshalGQL writes a formatted string value for GraphQL. -func (p Beacon_Transport) MarshalGQL(w io.Writer) { - graphql.MarshalString(p.String()).MarshalGQL(w) -} - -// UnmarshalGQL parses a GraphQL string representation into the enum. -func (p *Beacon_Transport) UnmarshalGQL(v interface{}) error { - str, err := graphql.UnmarshalString(v) - if err != nil { - return err - } - - return p.Scan(str) -} diff --git a/tavern/internal/ent/beacon.go b/tavern/internal/ent/beacon.go index fefcd2a6f..5dbc54ea9 100644 --- a/tavern/internal/ent/beacon.go +++ b/tavern/internal/ent/beacon.go @@ -37,8 +37,8 @@ type Beacon struct { NextSeenAt time.Time `json:"next_seen_at,omitempty"` // Duration until next callback, in seconds. Interval uint64 `json:"interval,omitempty"` - // Beacons current transport. - Transport c2pb.Beacon_Transport `json:"transport,omitempty"` + // Beacon's current transport. + Transport c2pb.ActiveTransport_Type `json:"transport,omitempty"` // Edges holds the relations/edges for other nodes in the graph. // The values are being populated by the BeaconQuery when eager-loading is set. Edges BeaconEdges `json:"edges"` @@ -99,7 +99,7 @@ func (*Beacon) scanValues(columns []string) ([]any, error) { for i := range columns { switch columns[i] { case beacon.FieldTransport: - values[i] = new(c2pb.Beacon_Transport) + values[i] = new(c2pb.ActiveTransport_Type) case beacon.FieldID, beacon.FieldInterval: values[i] = new(sql.NullInt64) case beacon.FieldName, beacon.FieldPrincipal, beacon.FieldIdentifier, beacon.FieldAgentIdentifier: @@ -184,7 +184,7 @@ func (b *Beacon) assignValues(columns []string, values []any) error { b.Interval = uint64(value.Int64) } case beacon.FieldTransport: - if value, ok := values[i].(*c2pb.Beacon_Transport); !ok { + if value, ok := values[i].(*c2pb.ActiveTransport_Type); !ok { return fmt.Errorf("unexpected type %T for field transport", values[i]) } else if value != nil { b.Transport = *value diff --git a/tavern/internal/ent/beacon/beacon.go b/tavern/internal/ent/beacon/beacon.go index d0803c2cb..5a496a222 100644 --- a/tavern/internal/ent/beacon/beacon.go +++ b/tavern/internal/ent/beacon/beacon.go @@ -126,9 +126,9 @@ var ( ) // TransportValidator is a validator for the "transport" field enum values. It is called by the builders before save. -func TransportValidator(t c2pb.Beacon_Transport) error { +func TransportValidator(t c2pb.ActiveTransport_Type) error { switch t.String() { - case "TRANSPORT_GRPC", "TRANSPORT_HTTP1", "TRANSPORT_DNS", "TRANSPORT_UNSPECIFIED": + case "TRANSPORT_DNS", "TRANSPORT_GRPC", "TRANSPORT_HTTP1", "TRANSPORT_UNSPECIFIED": return nil default: return fmt.Errorf("beacon: invalid enum value for transport field: %q", t) @@ -250,8 +250,8 @@ func newShellsStep() *sqlgraph.Step { } var ( - // c2pb.Beacon_Transport must implement graphql.Marshaler. - _ graphql.Marshaler = (*c2pb.Beacon_Transport)(nil) - // c2pb.Beacon_Transport must implement graphql.Unmarshaler. - _ graphql.Unmarshaler = (*c2pb.Beacon_Transport)(nil) + // c2pb.ActiveTransport_Type must implement graphql.Marshaler. + _ graphql.Marshaler = (*c2pb.ActiveTransport_Type)(nil) + // c2pb.ActiveTransport_Type must implement graphql.Unmarshaler. + _ graphql.Unmarshaler = (*c2pb.ActiveTransport_Type)(nil) ) diff --git a/tavern/internal/ent/beacon/where.go b/tavern/internal/ent/beacon/where.go index d63a38326..64494214b 100644 --- a/tavern/internal/ent/beacon/where.go +++ b/tavern/internal/ent/beacon/where.go @@ -612,22 +612,22 @@ func IntervalNotNil() predicate.Beacon { } // TransportEQ applies the EQ predicate on the "transport" field. -func TransportEQ(v c2pb.Beacon_Transport) predicate.Beacon { +func TransportEQ(v c2pb.ActiveTransport_Type) predicate.Beacon { return predicate.Beacon(sql.FieldEQ(FieldTransport, v)) } // TransportNEQ applies the NEQ predicate on the "transport" field. -func TransportNEQ(v c2pb.Beacon_Transport) predicate.Beacon { +func TransportNEQ(v c2pb.ActiveTransport_Type) predicate.Beacon { return predicate.Beacon(sql.FieldNEQ(FieldTransport, v)) } // TransportIn applies the In predicate on the "transport" field. -func TransportIn(vs ...c2pb.Beacon_Transport) predicate.Beacon { +func TransportIn(vs ...c2pb.ActiveTransport_Type) predicate.Beacon { return predicate.Beacon(sql.FieldIn(FieldTransport, vs...)) } // TransportNotIn applies the NotIn predicate on the "transport" field. -func TransportNotIn(vs ...c2pb.Beacon_Transport) predicate.Beacon { +func TransportNotIn(vs ...c2pb.ActiveTransport_Type) predicate.Beacon { return predicate.Beacon(sql.FieldNotIn(FieldTransport, vs...)) } diff --git a/tavern/internal/ent/beacon_create.go b/tavern/internal/ent/beacon_create.go index 1b0f4b9c4..89c264ead 100644 --- a/tavern/internal/ent/beacon_create.go +++ b/tavern/internal/ent/beacon_create.go @@ -153,8 +153,8 @@ func (bc *BeaconCreate) SetNillableInterval(u *uint64) *BeaconCreate { } // SetTransport sets the "transport" field. -func (bc *BeaconCreate) SetTransport(ct c2pb.Beacon_Transport) *BeaconCreate { - bc.mutation.SetTransport(ct) +func (bc *BeaconCreate) SetTransport(ctt c2pb.ActiveTransport_Type) *BeaconCreate { + bc.mutation.SetTransport(ctt) return bc } @@ -586,7 +586,7 @@ func (u *BeaconUpsert) ClearInterval() *BeaconUpsert { } // SetTransport sets the "transport" field. -func (u *BeaconUpsert) SetTransport(v c2pb.Beacon_Transport) *BeaconUpsert { +func (u *BeaconUpsert) SetTransport(v c2pb.ActiveTransport_Type) *BeaconUpsert { u.Set(beacon.FieldTransport, v) return u } @@ -786,7 +786,7 @@ func (u *BeaconUpsertOne) ClearInterval() *BeaconUpsertOne { } // SetTransport sets the "transport" field. -func (u *BeaconUpsertOne) SetTransport(v c2pb.Beacon_Transport) *BeaconUpsertOne { +func (u *BeaconUpsertOne) SetTransport(v c2pb.ActiveTransport_Type) *BeaconUpsertOne { return u.Update(func(s *BeaconUpsert) { s.SetTransport(v) }) @@ -1154,7 +1154,7 @@ func (u *BeaconUpsertBulk) ClearInterval() *BeaconUpsertBulk { } // SetTransport sets the "transport" field. -func (u *BeaconUpsertBulk) SetTransport(v c2pb.Beacon_Transport) *BeaconUpsertBulk { +func (u *BeaconUpsertBulk) SetTransport(v c2pb.ActiveTransport_Type) *BeaconUpsertBulk { return u.Update(func(s *BeaconUpsert) { s.SetTransport(v) }) diff --git a/tavern/internal/ent/beacon_update.go b/tavern/internal/ent/beacon_update.go index 0315091e4..8caa0f2b9 100644 --- a/tavern/internal/ent/beacon_update.go +++ b/tavern/internal/ent/beacon_update.go @@ -160,15 +160,15 @@ func (bu *BeaconUpdate) ClearInterval() *BeaconUpdate { } // SetTransport sets the "transport" field. -func (bu *BeaconUpdate) SetTransport(ct c2pb.Beacon_Transport) *BeaconUpdate { - bu.mutation.SetTransport(ct) +func (bu *BeaconUpdate) SetTransport(ctt c2pb.ActiveTransport_Type) *BeaconUpdate { + bu.mutation.SetTransport(ctt) return bu } // SetNillableTransport sets the "transport" field if the given value is not nil. -func (bu *BeaconUpdate) SetNillableTransport(ct *c2pb.Beacon_Transport) *BeaconUpdate { - if ct != nil { - bu.SetTransport(*ct) +func (bu *BeaconUpdate) SetNillableTransport(ctt *c2pb.ActiveTransport_Type) *BeaconUpdate { + if ctt != nil { + bu.SetTransport(*ctt) } return bu } @@ -652,15 +652,15 @@ func (buo *BeaconUpdateOne) ClearInterval() *BeaconUpdateOne { } // SetTransport sets the "transport" field. -func (buo *BeaconUpdateOne) SetTransport(ct c2pb.Beacon_Transport) *BeaconUpdateOne { - buo.mutation.SetTransport(ct) +func (buo *BeaconUpdateOne) SetTransport(ctt c2pb.ActiveTransport_Type) *BeaconUpdateOne { + buo.mutation.SetTransport(ctt) return buo } // SetNillableTransport sets the "transport" field if the given value is not nil. -func (buo *BeaconUpdateOne) SetNillableTransport(ct *c2pb.Beacon_Transport) *BeaconUpdateOne { - if ct != nil { - buo.SetTransport(*ct) +func (buo *BeaconUpdateOne) SetNillableTransport(ctt *c2pb.ActiveTransport_Type) *BeaconUpdateOne { + if ctt != nil { + buo.SetTransport(*ctt) } return buo } diff --git a/tavern/internal/ent/gql_where_input.go b/tavern/internal/ent/gql_where_input.go index 8a9076ea3..be56d565d 100644 --- a/tavern/internal/ent/gql_where_input.go +++ b/tavern/internal/ent/gql_where_input.go @@ -163,10 +163,10 @@ type BeaconWhereInput struct { IntervalNotNil bool `json:"intervalNotNil,omitempty"` // "transport" field predicates. - Transport *c2pb.Beacon_Transport `json:"transport,omitempty"` - TransportNEQ *c2pb.Beacon_Transport `json:"transportNEQ,omitempty"` - TransportIn []c2pb.Beacon_Transport `json:"transportIn,omitempty"` - TransportNotIn []c2pb.Beacon_Transport `json:"transportNotIn,omitempty"` + Transport *c2pb.ActiveTransport_Type `json:"transport,omitempty"` + TransportNEQ *c2pb.ActiveTransport_Type `json:"transportNEQ,omitempty"` + TransportIn []c2pb.ActiveTransport_Type `json:"transportIn,omitempty"` + TransportNotIn []c2pb.ActiveTransport_Type `json:"transportNotIn,omitempty"` // "host" edge predicates. HasHost *bool `json:"hasHost,omitempty"` diff --git a/tavern/internal/ent/migrate/schema.go b/tavern/internal/ent/migrate/schema.go index 78c9db8ba..c5cc098bc 100644 --- a/tavern/internal/ent/migrate/schema.go +++ b/tavern/internal/ent/migrate/schema.go @@ -21,7 +21,7 @@ var ( {Name: "last_seen_at", Type: field.TypeTime, Nullable: true}, {Name: "next_seen_at", Type: field.TypeTime, Nullable: true}, {Name: "interval", Type: field.TypeUint64, Nullable: true}, - {Name: "transport", Type: field.TypeEnum, Enums: []string{"TRANSPORT_GRPC", "TRANSPORT_HTTP1", "TRANSPORT_DNS", "TRANSPORT_UNSPECIFIED"}}, + {Name: "transport", Type: field.TypeEnum, Enums: []string{"TRANSPORT_DNS", "TRANSPORT_GRPC", "TRANSPORT_HTTP1", "TRANSPORT_UNSPECIFIED"}}, {Name: "beacon_host", Type: field.TypeInt}, } // BeaconsTable holds the schema information for the "beacons" table. diff --git a/tavern/internal/ent/mutation.go b/tavern/internal/ent/mutation.go index 9c016f526..709d9a99b 100644 --- a/tavern/internal/ent/mutation.go +++ b/tavern/internal/ent/mutation.go @@ -69,7 +69,7 @@ type BeaconMutation struct { next_seen_at *time.Time interval *uint64 addinterval *int64 - transport *c2pb.Beacon_Transport + transport *c2pb.ActiveTransport_Type clearedFields map[string]struct{} host *int clearedhost bool @@ -593,12 +593,12 @@ func (m *BeaconMutation) ResetInterval() { } // SetTransport sets the "transport" field. -func (m *BeaconMutation) SetTransport(ct c2pb.Beacon_Transport) { - m.transport = &ct +func (m *BeaconMutation) SetTransport(ctt c2pb.ActiveTransport_Type) { + m.transport = &ctt } // Transport returns the value of the "transport" field in the mutation. -func (m *BeaconMutation) Transport() (r c2pb.Beacon_Transport, exists bool) { +func (m *BeaconMutation) Transport() (r c2pb.ActiveTransport_Type, exists bool) { v := m.transport if v == nil { return @@ -609,7 +609,7 @@ func (m *BeaconMutation) Transport() (r c2pb.Beacon_Transport, exists bool) { // OldTransport returns the old "transport" field's value of the Beacon entity. // If the Beacon object wasn't provided to the builder, the object is fetched from the database. // An error is returned if the mutation operation is not UpdateOne, or the database query fails. -func (m *BeaconMutation) OldTransport(ctx context.Context) (v c2pb.Beacon_Transport, err error) { +func (m *BeaconMutation) OldTransport(ctx context.Context) (v c2pb.ActiveTransport_Type, err error) { if !m.op.Is(OpUpdateOne) { return v, errors.New("OldTransport is only allowed on UpdateOne operations") } @@ -970,7 +970,7 @@ func (m *BeaconMutation) SetField(name string, value ent.Value) error { m.SetInterval(v) return nil case beacon.FieldTransport: - v, ok := value.(c2pb.Beacon_Transport) + v, ok := value.(c2pb.ActiveTransport_Type) if !ok { return fmt.Errorf("unexpected type %T for field %s", value, name) } diff --git a/tavern/internal/ent/schema/beacon.go b/tavern/internal/ent/schema/beacon.go index 9ddc10b57..4d16b4521 100644 --- a/tavern/internal/ent/schema/beacon.go +++ b/tavern/internal/ent/schema/beacon.go @@ -12,6 +12,7 @@ import ( "entgo.io/ent/schema" "entgo.io/ent/schema/edge" "entgo.io/ent/schema/field" + "realm.pub/tavern/internal/c2/c2pb" "realm.pub/tavern/internal/namegen" ) @@ -73,6 +74,12 @@ func (Beacon) Fields() []ent.Field { entgql.Skip(entgql.SkipMutationUpdateInput), ). Comment("Duration until next callback, in seconds."), + field.Enum("transport"). + GoType(c2pb.ActiveTransport_Type(0)). + Annotations( + entgql.Skip(entgql.SkipMutationUpdateInput), + ). + Comment("Beacon's current transport."), } } diff --git a/tavern/internal/graphql/generated/ent.generated.go b/tavern/internal/graphql/generated/ent.generated.go index c27c1f706..1c6390749 100644 --- a/tavern/internal/graphql/generated/ent.generated.go +++ b/tavern/internal/graphql/generated/ent.generated.go @@ -4734,9 +4734,9 @@ func (ec *executionContext) _Beacon_transport(ctx context.Context, field graphql } return graphql.Null } - res := resTmp.(c2pb.Beacon_Transport) + res := resTmp.(c2pb.ActiveTransport_Type) fc.Result = res - return ec.marshalNBeaconTransport2realmᚗpubᚋtavernᚋinternalᚋc2ᚋc2pbᚐBeacon_Transport(ctx, field.Selections, res) + return ec.marshalNBeaconActiveTransport_Type2realmᚗpubᚋtavernᚋinternalᚋc2ᚋc2pbᚐActiveTransport_Type(ctx, field.Selections, res) } func (ec *executionContext) fieldContext_Beacon_transport(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { @@ -4746,7 +4746,7 @@ func (ec *executionContext) fieldContext_Beacon_transport(_ context.Context, fie IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type BeaconTransport does not have child fields") + return nil, errors.New("field of type BeaconActiveTransport_Type does not have child fields") }, } return fc, nil @@ -16446,28 +16446,28 @@ func (ec *executionContext) unmarshalInputBeaconWhereInput(ctx context.Context, it.IntervalNotNil = data case "transport": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("transport")) - data, err := ec.unmarshalOBeaconTransport2ᚖrealmᚗpubᚋtavernᚋinternalᚋc2ᚋc2pbᚐBeacon_Transport(ctx, v) + data, err := ec.unmarshalOBeaconActiveTransport_Type2ᚖrealmᚗpubᚋtavernᚋinternalᚋc2ᚋc2pbᚐActiveTransport_Type(ctx, v) if err != nil { return it, err } it.Transport = data case "transportNEQ": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("transportNEQ")) - data, err := ec.unmarshalOBeaconTransport2ᚖrealmᚗpubᚋtavernᚋinternalᚋc2ᚋc2pbᚐBeacon_Transport(ctx, v) + data, err := ec.unmarshalOBeaconActiveTransport_Type2ᚖrealmᚗpubᚋtavernᚋinternalᚋc2ᚋc2pbᚐActiveTransport_Type(ctx, v) if err != nil { return it, err } it.TransportNEQ = data case "transportIn": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("transportIn")) - data, err := ec.unmarshalOBeaconTransport2ᚕrealmᚗpubᚋtavernᚋinternalᚋc2ᚋc2pbᚐBeacon_Transportᚄ(ctx, v) + data, err := ec.unmarshalOBeaconActiveTransport_Type2ᚕrealmᚗpubᚋtavernᚋinternalᚋc2ᚋc2pbᚐActiveTransport_Typeᚄ(ctx, v) if err != nil { return it, err } it.TransportIn = data case "transportNotIn": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("transportNotIn")) - data, err := ec.unmarshalOBeaconTransport2ᚕrealmᚗpubᚋtavernᚋinternalᚋc2ᚋc2pbᚐBeacon_Transportᚄ(ctx, v) + data, err := ec.unmarshalOBeaconActiveTransport_Type2ᚕrealmᚗpubᚋtavernᚋinternalᚋc2ᚋc2pbᚐActiveTransport_Typeᚄ(ctx, v) if err != nil { return it, err } @@ -28565,6 +28565,16 @@ func (ec *executionContext) marshalNBeacon2ᚖrealmᚗpubᚋtavernᚋinternalᚋ return ec._Beacon(ctx, sel, v) } +func (ec *executionContext) unmarshalNBeaconActiveTransport_Type2realmᚗpubᚋtavernᚋinternalᚋc2ᚋc2pbᚐActiveTransport_Type(ctx context.Context, v any) (c2pb.ActiveTransport_Type, error) { + var res c2pb.ActiveTransport_Type + err := res.UnmarshalGQL(v) + return res, graphql.ErrorOnPath(ctx, err) +} + +func (ec *executionContext) marshalNBeaconActiveTransport_Type2realmᚗpubᚋtavernᚋinternalᚋc2ᚋc2pbᚐActiveTransport_Type(ctx context.Context, sel ast.SelectionSet, v c2pb.ActiveTransport_Type) graphql.Marshaler { + return v +} + func (ec *executionContext) marshalNBeaconConnection2realmᚗpubᚋtavernᚋinternalᚋentᚐBeaconConnection(ctx context.Context, sel ast.SelectionSet, v ent.BeaconConnection) graphql.Marshaler { return ec._BeaconConnection(ctx, sel, &v) } @@ -28600,16 +28610,6 @@ func (ec *executionContext) marshalNBeaconOrderField2ᚖrealmᚗpubᚋtavernᚋi return v } -func (ec *executionContext) unmarshalNBeaconTransport2realmᚗpubᚋtavernᚋinternalᚋc2ᚋc2pbᚐBeacon_Transport(ctx context.Context, v any) (c2pb.Beacon_Transport, error) { - var res c2pb.Beacon_Transport - err := res.UnmarshalGQL(v) - return res, graphql.ErrorOnPath(ctx, err) -} - -func (ec *executionContext) marshalNBeaconTransport2realmᚗpubᚋtavernᚋinternalᚋc2ᚋc2pbᚐBeacon_Transport(ctx context.Context, sel ast.SelectionSet, v c2pb.Beacon_Transport) graphql.Marshaler { - return v -} - func (ec *executionContext) unmarshalNBeaconWhereInput2ᚖrealmᚗpubᚋtavernᚋinternalᚋentᚐBeaconWhereInput(ctx context.Context, v any) (*ent.BeaconWhereInput, error) { res, err := ec.unmarshalInputBeaconWhereInput(ctx, v) return &res, graphql.ErrorOnPath(ctx, err) @@ -29366,7 +29366,27 @@ func (ec *executionContext) marshalOBeacon2ᚖrealmᚗpubᚋtavernᚋinternalᚋ return ec._Beacon(ctx, sel, v) } -func (ec *executionContext) marshalOBeaconEdge2ᚕᚖrealmᚗpubᚋtavernᚋinternalᚋentᚐBeaconEdge(ctx context.Context, sel ast.SelectionSet, v []*ent.BeaconEdge) graphql.Marshaler { +func (ec *executionContext) unmarshalOBeaconActiveTransport_Type2ᚕrealmᚗpubᚋtavernᚋinternalᚋc2ᚋc2pbᚐActiveTransport_Typeᚄ(ctx context.Context, v any) ([]c2pb.ActiveTransport_Type, error) { + if v == nil { + return nil, nil + } + var vSlice []any + if v != nil { + vSlice = graphql.CoerceList(v) + } + var err error + res := make([]c2pb.ActiveTransport_Type, len(vSlice)) + for i := range vSlice { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithIndex(i)) + res[i], err = ec.unmarshalNBeaconActiveTransport_Type2realmᚗpubᚋtavernᚋinternalᚋc2ᚋc2pbᚐActiveTransport_Type(ctx, vSlice[i]) + if err != nil { + return nil, err + } + } + return res, nil +} + +func (ec *executionContext) marshalOBeaconActiveTransport_Type2ᚕrealmᚗpubᚋtavernᚋinternalᚋc2ᚋc2pbᚐActiveTransport_Typeᚄ(ctx context.Context, sel ast.SelectionSet, v []c2pb.ActiveTransport_Type) graphql.Marshaler { if v == nil { return graphql.Null } @@ -29393,7 +29413,7 @@ func (ec *executionContext) marshalOBeaconEdge2ᚕᚖrealmᚗpubᚋtavernᚋinte if !isLen1 { defer wg.Done() } - ret[i] = ec.marshalOBeaconEdge2ᚖrealmᚗpubᚋtavernᚋinternalᚋentᚐBeaconEdge(ctx, sel, v[i]) + ret[i] = ec.marshalNBeaconActiveTransport_Type2realmᚗpubᚋtavernᚋinternalᚋc2ᚋc2pbᚐActiveTransport_Type(ctx, sel, v[i]) } if isLen1 { f(i) @@ -29404,57 +29424,32 @@ func (ec *executionContext) marshalOBeaconEdge2ᚕᚖrealmᚗpubᚋtavernᚋinte } wg.Wait() - return ret -} - -func (ec *executionContext) marshalOBeaconEdge2ᚖrealmᚗpubᚋtavernᚋinternalᚋentᚐBeaconEdge(ctx context.Context, sel ast.SelectionSet, v *ent.BeaconEdge) graphql.Marshaler { - if v == nil { - return graphql.Null + for _, e := range ret { + if e == graphql.Null { + return graphql.Null + } } - return ec._BeaconEdge(ctx, sel, v) + + return ret } -func (ec *executionContext) unmarshalOBeaconOrder2ᚕᚖrealmᚗpubᚋtavernᚋinternalᚋentᚐBeaconOrderᚄ(ctx context.Context, v any) ([]*ent.BeaconOrder, error) { +func (ec *executionContext) unmarshalOBeaconActiveTransport_Type2ᚖrealmᚗpubᚋtavernᚋinternalᚋc2ᚋc2pbᚐActiveTransport_Type(ctx context.Context, v any) (*c2pb.ActiveTransport_Type, error) { if v == nil { return nil, nil } - var vSlice []any - if v != nil { - vSlice = graphql.CoerceList(v) - } - var err error - res := make([]*ent.BeaconOrder, len(vSlice)) - for i := range vSlice { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithIndex(i)) - res[i], err = ec.unmarshalNBeaconOrder2ᚖrealmᚗpubᚋtavernᚋinternalᚋentᚐBeaconOrder(ctx, vSlice[i]) - if err != nil { - return nil, err - } - } - return res, nil + var res = new(c2pb.ActiveTransport_Type) + err := res.UnmarshalGQL(v) + return res, graphql.ErrorOnPath(ctx, err) } -func (ec *executionContext) unmarshalOBeaconTransport2ᚕrealmᚗpubᚋtavernᚋinternalᚋc2ᚋc2pbᚐBeacon_Transportᚄ(ctx context.Context, v any) ([]c2pb.Beacon_Transport, error) { +func (ec *executionContext) marshalOBeaconActiveTransport_Type2ᚖrealmᚗpubᚋtavernᚋinternalᚋc2ᚋc2pbᚐActiveTransport_Type(ctx context.Context, sel ast.SelectionSet, v *c2pb.ActiveTransport_Type) graphql.Marshaler { if v == nil { - return nil, nil - } - var vSlice []any - if v != nil { - vSlice = graphql.CoerceList(v) - } - var err error - res := make([]c2pb.Beacon_Transport, len(vSlice)) - for i := range vSlice { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithIndex(i)) - res[i], err = ec.unmarshalNBeaconTransport2realmᚗpubᚋtavernᚋinternalᚋc2ᚋc2pbᚐBeacon_Transport(ctx, vSlice[i]) - if err != nil { - return nil, err - } + return graphql.Null } - return res, nil + return v } -func (ec *executionContext) marshalOBeaconTransport2ᚕrealmᚗpubᚋtavernᚋinternalᚋc2ᚋc2pbᚐBeacon_Transportᚄ(ctx context.Context, sel ast.SelectionSet, v []c2pb.Beacon_Transport) graphql.Marshaler { +func (ec *executionContext) marshalOBeaconEdge2ᚕᚖrealmᚗpubᚋtavernᚋinternalᚋentᚐBeaconEdge(ctx context.Context, sel ast.SelectionSet, v []*ent.BeaconEdge) graphql.Marshaler { if v == nil { return graphql.Null } @@ -29481,7 +29476,7 @@ func (ec *executionContext) marshalOBeaconTransport2ᚕrealmᚗpubᚋtavernᚋin if !isLen1 { defer wg.Done() } - ret[i] = ec.marshalNBeaconTransport2realmᚗpubᚋtavernᚋinternalᚋc2ᚋc2pbᚐBeacon_Transport(ctx, sel, v[i]) + ret[i] = ec.marshalOBeaconEdge2ᚖrealmᚗpubᚋtavernᚋinternalᚋentᚐBeaconEdge(ctx, sel, v[i]) } if isLen1 { f(i) @@ -29492,29 +29487,34 @@ func (ec *executionContext) marshalOBeaconTransport2ᚕrealmᚗpubᚋtavernᚋin } wg.Wait() - for _, e := range ret { - if e == graphql.Null { - return graphql.Null - } - } - return ret } -func (ec *executionContext) unmarshalOBeaconTransport2ᚖrealmᚗpubᚋtavernᚋinternalᚋc2ᚋc2pbᚐBeacon_Transport(ctx context.Context, v any) (*c2pb.Beacon_Transport, error) { +func (ec *executionContext) marshalOBeaconEdge2ᚖrealmᚗpubᚋtavernᚋinternalᚋentᚐBeaconEdge(ctx context.Context, sel ast.SelectionSet, v *ent.BeaconEdge) graphql.Marshaler { if v == nil { - return nil, nil + return graphql.Null } - var res = new(c2pb.Beacon_Transport) - err := res.UnmarshalGQL(v) - return res, graphql.ErrorOnPath(ctx, err) + return ec._BeaconEdge(ctx, sel, v) } -func (ec *executionContext) marshalOBeaconTransport2ᚖrealmᚗpubᚋtavernᚋinternalᚋc2ᚋc2pbᚐBeacon_Transport(ctx context.Context, sel ast.SelectionSet, v *c2pb.Beacon_Transport) graphql.Marshaler { +func (ec *executionContext) unmarshalOBeaconOrder2ᚕᚖrealmᚗpubᚋtavernᚋinternalᚋentᚐBeaconOrderᚄ(ctx context.Context, v any) ([]*ent.BeaconOrder, error) { if v == nil { - return graphql.Null + return nil, nil } - return v + var vSlice []any + if v != nil { + vSlice = graphql.CoerceList(v) + } + var err error + res := make([]*ent.BeaconOrder, len(vSlice)) + for i := range vSlice { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithIndex(i)) + res[i], err = ec.unmarshalNBeaconOrder2ᚖrealmᚗpubᚋtavernᚋinternalᚋentᚐBeaconOrder(ctx, vSlice[i]) + if err != nil { + return nil, err + } + } + return res, nil } func (ec *executionContext) unmarshalOBeaconWhereInput2ᚕᚖrealmᚗpubᚋtavernᚋinternalᚋentᚐBeaconWhereInputᚄ(ctx context.Context, v any) ([]*ent.BeaconWhereInput, error) { diff --git a/tavern/internal/graphql/generated/root_.generated.go b/tavern/internal/graphql/generated/root_.generated.go index 5f1ba83fa..eadca5f0c 100644 --- a/tavern/internal/graphql/generated/root_.generated.go +++ b/tavern/internal/graphql/generated/root_.generated.go @@ -2436,9 +2436,9 @@ type Beacon implements Node { """ interval: Uint64 """ - Beacons current transport. + Beacon's current transport. """ - transport: BeaconTransport! + transport: BeaconActiveTransport_Type! """ Host this beacon is running on. """ @@ -2507,6 +2507,15 @@ type Beacon implements Node { ): ShellConnection! } """ +BeaconActiveTransport_Type is enum for the field transport +""" +enum BeaconActiveTransport_Type @goModel(model: "realm.pub/tavern/internal/c2/c2pb.ActiveTransport_Type") { + TRANSPORT_DNS + TRANSPORT_GRPC + TRANSPORT_HTTP1 + TRANSPORT_UNSPECIFIED +} +""" A connection to a list of items. """ type BeaconConnection { @@ -2560,14 +2569,6 @@ enum BeaconOrderField { INTERVAL } """ -BeaconTransport is enum for the field transport -""" -enum BeaconTransport @goModel(model: "realm.pub/tavern/internal/c2/c2pb.Beacon_Transport") { - TRANSPORT_GRPC - TRANSPORT_HTTP1 - TRANSPORT_UNSPECIFIED -} -""" BeaconWhereInput is used for filtering Beacon objects. Input was generated by ent. """ @@ -2718,10 +2719,10 @@ input BeaconWhereInput { """ transport field predicates """ - transport: BeaconTransport - transportNEQ: BeaconTransport - transportIn: [BeaconTransport!] - transportNotIn: [BeaconTransport!] + transport: BeaconActiveTransport_Type + transportNEQ: BeaconActiveTransport_Type + transportIn: [BeaconActiveTransport_Type!] + transportNotIn: [BeaconActiveTransport_Type!] """ host edge predicates """ diff --git a/tavern/internal/graphql/schema.graphql b/tavern/internal/graphql/schema.graphql index 927217486..5d7e8b1f3 100644 --- a/tavern/internal/graphql/schema.graphql +++ b/tavern/internal/graphql/schema.graphql @@ -44,9 +44,9 @@ type Beacon implements Node { """ interval: Uint64 """ - Beacons current transport. + Beacon's current transport. """ - transport: BeaconTransport! + transport: BeaconActiveTransport_Type! """ Host this beacon is running on. """ @@ -115,6 +115,15 @@ type Beacon implements Node { ): ShellConnection! } """ +BeaconActiveTransport_Type is enum for the field transport +""" +enum BeaconActiveTransport_Type @goModel(model: "realm.pub/tavern/internal/c2/c2pb.ActiveTransport_Type") { + TRANSPORT_DNS + TRANSPORT_GRPC + TRANSPORT_HTTP1 + TRANSPORT_UNSPECIFIED +} +""" A connection to a list of items. """ type BeaconConnection { @@ -168,14 +177,6 @@ enum BeaconOrderField { INTERVAL } """ -BeaconTransport is enum for the field transport -""" -enum BeaconTransport @goModel(model: "realm.pub/tavern/internal/c2/c2pb.Beacon_Transport") { - TRANSPORT_GRPC - TRANSPORT_HTTP1 - TRANSPORT_UNSPECIFIED -} -""" BeaconWhereInput is used for filtering Beacon objects. Input was generated by ent. """ @@ -326,10 +327,10 @@ input BeaconWhereInput { """ transport field predicates """ - transport: BeaconTransport - transportNEQ: BeaconTransport - transportIn: [BeaconTransport!] - transportNotIn: [BeaconTransport!] + transport: BeaconActiveTransport_Type + transportNEQ: BeaconActiveTransport_Type + transportIn: [BeaconActiveTransport_Type!] + transportNotIn: [BeaconActiveTransport_Type!] """ host edge predicates """ diff --git a/tavern/internal/graphql/schema/ent.graphql b/tavern/internal/graphql/schema/ent.graphql index b9c92cbba..369bacb81 100644 --- a/tavern/internal/graphql/schema/ent.graphql +++ b/tavern/internal/graphql/schema/ent.graphql @@ -39,9 +39,9 @@ type Beacon implements Node { """ interval: Uint64 """ - Beacons current transport. + Beacon's current transport. """ - transport: BeaconTransport! + transport: BeaconActiveTransport_Type! """ Host this beacon is running on. """ @@ -110,6 +110,15 @@ type Beacon implements Node { ): ShellConnection! } """ +BeaconActiveTransport_Type is enum for the field transport +""" +enum BeaconActiveTransport_Type @goModel(model: "realm.pub/tavern/internal/c2/c2pb.ActiveTransport_Type") { + TRANSPORT_DNS + TRANSPORT_GRPC + TRANSPORT_HTTP1 + TRANSPORT_UNSPECIFIED +} +""" A connection to a list of items. """ type BeaconConnection { @@ -163,14 +172,6 @@ enum BeaconOrderField { INTERVAL } """ -BeaconTransport is enum for the field transport -""" -enum BeaconTransport @goModel(model: "realm.pub/tavern/internal/c2/c2pb.Beacon_Transport") { - TRANSPORT_GRPC - TRANSPORT_HTTP1 - TRANSPORT_UNSPECIFIED -} -""" BeaconWhereInput is used for filtering Beacon objects. Input was generated by ent. """ @@ -321,10 +322,10 @@ input BeaconWhereInput { """ transport field predicates """ - transport: BeaconTransport - transportNEQ: BeaconTransport - transportIn: [BeaconTransport!] - transportNotIn: [BeaconTransport!] + transport: BeaconActiveTransport_Type + transportNEQ: BeaconActiveTransport_Type + transportIn: [BeaconActiveTransport_Type!] + transportNotIn: [BeaconActiveTransport_Type!] """ host edge predicates """ diff --git a/tavern/internal/www/schema.graphql b/tavern/internal/www/schema.graphql index 927217486..5d7e8b1f3 100644 --- a/tavern/internal/www/schema.graphql +++ b/tavern/internal/www/schema.graphql @@ -44,9 +44,9 @@ type Beacon implements Node { """ interval: Uint64 """ - Beacons current transport. + Beacon's current transport. """ - transport: BeaconTransport! + transport: BeaconActiveTransport_Type! """ Host this beacon is running on. """ @@ -115,6 +115,15 @@ type Beacon implements Node { ): ShellConnection! } """ +BeaconActiveTransport_Type is enum for the field transport +""" +enum BeaconActiveTransport_Type @goModel(model: "realm.pub/tavern/internal/c2/c2pb.ActiveTransport_Type") { + TRANSPORT_DNS + TRANSPORT_GRPC + TRANSPORT_HTTP1 + TRANSPORT_UNSPECIFIED +} +""" A connection to a list of items. """ type BeaconConnection { @@ -168,14 +177,6 @@ enum BeaconOrderField { INTERVAL } """ -BeaconTransport is enum for the field transport -""" -enum BeaconTransport @goModel(model: "realm.pub/tavern/internal/c2/c2pb.Beacon_Transport") { - TRANSPORT_GRPC - TRANSPORT_HTTP1 - TRANSPORT_UNSPECIFIED -} -""" BeaconWhereInput is used for filtering Beacon objects. Input was generated by ent. """ @@ -326,10 +327,10 @@ input BeaconWhereInput { """ transport field predicates """ - transport: BeaconTransport - transportNEQ: BeaconTransport - transportIn: [BeaconTransport!] - transportNotIn: [BeaconTransport!] + transport: BeaconActiveTransport_Type + transportNEQ: BeaconActiveTransport_Type + transportIn: [BeaconActiveTransport_Type!] + transportNotIn: [BeaconActiveTransport_Type!] """ host edge predicates """ From d21c50b6018b74fc233328cd6052c3c6dac8ea27 Mon Sep 17 00:00:00 2001 From: hulto <7121375+hulto@users.noreply.github.com> Date: Mon, 29 Dec 2025 22:46:12 +0000 Subject: [PATCH 03/18] Type --- tavern/internal/c2/api_claim_tasks.go | 2 +- tavern/internal/ent/beacon_create.go | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/tavern/internal/c2/api_claim_tasks.go b/tavern/internal/c2/api_claim_tasks.go index bd63fa9ac..16326ba65 100644 --- a/tavern/internal/c2/api_claim_tasks.go +++ b/tavern/internal/c2/api_claim_tasks.go @@ -164,7 +164,7 @@ func (srv *Server) ClaimTasks(ctx context.Context, req *c2pb.ClaimTasksRequest) SetLastSeenAt(now). SetNextSeenAt(now.Add(time.Duration(req.Beacon.ActiveTransport.Interval) * time.Second)). SetInterval(req.Beacon.ActiveTransport.Interval). - SetTransport(req.Beacon.ActiveTransport.Transport). + SetTransport(req.Beacon.ActiveTransport.Type). OnConflict(). UpdateNewValues(). ID(ctx) diff --git a/tavern/internal/ent/beacon_create.go b/tavern/internal/ent/beacon_create.go index 89c264ead..ad8e06d4b 100644 --- a/tavern/internal/ent/beacon_create.go +++ b/tavern/internal/ent/beacon_create.go @@ -26,6 +26,7 @@ type BeaconCreate struct { conflict []sql.ConflictOption } + // SetCreatedAt sets the "created_at" field. func (bc *BeaconCreate) SetCreatedAt(t time.Time) *BeaconCreate { bc.mutation.SetCreatedAt(t) From 0eb70afedef19df13e3a5972f2595d3da7a513b8 Mon Sep 17 00:00:00 2001 From: hulto <7121375+hulto@users.noreply.github.com> Date: Tue, 30 Dec 2025 00:28:35 +0000 Subject: [PATCH 04/18] clippy isnt angry --- implants/imix/src/agent.rs | 19 +++++- implants/imix/src/run.rs | 11 +++- implants/imixv2/src/agent.rs | 60 +++++++++++++---- .../imixv2/src/tests/agent_trait_tests.rs | 7 +- .../src/tests/callback_interval_test.rs | 6 +- .../runtime/messages/set_callback_interval.rs | 10 ++- .../src/runtime/messages/set_callback_uri.rs | 12 +++- implants/lib/pb/src/config.rs | 58 +++++++---------- implants/lib/pb/src/generated/c2.rs | 65 ++++++++++--------- implants/lib/transport/src/dns.rs | 6 +- implants/lib/transport/src/grpc.rs | 5 +- implants/lib/transport/src/http.rs | 4 +- implants/lib/transport/src/lib.rs | 4 +- implants/lib/transport/src/mock.rs | 9 +-- implants/lib/transport/src/transport.rs | 4 +- 15 files changed, 182 insertions(+), 98 deletions(-) diff --git a/implants/imix/src/agent.rs b/implants/imix/src/agent.rs index 3e58647f5..832bce170 100644 --- a/implants/imix/src/agent.rs +++ b/implants/imix/src/agent.rs @@ -1,5 +1,5 @@ use crate::task::TaskHandle; -use anyhow::Result; +use anyhow::{Context, Result}; use pb::{c2::ClaimTasksRequest, config::Config}; use std::time::{Duration, Instant}; use transport::Transport; @@ -88,7 +88,17 @@ impl Agent { * Callback once using the configured client to claim new tasks and report available output. */ pub async fn callback(&mut self) -> Result<()> { - self.t = T::new(self.cfg.callback_uri.clone(), self.cfg.proxy_uri.clone())?; + //TODO: Re-add proxy support + self.t = T::new( + self.cfg + .info + .clone() + .context("failed to get info")? + .active_transport + .context("failed to get transport")? + .uri, + None, + )?; self.claim_tasks(self.t.clone()).await?; self.report(self.t.clone()).await?; self.t = T::init(); // re-init to make sure no active connections during sleep @@ -121,7 +131,10 @@ impl Agent { } let interval = match self.cfg.info.clone() { - Some(b) => Ok(b.interval), + Some(b) => Ok(b + .active_transport + .context("failed to get transport")? + .interval), None => Err(anyhow::anyhow!("beacon info is missing from agent")), }?; let delay = match interval.checked_sub(start.elapsed().as_secs()) { diff --git a/implants/imix/src/run.rs b/implants/imix/src/run.rs index 1030e593e..057f6a325 100644 --- a/implants/imix/src/run.rs +++ b/implants/imix/src/run.rs @@ -20,7 +20,16 @@ pub async fn handle_main() { loop { let cfg = Config::default_with_imix_verison(VERSION); - let retry_interval = cfg.retry_interval; + let retry_interval = if let Some(beacon) = cfg.info.as_ref() { + if let Some(transport) = &beacon.active_transport { + transport.interval + } else { + 5 + } + } else { + 5 + }; + #[cfg(debug_assertions)] log::info!("agent config initialized {:#?}", cfg.clone()); diff --git a/implants/imixv2/src/agent.rs b/implants/imixv2/src/agent.rs index 82bd4b1ee..ee9da0ec5 100644 --- a/implants/imixv2/src/agent.rs +++ b/implants/imixv2/src/agent.rs @@ -29,7 +29,15 @@ impl ImixAgent { runtime_handle: tokio::runtime::Handle, task_registry: Arc, ) -> Self { - let uri = config.callback_uri.clone(); + //TODO: simplyify this section transport, callback_uris, active_uri_idx, and config seem to duplicate information. + let uri = config + .clone() + .info + .unwrap() + .active_transport + .unwrap() + .uri + .clone(); Self { config: Arc::new(RwLock::new(config)), transport: Arc::new(RwLock::new(transport)), @@ -52,7 +60,13 @@ impl ImixAgent { .info .as_ref() .ok_or_else(|| anyhow::anyhow!("No beacon info in config"))?; - Ok(info.interval) + let interval = info + .active_transport + .as_ref() + .ok_or_else(|| anyhow::anyhow!("no active transport set"))? + .interval; + + Ok(interval) } // Triggers config.refresh_primary_ip() in a write lock @@ -109,8 +123,9 @@ impl ImixAgent { // Fallback, should not happen unless empty uris.first().cloned().unwrap_or_default() }; - let cfg = self.config.read().await; - (callback_uri, cfg.proxy_uri.clone()) + // let cfg = self.config.read().await; + //TODO: Re-add proxy URI via an "extra" field in config. + (callback_uri, None) } pub async fn rotate_callback_uri(&self) { @@ -288,17 +303,38 @@ impl Agent for ImixAgent { .map_err(|e: String| e)?; let active_uri = self.get_active_callback_uri().unwrap_or_default(); + let config = cfg.clone(); + + let info = config + .info + .as_ref() + .context("failed to get config info") + .map_err(|e| e.to_string())?; + + let active_transport = info + .clone() + .active_transport + .context("failed to get active transport") + .map_err(|e| e.to_string())?; + map.insert("callback_uri".to_string(), active_uri); - if let Some(proxy) = &cfg.proxy_uri { - map.insert("proxy_uri".to_string(), proxy.clone()); - } - map.insert("retry_interval".to_string(), cfg.retry_interval.to_string()); + // TODO: Re-add proxy URI via an "extra" field in config. + // if let Some(proxy) = &cfg.proxy_uri { + // map.insert("proxy_uri".to_string(), proxy.clone()); + // } + map.insert( + "retry_interval".to_string(), + active_transport.interval.to_string(), + ); map.insert("run_once".to_string(), cfg.run_once.to_string()); if let Some(info) = &cfg.info { map.insert("beacon_id".to_string(), info.identifier.clone()); map.insert("principal".to_string(), info.principal.clone()); - map.insert("interval".to_string(), info.interval.to_string()); + map.insert( + "interval".to_string(), + active_transport.interval.to_string(), + ); if let Some(host) = &info.host { map.insert("hostname".to_string(), host.name.clone()); map.insert("platform".to_string(), host.platform.to_string()); @@ -355,8 +391,10 @@ impl Agent for ImixAgent { fn set_callback_interval(&self, interval: u64) -> Result<(), String> { self.block_on(async { let mut cfg = self.config.write().await; - if let Some(info) = &mut cfg.info { - info.interval = interval; + if let Some(info) = &mut cfg.info + && let Some(active_transport) = &mut info.active_transport + { + active_transport.interval = interval; } Ok(()) }) diff --git a/implants/imixv2/src/tests/agent_trait_tests.rs b/implants/imixv2/src/tests/agent_trait_tests.rs index 879e8c2af..acbed9403 100644 --- a/implants/imixv2/src/tests/agent_trait_tests.rs +++ b/implants/imixv2/src/tests/agent_trait_tests.rs @@ -199,9 +199,14 @@ async fn test_imix_agent_report_file() { #[allow(clippy::field_reassign_with_default)] async fn test_imix_agent_config_access() { let mut config = Config::default(); - config.callback_uri = "http://localhost:8080".to_string(); + config.info = Some(pb::c2::Beacon { identifier: "agent1".to_string(), + active_transport: Some(pb::c2::ActiveTransport { + uri: "http://localhost:8080".to_string(), + interval: 5, + ..Default::default() + }), ..Default::default() }); diff --git a/implants/imixv2/src/tests/callback_interval_test.rs b/implants/imixv2/src/tests/callback_interval_test.rs index 2630763d8..a20accc0f 100644 --- a/implants/imixv2/src/tests/callback_interval_test.rs +++ b/implants/imixv2/src/tests/callback_interval_test.rs @@ -25,7 +25,11 @@ async fn test_imix_agent_get_callback_interval_error() { async fn test_imix_agent_get_callback_interval_success() { let mut config = Config::default(); config.info = Some(pb::c2::Beacon { - interval: 10, + active_transport: Some(pb::c2::ActiveTransport { + uri: "http://example.com/callback".to_string(), + interval: 10, + ..Default::default() + }), ..Default::default() }); diff --git a/implants/lib/eldritch/src/runtime/messages/set_callback_interval.rs b/implants/lib/eldritch/src/runtime/messages/set_callback_interval.rs index fabb3a526..b3ee8d68a 100644 --- a/implants/lib/eldritch/src/runtime/messages/set_callback_interval.rs +++ b/implants/lib/eldritch/src/runtime/messages/set_callback_interval.rs @@ -27,8 +27,14 @@ impl SyncDispatcher for SetCallbackIntervalMessage { principal: b.principal, host: b.host, agent: b.agent, - interval: self.new_interval, - transport: transport.get_type() as i32, + active_transport: Some(pb::c2::ActiveTransport { + uri: b + .active_transport + .as_ref() + .map_or(String::new(), |at| at.uri.clone()), + interval: self.new_interval, + r#type: transport.get_type() as i32, + }), }); Ok(c) } diff --git a/implants/lib/eldritch/src/runtime/messages/set_callback_uri.rs b/implants/lib/eldritch/src/runtime/messages/set_callback_uri.rs index 354ecd255..1d49791c7 100644 --- a/implants/lib/eldritch/src/runtime/messages/set_callback_uri.rs +++ b/implants/lib/eldritch/src/runtime/messages/set_callback_uri.rs @@ -1,5 +1,5 @@ use super::{SyncDispatcher, Transport}; -use anyhow::Result; +use anyhow::{Context, Result}; use pb::config::Config; /* @@ -16,7 +16,15 @@ pub struct SetCallbackUriMessage { impl SyncDispatcher for SetCallbackUriMessage { fn dispatch(self, _transport: &mut impl Transport, cfg: Config) -> Result { let mut c = cfg.clone(); - c.callback_uri = self.new_uri; + //TODO: make sure this works :? + c.info + .as_mut() + .context("missing config info")? + .active_transport + .as_mut() + .context("missing active transport")? + .uri = self.new_uri; + Ok(c) } } diff --git a/implants/lib/pb/src/config.rs b/implants/lib/pb/src/config.rs index b0a8b2e57..60dfe13cf 100644 --- a/implants/lib/pb/src/config.rs +++ b/implants/lib/pb/src/config.rs @@ -1,7 +1,7 @@ use tonic::transport; use uuid::Uuid; -use crate::c2::beacon::Transport; +use crate::c2::ActiveTransport; /// Config holds values necessary to configure an Agent. #[allow(clippy::derive_partial_eq_without_eq)] @@ -9,13 +9,13 @@ use crate::c2::beacon::Transport; pub struct Config { #[prost(message, optional, tag = "1")] pub info: ::core::option::Option, - #[prost(string, tag = "2")] - pub callback_uri: ::prost::alloc::string::String, - #[prost(string, optional, tag = "3")] - pub proxy_uri: ::core::option::Option<::prost::alloc::string::String>, - #[prost(uint64, tag = "4")] - pub retry_interval: u64, - #[prost(bool, tag = "5")] + // #[prost(string, tag = "2")] + // pub callback_uri: ::prost::alloc::string::String, + // #[prost(string, optional, tag = "3")] + // pub proxy_uri: ::core::option::Option<::prost::alloc::string::String>, + // #[prost(uint64, tag = "4")] + // pub retry_interval: u64, + #[prost(bool, tag = "2")] pub run_once: bool, } @@ -106,18 +106,17 @@ impl Config { let beacon_id = std::env::var("IMIX_BEACON_ID").unwrap_or_else(|_| String::from(Uuid::new_v4())); - #[cfg(feature = "dns")] - let transport = crate::c2::beacon::Transport::Dns; - #[cfg(feature = "http1")] - let transport = crate::c2::beacon::Transport::Http1; - #[cfg(feature = "grpc")] - let transport = crate::c2::beacon::Transport::Grpc; - #[cfg(not(any(feature = "dns", feature = "http1", feature = "grpc")))] - let transport = crate::c2::beacon::Transport::Unspecified; + let transport_type = match CALLBACK_URI.split(":").nth(0).unwrap_or("unspecified") { + "dns" => crate::c2::active_transport::Type::TransportDns, + "http1" => crate::c2::active_transport::Type::TransportHttp1, + "https1" => crate::c2::active_transport::Type::TransportHttp1, + "https" => crate::c2::active_transport::Type::TransportGrpc, + "http" => crate::c2::active_transport::Type::TransportGrpc, + _ => crate::c2::active_transport::Type::TransportUnspecified, + }; - let info = crate::c2::Beacon { - identifier: beacon_id, - principal: whoami::username(), + let active_transport = ActiveTransport { + uri: String::from(CALLBACK_URI), interval: match CALLBACK_INTERVAL.parse::() { Ok(i) => i, Err(_err) => { @@ -127,26 +126,19 @@ impl Config { 5_u64 } }, - transport: transport as i32, + r#type: transport_type as i32, + }; + + let info = crate::c2::Beacon { + identifier: beacon_id, + principal: whoami::username(), + active_transport: Some(active_transport), host: Some(host), agent: Some(agent), }; Config { info: Some(info), - callback_uri: String::from(CALLBACK_URI), - proxy_uri: get_system_proxy(), - retry_interval: match RETRY_INTERVAL.parse::() { - Ok(i) => i, - Err(_err) => { - #[cfg(debug_assertions)] - log::error!( - "failed to parse retry interval constant, defaulting to 5 seconds: {_err}" - ); - - 5 - } - }, run_once: RUN_ONCE, } } diff --git a/implants/lib/pb/src/generated/c2.rs b/implants/lib/pb/src/generated/c2.rs index 816200dd5..5da2c0683 100644 --- a/implants/lib/pb/src/generated/c2.rs +++ b/implants/lib/pb/src/generated/c2.rs @@ -6,26 +6,18 @@ pub struct Agent { #[prost(string, tag = "1")] pub identifier: ::prost::alloc::string::String, } -/// Beacon information that is unique to the current running beacon. #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] -pub struct Beacon { +pub struct ActiveTransport { #[prost(string, tag = "1")] - pub identifier: ::prost::alloc::string::String, - #[prost(string, tag = "2")] - pub principal: ::prost::alloc::string::String, - #[prost(message, optional, tag = "3")] - pub host: ::core::option::Option, - #[prost(message, optional, tag = "4")] - pub agent: ::core::option::Option, - /// Duration until next callback, in seconds. - #[prost(uint64, tag = "5")] + pub uri: ::prost::alloc::string::String, + #[prost(uint64, tag = "2")] pub interval: u64, - #[prost(enumeration = "beacon::Transport", tag = "6")] - pub transport: i32, + #[prost(enumeration = "active_transport::Type", tag = "3")] + pub r#type: i32, } -/// Nested message and enum types in `Beacon`. -pub mod beacon { +/// Nested message and enum types in `ActiveTransport`. +pub mod active_transport { #[derive( Clone, Copy, @@ -38,37 +30,52 @@ pub mod beacon { ::prost::Enumeration )] #[repr(i32)] - pub enum Transport { - Unspecified = 0, - Grpc = 1, - Http1 = 2, - Dns = 3, + pub enum Type { + TransportUnspecified = 0, + TransportGrpc = 1, + TransportHttp1 = 2, + TransportDns = 3, } - impl Transport { + impl Type { /// String value of the enum field names used in the ProtoBuf definition. /// /// The values are not transformed in any way and thus are considered stable /// (if the ProtoBuf definition does not change) and safe for programmatic use. pub fn as_str_name(&self) -> &'static str { match self { - Transport::Unspecified => "TRANSPORT_UNSPECIFIED", - Transport::Grpc => "TRANSPORT_GRPC", - Transport::Http1 => "TRANSPORT_HTTP1", - Transport::Dns => "TRANSPORT_DNS", + Type::TransportUnspecified => "TRANSPORT_UNSPECIFIED", + Type::TransportGrpc => "TRANSPORT_GRPC", + Type::TransportHttp1 => "TRANSPORT_HTTP1", + Type::TransportDns => "TRANSPORT_DNS", } } /// Creates an enum from field names used in the ProtoBuf definition. pub fn from_str_name(value: &str) -> ::core::option::Option { match value { - "TRANSPORT_UNSPECIFIED" => Some(Self::Unspecified), - "TRANSPORT_GRPC" => Some(Self::Grpc), - "TRANSPORT_HTTP1" => Some(Self::Http1), - "TRANSPORT_DNS" => Some(Self::Dns), + "TRANSPORT_UNSPECIFIED" => Some(Self::TransportUnspecified), + "TRANSPORT_GRPC" => Some(Self::TransportGrpc), + "TRANSPORT_HTTP1" => Some(Self::TransportHttp1), + "TRANSPORT_DNS" => Some(Self::TransportDns), _ => None, } } } } +/// Beacon information that is unique to the current running beacon. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Beacon { + #[prost(string, tag = "1")] + pub identifier: ::prost::alloc::string::String, + #[prost(string, tag = "2")] + pub principal: ::prost::alloc::string::String, + #[prost(message, optional, tag = "3")] + pub host: ::core::option::Option, + #[prost(message, optional, tag = "4")] + pub agent: ::core::option::Option, + #[prost(message, optional, tag = "5")] + pub active_transport: ::core::option::Option, +} /// Host information for the system a beacon is running on. #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] diff --git a/implants/lib/transport/src/dns.rs b/implants/lib/transport/src/dns.rs index cef8ece3b..6d302bd7d 100644 --- a/implants/lib/transport/src/dns.rs +++ b/implants/lib/transport/src/dns.rs @@ -1070,8 +1070,8 @@ impl Transport for DNS { )) } - fn get_type(&mut self) -> beacon::Transport { - beacon::Transport::Dns + fn get_type(&mut self) -> pb::c2::active_transport::Type { + return pb::c2::active_transport::Type::TransportDns; } fn is_active(&self) -> bool { @@ -1540,7 +1540,7 @@ mod tests { #[test] fn test_get_type() { let mut dns = DNS::init(); - assert_eq!(dns.get_type(), beacon::Transport::Dns); + assert_eq!(dns.get_type(), active_transport::Type::TransportDns); } // ============================================================ diff --git a/implants/lib/transport/src/grpc.rs b/implants/lib/transport/src/grpc.rs index 96551f712..be7321cb8 100644 --- a/implants/lib/transport/src/grpc.rs +++ b/implants/lib/transport/src/grpc.rs @@ -194,9 +194,10 @@ impl Transport for GRPC { Ok(()) } - fn get_type(&mut self) -> pb::c2::beacon::Transport { - return pb::c2::beacon::Transport::Grpc; + fn get_type(&mut self) -> pb::c2::active_transport::Type { + return pb::c2::active_transport::Type::TransportGrpc; } + fn is_active(&self) -> bool { self.grpc.is_some() } diff --git a/implants/lib/transport/src/http.rs b/implants/lib/transport/src/http.rs index 9a731f28e..3f429ae79 100644 --- a/implants/lib/transport/src/http.rs +++ b/implants/lib/transport/src/http.rs @@ -422,8 +422,8 @@ impl Transport for HTTP { )) } - fn get_type(&mut self) -> pb::c2::beacon::Transport { - return pb::c2::beacon::Transport::Http1; + fn get_type(&mut self) -> pb::c2::active_transport::Type { + return pb::c2::active_transport::Type::TransportHttp1; } fn is_active(&self) -> bool { diff --git a/implants/lib/transport/src/lib.rs b/implants/lib/transport/src/lib.rs index 44b51ff39..690a00bc1 100644 --- a/implants/lib/transport/src/lib.rs +++ b/implants/lib/transport/src/lib.rs @@ -208,7 +208,7 @@ impl Transport for ActiveTransport { } } - fn get_type(&mut self) -> beacon::Transport { + fn get_type(&mut self) -> active_transport::Type { match self { #[cfg(feature = "grpc")] Self::Grpc(t) => t.get_type(), @@ -218,7 +218,7 @@ impl Transport for ActiveTransport { Self::Dns(t) => t.get_type(), #[cfg(feature = "mock")] Self::Mock(t) => t.get_type(), - Self::Empty => beacon::Transport::Unspecified, + Self::Empty => active_transport::Type::TransportUnspecified, } } diff --git a/implants/lib/transport/src/mock.rs b/implants/lib/transport/src/mock.rs index eb19cf066..a76baaaa6 100644 --- a/implants/lib/transport/src/mock.rs +++ b/implants/lib/transport/src/mock.rs @@ -48,10 +48,11 @@ mock! { tx: tokio::sync::mpsc::Sender, ) -> Result<()>; - fn get_type(&mut self) -> pb::c2::beacon::Transport { - return Transport::Unspecified - } - fn is_active(&self) -> bool; + fn get_type(&mut self) -> pb::c2::active_transport::Type { + return pb::c2::active_transport::Type::TransportUnspecified; + } + + fn is_active(&self) -> bool; fn name(&self) -> &'static str; diff --git a/implants/lib/transport/src/transport.rs b/implants/lib/transport/src/transport.rs index 2848acbae..a59e8737e 100644 --- a/implants/lib/transport/src/transport.rs +++ b/implants/lib/transport/src/transport.rs @@ -1,5 +1,5 @@ use anyhow::Result; -use pb::c2::{beacon, *}; +use pb::c2::*; use std::sync::mpsc::{Receiver, Sender}; #[trait_variant::make(Transport: Send)] @@ -80,7 +80,7 @@ pub trait UnsafeTransport: Clone + Send { ) -> Result<()>; #[allow(dead_code)] - fn get_type(&mut self) -> beacon::Transport; + fn get_type(&mut self) -> active_transport::Type; /// Returns true if the transport is fully initialized and active #[allow(dead_code)] fn is_active(&self) -> bool; From 6cf77d6ebecd8dd9d8a24203502fa8072917160f Mon Sep 17 00:00:00 2001 From: hulto <7121375+hulto@users.noreply.github.com> Date: Tue, 30 Dec 2025 00:41:48 +0000 Subject: [PATCH 05/18] todo --- implants/lib/pb/src/config.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/implants/lib/pb/src/config.rs b/implants/lib/pb/src/config.rs index 60dfe13cf..57796822e 100644 --- a/implants/lib/pb/src/config.rs +++ b/implants/lib/pb/src/config.rs @@ -3,6 +3,8 @@ use uuid::Uuid; use crate::c2::ActiveTransport; +//TODO: Migrate most of this into a config crate or as a part of the agent. + /// Config holds values necessary to configure an Agent. #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] From c88f261ebc4466eeb74ba306a4f73e00661f3707 Mon Sep 17 00:00:00 2001 From: hulto <7121375+hulto@users.noreply.github.com> Date: Tue, 30 Dec 2025 00:43:07 +0000 Subject: [PATCH 06/18] generate --- tavern/internal/ent/beacon_create.go | 1 - 1 file changed, 1 deletion(-) diff --git a/tavern/internal/ent/beacon_create.go b/tavern/internal/ent/beacon_create.go index ad8e06d4b..89c264ead 100644 --- a/tavern/internal/ent/beacon_create.go +++ b/tavern/internal/ent/beacon_create.go @@ -26,7 +26,6 @@ type BeaconCreate struct { conflict []sql.ConflictOption } - // SetCreatedAt sets the "created_at" field. func (bc *BeaconCreate) SetCreatedAt(t time.Time) *BeaconCreate { bc.mutation.SetCreatedAt(t) From a69f1ad347bf6c09e51b6a460dabff28d9572657 Mon Sep 17 00:00:00 2001 From: hulto <7121375+hulto@users.noreply.github.com> Date: Tue, 30 Dec 2025 00:50:05 +0000 Subject: [PATCH 07/18] Add extra field --- implants/imix/src/run.rs | 2 +- implants/imixv2/src/run.rs | 2 +- .../runtime/messages/set_callback_interval.rs | 5 + implants/lib/pb/src/config.rs | 3 +- implants/lib/pb/src/generated/c2.rs | 2 + tavern/internal/c2/c2pb/c2.pb.go | 312 +++++++++--------- tavern/internal/c2/proto/c2.proto | 1 + 7 files changed, 173 insertions(+), 154 deletions(-) diff --git a/implants/imix/src/run.rs b/implants/imix/src/run.rs index 057f6a325..c57b53c81 100644 --- a/implants/imix/src/run.rs +++ b/implants/imix/src/run.rs @@ -19,7 +19,7 @@ pub async fn handle_main() { } loop { - let cfg = Config::default_with_imix_verison(VERSION); + let cfg = Config::default_with_imix_version(VERSION); let retry_interval = if let Some(beacon) = cfg.info.as_ref() { if let Some(transport) = &beacon.active_transport { transport.interval diff --git a/implants/imixv2/src/run.rs b/implants/imixv2/src/run.rs index 4c6b1a8eb..341366ce7 100644 --- a/implants/imixv2/src/run.rs +++ b/implants/imixv2/src/run.rs @@ -15,7 +15,7 @@ pub async fn run_agent() -> Result<()> { init_logger(); // Load config / defaults - let config = Config::default_with_imix_verison(VERSION); + let config = Config::default_with_imix_version(VERSION); #[cfg(debug_assertions)] log::info!("Loaded config: {config:#?}"); diff --git a/implants/lib/eldritch/src/runtime/messages/set_callback_interval.rs b/implants/lib/eldritch/src/runtime/messages/set_callback_interval.rs index b3ee8d68a..3cee84aed 100644 --- a/implants/lib/eldritch/src/runtime/messages/set_callback_interval.rs +++ b/implants/lib/eldritch/src/runtime/messages/set_callback_interval.rs @@ -22,6 +22,7 @@ impl SyncDispatcher for SetCallbackIntervalMessage { "SetCallbackIntervalMessage: beacon is missing from config" )), }?; + // TODO: we can probably just modify the interval not rebuild the entire beacon see set_callback_uri.rs c.info = Some(Beacon { identifier: b.identifier, principal: b.principal, @@ -34,6 +35,10 @@ impl SyncDispatcher for SetCallbackIntervalMessage { .map_or(String::new(), |at| at.uri.clone()), interval: self.new_interval, r#type: transport.get_type() as i32, + extra: b + .active_transport + .as_ref() + .map_or(String::new(), |at| at.extra.clone()), }), }); Ok(c) diff --git a/implants/lib/pb/src/config.rs b/implants/lib/pb/src/config.rs index 57796822e..3454edce3 100644 --- a/implants/lib/pb/src/config.rs +++ b/implants/lib/pb/src/config.rs @@ -90,7 +90,7 @@ pub const RUN_ONCE: bool = run_once!(); * Config methods. */ impl Config { - pub fn default_with_imix_verison(imix_version: &str) -> Self { + pub fn default_with_imix_version(imix_version: &str) -> Self { let agent = crate::c2::Agent { identifier: format!("imix-v{}", imix_version), }; @@ -129,6 +129,7 @@ impl Config { } }, r#type: transport_type as i32, + extra: String::from(""), }; let info = crate::c2::Beacon { diff --git a/implants/lib/pb/src/generated/c2.rs b/implants/lib/pb/src/generated/c2.rs index 5da2c0683..8b7266bf1 100644 --- a/implants/lib/pb/src/generated/c2.rs +++ b/implants/lib/pb/src/generated/c2.rs @@ -15,6 +15,8 @@ pub struct ActiveTransport { pub interval: u64, #[prost(enumeration = "active_transport::Type", tag = "3")] pub r#type: i32, + #[prost(string, tag = "4")] + pub extra: ::prost::alloc::string::String, } /// Nested message and enum types in `ActiveTransport`. pub mod active_transport { diff --git a/tavern/internal/c2/c2pb/c2.pb.go b/tavern/internal/c2/c2pb/c2.pb.go index 399b61185..3d862c233 100644 --- a/tavern/internal/c2/c2pb/c2.pb.go +++ b/tavern/internal/c2/c2pb/c2.pb.go @@ -229,6 +229,7 @@ type ActiveTransport struct { Uri string `protobuf:"bytes,1,opt,name=uri,proto3" json:"uri,omitempty"` Interval uint64 `protobuf:"varint,2,opt,name=interval,proto3" json:"interval,omitempty"` Type ActiveTransport_Type `protobuf:"varint,3,opt,name=type,proto3,enum=c2.ActiveTransport_Type" json:"type,omitempty"` + Extra string `protobuf:"bytes,4,opt,name=extra,proto3" json:"extra,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -284,6 +285,13 @@ func (x *ActiveTransport) GetType() ActiveTransport_Type { return ActiveTransport_TRANSPORT_UNSPECIFIED } +func (x *ActiveTransport) GetExtra() string { + if x != nil { + return x.Extra + } + return "" +} + // Beacon information that is unique to the current running beacon. type Beacon struct { state protoimpl.MessageState `protogen:"open.v1"` @@ -1257,168 +1265,170 @@ var file_c2_proto_rawDesc = string([]byte{ 0x0e, 0x65, 0x6c, 0x64, 0x72, 0x69, 0x74, 0x63, 0x68, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x27, 0x0a, 0x05, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x12, 0x1e, 0x0a, 0x0a, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x69, 0x64, - 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x22, 0xcc, 0x01, 0x0a, 0x0f, 0x41, 0x63, 0x74, + 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x22, 0xe2, 0x01, 0x0a, 0x0f, 0x41, 0x63, 0x74, 0x69, 0x76, 0x65, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x72, 0x69, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x69, 0x12, 0x1a, 0x0a, 0x08, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x12, 0x2c, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x18, 0x2e, 0x63, 0x32, 0x2e, 0x41, 0x63, 0x74, 0x69, 0x76, 0x65, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x54, 0x79, - 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x22, 0x5d, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, - 0x12, 0x19, 0x0a, 0x15, 0x54, 0x52, 0x41, 0x4e, 0x53, 0x50, 0x4f, 0x52, 0x54, 0x5f, 0x55, 0x4e, - 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x12, 0x0a, 0x0e, 0x54, - 0x52, 0x41, 0x4e, 0x53, 0x50, 0x4f, 0x52, 0x54, 0x5f, 0x47, 0x52, 0x50, 0x43, 0x10, 0x01, 0x12, - 0x13, 0x0a, 0x0f, 0x54, 0x52, 0x41, 0x4e, 0x53, 0x50, 0x4f, 0x52, 0x54, 0x5f, 0x48, 0x54, 0x54, - 0x50, 0x31, 0x10, 0x02, 0x12, 0x11, 0x0a, 0x0d, 0x54, 0x52, 0x41, 0x4e, 0x53, 0x50, 0x4f, 0x52, - 0x54, 0x5f, 0x44, 0x4e, 0x53, 0x10, 0x03, 0x22, 0xc5, 0x01, 0x0a, 0x06, 0x42, 0x65, 0x61, 0x63, - 0x6f, 0x6e, 0x12, 0x1e, 0x0a, 0x0a, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, - 0x65, 0x72, 0x12, 0x1c, 0x0a, 0x09, 0x70, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x70, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, - 0x12, 0x1c, 0x0a, 0x04, 0x68, 0x6f, 0x73, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x08, - 0x2e, 0x63, 0x32, 0x2e, 0x48, 0x6f, 0x73, 0x74, 0x52, 0x04, 0x68, 0x6f, 0x73, 0x74, 0x12, 0x1f, - 0x0a, 0x05, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x09, 0x2e, - 0x63, 0x32, 0x2e, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x52, 0x05, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x12, - 0x3e, 0x0a, 0x10, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, - 0x6f, 0x72, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x63, 0x32, 0x2e, 0x41, - 0x63, 0x74, 0x69, 0x76, 0x65, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x0f, - 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x22, - 0xfe, 0x01, 0x0a, 0x04, 0x48, 0x6f, 0x73, 0x74, 0x12, 0x1e, 0x0a, 0x0a, 0x69, 0x64, 0x65, 0x6e, + 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x78, 0x74, 0x72, + 0x61, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x78, 0x74, 0x72, 0x61, 0x22, 0x5d, + 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x19, 0x0a, 0x15, 0x54, 0x52, 0x41, 0x4e, 0x53, 0x50, + 0x4f, 0x52, 0x54, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, + 0x00, 0x12, 0x12, 0x0a, 0x0e, 0x54, 0x52, 0x41, 0x4e, 0x53, 0x50, 0x4f, 0x52, 0x54, 0x5f, 0x47, + 0x52, 0x50, 0x43, 0x10, 0x01, 0x12, 0x13, 0x0a, 0x0f, 0x54, 0x52, 0x41, 0x4e, 0x53, 0x50, 0x4f, + 0x52, 0x54, 0x5f, 0x48, 0x54, 0x54, 0x50, 0x31, 0x10, 0x02, 0x12, 0x11, 0x0a, 0x0d, 0x54, 0x52, + 0x41, 0x4e, 0x53, 0x50, 0x4f, 0x52, 0x54, 0x5f, 0x44, 0x4e, 0x53, 0x10, 0x03, 0x22, 0xc5, 0x01, + 0x0a, 0x06, 0x42, 0x65, 0x61, 0x63, 0x6f, 0x6e, 0x12, 0x1e, 0x0a, 0x0a, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x69, 0x64, - 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x2d, 0x0a, 0x08, - 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x11, - 0x2e, 0x63, 0x32, 0x2e, 0x48, 0x6f, 0x73, 0x74, 0x2e, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, - 0x6d, 0x52, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x12, 0x1d, 0x0a, 0x0a, 0x70, - 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x5f, 0x69, 0x70, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x09, 0x70, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x49, 0x70, 0x22, 0x74, 0x0a, 0x08, 0x50, 0x6c, - 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x12, 0x18, 0x0a, 0x14, 0x50, 0x4c, 0x41, 0x54, 0x46, 0x4f, - 0x52, 0x4d, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, - 0x12, 0x14, 0x0a, 0x10, 0x50, 0x4c, 0x41, 0x54, 0x46, 0x4f, 0x52, 0x4d, 0x5f, 0x57, 0x49, 0x4e, - 0x44, 0x4f, 0x57, 0x53, 0x10, 0x01, 0x12, 0x12, 0x0a, 0x0e, 0x50, 0x4c, 0x41, 0x54, 0x46, 0x4f, - 0x52, 0x4d, 0x5f, 0x4c, 0x49, 0x4e, 0x55, 0x58, 0x10, 0x02, 0x12, 0x12, 0x0a, 0x0e, 0x50, 0x4c, - 0x41, 0x54, 0x46, 0x4f, 0x52, 0x4d, 0x5f, 0x4d, 0x41, 0x43, 0x4f, 0x53, 0x10, 0x03, 0x12, 0x10, - 0x0a, 0x0c, 0x50, 0x4c, 0x41, 0x54, 0x46, 0x4f, 0x52, 0x4d, 0x5f, 0x42, 0x53, 0x44, 0x10, 0x04, - 0x22, 0x59, 0x0a, 0x04, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x03, 0x52, 0x02, 0x69, 0x64, 0x12, 0x22, 0x0a, 0x04, 0x74, 0x6f, 0x6d, 0x65, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x65, 0x6c, 0x64, 0x72, 0x69, 0x74, 0x63, - 0x68, 0x2e, 0x54, 0x6f, 0x6d, 0x65, 0x52, 0x04, 0x74, 0x6f, 0x6d, 0x65, 0x12, 0x1d, 0x0a, 0x0a, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x09, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0x1d, 0x0a, 0x09, 0x54, - 0x61, 0x73, 0x6b, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x10, 0x0a, 0x03, 0x6d, 0x73, 0x67, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6d, 0x73, 0x67, 0x22, 0xe3, 0x01, 0x0a, 0x0a, 0x54, - 0x61, 0x73, 0x6b, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x02, 0x69, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x6f, 0x75, 0x74, - 0x70, 0x75, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6f, 0x75, 0x74, 0x70, 0x75, - 0x74, 0x12, 0x23, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x0d, 0x2e, 0x63, 0x32, 0x2e, 0x54, 0x61, 0x73, 0x6b, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, - 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x42, 0x0a, 0x0f, 0x65, 0x78, 0x65, 0x63, 0x5f, 0x73, - 0x74, 0x61, 0x72, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, - 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0d, 0x65, 0x78, 0x65, - 0x63, 0x53, 0x74, 0x61, 0x72, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x44, 0x0a, 0x10, 0x65, 0x78, - 0x65, 0x63, 0x5f, 0x66, 0x69, 0x6e, 0x69, 0x73, 0x68, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x05, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, - 0x52, 0x0e, 0x65, 0x78, 0x65, 0x63, 0x46, 0x69, 0x6e, 0x69, 0x73, 0x68, 0x65, 0x64, 0x41, 0x74, - 0x22, 0x37, 0x0a, 0x11, 0x43, 0x6c, 0x61, 0x69, 0x6d, 0x54, 0x61, 0x73, 0x6b, 0x73, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x22, 0x0a, 0x06, 0x62, 0x65, 0x61, 0x63, 0x6f, 0x6e, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0a, 0x2e, 0x63, 0x32, 0x2e, 0x42, 0x65, 0x61, 0x63, 0x6f, - 0x6e, 0x52, 0x06, 0x62, 0x65, 0x61, 0x63, 0x6f, 0x6e, 0x22, 0x34, 0x0a, 0x12, 0x43, 0x6c, 0x61, - 0x69, 0x6d, 0x54, 0x61, 0x73, 0x6b, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, - 0x1e, 0x0a, 0x05, 0x74, 0x61, 0x73, 0x6b, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x08, - 0x2e, 0x63, 0x32, 0x2e, 0x54, 0x61, 0x73, 0x6b, 0x52, 0x05, 0x74, 0x61, 0x73, 0x6b, 0x73, 0x22, - 0x27, 0x0a, 0x11, 0x46, 0x65, 0x74, 0x63, 0x68, 0x41, 0x73, 0x73, 0x65, 0x74, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x2a, 0x0a, 0x12, 0x46, 0x65, 0x74, 0x63, - 0x68, 0x41, 0x73, 0x73, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x14, - 0x0a, 0x05, 0x63, 0x68, 0x75, 0x6e, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x63, - 0x68, 0x75, 0x6e, 0x6b, 0x22, 0x68, 0x0a, 0x17, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x43, 0x72, - 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, - 0x17, 0x0a, 0x07, 0x74, 0x61, 0x73, 0x6b, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, - 0x52, 0x06, 0x74, 0x61, 0x73, 0x6b, 0x49, 0x64, 0x12, 0x34, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x64, - 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x65, - 0x6c, 0x64, 0x72, 0x69, 0x74, 0x63, 0x68, 0x2e, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, - 0x61, 0x6c, 0x52, 0x0a, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x22, 0x1a, - 0x0a, 0x18, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, - 0x61, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x52, 0x0a, 0x11, 0x52, 0x65, - 0x70, 0x6f, 0x72, 0x74, 0x46, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, - 0x17, 0x0a, 0x07, 0x74, 0x61, 0x73, 0x6b, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, - 0x52, 0x06, 0x74, 0x61, 0x73, 0x6b, 0x49, 0x64, 0x12, 0x24, 0x0a, 0x05, 0x63, 0x68, 0x75, 0x6e, - 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x65, 0x6c, 0x64, 0x72, 0x69, 0x74, - 0x63, 0x68, 0x2e, 0x46, 0x69, 0x6c, 0x65, 0x52, 0x05, 0x63, 0x68, 0x75, 0x6e, 0x6b, 0x22, 0x14, - 0x0a, 0x12, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x46, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x5e, 0x0a, 0x18, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x50, 0x72, - 0x6f, 0x63, 0x65, 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x12, 0x17, 0x0a, 0x07, 0x74, 0x61, 0x73, 0x6b, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x03, 0x52, 0x06, 0x74, 0x61, 0x73, 0x6b, 0x49, 0x64, 0x12, 0x29, 0x0a, 0x04, 0x6c, 0x69, 0x73, - 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x65, 0x6c, 0x64, 0x72, 0x69, 0x74, - 0x63, 0x68, 0x2e, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x04, - 0x6c, 0x69, 0x73, 0x74, 0x22, 0x1b, 0x0a, 0x19, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x50, 0x72, - 0x6f, 0x63, 0x65, 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x22, 0x41, 0x0a, 0x17, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x54, 0x61, 0x73, 0x6b, 0x4f, - 0x75, 0x74, 0x70, 0x75, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x26, 0x0a, 0x06, - 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x63, - 0x32, 0x2e, 0x54, 0x61, 0x73, 0x6b, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x52, 0x06, 0x6f, 0x75, - 0x74, 0x70, 0x75, 0x74, 0x22, 0x1a, 0x0a, 0x18, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x54, 0x61, - 0x73, 0x6b, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x22, 0x73, 0x0a, 0x13, 0x52, 0x65, 0x76, 0x65, 0x72, 0x73, 0x65, 0x53, 0x68, 0x65, 0x6c, 0x6c, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2f, 0x0a, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1b, 0x2e, 0x63, 0x32, 0x2e, 0x52, 0x65, 0x76, 0x65, 0x72, - 0x73, 0x65, 0x53, 0x68, 0x65, 0x6c, 0x6c, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x4b, 0x69, - 0x6e, 0x64, 0x52, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x12, 0x17, 0x0a, 0x07, - 0x74, 0x61, 0x73, 0x6b, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x74, - 0x61, 0x73, 0x6b, 0x49, 0x64, 0x22, 0x5b, 0x0a, 0x14, 0x52, 0x65, 0x76, 0x65, 0x72, 0x73, 0x65, - 0x53, 0x68, 0x65, 0x6c, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2f, 0x0a, + 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x12, 0x1c, 0x0a, 0x09, 0x70, 0x72, 0x69, 0x6e, + 0x63, 0x69, 0x70, 0x61, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x70, 0x72, 0x69, + 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, 0x12, 0x1c, 0x0a, 0x04, 0x68, 0x6f, 0x73, 0x74, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x08, 0x2e, 0x63, 0x32, 0x2e, 0x48, 0x6f, 0x73, 0x74, 0x52, 0x04, + 0x68, 0x6f, 0x73, 0x74, 0x12, 0x1f, 0x0a, 0x05, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x18, 0x04, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x09, 0x2e, 0x63, 0x32, 0x2e, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x52, 0x05, + 0x61, 0x67, 0x65, 0x6e, 0x74, 0x12, 0x3e, 0x0a, 0x10, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x5f, + 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x13, 0x2e, 0x63, 0x32, 0x2e, 0x41, 0x63, 0x74, 0x69, 0x76, 0x65, 0x54, 0x72, 0x61, 0x6e, 0x73, + 0x70, 0x6f, 0x72, 0x74, 0x52, 0x0f, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x54, 0x72, 0x61, 0x6e, + 0x73, 0x70, 0x6f, 0x72, 0x74, 0x22, 0xfe, 0x01, 0x0a, 0x04, 0x48, 0x6f, 0x73, 0x74, 0x12, 0x1e, + 0x0a, 0x0a, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0a, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x12, 0x12, + 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, + 0x6d, 0x65, 0x12, 0x2d, 0x0a, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x0e, 0x32, 0x11, 0x2e, 0x63, 0x32, 0x2e, 0x48, 0x6f, 0x73, 0x74, 0x2e, 0x50, + 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x52, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, + 0x6d, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x5f, 0x69, 0x70, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x70, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x49, 0x70, + 0x22, 0x74, 0x0a, 0x08, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x12, 0x18, 0x0a, 0x14, + 0x50, 0x4c, 0x41, 0x54, 0x46, 0x4f, 0x52, 0x4d, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, + 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x14, 0x0a, 0x10, 0x50, 0x4c, 0x41, 0x54, 0x46, 0x4f, + 0x52, 0x4d, 0x5f, 0x57, 0x49, 0x4e, 0x44, 0x4f, 0x57, 0x53, 0x10, 0x01, 0x12, 0x12, 0x0a, 0x0e, + 0x50, 0x4c, 0x41, 0x54, 0x46, 0x4f, 0x52, 0x4d, 0x5f, 0x4c, 0x49, 0x4e, 0x55, 0x58, 0x10, 0x02, + 0x12, 0x12, 0x0a, 0x0e, 0x50, 0x4c, 0x41, 0x54, 0x46, 0x4f, 0x52, 0x4d, 0x5f, 0x4d, 0x41, 0x43, + 0x4f, 0x53, 0x10, 0x03, 0x12, 0x10, 0x0a, 0x0c, 0x50, 0x4c, 0x41, 0x54, 0x46, 0x4f, 0x52, 0x4d, + 0x5f, 0x42, 0x53, 0x44, 0x10, 0x04, 0x22, 0x59, 0x0a, 0x04, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x0e, + 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x02, 0x69, 0x64, 0x12, 0x22, + 0x0a, 0x04, 0x74, 0x6f, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x65, + 0x6c, 0x64, 0x72, 0x69, 0x74, 0x63, 0x68, 0x2e, 0x54, 0x6f, 0x6d, 0x65, 0x52, 0x04, 0x74, 0x6f, + 0x6d, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4e, 0x61, 0x6d, + 0x65, 0x22, 0x1d, 0x0a, 0x09, 0x54, 0x61, 0x73, 0x6b, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x10, + 0x0a, 0x03, 0x6d, 0x73, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6d, 0x73, 0x67, + 0x22, 0xe3, 0x01, 0x0a, 0x0a, 0x54, 0x61, 0x73, 0x6b, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x12, + 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x02, 0x69, 0x64, 0x12, + 0x16, 0x0a, 0x06, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x06, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x12, 0x23, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x63, 0x32, 0x2e, 0x54, 0x61, 0x73, 0x6b, + 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x42, 0x0a, 0x0f, + 0x65, 0x78, 0x65, 0x63, 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, + 0x70, 0x52, 0x0d, 0x65, 0x78, 0x65, 0x63, 0x53, 0x74, 0x61, 0x72, 0x74, 0x65, 0x64, 0x41, 0x74, + 0x12, 0x44, 0x0a, 0x10, 0x65, 0x78, 0x65, 0x63, 0x5f, 0x66, 0x69, 0x6e, 0x69, 0x73, 0x68, 0x65, + 0x64, 0x5f, 0x61, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, + 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, + 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0e, 0x65, 0x78, 0x65, 0x63, 0x46, 0x69, 0x6e, 0x69, + 0x73, 0x68, 0x65, 0x64, 0x41, 0x74, 0x22, 0x37, 0x0a, 0x11, 0x43, 0x6c, 0x61, 0x69, 0x6d, 0x54, + 0x61, 0x73, 0x6b, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x22, 0x0a, 0x06, 0x62, + 0x65, 0x61, 0x63, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0a, 0x2e, 0x63, 0x32, + 0x2e, 0x42, 0x65, 0x61, 0x63, 0x6f, 0x6e, 0x52, 0x06, 0x62, 0x65, 0x61, 0x63, 0x6f, 0x6e, 0x22, + 0x34, 0x0a, 0x12, 0x43, 0x6c, 0x61, 0x69, 0x6d, 0x54, 0x61, 0x73, 0x6b, 0x73, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1e, 0x0a, 0x05, 0x74, 0x61, 0x73, 0x6b, 0x73, 0x18, 0x01, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x08, 0x2e, 0x63, 0x32, 0x2e, 0x54, 0x61, 0x73, 0x6b, 0x52, 0x05, + 0x74, 0x61, 0x73, 0x6b, 0x73, 0x22, 0x27, 0x0a, 0x11, 0x46, 0x65, 0x74, 0x63, 0x68, 0x41, 0x73, + 0x73, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, + 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x2a, + 0x0a, 0x12, 0x46, 0x65, 0x74, 0x63, 0x68, 0x41, 0x73, 0x73, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x68, 0x75, 0x6e, 0x6b, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0c, 0x52, 0x05, 0x63, 0x68, 0x75, 0x6e, 0x6b, 0x22, 0x68, 0x0a, 0x17, 0x52, 0x65, + 0x70, 0x6f, 0x72, 0x74, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x17, 0x0a, 0x07, 0x74, 0x61, 0x73, 0x6b, 0x5f, 0x69, 0x64, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x74, 0x61, 0x73, 0x6b, 0x49, 0x64, 0x12, 0x34, + 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x65, 0x6c, 0x64, 0x72, 0x69, 0x74, 0x63, 0x68, 0x2e, 0x43, 0x72, + 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x52, 0x0a, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, + 0x74, 0x69, 0x61, 0x6c, 0x22, 0x1a, 0x0a, 0x18, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x43, 0x72, + 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x22, 0x52, 0x0a, 0x11, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x46, 0x69, 0x6c, 0x65, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x17, 0x0a, 0x07, 0x74, 0x61, 0x73, 0x6b, 0x5f, 0x69, 0x64, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x74, 0x61, 0x73, 0x6b, 0x49, 0x64, 0x12, 0x24, + 0x0a, 0x05, 0x63, 0x68, 0x75, 0x6e, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, + 0x65, 0x6c, 0x64, 0x72, 0x69, 0x74, 0x63, 0x68, 0x2e, 0x46, 0x69, 0x6c, 0x65, 0x52, 0x05, 0x63, + 0x68, 0x75, 0x6e, 0x6b, 0x22, 0x14, 0x0a, 0x12, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x46, 0x69, + 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x5e, 0x0a, 0x18, 0x52, 0x65, + 0x70, 0x6f, 0x72, 0x74, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x17, 0x0a, 0x07, 0x74, 0x61, 0x73, 0x6b, 0x5f, 0x69, + 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x74, 0x61, 0x73, 0x6b, 0x49, 0x64, 0x12, + 0x29, 0x0a, 0x04, 0x6c, 0x69, 0x73, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, + 0x65, 0x6c, 0x64, 0x72, 0x69, 0x74, 0x63, 0x68, 0x2e, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, + 0x4c, 0x69, 0x73, 0x74, 0x52, 0x04, 0x6c, 0x69, 0x73, 0x74, 0x22, 0x1b, 0x0a, 0x19, 0x52, 0x65, + 0x70, 0x6f, 0x72, 0x74, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x41, 0x0a, 0x17, 0x52, 0x65, 0x70, 0x6f, 0x72, + 0x74, 0x54, 0x61, 0x73, 0x6b, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x12, 0x26, 0x0a, 0x06, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x63, 0x32, 0x2e, 0x54, 0x61, 0x73, 0x6b, 0x4f, 0x75, 0x74, 0x70, + 0x75, 0x74, 0x52, 0x06, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x22, 0x1a, 0x0a, 0x18, 0x52, 0x65, + 0x70, 0x6f, 0x72, 0x74, 0x54, 0x61, 0x73, 0x6b, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x73, 0x0a, 0x13, 0x52, 0x65, 0x76, 0x65, 0x72, 0x73, + 0x65, 0x53, 0x68, 0x65, 0x6c, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2f, 0x0a, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1b, 0x2e, 0x63, 0x32, 0x2e, 0x52, 0x65, 0x76, 0x65, 0x72, 0x73, 0x65, 0x53, 0x68, 0x65, 0x6c, 0x6c, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x4b, 0x69, 0x6e, 0x64, 0x52, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x64, 0x61, - 0x74, 0x61, 0x2a, 0x8f, 0x01, 0x0a, 0x17, 0x52, 0x65, 0x76, 0x65, 0x72, 0x73, 0x65, 0x53, 0x68, - 0x65, 0x6c, 0x6c, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x4b, 0x69, 0x6e, 0x64, 0x12, 0x2a, - 0x0a, 0x26, 0x52, 0x45, 0x56, 0x45, 0x52, 0x53, 0x45, 0x5f, 0x53, 0x48, 0x45, 0x4c, 0x4c, 0x5f, - 0x4d, 0x45, 0x53, 0x53, 0x41, 0x47, 0x45, 0x5f, 0x4b, 0x49, 0x4e, 0x44, 0x5f, 0x55, 0x4e, 0x53, - 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x23, 0x0a, 0x1f, 0x52, 0x45, - 0x56, 0x45, 0x52, 0x53, 0x45, 0x5f, 0x53, 0x48, 0x45, 0x4c, 0x4c, 0x5f, 0x4d, 0x45, 0x53, 0x53, - 0x41, 0x47, 0x45, 0x5f, 0x4b, 0x49, 0x4e, 0x44, 0x5f, 0x44, 0x41, 0x54, 0x41, 0x10, 0x01, 0x12, - 0x23, 0x0a, 0x1f, 0x52, 0x45, 0x56, 0x45, 0x52, 0x53, 0x45, 0x5f, 0x53, 0x48, 0x45, 0x4c, 0x4c, - 0x5f, 0x4d, 0x45, 0x53, 0x53, 0x41, 0x47, 0x45, 0x5f, 0x4b, 0x49, 0x4e, 0x44, 0x5f, 0x50, 0x49, - 0x4e, 0x47, 0x10, 0x02, 0x32, 0xfc, 0x03, 0x0a, 0x02, 0x43, 0x32, 0x12, 0x3d, 0x0a, 0x0a, 0x43, - 0x6c, 0x61, 0x69, 0x6d, 0x54, 0x61, 0x73, 0x6b, 0x73, 0x12, 0x15, 0x2e, 0x63, 0x32, 0x2e, 0x43, - 0x6c, 0x61, 0x69, 0x6d, 0x54, 0x61, 0x73, 0x6b, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x16, 0x2e, 0x63, 0x32, 0x2e, 0x43, 0x6c, 0x61, 0x69, 0x6d, 0x54, 0x61, 0x73, 0x6b, 0x73, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x3d, 0x0a, 0x0a, 0x46, 0x65, - 0x74, 0x63, 0x68, 0x41, 0x73, 0x73, 0x65, 0x74, 0x12, 0x15, 0x2e, 0x63, 0x32, 0x2e, 0x46, 0x65, - 0x74, 0x63, 0x68, 0x41, 0x73, 0x73, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x16, 0x2e, 0x63, 0x32, 0x2e, 0x46, 0x65, 0x74, 0x63, 0x68, 0x41, 0x73, 0x73, 0x65, 0x74, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x30, 0x01, 0x12, 0x4d, 0x0a, 0x10, 0x52, 0x65, 0x70, - 0x6f, 0x72, 0x74, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x12, 0x1b, 0x2e, - 0x63, 0x32, 0x2e, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, - 0x69, 0x61, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x63, 0x32, 0x2e, - 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3d, 0x0a, 0x0a, 0x52, 0x65, 0x70, 0x6f, - 0x72, 0x74, 0x46, 0x69, 0x6c, 0x65, 0x12, 0x15, 0x2e, 0x63, 0x32, 0x2e, 0x52, 0x65, 0x70, 0x6f, - 0x72, 0x74, 0x46, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, - 0x63, 0x32, 0x2e, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x46, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x28, 0x01, 0x12, 0x50, 0x0a, 0x11, 0x52, 0x65, 0x70, 0x6f, 0x72, - 0x74, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x1c, 0x2e, 0x63, - 0x32, 0x2e, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x4c, - 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x63, 0x32, 0x2e, - 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x4c, 0x69, 0x73, - 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4f, 0x0a, 0x10, 0x52, 0x65, 0x70, - 0x6f, 0x72, 0x74, 0x54, 0x61, 0x73, 0x6b, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x12, 0x1b, 0x2e, - 0x63, 0x32, 0x2e, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x54, 0x61, 0x73, 0x6b, 0x4f, 0x75, 0x74, - 0x70, 0x75, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x63, 0x32, 0x2e, - 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x54, 0x61, 0x73, 0x6b, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x47, 0x0a, 0x0c, 0x52, 0x65, - 0x76, 0x65, 0x72, 0x73, 0x65, 0x53, 0x68, 0x65, 0x6c, 0x6c, 0x12, 0x17, 0x2e, 0x63, 0x32, 0x2e, - 0x52, 0x65, 0x76, 0x65, 0x72, 0x73, 0x65, 0x53, 0x68, 0x65, 0x6c, 0x6c, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x63, 0x32, 0x2e, 0x52, 0x65, 0x76, 0x65, 0x72, 0x73, 0x65, - 0x53, 0x68, 0x65, 0x6c, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x28, - 0x01, 0x30, 0x01, 0x42, 0x23, 0x5a, 0x21, 0x72, 0x65, 0x61, 0x6c, 0x6d, 0x2e, 0x70, 0x75, 0x62, - 0x2f, 0x74, 0x61, 0x76, 0x65, 0x72, 0x6e, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, - 0x2f, 0x63, 0x32, 0x2f, 0x63, 0x32, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x74, 0x61, 0x12, 0x17, 0x0a, 0x07, 0x74, 0x61, 0x73, 0x6b, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x03, 0x52, 0x06, 0x74, 0x61, 0x73, 0x6b, 0x49, 0x64, 0x22, 0x5b, 0x0a, 0x14, 0x52, + 0x65, 0x76, 0x65, 0x72, 0x73, 0x65, 0x53, 0x68, 0x65, 0x6c, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x2f, 0x0a, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0e, 0x32, 0x1b, 0x2e, 0x63, 0x32, 0x2e, 0x52, 0x65, 0x76, 0x65, 0x72, 0x73, 0x65, 0x53, 0x68, + 0x65, 0x6c, 0x6c, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x4b, 0x69, 0x6e, 0x64, 0x52, 0x04, + 0x6b, 0x69, 0x6e, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x0c, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x2a, 0x8f, 0x01, 0x0a, 0x17, 0x52, 0x65, 0x76, + 0x65, 0x72, 0x73, 0x65, 0x53, 0x68, 0x65, 0x6c, 0x6c, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x4b, 0x69, 0x6e, 0x64, 0x12, 0x2a, 0x0a, 0x26, 0x52, 0x45, 0x56, 0x45, 0x52, 0x53, 0x45, 0x5f, + 0x53, 0x48, 0x45, 0x4c, 0x4c, 0x5f, 0x4d, 0x45, 0x53, 0x53, 0x41, 0x47, 0x45, 0x5f, 0x4b, 0x49, + 0x4e, 0x44, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, + 0x12, 0x23, 0x0a, 0x1f, 0x52, 0x45, 0x56, 0x45, 0x52, 0x53, 0x45, 0x5f, 0x53, 0x48, 0x45, 0x4c, + 0x4c, 0x5f, 0x4d, 0x45, 0x53, 0x53, 0x41, 0x47, 0x45, 0x5f, 0x4b, 0x49, 0x4e, 0x44, 0x5f, 0x44, + 0x41, 0x54, 0x41, 0x10, 0x01, 0x12, 0x23, 0x0a, 0x1f, 0x52, 0x45, 0x56, 0x45, 0x52, 0x53, 0x45, + 0x5f, 0x53, 0x48, 0x45, 0x4c, 0x4c, 0x5f, 0x4d, 0x45, 0x53, 0x53, 0x41, 0x47, 0x45, 0x5f, 0x4b, + 0x49, 0x4e, 0x44, 0x5f, 0x50, 0x49, 0x4e, 0x47, 0x10, 0x02, 0x32, 0xfc, 0x03, 0x0a, 0x02, 0x43, + 0x32, 0x12, 0x3d, 0x0a, 0x0a, 0x43, 0x6c, 0x61, 0x69, 0x6d, 0x54, 0x61, 0x73, 0x6b, 0x73, 0x12, + 0x15, 0x2e, 0x63, 0x32, 0x2e, 0x43, 0x6c, 0x61, 0x69, 0x6d, 0x54, 0x61, 0x73, 0x6b, 0x73, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x63, 0x32, 0x2e, 0x43, 0x6c, 0x61, 0x69, + 0x6d, 0x54, 0x61, 0x73, 0x6b, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, + 0x12, 0x3d, 0x0a, 0x0a, 0x46, 0x65, 0x74, 0x63, 0x68, 0x41, 0x73, 0x73, 0x65, 0x74, 0x12, 0x15, + 0x2e, 0x63, 0x32, 0x2e, 0x46, 0x65, 0x74, 0x63, 0x68, 0x41, 0x73, 0x73, 0x65, 0x74, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x63, 0x32, 0x2e, 0x46, 0x65, 0x74, 0x63, 0x68, + 0x41, 0x73, 0x73, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x30, 0x01, 0x12, + 0x4d, 0x0a, 0x10, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, + 0x69, 0x61, 0x6c, 0x12, 0x1b, 0x2e, 0x63, 0x32, 0x2e, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x43, + 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x1c, 0x2e, 0x63, 0x32, 0x2e, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x43, 0x72, 0x65, 0x64, + 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3d, + 0x0a, 0x0a, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x46, 0x69, 0x6c, 0x65, 0x12, 0x15, 0x2e, 0x63, + 0x32, 0x2e, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x46, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x63, 0x32, 0x2e, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x46, + 0x69, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x28, 0x01, 0x12, 0x50, 0x0a, + 0x11, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x4c, 0x69, + 0x73, 0x74, 0x12, 0x1c, 0x2e, 0x63, 0x32, 0x2e, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x50, 0x72, + 0x6f, 0x63, 0x65, 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x1d, 0x2e, 0x63, 0x32, 0x2e, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x50, 0x72, 0x6f, 0x63, + 0x65, 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x4f, 0x0a, 0x10, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x54, 0x61, 0x73, 0x6b, 0x4f, 0x75, 0x74, + 0x70, 0x75, 0x74, 0x12, 0x1b, 0x2e, 0x63, 0x32, 0x2e, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x54, + 0x61, 0x73, 0x6b, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x1c, 0x2e, 0x63, 0x32, 0x2e, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x54, 0x61, 0x73, 0x6b, + 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, + 0x12, 0x47, 0x0a, 0x0c, 0x52, 0x65, 0x76, 0x65, 0x72, 0x73, 0x65, 0x53, 0x68, 0x65, 0x6c, 0x6c, + 0x12, 0x17, 0x2e, 0x63, 0x32, 0x2e, 0x52, 0x65, 0x76, 0x65, 0x72, 0x73, 0x65, 0x53, 0x68, 0x65, + 0x6c, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x63, 0x32, 0x2e, 0x52, + 0x65, 0x76, 0x65, 0x72, 0x73, 0x65, 0x53, 0x68, 0x65, 0x6c, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x22, 0x00, 0x28, 0x01, 0x30, 0x01, 0x42, 0x23, 0x5a, 0x21, 0x72, 0x65, 0x61, + 0x6c, 0x6d, 0x2e, 0x70, 0x75, 0x62, 0x2f, 0x74, 0x61, 0x76, 0x65, 0x72, 0x6e, 0x2f, 0x69, 0x6e, + 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x63, 0x32, 0x2f, 0x63, 0x32, 0x70, 0x62, 0x62, 0x06, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, }) var ( diff --git a/tavern/internal/c2/proto/c2.proto b/tavern/internal/c2/proto/c2.proto index 8fced3156..d9aaa82b7 100644 --- a/tavern/internal/c2/proto/c2.proto +++ b/tavern/internal/c2/proto/c2.proto @@ -29,6 +29,7 @@ message ActiveTransport { } Type type = 3; + string extra = 4; } // Beacon information that is unique to the current running beacon. From 924d50daead5183d3f1cd101115df867a9b6b533 Mon Sep 17 00:00:00 2001 From: hulto <7121375+hulto@users.noreply.github.com> Date: Tue, 30 Dec 2025 01:02:46 +0000 Subject: [PATCH 08/18] Update docs. --- docs/_docs/dev-guide/imix.md | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/docs/_docs/dev-guide/imix.md b/docs/_docs/dev-guide/imix.md index 3824613c4..c183c01dc 100644 --- a/docs/_docs/dev-guide/imix.md +++ b/docs/_docs/dev-guide/imix.md @@ -18,7 +18,33 @@ In order to keep these configuration options in sync realm uses protobuf and cod If you need to update these fields start with the `tavern/internal/c2/proto/c2.proto` file. -Once you've finished making your changes apply these changes across the project. +Once you've finished making your changes apply these changes across the project using `cd /workspaces/realm/ && go generater ./tavern/...` + +To generate the associated agent proto's use cargo build in the `implants` direcotry. This will copy the necesarry protos from tavern and preform the code generation. + +### Adding enums + +Add your enum type to the `*.proto` file under the message type that will use it. +For example: +``` +message ActiveTransport { + string uri = 1; + uint64 interval = 2; + + enum Type { + TRANSPORT_UNSPECIFIED = 0; + TRANSPORT_GRPC = 1; + TRANSPORT_HTTP1 = 2; + TRANSPORT_DNS = 3; + } + + Type type = 3; + string extra = 4; +} +``` + +And add a new enum definition to `tavern/internal/c2/c2pb/enum__.go` This should be similar to other enums that exist you can likely copy and rename an existing one. See `tavern/internal/c2/c2pb/enum_beacon_active_transport_type.go` + ## Host Selector From ad470cf736239e78ab3e969c65c540c1a83afa68 Mon Sep 17 00:00:00 2001 From: hulto <7121375+hulto@users.noreply.github.com> Date: Tue, 30 Dec 2025 01:29:55 +0000 Subject: [PATCH 09/18] Cleanup bad unwraps --- implants/imixv2/src/agent.rs | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/implants/imixv2/src/agent.rs b/implants/imixv2/src/agent.rs index ee9da0ec5..6a7e2f40d 100644 --- a/implants/imixv2/src/agent.rs +++ b/implants/imixv2/src/agent.rs @@ -30,14 +30,13 @@ impl ImixAgent { task_registry: Arc, ) -> Self { //TODO: simplyify this section transport, callback_uris, active_uri_idx, and config seem to duplicate information. - let uri = config - .clone() + let c = config.clone(); + let active_transport = c .info - .unwrap() - .active_transport - .unwrap() - .uri - .clone(); + .as_ref() + .and_then(|info| info.active_transport.as_ref()); + let uri = active_transport.map(|t| t.uri.clone()).unwrap_or_default(); + Self { config: Arc::new(RwLock::new(config)), transport: Arc::new(RwLock::new(transport)), From 3893c2600629a438645808b35bd14ea7bf7d7db7 Mon Sep 17 00:00:00 2001 From: hulto <7121375+hulto@users.noreply.github.com> Date: Fri, 2 Jan 2026 03:54:54 +0000 Subject: [PATCH 10/18] Add extra to config and pass it through. --- implants/imix/src/agent.rs | 4 +- implants/imixv2/src/agent.rs | 18 ++++++-- implants/imixv2/src/run.rs | 7 +-- implants/lib/pb/build.rs | 21 +++++++++ implants/lib/pb/src/config.rs | 21 ++++----- implants/lib/transport/Cargo.toml | 1 + implants/lib/transport/src/dns.rs | 59 +++++++++++++++---------- implants/lib/transport/src/grpc.rs | 32 +++++++++++--- implants/lib/transport/src/http.rs | 4 +- implants/lib/transport/src/lib.rs | 10 ++--- implants/lib/transport/src/mock.rs | 2 +- implants/lib/transport/src/transport.rs | 4 +- 12 files changed, 127 insertions(+), 56 deletions(-) diff --git a/implants/imix/src/agent.rs b/implants/imix/src/agent.rs index 832bce170..f6cd4c76e 100644 --- a/implants/imix/src/agent.rs +++ b/implants/imix/src/agent.rs @@ -88,7 +88,7 @@ impl Agent { * Callback once using the configured client to claim new tasks and report available output. */ pub async fn callback(&mut self) -> Result<()> { - //TODO: Re-add proxy support + //TODO: De-dupe this fields - probably just need to pass the config not the callback URI. self.t = T::new( self.cfg .info @@ -97,7 +97,7 @@ impl Agent { .active_transport .context("failed to get transport")? .uri, - None, + self.cfg.clone(), )?; self.claim_tasks(self.t.clone()).await?; self.report(self.t.clone()).await?; diff --git a/implants/imixv2/src/agent.rs b/implants/imixv2/src/agent.rs index 6a7e2f40d..8814f0879 100644 --- a/implants/imixv2/src/agent.rs +++ b/implants/imixv2/src/agent.rs @@ -113,7 +113,8 @@ impl ImixAgent { } // Helper to get config URIs for creating new transport - pub async fn get_transport_config(&self) -> (String, Option) { + pub async fn get_transport_config(&self) -> (String, Config) { + let config = self.config.read().await.clone(); let uris = self.callback_uris.read().await; let idx = *self.active_uri_idx.read().await; let callback_uri = if idx < uris.len() { @@ -122,9 +123,8 @@ impl ImixAgent { // Fallback, should not happen unless empty uris.first().cloned().unwrap_or_default() }; - // let cfg = self.config.read().await; //TODO: Re-add proxy URI via an "extra" field in config. - (callback_uri, None) + (callback_uri, config) } pub async fn rotate_callback_uri(&self) { @@ -339,6 +339,18 @@ impl Agent for ImixAgent { map.insert("platform".to_string(), host.platform.to_string()); map.insert("primary_ip".to_string(), host.primary_ip.clone()); } + if let Some(active_transport) = &info.active_transport { + map.insert("uri".to_string(), active_transport.uri.clone()); + map.insert( + "interval".to_string(), + active_transport.interval.clone().to_string(), + ); + map.insert("primary_ip".to_string(), active_transport.extra.clone()); + map.insert( + "type".to_string(), + active_transport.r#type.clone().to_string(), + ); + } } Ok(map) } diff --git a/implants/imixv2/src/run.rs b/implants/imixv2/src/run.rs index 341366ce7..d5501d2d5 100644 --- a/implants/imixv2/src/run.rs +++ b/implants/imixv2/src/run.rs @@ -1,4 +1,5 @@ -use anyhow::Result; +use anyhow::{Context, Result}; +use eldritch_agent::Agent; use std::sync::Arc; use std::sync::atomic::{AtomicBool, Ordering}; use std::time::{Duration, Instant}; @@ -88,9 +89,9 @@ async fn run_agent_cycle(agent: Arc>, registry: Arc t, Err(_e) => { #[cfg(debug_assertions)] diff --git a/implants/lib/pb/build.rs b/implants/lib/pb/build.rs index 5acc469bd..a08515f18 100644 --- a/implants/lib/pb/build.rs +++ b/implants/lib/pb/build.rs @@ -1,3 +1,4 @@ +use std::collections::HashMap; use std::env; use std::path::PathBuf; use which::which; @@ -64,8 +65,28 @@ fn get_pub_key() { ); } +fn build_extra_vars() -> Result<(), Box> { + let mut res = HashMap::new(); + for (key, value) in std::env::vars() { + if key.starts_with("IMIX_TRANSPORT_EXTRA_") { + println!("{}", key); + match key.strip_prefix("IMIX_TRANSPORT_EXTRA_") { + Some(k) => { + let suffixed_key = String::from(k); + res.insert(suffixed_key, value); + } + None => panic!("failed to strip prefix"), + } + } + } + let res_str = serde_json::to_string(&res)?; + println!("cargo:rustc-env=IMIX_TRANSPORT_EXTRA={}", res_str); + Ok(()) +} + fn main() -> Result<(), Box> { get_pub_key(); + build_extra_vars()?; // Skip if no `protoc` can be found match env::var_os("PROTOC") diff --git a/implants/lib/pb/src/config.rs b/implants/lib/pb/src/config.rs index 3454edce3..0aa8eb634 100644 --- a/implants/lib/pb/src/config.rs +++ b/implants/lib/pb/src/config.rs @@ -1,22 +1,14 @@ -use tonic::transport; use uuid::Uuid; use crate::c2::ActiveTransport; -//TODO: Migrate most of this into a config crate or as a part of the agent. - +//TODO: Can this struct be removed? /// Config holds values necessary to configure an Agent. #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct Config { #[prost(message, optional, tag = "1")] pub info: ::core::option::Option, - // #[prost(string, tag = "2")] - // pub callback_uri: ::prost::alloc::string::String, - // #[prost(string, optional, tag = "3")] - // pub proxy_uri: ::core::option::Option<::prost::alloc::string::String>, - // #[prost(uint64, tag = "4")] - // pub retry_interval: u64, #[prost(bool, tag = "2")] pub run_once: bool, } @@ -81,6 +73,15 @@ macro_rules! run_once { }; } +macro_rules! extra { + () => { + match option_env!("IMIX_TRANSPORT_EXTRA") { + Some(extra) => extra.to_string(), + None => String::from(""), + } + }; +} + /* Compile-time constant for the agent run once flag, derived from the IMIX_RUN_ONCE environment variable during compilation. * Defaults to false if unset. */ @@ -129,7 +130,7 @@ impl Config { } }, r#type: transport_type as i32, - extra: String::from(""), + extra: extra!(), }; let info = crate::c2::Beacon { diff --git a/implants/lib/transport/Cargo.toml b/implants/lib/transport/Cargo.toml index 6f52aaad0..9295ab33c 100644 --- a/implants/lib/transport/Cargo.toml +++ b/implants/lib/transport/Cargo.toml @@ -13,6 +13,7 @@ mock = ["dep:mockall"] [dependencies] pb = { workspace = true } +serde_json = { workspace = true } anyhow = { workspace = true } bytes = { workspace = true } diff --git a/implants/lib/transport/src/dns.rs b/implants/lib/transport/src/dns.rs index 6d302bd7d..5ed3bdb86 100644 --- a/implants/lib/transport/src/dns.rs +++ b/implants/lib/transport/src/dns.rs @@ -1,6 +1,7 @@ use crate::Transport; use anyhow::{Context, Result}; use pb::c2::*; +use pb::config::Config; use pb::dns::*; use prost::Message; use std::sync::mpsc::{Receiver, Sender}; @@ -106,7 +107,7 @@ impl DNS { // Calculate protobuf overhead with worst-case varint sizes let sample_packet = DnsPacket { - r#type: PacketType::Data.into(), + r#type: PacketType::Data as i32, sequence: total_chunks, conversation_id: "a".repeat(CONV_ID_LENGTH), data: vec![], @@ -462,7 +463,7 @@ impl DNS { ); let init_packet = DnsPacket { - r#type: PacketType::Init.into(), + r#type: PacketType::Init as i32, sequence: 0, conversation_id: conv_id.to_string(), data: init_payload_bytes, @@ -492,7 +493,7 @@ impl DNS { let mut nacks = Vec::new(); if let Ok(status_packet) = DnsPacket::decode(response_data) { - if status_packet.r#type == PacketType::Status.into() { + if status_packet.r#type == PacketType::Status as i32 { // Process ACKs - collect acknowledged sequences for ack_range in &status_packet.acks { for ack_seq in ack_range.start_seq..=ack_range.end_seq { @@ -549,7 +550,7 @@ impl DNS { // Spawn concurrent task for this packet let task = tokio::spawn(async move { let data_packet = DnsPacket { - r#type: PacketType::Data.into(), + r#type: PacketType::Data as i32, sequence: seq_u32, conversation_id: conv_id_clone, data: chunk.clone(), @@ -666,7 +667,7 @@ impl DNS { if let Some(chunk) = chunks.get((nack_seq - 1) as usize) { let retransmit_packet = DnsPacket { - r#type: PacketType::Data.into(), + r#type: PacketType::Data as i32, sequence: nack_seq, conversation_id: conv_id.to_string(), data: chunk.clone(), @@ -718,7 +719,7 @@ impl DNS { ); let fetch_packet = DnsPacket { - r#type: PacketType::Fetch.into(), + r#type: PacketType::Fetch as i32, sequence: (total_chunks + 1) as u32, conversation_id: conv_id.to_string(), data: vec![], @@ -775,7 +776,7 @@ impl DNS { fetch_payload.encode(&mut fetch_payload_bytes)?; let fetch_packet = DnsPacket { - r#type: PacketType::Fetch.into(), + r#type: PacketType::Fetch as i32, sequence: (base_sequence as u32 + 2 + chunk_idx as u32), conversation_id: conv_id.to_string(), data: fetch_payload_bytes, @@ -865,7 +866,7 @@ impl Transport for DNS { } } - fn new(callback: String, _proxy_uri: Option) -> Result { + fn new(callback: String, _config: Config) -> Result { // Parse DNS URL formats: // dns://server:port?domain=dnsc2.realm.pub&type=txt (single server, TXT records) // dns://*?domain=dnsc2.realm.pub&type=a (use system DNS + fallbacks, A records) @@ -1170,8 +1171,11 @@ mod tests { #[test] fn test_new_single_server() { - let dns = DNS::new("dns://8.8.8.8:53?domain=dnsc2.realm.pub".to_string(), None) - .expect("should parse"); + let dns = DNS::new( + "dns://8.8.8.8:53?domain=dnsc2.realm.pub".to_string(), + Config::default(), + ) + .expect("should parse"); assert_eq!(dns.base_domain, "dnsc2.realm.pub"); assert!(dns.dns_servers.contains(&"8.8.8.8:53".to_string())); @@ -1183,7 +1187,7 @@ mod tests { // Multiple servers are specified in the host portion, comma-separated let dns = DNS::new( "dns://8.8.8.8,1.1.1.1:53?domain=dnsc2.realm.pub".to_string(), - None, + Config::default(), ) .expect("should parse"); @@ -1196,7 +1200,7 @@ mod tests { fn test_new_record_type_a() { let dns = DNS::new( "dns://8.8.8.8?domain=dnsc2.realm.pub&type=a".to_string(), - None, + Config::default(), ) .expect("should parse"); assert_eq!(dns.record_type, DnsRecordType::A); @@ -1206,7 +1210,7 @@ mod tests { fn test_new_record_type_aaaa() { let dns = DNS::new( "dns://8.8.8.8?domain=dnsc2.realm.pub&type=aaaa".to_string(), - None, + Config::default(), ) .expect("should parse"); assert_eq!(dns.record_type, DnsRecordType::AAAA); @@ -1214,15 +1218,21 @@ mod tests { #[test] fn test_new_record_type_txt_default() { - let dns = DNS::new("dns://8.8.8.8?domain=dnsc2.realm.pub".to_string(), None) - .expect("should parse"); + let dns = DNS::new( + "dns://8.8.8.8?domain=dnsc2.realm.pub".to_string(), + Config::default(), + ) + .expect("should parse"); assert_eq!(dns.record_type, DnsRecordType::TXT); } #[test] fn test_new_wildcard_uses_fallbacks() { - let dns = - DNS::new("dns://*?domain=dnsc2.realm.pub".to_string(), None).expect("should parse"); + let dns = DNS::new( + "dns://*?domain=dnsc2.realm.pub".to_string(), + Config::default(), + ) + .expect("should parse"); // Should have fallback servers assert!(!dns.dns_servers.is_empty()); @@ -1236,7 +1246,7 @@ mod tests { #[test] fn test_new_missing_domain() { - let result = DNS::new("dns://8.8.8.8:53".to_string(), None); + let result = DNS::new("dns://8.8.8.8:53".to_string(), Config::default()); assert!(result.is_err()); assert!(result .unwrap_err() @@ -1246,8 +1256,11 @@ mod tests { #[test] fn test_new_without_scheme() { - let dns = - DNS::new("8.8.8.8:53?domain=dnsc2.realm.pub".to_string(), None).expect("should parse"); + let dns = DNS::new( + "8.8.8.8:53?domain=dnsc2.realm.pub".to_string(), + Config::default(), + ) + .expect("should parse"); assert_eq!(dns.base_domain, "dnsc2.realm.pub"); } @@ -1265,7 +1278,7 @@ mod tests { }; let packet = DnsPacket { - r#type: PacketType::Init.into(), + r#type: PacketType::Init as i32, sequence: 0, conversation_id: "test1234".to_string(), data: vec![0x01, 0x02], @@ -1304,7 +1317,7 @@ mod tests { // Create a packet with enough data to require label splitting let packet = DnsPacket { - r#type: PacketType::Data.into(), + r#type: PacketType::Data as i32, sequence: 1, conversation_id: "test1234".to_string(), data: vec![0xAA; 50], // 50 bytes of data @@ -1574,7 +1587,7 @@ mod tests { fn test_process_chunk_response_valid_status() { // Create a valid STATUS packet with ACKs let status_packet = DnsPacket { - r#type: PacketType::Status.into(), + r#type: PacketType::Status as i32, sequence: 0, conversation_id: "test".to_string(), data: vec![], diff --git a/implants/lib/transport/src/grpc.rs b/implants/lib/transport/src/grpc.rs index be7321cb8..addaade05 100644 --- a/implants/lib/transport/src/grpc.rs +++ b/implants/lib/transport/src/grpc.rs @@ -1,6 +1,8 @@ use anyhow::Result; use hyper::Uri; use pb::c2::*; +use pb::config::Config; +use std::collections::HashMap; use std::str::FromStr; use std::sync::mpsc::{Receiver, Sender}; use tonic::GrpcMethod; @@ -35,17 +37,37 @@ impl Transport for GRPC { GRPC { grpc: None } } - fn new(callback: String, proxy_uri: Option) -> Result { + fn new(callback: String, config: Config) -> Result { let endpoint = tonic::transport::Endpoint::from_shared(callback)?; - // Create HTTP connector with DNS-over-HTTPS support if enabled + // Parse the EXTRA map + let extra_map: HashMap = if let Some(info) = config.info { + if let Some(active_transport) = info.active_transport { + serde_json::from_str::>(&active_transport.extra)? + } else { + HashMap::new() + } + } else { + HashMap::new() + }; + + #[cfg(feature = "grpc-doh")] + let doh: Option<&String> = extra_map.get("DOH"); + #[cfg(feature = "grpc-doh")] - let mut http: HttpConnector = - crate::dns_resolver::doh::create_doh_connector(DohProvider::Cloudflare)?; + let mut http = match doh { + // TODO: Add provider selection + Some(_provider) => { + crate::dns_resolver::doh::create_doh_connector(DohProvider::Cloudflare)? + } + None => hyper::client::HttpConnector::new(), + }; #[cfg(not(feature = "grpc-doh"))] let mut http = hyper::client::HttpConnector::new(); + let proxy_uri = extra_map.get("HTTP_PROXY"); + http.enforce_http(false); http.set_nodelay(true); @@ -195,7 +217,7 @@ impl Transport for GRPC { } fn get_type(&mut self) -> pb::c2::active_transport::Type { - return pb::c2::active_transport::Type::TransportGrpc; + pb::c2::active_transport::Type::TransportGrpc } fn is_active(&self) -> bool { diff --git a/implants/lib/transport/src/http.rs b/implants/lib/transport/src/http.rs index 3f429ae79..cea3476ef 100644 --- a/implants/lib/transport/src/http.rs +++ b/implants/lib/transport/src/http.rs @@ -3,7 +3,7 @@ use anyhow::{Context, Result}; use bytes::BytesMut; use hyper::body::HttpBody; use hyper::StatusCode; -use pb::c2::*; +use pb::{c2::*, config::Config}; use prost::Message; use std::sync::mpsc::{Receiver, Sender}; @@ -309,7 +309,7 @@ impl Transport for HTTP { } } - fn new(callback: String, _proxy_uri: Option) -> Result { + fn new(callback: String, _config: Config) -> Result { // Create HTTP connector let mut connector = hyper::client::HttpConnector::new(); connector.enforce_http(false); // Allow HTTPS diff --git a/implants/lib/transport/src/lib.rs b/implants/lib/transport/src/lib.rs index 690a00bc1..f3a8ee2b6 100644 --- a/implants/lib/transport/src/lib.rs +++ b/implants/lib/transport/src/lib.rs @@ -1,5 +1,5 @@ use anyhow::{anyhow, Result}; -use pb::c2::*; +use pb::{c2::*, config::Config}; use std::sync::mpsc::{Receiver, Sender}; #[cfg(feature = "grpc")] @@ -40,7 +40,7 @@ impl Transport for ActiveTransport { Self::Empty } - fn new(uri: String, proxy_uri: Option) -> Result { + fn new(uri: String, proxy_uri: Config) -> Result { match uri { // 1. gRPC: Passthrough s if s.starts_with("http://") || s.starts_with("https://") => { @@ -283,7 +283,7 @@ mod tests { ]; for uri in inputs { - let result = ActiveTransport::new(uri.to_string(), None); + let result = ActiveTransport::new(uri.to_string(), Config::default()); // 1. Assert strictly on the Variant type assert!( @@ -322,7 +322,7 @@ mod tests { ]; for uri in inputs { - let result = ActiveTransport::new(uri.to_string(), None); + let result = ActiveTransport::new(uri.to_string(), Config::default()); assert!( matches!(result, Ok(ActiveTransport::Dns(_))), @@ -352,7 +352,7 @@ mod tests { let inputs = vec!["ftp://example.com", "ws://example.com", "random-string", ""]; for uri in inputs { - let result = ActiveTransport::new(uri.to_string(), None); + let result = ActiveTransport::new(uri.to_string(), Config::default()); assert!( result.is_err(), "Expected error for unknown URI scheme: '{}'", diff --git a/implants/lib/transport/src/mock.rs b/implants/lib/transport/src/mock.rs index a76baaaa6..15c6c29f0 100644 --- a/implants/lib/transport/src/mock.rs +++ b/implants/lib/transport/src/mock.rs @@ -12,7 +12,7 @@ mock! { impl super::Transport for Transport { fn init() -> Self; - fn new(uri: String, proxy_uri: Option) -> Result; + fn new(uri: String, config: pb::config::Config) -> Result; async fn claim_tasks(&mut self, request: ClaimTasksRequest) -> Result; diff --git a/implants/lib/transport/src/transport.rs b/implants/lib/transport/src/transport.rs index a59e8737e..023eab624 100644 --- a/implants/lib/transport/src/transport.rs +++ b/implants/lib/transport/src/transport.rs @@ -1,5 +1,5 @@ use anyhow::Result; -use pb::c2::*; +use pb::{c2::*, config::Config}; use std::sync::mpsc::{Receiver, Sender}; #[trait_variant::make(Transport: Send)] @@ -10,7 +10,7 @@ pub trait UnsafeTransport: Clone + Send { // New will create a new instance of the transport using the provided URI. #[allow(dead_code)] - fn new(uri: String, proxy_uri: Option) -> Result; + fn new(uri: String, proxy_uri: Config) -> Result; /// /// Contact the server for new tasks to execute. From e4af562acd1a4d760aa2460b9fb38b3465766ed3 Mon Sep 17 00:00:00 2001 From: hulto <7121375+hulto@users.noreply.github.com> Date: Fri, 2 Jan 2026 03:57:02 +0000 Subject: [PATCH 11/18] Fix proxy uri name. --- implants/lib/transport/src/transport.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/implants/lib/transport/src/transport.rs b/implants/lib/transport/src/transport.rs index 023eab624..1858798a9 100644 --- a/implants/lib/transport/src/transport.rs +++ b/implants/lib/transport/src/transport.rs @@ -10,7 +10,7 @@ pub trait UnsafeTransport: Clone + Send { // New will create a new instance of the transport using the provided URI. #[allow(dead_code)] - fn new(uri: String, proxy_uri: Config) -> Result; + fn new(uri: String, config: Config) -> Result; /// /// Contact the server for new tasks to execute. From 2439dd46eeb2d1c2d993f055730dd8b19e5192bb Mon Sep 17 00:00:00 2001 From: hulto <7121375+hulto@users.noreply.github.com> Date: Fri, 2 Jan 2026 04:03:13 +0000 Subject: [PATCH 12/18] Remove proxy_uri ref --- docs/_docs/dev-guide/imix.md | 2 +- docs/_docs/user-guide/imix.md | 4 ++- implants/imixv2/src/agent.rs | 12 ++++---- implants/lib/pb/Cargo.toml | 1 + implants/lib/pb/src/config.rs | 51 ++----------------------------- implants/lib/transport/src/lib.rs | 10 +++--- 6 files changed, 18 insertions(+), 62 deletions(-) diff --git a/docs/_docs/dev-guide/imix.md b/docs/_docs/dev-guide/imix.md index c183c01dc..f6b1dc6b8 100644 --- a/docs/_docs/dev-guide/imix.md +++ b/docs/_docs/dev-guide/imix.md @@ -163,7 +163,7 @@ impl Transport for Custom { // e.g., client: None } } - fn new(callback: String, proxy_uri: Option) -> Result { + fn new(callback: String, config: Config) -> Result { // TODO: setup connection/client hook in proxy, anything else needed // before functions get called. Err(anyhow!("Unimplemented!")) diff --git a/docs/_docs/user-guide/imix.md b/docs/_docs/user-guide/imix.md index 3c1bca382..e29e8b232 100644 --- a/docs/_docs/user-guide/imix.md +++ b/docs/_docs/user-guide/imix.md @@ -22,9 +22,11 @@ Building in the dev container limits variables that might cause issues and is th | IMIX_SERVER_PUBKEY | The public key for the tavern server (obtain from server using `curl $IMIX_CALLBACK_URI/status`). | automatic | Yes | | IMIX_CALLBACK_INTERVAL | Duration between callbacks, in seconds. | `5` | No | | IMIX_RETRY_INTERVAL | Duration to wait before restarting the agent loop if an error occurs, in seconds. | `5` | No | -| IMIX_PROXY_URI | Overide system settings for proxy URI over HTTP(S) (must specify a scheme, e.g. `https://`) | No proxy | No | | IMIX_HOST_ID | Manually specify the host ID for this beacon. Supersedes the file on disk. | - | No | | IMIX_RUN_ONCE | Imix will only do one callback and execution of queued tasks (may want to pair with runtime environment variable `IMIX_BEACON_ID`) | false | No | +| IMIX_TRANSPORT_EXTRA_HTTP_PROXY | Overide system settings for proxy URI over HTTP(S) (must specify a scheme, e.g. `https://`) | No proxy | No | +| IMIX_TRANSPORT_EXTRA_DOH | Enable DoH, eventually specify which DoH service to use. Requires the grpc-doh flag. | No DoH. | No | + Imix has run-time configuration, that may be specified using environment variables during execution. diff --git a/implants/imixv2/src/agent.rs b/implants/imixv2/src/agent.rs index 8814f0879..e5e7bfae5 100644 --- a/implants/imixv2/src/agent.rs +++ b/implants/imixv2/src/agent.rs @@ -148,8 +148,8 @@ impl ImixAgent { } // 2. Create new transport from config - let (callback_uri, proxy_uri) = self.get_transport_config().await; - let t = T::new(callback_uri, proxy_uri).context("Failed to create on-demand transport")?; + let (callback_uri, config) = self.get_transport_config().await; + let t = T::new(callback_uri, config).context("Failed to create on-demand transport")?; #[cfg(debug_assertions)] log::debug!("Created on-demand transport for background task"); @@ -317,10 +317,6 @@ impl Agent for ImixAgent { .map_err(|e| e.to_string())?; map.insert("callback_uri".to_string(), active_uri); - // TODO: Re-add proxy URI via an "extra" field in config. - // if let Some(proxy) = &cfg.proxy_uri { - // map.insert("proxy_uri".to_string(), proxy.clone()); - // } map.insert( "retry_interval".to_string(), active_transport.interval.to_string(), @@ -350,6 +346,10 @@ impl Agent for ImixAgent { "type".to_string(), active_transport.r#type.clone().to_string(), ); + map.insert( + "extra".to_string(), + active_transport.extra.clone().to_string(), + ); } } Ok(map) diff --git a/implants/lib/pb/Cargo.toml b/implants/lib/pb/Cargo.toml index 10a0fa1d4..bd4ddbee2 100644 --- a/implants/lib/pb/Cargo.toml +++ b/implants/lib/pb/Cargo.toml @@ -17,6 +17,7 @@ host_unique = { workspace = true } log = { workspace = true } netdev = { workspace = true } prost = { workspace = true } +serde_json = { workspace = true } prost-types = { workspace = true } rand_chacha = { workspace = true } tokio = { workspace = true, features = ["macros", "rt-multi-thread"] } diff --git a/implants/lib/pb/src/config.rs b/implants/lib/pb/src/config.rs index 0aa8eb634..acadfd136 100644 --- a/implants/lib/pb/src/config.rs +++ b/implants/lib/pb/src/config.rs @@ -1,3 +1,5 @@ +use std::collections::HashMap; + use uuid::Uuid; use crate::c2::ActiveTransport; @@ -22,16 +24,6 @@ macro_rules! callback_uri { }; } -/* - * Compile-time constant for the agent proxy URI, derived from the IMIX_PROXY_URI environment variable during compilation. - * Defaults to None if this is unset. - */ -macro_rules! proxy_uri { - () => { - option_env!("IMIX_PROXY_URI") - }; -} - /* * Compile-time constant for the agent callback URI, derived from the IMIX_CALLBACK_URI environment variable during compilation. * Defaults to "http://127.0.0.1:8000/grpc" if this is unset. @@ -172,45 +164,6 @@ impl Config { } } -fn get_system_proxy() -> Option { - let proxy_uri_compile_time_override = proxy_uri!(); - if let Some(proxy_uri) = proxy_uri_compile_time_override { - return Some(proxy_uri.to_string()); - } - - #[cfg(target_os = "linux")] - { - match std::env::var("http_proxy") { - Ok(val) => return Some(val), - Err(_e) => { - #[cfg(debug_assertions)] - log::debug!("Didn't find http_proxy env var: {}", _e); - } - } - - match std::env::var("https_proxy") { - Ok(val) => return Some(val), - Err(_e) => { - #[cfg(debug_assertions)] - log::debug!("Didn't find https_proxy env var: {}", _e); - } - } - None - } - #[cfg(target_os = "windows")] - { - None - } - #[cfg(target_os = "macos")] - { - None - } - #[cfg(target_os = "freebsd")] - { - None - } -} - /* * Returns which Platform imix has been compiled for. */ diff --git a/implants/lib/transport/src/lib.rs b/implants/lib/transport/src/lib.rs index f3a8ee2b6..f1c406802 100644 --- a/implants/lib/transport/src/lib.rs +++ b/implants/lib/transport/src/lib.rs @@ -40,12 +40,12 @@ impl Transport for ActiveTransport { Self::Empty } - fn new(uri: String, proxy_uri: Config) -> Result { + fn new(uri: String, config: Config) -> Result { match uri { // 1. gRPC: Passthrough s if s.starts_with("http://") || s.starts_with("https://") => { #[cfg(feature = "grpc")] - return Ok(ActiveTransport::Grpc(grpc::GRPC::new(s, proxy_uri)?)); + return Ok(ActiveTransport::Grpc(grpc::GRPC::new(s, config)?)); #[cfg(not(feature = "grpc"))] return Err(anyhow!("gRPC transport not enabled")); } @@ -57,7 +57,7 @@ impl Transport for ActiveTransport { let new = s .replacen("grpcs://", "https://", 1) .replacen("grpc://", "http://", 1); - Ok(ActiveTransport::Grpc(grpc::GRPC::new(new, proxy_uri)?)) + Ok(ActiveTransport::Grpc(grpc::GRPC::new(new, config)?)) } #[cfg(not(feature = "grpc"))] return Err(anyhow!("gRPC transport not enabled")); @@ -70,7 +70,7 @@ impl Transport for ActiveTransport { let new = s .replacen("https1://", "https://", 1) .replacen("http1://", "http://", 1); - Ok(ActiveTransport::Http(http::HTTP::new(new, proxy_uri)?)) + Ok(ActiveTransport::Http(http::HTTP::new(new, config)?)) } #[cfg(not(feature = "http1"))] return Err(anyhow!("http1 transport not enabled")); @@ -80,7 +80,7 @@ impl Transport for ActiveTransport { s if s.starts_with("dns://") => { #[cfg(feature = "dns")] { - Ok(ActiveTransport::Dns(dns::DNS::new(s, proxy_uri)?)) + Ok(ActiveTransport::Dns(dns::DNS::new(s, config)?)) } #[cfg(not(feature = "dns"))] return Err(anyhow!("DNS transport not enabled")); From 1fe0305e30be3020e72f66ef4c8b7e243033100d Mon Sep 17 00:00:00 2001 From: hulto <7121375+hulto@users.noreply.github.com> Date: Fri, 2 Jan 2026 04:04:46 +0000 Subject: [PATCH 13/18] Update docs. --- docs/_docs/user-guide/imix.md | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/docs/_docs/user-guide/imix.md b/docs/_docs/user-guide/imix.md index e29e8b232..e2d4d39c9 100644 --- a/docs/_docs/user-guide/imix.md +++ b/docs/_docs/user-guide/imix.md @@ -120,13 +120,7 @@ Every callback interval imix will query each active thread for new output and re ## Proxy support -Imix's default `grpc` transport supports http and https proxies for outbound communication. -By default imix will try to determine the systems proxy settings: - -- On Linux reading the environment variables `http_proxy` and then `https_proxy` -- On Windows - we cannot automatically determine the default proxy -- On MacOS - we cannot automatically determine the default proxy -- On FreeBSD - we cannot automatically determine the default proxy +Imix's default `grpc` transport supports http and https proxies for outbound communication. These must be set at compile time. ## Identifying unique hosts From 41c39ee6378ca1df7c86bebb33e7a8a53d0b6bcf Mon Sep 17 00:00:00 2001 From: Hulto <7121375+hulto@users.noreply.github.com> Date: Fri, 2 Jan 2026 00:08:22 -0500 Subject: [PATCH 14/18] Address PR review comments for active transport refactor (#1490) --- implants/imix/src/run.rs | 17 ++++++++--------- implants/imixv2/src/agent.rs | 14 ++------------ 2 files changed, 10 insertions(+), 21 deletions(-) diff --git a/implants/imix/src/run.rs b/implants/imix/src/run.rs index c57b53c81..ad945bb0f 100644 --- a/implants/imix/src/run.rs +++ b/implants/imix/src/run.rs @@ -8,6 +8,8 @@ pub use pb::config::Config; use transport::{ActiveTransport, Transport}; +const DEFAULT_RETRY_INTERVAL: u64 = 5; + pub async fn handle_main() { if let Some(("install", _)) = Command::new("imix") .subcommand(Command::new("install").about("Install imix")) @@ -20,15 +22,12 @@ pub async fn handle_main() { loop { let cfg = Config::default_with_imix_version(VERSION); - let retry_interval = if let Some(beacon) = cfg.info.as_ref() { - if let Some(transport) = &beacon.active_transport { - transport.interval - } else { - 5 - } - } else { - 5 - }; + let retry_interval = cfg + .info + .as_ref() + .and_then(|beacon| beacon.active_transport.as_ref()) + .map(|transport| transport.interval) + .unwrap_or(DEFAULT_RETRY_INTERVAL); #[cfg(debug_assertions)] log::info!("agent config initialized {:#?}", cfg.clone()); diff --git a/implants/imixv2/src/agent.rs b/implants/imixv2/src/agent.rs index e5e7bfae5..8fceb643d 100644 --- a/implants/imixv2/src/agent.rs +++ b/implants/imixv2/src/agent.rs @@ -304,15 +304,10 @@ impl Agent for ImixAgent { let active_uri = self.get_active_callback_uri().unwrap_or_default(); let config = cfg.clone(); - let info = config + let active_transport = config .info .as_ref() - .context("failed to get config info") - .map_err(|e| e.to_string())?; - - let active_transport = info - .clone() - .active_transport + .and_then(|info| info.active_transport.as_ref()) .context("failed to get active transport") .map_err(|e| e.to_string())?; @@ -337,11 +332,6 @@ impl Agent for ImixAgent { } if let Some(active_transport) = &info.active_transport { map.insert("uri".to_string(), active_transport.uri.clone()); - map.insert( - "interval".to_string(), - active_transport.interval.clone().to_string(), - ); - map.insert("primary_ip".to_string(), active_transport.extra.clone()); map.insert( "type".to_string(), active_transport.r#type.clone().to_string(), From 3cd57d16eedafffb20fc9416ef74552fe098b30f Mon Sep 17 00:00:00 2001 From: hulto <7121375+hulto@users.noreply.github.com> Date: Fri, 2 Jan 2026 17:11:35 +0000 Subject: [PATCH 15/18] Cleanup todos --- implants/imixv2/src/agent.rs | 1 - implants/lib/eldritch/src/runtime/messages/set_callback_uri.rs | 1 - 2 files changed, 2 deletions(-) diff --git a/implants/imixv2/src/agent.rs b/implants/imixv2/src/agent.rs index 8fceb643d..988dfd2ba 100644 --- a/implants/imixv2/src/agent.rs +++ b/implants/imixv2/src/agent.rs @@ -123,7 +123,6 @@ impl ImixAgent { // Fallback, should not happen unless empty uris.first().cloned().unwrap_or_default() }; - //TODO: Re-add proxy URI via an "extra" field in config. (callback_uri, config) } diff --git a/implants/lib/eldritch/src/runtime/messages/set_callback_uri.rs b/implants/lib/eldritch/src/runtime/messages/set_callback_uri.rs index 1d49791c7..74cdddb56 100644 --- a/implants/lib/eldritch/src/runtime/messages/set_callback_uri.rs +++ b/implants/lib/eldritch/src/runtime/messages/set_callback_uri.rs @@ -16,7 +16,6 @@ pub struct SetCallbackUriMessage { impl SyncDispatcher for SetCallbackUriMessage { fn dispatch(self, _transport: &mut impl Transport, cfg: Config) -> Result { let mut c = cfg.clone(); - //TODO: make sure this works :? c.info .as_mut() .context("missing config info")? From 8ee15e3d0e9720946bf3decb9e4c1533773ff772 Mon Sep 17 00:00:00 2001 From: hulto <7121375+hulto@users.noreply.github.com> Date: Fri, 2 Jan 2026 17:17:55 +0000 Subject: [PATCH 16/18] go generate --- tavern/internal/graphql/schema.graphql | 9 --------- tavern/internal/graphql/schema/ent.graphql | 9 --------- tavern/internal/www/schema.graphql | 9 --------- 3 files changed, 27 deletions(-) diff --git a/tavern/internal/graphql/schema.graphql b/tavern/internal/graphql/schema.graphql index 309ba859d..5d7e8b1f3 100644 --- a/tavern/internal/graphql/schema.graphql +++ b/tavern/internal/graphql/schema.graphql @@ -177,15 +177,6 @@ enum BeaconOrderField { INTERVAL } """ -BeaconTransport is enum for the field transport -""" -enum BeaconTransport @goModel(model: "realm.pub/tavern/internal/c2/c2pb.Beacon_Transport") { - TRANSPORT_DNS - TRANSPORT_GRPC - TRANSPORT_HTTP1 - TRANSPORT_UNSPECIFIED -} -""" BeaconWhereInput is used for filtering Beacon objects. Input was generated by ent. """ diff --git a/tavern/internal/graphql/schema/ent.graphql b/tavern/internal/graphql/schema/ent.graphql index 7becd1cca..369bacb81 100644 --- a/tavern/internal/graphql/schema/ent.graphql +++ b/tavern/internal/graphql/schema/ent.graphql @@ -172,15 +172,6 @@ enum BeaconOrderField { INTERVAL } """ -BeaconTransport is enum for the field transport -""" -enum BeaconTransport @goModel(model: "realm.pub/tavern/internal/c2/c2pb.Beacon_Transport") { - TRANSPORT_DNS - TRANSPORT_GRPC - TRANSPORT_HTTP1 - TRANSPORT_UNSPECIFIED -} -""" BeaconWhereInput is used for filtering Beacon objects. Input was generated by ent. """ diff --git a/tavern/internal/www/schema.graphql b/tavern/internal/www/schema.graphql index 309ba859d..5d7e8b1f3 100644 --- a/tavern/internal/www/schema.graphql +++ b/tavern/internal/www/schema.graphql @@ -177,15 +177,6 @@ enum BeaconOrderField { INTERVAL } """ -BeaconTransport is enum for the field transport -""" -enum BeaconTransport @goModel(model: "realm.pub/tavern/internal/c2/c2pb.Beacon_Transport") { - TRANSPORT_DNS - TRANSPORT_GRPC - TRANSPORT_HTTP1 - TRANSPORT_UNSPECIFIED -} -""" BeaconWhereInput is used for filtering Beacon objects. Input was generated by ent. """ From 903f87980d53c3bdc0b424c882c29b918bd66d2b Mon Sep 17 00:00:00 2001 From: hulto <7121375+hulto@users.noreply.github.com> Date: Fri, 2 Jan 2026 17:35:22 +0000 Subject: [PATCH 17/18] fix e2e test --- tavern/test_data.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tavern/test_data.go b/tavern/test_data.go index a89b49e76..606f18b2f 100644 --- a/tavern/test_data.go +++ b/tavern/test_data.go @@ -84,8 +84,8 @@ func createTestData(ctx context.Context, client *ent.Client) { SaveX(ctx) // Cycle through transports: HTTP1, GRPC, DNS - getTransport := func(idx int) c2pb.Beacon_Transport { - transports := []c2pb.Beacon_Transport{ + getTransport := func(idx int) c2pb.ActiveTransport_Type { + transports := []c2pb.ActiveTransport_Type{ c2pb.ActiveTransport_TRANSPORT_HTTP1, c2pb.ActiveTransport_TRANSPORT_GRPC, c2pb.ActiveTransport_TRANSPORT_DNS, From 0bebdc76b16a7890c45cb18de7bcf375824e74d1 Mon Sep 17 00:00:00 2001 From: hulto <7121375+hulto@users.noreply.github.com> Date: Fri, 2 Jan 2026 17:57:47 +0000 Subject: [PATCH 18/18] fmt --- implants/imixv2/src/agent.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/implants/imixv2/src/agent.rs b/implants/imixv2/src/agent.rs index 2ca77fe26..867b4eb16 100644 --- a/implants/imixv2/src/agent.rs +++ b/implants/imixv2/src/agent.rs @@ -405,12 +405,12 @@ impl Agent for ImixAgent { fn set_callback_interval(&self, interval: u64) -> Result<(), String> { self.block_on(async { { - let mut cfg = self.config.write().await; - if let Some(info) = &mut cfg.info - && let Some(active_transport) = &mut info.active_transport - { - active_transport.interval = interval; - } + let mut cfg = self.config.write().await; + if let Some(info) = &mut cfg.info + && let Some(active_transport) = &mut info.active_transport + { + active_transport.interval = interval; + } } // We force a check-in to update the server with the new interval let _ = self.process_job_request().await;