diff --git a/api/grpc/scanner/scanner.pb.go b/api/grpc/scanner/scanner.pb.go new file mode 100644 index 0000000000..bb70c71009 --- /dev/null +++ b/api/grpc/scanner/scanner.pb.go @@ -0,0 +1,321 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.26.0 +// protoc v5.26.1 +// source: scanner/scanner.proto + +package scanner + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type PortCheckRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Port uint32 `protobuf:"varint,1,opt,name=port,proto3" json:"port,omitempty"` +} + +func (x *PortCheckRequest) Reset() { + *x = PortCheckRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_scanner_scanner_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *PortCheckRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PortCheckRequest) ProtoMessage() {} + +func (x *PortCheckRequest) ProtoReflect() protoreflect.Message { + mi := &file_scanner_scanner_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PortCheckRequest.ProtoReflect.Descriptor instead. +func (*PortCheckRequest) Descriptor() ([]byte, []int) { + return file_scanner_scanner_proto_rawDescGZIP(), []int{0} +} + +func (x *PortCheckRequest) GetPort() uint32 { + if x != nil { + return x.Port + } + return 0 +} + +type HostPortCheckRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Port uint32 `protobuf:"varint,1,opt,name=port,proto3" json:"port,omitempty"` + Host string `protobuf:"bytes,2,opt,name=host,proto3" json:"host,omitempty"` +} + +func (x *HostPortCheckRequest) Reset() { + *x = HostPortCheckRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_scanner_scanner_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *HostPortCheckRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*HostPortCheckRequest) ProtoMessage() {} + +func (x *HostPortCheckRequest) ProtoReflect() protoreflect.Message { + mi := &file_scanner_scanner_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use HostPortCheckRequest.ProtoReflect.Descriptor instead. +func (*HostPortCheckRequest) Descriptor() ([]byte, []int) { + return file_scanner_scanner_proto_rawDescGZIP(), []int{1} +} + +func (x *HostPortCheckRequest) GetPort() uint32 { + if x != nil { + return x.Port + } + return 0 +} + +func (x *HostPortCheckRequest) GetHost() string { + if x != nil { + return x.Host + } + return "" +} + +type PortCheckResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Port uint32 `protobuf:"varint,1,opt,name=port,proto3" json:"port,omitempty"` + Host string `protobuf:"bytes,2,opt,name=host,proto3" json:"host,omitempty"` + Status string `protobuf:"bytes,3,opt,name=status,proto3" json:"status,omitempty"` + Msg string `protobuf:"bytes,4,opt,name=msg,proto3" json:"msg,omitempty"` +} + +func (x *PortCheckResponse) Reset() { + *x = PortCheckResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_scanner_scanner_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *PortCheckResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PortCheckResponse) ProtoMessage() {} + +func (x *PortCheckResponse) ProtoReflect() protoreflect.Message { + mi := &file_scanner_scanner_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PortCheckResponse.ProtoReflect.Descriptor instead. +func (*PortCheckResponse) Descriptor() ([]byte, []int) { + return file_scanner_scanner_proto_rawDescGZIP(), []int{2} +} + +func (x *PortCheckResponse) GetPort() uint32 { + if x != nil { + return x.Port + } + return 0 +} + +func (x *PortCheckResponse) GetHost() string { + if x != nil { + return x.Host + } + return "" +} + +func (x *PortCheckResponse) GetStatus() string { + if x != nil { + return x.Status + } + return "" +} + +func (x *PortCheckResponse) GetMsg() string { + if x != nil { + return x.Msg + } + return "" +} + +var File_scanner_scanner_proto protoreflect.FileDescriptor + +var file_scanner_scanner_proto_rawDesc = []byte{ + 0x0a, 0x15, 0x73, 0x63, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x2f, 0x73, 0x63, 0x61, 0x6e, 0x6e, 0x65, + 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x07, 0x73, 0x63, 0x61, 0x6e, 0x6e, 0x65, 0x72, + 0x22, 0x26, 0x0a, 0x10, 0x50, 0x6f, 0x72, 0x74, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0d, 0x52, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x22, 0x3e, 0x0a, 0x14, 0x48, 0x6f, 0x73, 0x74, + 0x50, 0x6f, 0x72, 0x74, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x12, 0x12, 0x0a, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, + 0x70, 0x6f, 0x72, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x6f, 0x73, 0x74, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x04, 0x68, 0x6f, 0x73, 0x74, 0x22, 0x65, 0x0a, 0x11, 0x50, 0x6f, 0x72, 0x74, + 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x12, 0x0a, + 0x04, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x70, 0x6f, 0x72, + 0x74, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x6f, 0x73, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x04, 0x68, 0x6f, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x10, 0x0a, + 0x03, 0x6d, 0x73, 0x67, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6d, 0x73, 0x67, 0x32, + 0xa5, 0x01, 0x0a, 0x13, 0x52, 0x65, 0x61, 0x63, 0x68, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, + 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x44, 0x0a, 0x09, 0x50, 0x6f, 0x72, 0x74, 0x43, + 0x68, 0x65, 0x63, 0x6b, 0x12, 0x19, 0x2e, 0x73, 0x63, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x2e, 0x50, + 0x6f, 0x72, 0x74, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x1a, 0x2e, 0x73, 0x63, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x2e, 0x50, 0x6f, 0x72, 0x74, 0x43, 0x68, + 0x65, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x48, 0x0a, + 0x0d, 0x48, 0x6f, 0x73, 0x74, 0x50, 0x6f, 0x72, 0x74, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x12, 0x19, + 0x2e, 0x73, 0x63, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x2e, 0x50, 0x6f, 0x72, 0x74, 0x43, 0x68, 0x65, + 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x73, 0x63, 0x61, 0x6e, + 0x6e, 0x65, 0x72, 0x2e, 0x50, 0x6f, 0x72, 0x74, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x2f, 0x5a, 0x2d, 0x67, 0x69, 0x74, 0x68, 0x75, + 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x4c, 0x61, 0x79, 0x72, 0x2d, 0x4c, 0x61, 0x62, 0x73, 0x2f, + 0x65, 0x69, 0x67, 0x65, 0x6e, 0x64, 0x61, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x67, 0x72, 0x70, 0x63, + 0x2f, 0x73, 0x63, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_scanner_scanner_proto_rawDescOnce sync.Once + file_scanner_scanner_proto_rawDescData = file_scanner_scanner_proto_rawDesc +) + +func file_scanner_scanner_proto_rawDescGZIP() []byte { + file_scanner_scanner_proto_rawDescOnce.Do(func() { + file_scanner_scanner_proto_rawDescData = protoimpl.X.CompressGZIP(file_scanner_scanner_proto_rawDescData) + }) + return file_scanner_scanner_proto_rawDescData +} + +var file_scanner_scanner_proto_msgTypes = make([]protoimpl.MessageInfo, 3) +var file_scanner_scanner_proto_goTypes = []interface{}{ + (*PortCheckRequest)(nil), // 0: scanner.PortCheckRequest + (*HostPortCheckRequest)(nil), // 1: scanner.HostPortCheckRequest + (*PortCheckResponse)(nil), // 2: scanner.PortCheckResponse +} +var file_scanner_scanner_proto_depIdxs = []int32{ + 0, // 0: scanner.ReachabilityService.PortCheck:input_type -> scanner.PortCheckRequest + 0, // 1: scanner.ReachabilityService.HostPortCheck:input_type -> scanner.PortCheckRequest + 2, // 2: scanner.ReachabilityService.PortCheck:output_type -> scanner.PortCheckResponse + 2, // 3: scanner.ReachabilityService.HostPortCheck:output_type -> scanner.PortCheckResponse + 2, // [2:4] is the sub-list for method output_type + 0, // [0:2] is the sub-list for method input_type + 0, // [0:0] is the sub-list for extension type_name + 0, // [0:0] is the sub-list for extension extendee + 0, // [0:0] is the sub-list for field type_name +} + +func init() { file_scanner_scanner_proto_init() } +func file_scanner_scanner_proto_init() { + if File_scanner_scanner_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_scanner_scanner_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*PortCheckRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_scanner_scanner_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*HostPortCheckRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_scanner_scanner_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*PortCheckResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_scanner_scanner_proto_rawDesc, + NumEnums: 0, + NumMessages: 3, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_scanner_scanner_proto_goTypes, + DependencyIndexes: file_scanner_scanner_proto_depIdxs, + MessageInfos: file_scanner_scanner_proto_msgTypes, + }.Build() + File_scanner_scanner_proto = out.File + file_scanner_scanner_proto_rawDesc = nil + file_scanner_scanner_proto_goTypes = nil + file_scanner_scanner_proto_depIdxs = nil +} diff --git a/api/grpc/scanner/scanner_grpc.pb.go b/api/grpc/scanner/scanner_grpc.pb.go new file mode 100644 index 0000000000..92db69286c --- /dev/null +++ b/api/grpc/scanner/scanner_grpc.pb.go @@ -0,0 +1,137 @@ +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. + +package scanner + +import ( + context "context" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" +) + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +// Requires gRPC-Go v1.32.0 or later. +const _ = grpc.SupportPackageIsVersion7 + +// ReachabilityServiceClient is the client API for ReachabilityService service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +type ReachabilityServiceClient interface { + PortCheck(ctx context.Context, in *PortCheckRequest, opts ...grpc.CallOption) (*PortCheckResponse, error) + HostPortCheck(ctx context.Context, in *PortCheckRequest, opts ...grpc.CallOption) (*PortCheckResponse, error) +} + +type reachabilityServiceClient struct { + cc grpc.ClientConnInterface +} + +func NewReachabilityServiceClient(cc grpc.ClientConnInterface) ReachabilityServiceClient { + return &reachabilityServiceClient{cc} +} + +func (c *reachabilityServiceClient) PortCheck(ctx context.Context, in *PortCheckRequest, opts ...grpc.CallOption) (*PortCheckResponse, error) { + out := new(PortCheckResponse) + err := c.cc.Invoke(ctx, "/scanner.ReachabilityService/PortCheck", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *reachabilityServiceClient) HostPortCheck(ctx context.Context, in *PortCheckRequest, opts ...grpc.CallOption) (*PortCheckResponse, error) { + out := new(PortCheckResponse) + err := c.cc.Invoke(ctx, "/scanner.ReachabilityService/HostPortCheck", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// ReachabilityServiceServer is the server API for ReachabilityService service. +// All implementations must embed UnimplementedReachabilityServiceServer +// for forward compatibility +type ReachabilityServiceServer interface { + PortCheck(context.Context, *PortCheckRequest) (*PortCheckResponse, error) + HostPortCheck(context.Context, *PortCheckRequest) (*PortCheckResponse, error) + mustEmbedUnimplementedReachabilityServiceServer() +} + +// UnimplementedReachabilityServiceServer must be embedded to have forward compatible implementations. +type UnimplementedReachabilityServiceServer struct { +} + +func (UnimplementedReachabilityServiceServer) PortCheck(context.Context, *PortCheckRequest) (*PortCheckResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method PortCheck not implemented") +} +func (UnimplementedReachabilityServiceServer) HostPortCheck(context.Context, *PortCheckRequest) (*PortCheckResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method HostPortCheck not implemented") +} +func (UnimplementedReachabilityServiceServer) mustEmbedUnimplementedReachabilityServiceServer() {} + +// UnsafeReachabilityServiceServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to ReachabilityServiceServer will +// result in compilation errors. +type UnsafeReachabilityServiceServer interface { + mustEmbedUnimplementedReachabilityServiceServer() +} + +func RegisterReachabilityServiceServer(s grpc.ServiceRegistrar, srv ReachabilityServiceServer) { + s.RegisterService(&ReachabilityService_ServiceDesc, srv) +} + +func _ReachabilityService_PortCheck_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(PortCheckRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ReachabilityServiceServer).PortCheck(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/scanner.ReachabilityService/PortCheck", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ReachabilityServiceServer).PortCheck(ctx, req.(*PortCheckRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _ReachabilityService_HostPortCheck_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(PortCheckRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ReachabilityServiceServer).HostPortCheck(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/scanner.ReachabilityService/HostPortCheck", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ReachabilityServiceServer).HostPortCheck(ctx, req.(*PortCheckRequest)) + } + return interceptor(ctx, in, info, handler) +} + +// ReachabilityService_ServiceDesc is the grpc.ServiceDesc for ReachabilityService service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var ReachabilityService_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "scanner.ReachabilityService", + HandlerType: (*ReachabilityServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "PortCheck", + Handler: _ReachabilityService_PortCheck_Handler, + }, + { + MethodName: "HostPortCheck", + Handler: _ReachabilityService_HostPortCheck_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "scanner/scanner.proto", +} diff --git a/api/proto/scanner/scanner.proto b/api/proto/scanner/scanner.proto new file mode 100644 index 0000000000..62686b42e9 --- /dev/null +++ b/api/proto/scanner/scanner.proto @@ -0,0 +1,26 @@ +syntax = "proto3"; + +package scanner; + +option go_package = "github.com/Layr-Labs/eigenda/api/grpc/scanner"; + +message PortCheckRequest { + uint32 port = 1; +} + +message HostPortCheckRequest { + uint32 port = 1; + string host = 2; +} + +message PortCheckResponse { + uint32 port = 1; + string host = 2; + string status = 3; + string msg = 4; +} + +service ReachabilityService { + rpc PortCheck (PortCheckRequest) returns (PortCheckResponse) {} + rpc HostPortCheck (PortCheckRequest) returns (PortCheckResponse) {} +} diff --git a/go.mod b/go.mod index c94d1c6783..113d0917c6 100644 --- a/go.mod +++ b/go.mod @@ -7,6 +7,7 @@ toolchain go1.21.1 require ( github.com/Layr-Labs/eigenda/api v0.0.0 github.com/Layr-Labs/eigensdk-go v0.1.6-0.20240409054704-47c41ef999a9 + github.com/Ullaakut/nmap/v3 v3.0.3 github.com/aws/aws-sdk-go-v2 v1.26.0 github.com/aws/aws-sdk-go-v2/credentials v1.17.9 github.com/aws/aws-sdk-go-v2/feature/dynamodb/attributevalue v1.13.12 diff --git a/go.sum b/go.sum index 35ef87e1c1..dcd528791e 100644 --- a/go.sum +++ b/go.sum @@ -27,6 +27,8 @@ github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdko github.com/Shopify/goreferrer v0.0.0-20181106222321-ec9c9a553398/go.mod h1:a1uqRtAwp2Xwc6WNPJEufxJ7fx3npB4UV/JOLmbu5I0= github.com/StackExchange/wmi v1.2.1 h1:VIkavFPXSjcnS+O8yTq7NI32k0R5Aj+v39y29VYDOSA= github.com/StackExchange/wmi v1.2.1/go.mod h1:rcmrprowKIVzvc+NUiLncP2uuArMWLCbu9SBzvHz7e8= +github.com/Ullaakut/nmap v2.0.2+incompatible h1:edw45QpSQBQ2B/Hqfg86Bt5rrK79tp/fAcqIHyNSdQs= +github.com/Ullaakut/nmap v2.0.2+incompatible/go.mod h1:fkC066hwfcoKwlI7DS2ARTggSVtBTZYCjVH1TzuTMaQ= github.com/VictoriaMetrics/fastcache v1.12.1 h1:i0mICQuojGDL3KblA7wUNlY5lOK6a4bwt3uRKnkZU40= github.com/VictoriaMetrics/fastcache v1.12.1/go.mod h1:tX04vaqcNoQeGLD+ra5pU5sWkuxnzWhEzLwhP9w653o= github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY= diff --git a/scanner/Makefile b/scanner/Makefile new file mode 100644 index 0000000000..0e56f9bc64 --- /dev/null +++ b/scanner/Makefile @@ -0,0 +1,15 @@ +build: clean + # cd .. && make protoc + go mod tidy + go build -o ./bin/scanner ./cmd + +docker: build + cd .. && docker build . -t scanner -f scanner/cmd/Dockerfile + +clean: + rm -rf ./bin + +lint: + golint -set_exit_status ./... + go tool fix ./.. + golangci-lint run diff --git a/scanner/README.md b/scanner/README.md new file mode 100644 index 0000000000..9338779576 --- /dev/null +++ b/scanner/README.md @@ -0,0 +1,3 @@ +# EigenDA Node Reachability Scanner + +The EigenDA Node Reachability Scanner allows Operators to initiate port scans from the EigenDA backend to validate e2e reachability. diff --git a/scanner/cmd/Dockerfile b/scanner/cmd/Dockerfile new file mode 100644 index 0000000000..ad4549e080 --- /dev/null +++ b/scanner/cmd/Dockerfile @@ -0,0 +1,21 @@ +FROM golang:1.21.1-alpine3.18 as builder + +RUN apk add --no-cache make musl-dev linux-headers gcc git jq bash + +# build node scanner with local monorepo go modules +COPY ./scanner /app/scanner +COPY api /app/api +COPY common /app/common +COPY core /app/core +COPY go.mod /app +COPY go.sum /app + +WORKDIR /app/scanner + +RUN go build -o ./bin/scanner ./cmd + +FROM alpine:3.18 + +COPY --from=builder /app/scanner/bin/scanner /usr/local/bin + +ENTRYPOINT ["scanner"] diff --git a/scanner/cmd/main.go b/scanner/cmd/main.go new file mode 100644 index 0000000000..eebf476fd7 --- /dev/null +++ b/scanner/cmd/main.go @@ -0,0 +1,68 @@ +package main + +import ( + "context" + "fmt" + "log" + "os" + + "github.com/urfave/cli" + + "github.com/Layr-Labs/eigenda/common" + "github.com/Layr-Labs/eigenda/scanner" + "github.com/Layr-Labs/eigenda/scanner/flags" + "github.com/Layr-Labs/eigenda/scanner/grpc" +) + +func main() { + app := cli.NewApp() + app.Flags = flags.Flags + app.Version = fmt.Sprintf("%s-%s-%s", scanner.SemVer, scanner.GitCommit, scanner.GitDate) + app.Name = scanner.AppName + app.Usage = "EigenDA Node Reachability Scanner" + app.Description = "Service for checking the reachabilty of operator nodes" + + app.Action = ScannerMain + err := app.Run(os.Args) + if err != nil { + log.Fatalf("application failed: %v", err) + } + + select {} +} + +// ScannerMain func +func ScannerMain(ctx *cli.Context) error { + log.Println("Initializing node scanner") + config, err := scanner.NewConfig(ctx) + if err != nil { + return err + } + + logger, err := common.NewLogger(config.LoggerConfig) + if err != nil { + return err + } + + // Create the node scanner. + scanner, err := scanner.NewScanner(config, logger) + if err != nil { + return err + } + + err = scanner.Start(context.Background()) + if err != nil { + scanner.Logger.Error("could not start node scanner", "error", err) + return err + } + + //ratelimiter := ratelimit.NewRateLimiter(globalParams, bucketStore, logger) + + // Creates the GRPC server. + server := grpc.NewServer(config, scanner, logger) //, ratelimiter) + if err := server.Start(); err != nil { + log.Fatalf("Failed to start server: %v", err) + } + + return nil +} diff --git a/scanner/config.go b/scanner/config.go new file mode 100644 index 0000000000..0abd267832 --- /dev/null +++ b/scanner/config.go @@ -0,0 +1,47 @@ +package scanner + +import ( + "time" + + "github.com/Layr-Labs/eigenda/common" + "github.com/Layr-Labs/eigenda/scanner/flags" + "github.com/urfave/cli" +) + +// Scanner +const ( + AppName = "scanner" + SemVer = "1.0.0" + GitCommit = "" + GitDate = "" +) + +// Config contains all of the configuration information for a scanner +type Config struct { + ServerPort string + MetricsPort string + Timeout time.Duration + + LoggerConfig common.LoggerConfig +} + +// NewConfig parses the Config from the provided flags or environment variables and +// returns a Config. +func NewConfig(ctx *cli.Context) (*Config, error) { + timeout, err := time.ParseDuration(ctx.GlobalString(flags.TimeoutFlag.Name)) + if err != nil { + return &Config{}, err + } + + loggerConfig, err := common.ReadLoggerCLIConfig(ctx, flags.FlagPrefix) + if err != nil { + return nil, err + } + + return &Config{ + ServerPort: ctx.GlobalString(flags.ServerPortFlag.Name), + MetricsPort: ctx.GlobalString(flags.MetricsPortFlag.Name), + Timeout: timeout, + LoggerConfig: *loggerConfig, + }, nil +} diff --git a/scanner/flags/flags.go b/scanner/flags/flags.go new file mode 100644 index 0000000000..32bdf034a3 --- /dev/null +++ b/scanner/flags/flags.go @@ -0,0 +1,58 @@ +package flags + +import ( + "github.com/Layr-Labs/eigenda/common" + "github.com/urfave/cli" +) + +// constants +const ( + FlagPrefix = "scanner" + EnvVarPrefix = "SCANNER" +) + +var ( + /* Required Flags */ + + // ServerPortFlag used to serve requests + ServerPortFlag = cli.StringFlag{ + Name: common.PrefixFlag(FlagPrefix, "port"), + Usage: "Server listening port", + Value: "32001", + Required: false, + EnvVar: common.PrefixEnvVar(EnvVarPrefix, "PORT"), + } + // MetricsPortFlag used to serve metrics + MetricsPortFlag = cli.StringFlag{ + Name: common.PrefixFlag(FlagPrefix, "metrics-port"), + Usage: "Metrics listening port", + Required: false, + Value: "9091", + EnvVar: common.PrefixEnvVar(EnvVarPrefix, "METRICS_PORT"), + } + // TimeoutFlag determines scan timeout + TimeoutFlag = cli.StringFlag{ + Name: common.PrefixFlag(FlagPrefix, "timeout"), + Usage: "Amount of time to wait for port scan to complete", + Required: false, + Value: "5s", + EnvVar: common.PrefixEnvVar(EnvVarPrefix, "TIMEOUT"), + } +) + +var requiredFlags = []cli.Flag{ + ServerPortFlag, + MetricsPortFlag, + TimeoutFlag, +} + +var optionalFlags = []cli.Flag{} + +// init +func init() { + Flags = append(requiredFlags, optionalFlags...) + Flags = append(Flags, common.LoggerCLIFlags(EnvVarPrefix, FlagPrefix)...) +} + +// Flags contains the list of configuration options available to the binary. +var Flags []cli.Flag diff --git a/scanner/grpc/server.go b/scanner/grpc/server.go new file mode 100644 index 0000000000..357f9450e2 --- /dev/null +++ b/scanner/grpc/server.go @@ -0,0 +1,155 @@ +package grpc + +import ( + "context" + "fmt" + "log" + "net" + "time" + + pb "github.com/Layr-Labs/eigenda/api/grpc/scanner" + "github.com/Layr-Labs/eigenda/common" + "github.com/Layr-Labs/eigenda/scanner" + "github.com/Layr-Labs/eigensdk-go/logging" + "github.com/Ullaakut/nmap" + + "google.golang.org/grpc" + "google.golang.org/grpc/peer" + "google.golang.org/grpc/reflection" +) + +const localhost = "0.0.0.0" + +// Server implements the Scanner proto APIs. +type Server struct { + pb.UnimplementedReachabilityServer + + scanner *scanner.Scanner + config *scanner.Config + logger logging.Logger + + ratelimiter common.RateLimiter +} + +// NewServer func +func NewServer(config *scanner.Config, scanner *scanner.Scanner, logger logging.Logger) *Server { + return &Server{ + config: config, + logger: logger, + scanner: scanner, + ratelimiter: nil, + } +} + +// Start func +func (s *Server) Start() error { + + addr := fmt.Sprintf("%s:%s", localhost, s.config.ServerPort) + lis, err := net.Listen("tcp", addr) + if err != nil { + log.Fatalf("failed to start tcp listener: %v", err) + } + + s.logger.Info("registering service") + //opt := grpc.MaxRecvMsgSize(128) + gs := grpc.NewServer() + reflection.Register(gs) + pb.RegisterReachabilityServer(gs, s) + + s.logger.Info("port", s.config.ServerPort, "address", lis.Addr().String(), "GRPC Listening") + if err := gs.Serve(lis); err != nil { + log.Fatalf("failed to serve: %v", err) + } + return nil +} + +// PortCheck func +func (s *Server) PortCheck(ctx context.Context, in *pb.PortCheckRequest) (*pb.PortCheckResponse, error) { + + p, ok := peer.FromContext(ctx) + if !ok { + log.Println("Could not get peer from context") + return &pb.PortCheckResponse{Status: "error", Msg: "Could not get peer ip from context"}, nil + } + peerAddr := p.Addr.String() + ip, _, err := net.SplitHostPort(peerAddr) + if err != nil { + log.Printf("Could not split host and port: %v", err) + return &pb.PortCheckResponse{Status: "error", Msg: "Could not parse host ip"}, nil + } + + var timeout = 5 * time.Second + _, cancel := context.WithTimeout(context.Background(), timeout) + defer cancel() + + scan, err := nmap.NewScanner( + nmap.WithTargets(ip), + nmap.WithPorts(fmt.Sprintf("%d", in.Port)), + ) + if err != nil { + //log.Fatalf("unable to create nmap scanner: %v", err) + return &pb.PortCheckResponse{Status: "error", Msg: "Port scan failed", Host: ip, Port: in.Port}, nil + } + + result, warnings, err := scan.Run() + if len(warnings) > 0 { + log.Printf("run finished with warnings: %s\n", warnings) // Warnings are non-critical errors from nmap. + } + if err != nil { + //log.Fatalf("unable to run nmap scan: %v", err) + return &pb.PortCheckResponse{Status: "error", Msg: "Port scan failed", Host: ip, Port: in.Port}, nil + } + + // Use the results to print an example output + host := result.Hosts[0] + if len(host.Ports) == 0 || len(host.Addresses) == 0 { + return &pb.PortCheckResponse{Status: "error", Msg: "No scan results"}, nil + } + + port := host.Ports[0] + fmt.Printf("\tPort %d %s\n", port.ID, port.State) + fmt.Printf("Host scanned in %.2f seconds\n", result.Stats.Finished.Elapsed) + return &pb.PortCheckResponse{Status: port.State.String(), Msg: "", Port: in.Port, Host: ip}, nil +} + +// HostPortCheck func +func (s *Server) HostPortCheck(ctx context.Context, in *pb.HostPortCheckRequest) (*pb.PortCheckResponse, error) { + + if in.Host == "" { + //log.Fatalf("unable to create nmap scanner: %v", err) + return &pb.PortCheckResponse{Status: "error", Msg: "Host must be specified", Host: in.Host, Port: in.Port}, nil + } + var timeout = 5 * time.Second + _, cancel := context.WithTimeout(context.Background(), timeout) + defer cancel() + + scan, err := nmap.NewScanner( + nmap.WithTargets(in.Host), + nmap.WithPorts(fmt.Sprintf("%d", in.Port)), + ) + if err != nil { + //log.Fatalf("unable to create nmap scanner: %v", err) + return &pb.PortCheckResponse{Status: "error", Msg: "Port scan failed", Host: in.Host, Port: in.Port}, nil + } + + result, warnings, err := scan.Run() + if len(warnings) > 0 { + log.Printf("run finished with warnings: %s\n", warnings) // Warnings are non-critical errors from nmap. + } + if err != nil { + //log.Fatalf("unable to run nmap scan: %v", err) + return &pb.PortCheckResponse{Status: "error", Msg: "Port scan failed", Host: in.Host, Port: in.Port}, nil + } + + // Use the results to print an example output + host := result.Hosts[0] + if len(host.Ports) == 0 || len(host.Addresses) == 0 { + return &pb.PortCheckResponse{Status: "error", Msg: "No scan results"}, nil + } + + port := host.Ports[0] + + fmt.Printf("\tPort %d %s\n", port.ID, port.State) + fmt.Printf("Host scanned in %.2f seconds\n", result.Stats.Finished.Elapsed) + return &pb.PortCheckResponse{Status: port.State.String(), Msg: "", Port: in.Port, Host: in.Host}, nil +} diff --git a/scanner/metrics.go b/scanner/metrics.go new file mode 100644 index 0000000000..9986aee6cb --- /dev/null +++ b/scanner/metrics.go @@ -0,0 +1,84 @@ +package scanner + +import ( + "context" + + "github.com/Layr-Labs/eigensdk-go/logging" + eigenmetrics "github.com/Layr-Labs/eigensdk-go/metrics" + + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/collectors" + "github.com/prometheus/client_golang/prometheus/promauto" +) + +// Namespace +const ( + Namespace = "scanner" +) + +// Metrics struct +type Metrics struct { + logger logging.Logger + + // Accumulated number of scan requests received. + AccNumRequests *prometheus.CounterVec + // The latency (in ms) to process the request. + RequestLatency *prometheus.SummaryVec + // EigenMetrics + EigenMetrics eigenmetrics.Metrics + + registry *prometheus.Registry + // socketAddr is the address at which the metrics server will be listening. + // should be in format ip:port + socketAddr string +} + +// NewMetrics metrics +func NewMetrics(eigenMetrics eigenmetrics.Metrics, reg *prometheus.Registry, logger logging.Logger, socketAddr string) *Metrics { + + // Add Go module collectors + reg.MustRegister(collectors.NewProcessCollector(collectors.ProcessCollectorOpts{})) + reg.MustRegister(collectors.NewGoCollector()) + + metrics := &Metrics{ + // The "status" label has values: success, failure. + AccNumRequests: promauto.With(reg).NewCounterVec( + prometheus.CounterOpts{ + Namespace: Namespace, + Name: "eigenda_scanner_requests_total", + Help: "the total number of scan requests processed by the scanner", + }, + []string{"method", "status"}, + ), + RequestLatency: promauto.With(reg).NewSummaryVec( + prometheus.SummaryOpts{ + Namespace: Namespace, + Name: "eigenda_scanner_request_latency_ms", + Help: "latency summary in milliseconds", + Objectives: map[float64]float64{0.5: 0.05, 0.9: 0.01, 0.95: 0.01, 0.99: 0.001}, + }, + []string{"method", "stage"}, + ), + EigenMetrics: eigenMetrics, + logger: logger.With("component", "ScannerMetrics"), + registry: reg, + socketAddr: socketAddr, + } + + return metrics +} + +// Start func +func (g *Metrics) Start() { + _ = g.EigenMetrics.Start(context.Background(), g.registry) +} + +// RecordRPCRequest func +func (g *Metrics) RecordRPCRequest(method string, status string) { + g.AccNumRequests.WithLabelValues(method, status).Inc() +} + +// ObserveLatency func +func (g *Metrics) ObserveLatency(method, stage string, latencyMs float64) { + g.RequestLatency.WithLabelValues(method, stage).Observe(latencyMs) +} diff --git a/scanner/scanner.go b/scanner/scanner.go new file mode 100644 index 0000000000..8ad38df532 --- /dev/null +++ b/scanner/scanner.go @@ -0,0 +1,40 @@ +package scanner + +import ( + "context" + + "github.com/prometheus/client_golang/prometheus" + + //"github.com/Layr-Labs/eigenda/api/grpc/scanner" + "github.com/Layr-Labs/eigensdk-go/logging" + "github.com/Layr-Labs/eigensdk-go/metrics" +) + +// Scanner struct +type Scanner struct { + Config *Config + Logger logging.Logger + Metrics *Metrics +} + +// NewScanner creates a new scanner with the provided config. +func NewScanner(config *Config, logger logging.Logger) (*Scanner, error) { + promReg := prometheus.NewRegistry() + eigenMetrics := metrics.NewEigenMetrics(AppName, ":"+config.MetricsPort, promReg, logger.With("component", "EigenMetrics")) + + metrics := NewMetrics(eigenMetrics, promReg, logger, ":"+config.MetricsPort) + + return &Scanner{ + Config: config, + Logger: logger.With("component", "Node"), + Metrics: metrics, + }, nil +} + +// Start the Scanner. +func (s *Scanner) Start(ctx context.Context) error { + s.Metrics.Start() + s.Logger.Info("Enabled metrics", "socket", s.Metrics.socketAddr) + + return nil +}