From af688fb2e7c8cc5bded11f1c9f5cc19b9c7c3e83 Mon Sep 17 00:00:00 2001 From: Manuel Bluhm Date: Fri, 8 Nov 2024 12:26:56 +0400 Subject: [PATCH] Simplify dbus-proxy - re-organizing socket-proxy - adding user dbus test - adjusting systemd targets Signed-off-by: Manuel Bluhm --- api/socket/socket.pb.go | 148 ++-------- api/socket/socket.proto | 11 +- api/socket/socket_grpc.pb.go | 96 ++----- internal/cmd/givc-agent/main.go | 85 +++--- internal/pkgs/applications/applications.go | 2 + .../pkgs/applications/applications_test.go | 2 + internal/pkgs/socketproxy/controller.go | 37 ++- internal/pkgs/socketproxy/transport.go | 265 +++++++++--------- nixos/modules/appvm.nix | 1 + nixos/modules/dbus.nix | 10 +- nixos/modules/sysvm.nix | 14 +- nixos/tests/admin.nix | 2 + nixos/tests/dbus.nix | 120 +++++--- nixos/tests/default.nix | 2 + nixos/tests/netvm.nix | 4 +- 15 files changed, 351 insertions(+), 448 deletions(-) diff --git a/api/socket/socket.pb.go b/api/socket/socket.pb.go index 3f2e239..30f673f 100644 --- a/api/socket/socket.pb.go +++ b/api/socket/socket.pb.go @@ -23,26 +23,28 @@ const ( _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) -type Empty struct { +type BytePacket struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields + + Data []byte `protobuf:"bytes,1,opt,name=Data,proto3" json:"Data,omitempty"` } -func (x *Empty) Reset() { - *x = Empty{} +func (x *BytePacket) Reset() { + *x = BytePacket{} mi := &file_socket_proto_msgTypes[0] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *Empty) String() string { +func (x *BytePacket) String() string { return protoimpl.X.MessageStringOf(x) } -func (*Empty) ProtoMessage() {} +func (*BytePacket) ProtoMessage() {} -func (x *Empty) ProtoReflect() protoreflect.Message { +func (x *BytePacket) ProtoReflect() protoreflect.Message { mi := &file_socket_proto_msgTypes[0] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -54,95 +56,12 @@ func (x *Empty) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use Empty.ProtoReflect.Descriptor instead. -func (*Empty) Descriptor() ([]byte, []int) { +// Deprecated: Use BytePacket.ProtoReflect.Descriptor instead. +func (*BytePacket) Descriptor() ([]byte, []int) { return file_socket_proto_rawDescGZIP(), []int{0} } -type SyncData struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Status uint32 `protobuf:"varint,1,opt,name=Status,proto3" json:"Status,omitempty"` -} - -func (x *SyncData) Reset() { - *x = SyncData{} - mi := &file_socket_proto_msgTypes[1] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *SyncData) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*SyncData) ProtoMessage() {} - -func (x *SyncData) ProtoReflect() protoreflect.Message { - mi := &file_socket_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 SyncData.ProtoReflect.Descriptor instead. -func (*SyncData) Descriptor() ([]byte, []int) { - return file_socket_proto_rawDescGZIP(), []int{1} -} - -func (x *SyncData) GetStatus() uint32 { - if x != nil { - return x.Status - } - return 0 -} - -type SocketDataStream struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Data []byte `protobuf:"bytes,1,opt,name=Data,proto3" json:"Data,omitempty"` -} - -func (x *SocketDataStream) Reset() { - *x = SocketDataStream{} - mi := &file_socket_proto_msgTypes[2] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *SocketDataStream) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*SocketDataStream) ProtoMessage() {} - -func (x *SocketDataStream) ProtoReflect() protoreflect.Message { - mi := &file_socket_proto_msgTypes[2] - if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use SocketDataStream.ProtoReflect.Descriptor instead. -func (*SocketDataStream) Descriptor() ([]byte, []int) { - return file_socket_proto_rawDescGZIP(), []int{2} -} - -func (x *SocketDataStream) GetData() []byte { +func (x *BytePacket) GetData() []byte { if x != nil { return x.Data } @@ -153,23 +72,16 @@ var File_socket_proto protoreflect.FileDescriptor var file_socket_proto_rawDesc = []byte{ 0x0a, 0x0c, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0b, - 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x22, 0x07, 0x0a, 0x05, 0x45, - 0x6d, 0x70, 0x74, 0x79, 0x22, 0x22, 0x0a, 0x08, 0x53, 0x79, 0x6e, 0x63, 0x44, 0x61, 0x74, 0x61, - 0x12, 0x16, 0x0a, 0x06, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, - 0x52, 0x06, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x26, 0x0a, 0x10, 0x53, 0x6f, 0x63, 0x6b, - 0x65, 0x74, 0x44, 0x61, 0x74, 0x61, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, 0x12, 0x0a, 0x04, - 0x44, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x44, 0x61, 0x74, 0x61, - 0x32, 0x8c, 0x01, 0x0a, 0x0c, 0x53, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x53, 0x74, 0x72, 0x65, 0x61, - 0x6d, 0x12, 0x36, 0x0a, 0x04, 0x53, 0x79, 0x6e, 0x63, 0x12, 0x15, 0x2e, 0x73, 0x6f, 0x63, 0x6b, - 0x65, 0x74, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x44, 0x61, 0x74, 0x61, - 0x1a, 0x15, 0x2e, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x53, - 0x79, 0x6e, 0x63, 0x44, 0x61, 0x74, 0x61, 0x22, 0x00, 0x12, 0x44, 0x0a, 0x0b, 0x52, 0x65, 0x63, - 0x65, 0x69, 0x76, 0x65, 0x44, 0x61, 0x74, 0x61, 0x12, 0x1d, 0x2e, 0x73, 0x6f, 0x63, 0x6b, 0x65, - 0x74, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x53, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x44, 0x61, 0x74, - 0x61, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x1a, 0x12, 0x2e, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, - 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x28, 0x01, 0x42, - 0x0f, 0x5a, 0x0d, 0x2e, 0x2f, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x70, 0x72, 0x6f, 0x78, 0x79, - 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x22, 0x20, 0x0a, 0x0a, 0x42, + 0x79, 0x74, 0x65, 0x50, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x44, 0x61, 0x74, + 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x44, 0x61, 0x74, 0x61, 0x32, 0x56, 0x0a, + 0x0c, 0x53, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, 0x46, 0x0a, + 0x0c, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x44, 0x61, 0x74, 0x61, 0x12, 0x17, 0x2e, + 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x42, 0x79, 0x74, 0x65, + 0x50, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x1a, 0x17, 0x2e, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x70, + 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x42, 0x79, 0x74, 0x65, 0x50, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x22, + 0x00, 0x28, 0x01, 0x30, 0x01, 0x42, 0x0f, 0x5a, 0x0d, 0x2e, 0x2f, 0x73, 0x6f, 0x63, 0x6b, 0x65, + 0x74, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -184,19 +96,15 @@ func file_socket_proto_rawDescGZIP() []byte { return file_socket_proto_rawDescData } -var file_socket_proto_msgTypes = make([]protoimpl.MessageInfo, 3) +var file_socket_proto_msgTypes = make([]protoimpl.MessageInfo, 1) var file_socket_proto_goTypes = []any{ - (*Empty)(nil), // 0: socketproxy.Empty - (*SyncData)(nil), // 1: socketproxy.SyncData - (*SocketDataStream)(nil), // 2: socketproxy.SocketDataStream + (*BytePacket)(nil), // 0: socketproxy.BytePacket } var file_socket_proto_depIdxs = []int32{ - 1, // 0: socketproxy.SocketStream.Sync:input_type -> socketproxy.SyncData - 2, // 1: socketproxy.SocketStream.ReceiveData:input_type -> socketproxy.SocketDataStream - 1, // 2: socketproxy.SocketStream.Sync:output_type -> socketproxy.SyncData - 0, // 3: socketproxy.SocketStream.ReceiveData:output_type -> socketproxy.Empty - 2, // [2:4] is the sub-list for method output_type - 0, // [0:2] is the sub-list for method input_type + 0, // 0: socketproxy.SocketStream.TransferData:input_type -> socketproxy.BytePacket + 0, // 1: socketproxy.SocketStream.TransferData:output_type -> socketproxy.BytePacket + 1, // [1:2] is the sub-list for method output_type + 0, // [0:1] 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 @@ -213,7 +121,7 @@ func file_socket_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_socket_proto_rawDesc, NumEnums: 0, - NumMessages: 3, + NumMessages: 1, NumExtensions: 0, NumServices: 1, }, diff --git a/api/socket/socket.proto b/api/socket/socket.proto index 6b1e22d..d7ae8c9 100644 --- a/api/socket/socket.proto +++ b/api/socket/socket.proto @@ -4,18 +4,11 @@ syntax = "proto3"; option go_package = "./socketproxy"; package socketproxy; -message Empty {} - -message SyncData { - uint32 Status = 1; -} - -message SocketDataStream { +message BytePacket { bytes Data = 1; } service SocketStream { - rpc Sync(SyncData) returns (SyncData) {} - rpc ReceiveData(stream SocketDataStream) returns (Empty) {} + rpc TransferData(stream BytePacket) returns (stream BytePacket) {} } diff --git a/api/socket/socket_grpc.pb.go b/api/socket/socket_grpc.pb.go index 027885f..b656d3c 100644 --- a/api/socket/socket_grpc.pb.go +++ b/api/socket/socket_grpc.pb.go @@ -22,16 +22,14 @@ import ( const _ = grpc.SupportPackageIsVersion7 const ( - SocketStream_Sync_FullMethodName = "/socketproxy.SocketStream/Sync" - SocketStream_ReceiveData_FullMethodName = "/socketproxy.SocketStream/ReceiveData" + SocketStream_TransferData_FullMethodName = "/socketproxy.SocketStream/TransferData" ) // SocketStreamClient is the client API for SocketStream 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 SocketStreamClient interface { - Sync(ctx context.Context, in *SyncData, opts ...grpc.CallOption) (*SyncData, error) - ReceiveData(ctx context.Context, opts ...grpc.CallOption) (SocketStream_ReceiveDataClient, error) + TransferData(ctx context.Context, opts ...grpc.CallOption) (SocketStream_TransferDataClient, error) } type socketStreamClient struct { @@ -42,43 +40,31 @@ func NewSocketStreamClient(cc grpc.ClientConnInterface) SocketStreamClient { return &socketStreamClient{cc} } -func (c *socketStreamClient) Sync(ctx context.Context, in *SyncData, opts ...grpc.CallOption) (*SyncData, error) { - out := new(SyncData) - err := c.cc.Invoke(ctx, SocketStream_Sync_FullMethodName, in, out, opts...) +func (c *socketStreamClient) TransferData(ctx context.Context, opts ...grpc.CallOption) (SocketStream_TransferDataClient, error) { + stream, err := c.cc.NewStream(ctx, &SocketStream_ServiceDesc.Streams[0], SocketStream_TransferData_FullMethodName, opts...) if err != nil { return nil, err } - return out, nil -} - -func (c *socketStreamClient) ReceiveData(ctx context.Context, opts ...grpc.CallOption) (SocketStream_ReceiveDataClient, error) { - stream, err := c.cc.NewStream(ctx, &SocketStream_ServiceDesc.Streams[0], SocketStream_ReceiveData_FullMethodName, opts...) - if err != nil { - return nil, err - } - x := &socketStreamReceiveDataClient{stream} + x := &socketStreamTransferDataClient{stream} return x, nil } -type SocketStream_ReceiveDataClient interface { - Send(*SocketDataStream) error - CloseAndRecv() (*Empty, error) +type SocketStream_TransferDataClient interface { + Send(*BytePacket) error + Recv() (*BytePacket, error) grpc.ClientStream } -type socketStreamReceiveDataClient struct { +type socketStreamTransferDataClient struct { grpc.ClientStream } -func (x *socketStreamReceiveDataClient) Send(m *SocketDataStream) error { +func (x *socketStreamTransferDataClient) Send(m *BytePacket) error { return x.ClientStream.SendMsg(m) } -func (x *socketStreamReceiveDataClient) CloseAndRecv() (*Empty, error) { - if err := x.ClientStream.CloseSend(); err != nil { - return nil, err - } - m := new(Empty) +func (x *socketStreamTransferDataClient) Recv() (*BytePacket, error) { + m := new(BytePacket) if err := x.ClientStream.RecvMsg(m); err != nil { return nil, err } @@ -89,8 +75,7 @@ func (x *socketStreamReceiveDataClient) CloseAndRecv() (*Empty, error) { // All implementations must embed UnimplementedSocketStreamServer // for forward compatibility type SocketStreamServer interface { - Sync(context.Context, *SyncData) (*SyncData, error) - ReceiveData(SocketStream_ReceiveDataServer) error + TransferData(SocketStream_TransferDataServer) error mustEmbedUnimplementedSocketStreamServer() } @@ -98,11 +83,8 @@ type SocketStreamServer interface { type UnimplementedSocketStreamServer struct { } -func (UnimplementedSocketStreamServer) Sync(context.Context, *SyncData) (*SyncData, error) { - return nil, status.Errorf(codes.Unimplemented, "method Sync not implemented") -} -func (UnimplementedSocketStreamServer) ReceiveData(SocketStream_ReceiveDataServer) error { - return status.Errorf(codes.Unimplemented, "method ReceiveData not implemented") +func (UnimplementedSocketStreamServer) TransferData(SocketStream_TransferDataServer) error { + return status.Errorf(codes.Unimplemented, "method TransferData not implemented") } func (UnimplementedSocketStreamServer) mustEmbedUnimplementedSocketStreamServer() {} @@ -117,44 +99,26 @@ func RegisterSocketStreamServer(s grpc.ServiceRegistrar, srv SocketStreamServer) s.RegisterService(&SocketStream_ServiceDesc, srv) } -func _SocketStream_Sync_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(SyncData) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(SocketStreamServer).Sync(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: SocketStream_Sync_FullMethodName, - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(SocketStreamServer).Sync(ctx, req.(*SyncData)) - } - return interceptor(ctx, in, info, handler) -} - -func _SocketStream_ReceiveData_Handler(srv interface{}, stream grpc.ServerStream) error { - return srv.(SocketStreamServer).ReceiveData(&socketStreamReceiveDataServer{stream}) +func _SocketStream_TransferData_Handler(srv interface{}, stream grpc.ServerStream) error { + return srv.(SocketStreamServer).TransferData(&socketStreamTransferDataServer{stream}) } -type SocketStream_ReceiveDataServer interface { - SendAndClose(*Empty) error - Recv() (*SocketDataStream, error) +type SocketStream_TransferDataServer interface { + Send(*BytePacket) error + Recv() (*BytePacket, error) grpc.ServerStream } -type socketStreamReceiveDataServer struct { +type socketStreamTransferDataServer struct { grpc.ServerStream } -func (x *socketStreamReceiveDataServer) SendAndClose(m *Empty) error { +func (x *socketStreamTransferDataServer) Send(m *BytePacket) error { return x.ServerStream.SendMsg(m) } -func (x *socketStreamReceiveDataServer) Recv() (*SocketDataStream, error) { - m := new(SocketDataStream) +func (x *socketStreamTransferDataServer) Recv() (*BytePacket, error) { + m := new(BytePacket) if err := x.ServerStream.RecvMsg(m); err != nil { return nil, err } @@ -167,16 +131,12 @@ func (x *socketStreamReceiveDataServer) Recv() (*SocketDataStream, error) { var SocketStream_ServiceDesc = grpc.ServiceDesc{ ServiceName: "socketproxy.SocketStream", HandlerType: (*SocketStreamServer)(nil), - Methods: []grpc.MethodDesc{ - { - MethodName: "Sync", - Handler: _SocketStream_Sync_Handler, - }, - }, + Methods: []grpc.MethodDesc{}, Streams: []grpc.StreamDesc{ { - StreamName: "ReceiveData", - Handler: _SocketStream_ReceiveData_Handler, + StreamName: "TransferData", + Handler: _SocketStream_TransferData_Handler, + ServerStreams: true, ClientStreams: true, }, }, diff --git a/internal/cmd/givc-agent/main.go b/internal/cmd/givc-agent/main.go index cb8e5d7..56977f8 100644 --- a/internal/cmd/givc-agent/main.go +++ b/internal/cmd/givc-agent/main.go @@ -10,6 +10,7 @@ import ( "path/filepath" "strconv" "strings" + "time" givc_admin "givc/api/admin" givc_app "givc/internal/pkgs/applications" @@ -179,8 +180,10 @@ func main() { // Register agent with admin server _, err := givc_serviceclient.RegisterRemoteService(cfgAdminServer, agentEntryRequest) - if err != nil { - log.Fatalf("Error register agent: %s", err) + for err != nil { + log.Warnf("Error register agent: %s", err) + time.Sleep(1 * time.Second) + _, err = givc_serviceclient.RegisterRemoteService(cfgAdminServer, agentEntryRequest) } // Register services with admin server @@ -250,27 +253,17 @@ func main() { // Create socket proxy server (optional) for _, proxyConfig := range proxyConfigs { - log.Infof("Configuring socket proxy server: %v", proxyConfig) - - ctx, ctxCancel := context.WithCancel(context.Background()) - proxyServerStarted := make(chan struct{}) - - // Start proxy server - go func(proxyConfig givc_types.ProxyConfig) { - defer ctxCancel() + // Create socket proxy server for dbus + socketProxyServer, err := givc_socketproxy.NewSocketProxyServer(proxyConfig.Socket, proxyConfig.Server) + if err != nil { + log.Errorf("Cannot create socket proxy server: %v", err) + } - // Create socket proxy server for dbus - var grpcProxyService []givc_types.GrpcServiceRegistration - socketProxyServer, err := givc_socketproxy.NewSocketProxyServer(proxyConfig.Socket, proxyConfig.Server) - if err != nil { - log.Errorf("Cannot create socket proxy server: %v", err) - } - grpcProxyService = append(grpcProxyService, socketProxyServer) + // Run proxy client + if !proxyConfig.Server { + log.Infof("Configuring socket proxy client: %v", proxyConfig) - // Start socket stream when server ready go func(proxyConfig givc_types.ProxyConfig) { - defer ctxCancel() - <-proxyServerStarted // Configure client endpoint socketClient := &givc_types.EndpointConfig{ @@ -278,34 +271,44 @@ func main() { TlsConfig: tlsConfig, } - err = socketProxyServer.StreamToRemote(ctx, socketClient) + err = socketProxyServer.StreamToRemote(context.Background(), socketClient) if err != nil { - log.Errorf("Socket stream exited: %v", err) + log.Errorf("Socket client stream exited: %v", err) } }(proxyConfig) + } - // Socket proxy server config - cfgProxyServer := &givc_types.EndpointConfig{ - Transport: givc_types.TransportConfig{ - Name: cfgAgent.Transport.Name, - Address: cfgAgent.Transport.Address, - Port: proxyConfig.Transport.Port, - Protocol: proxyConfig.Transport.Protocol, - }, - TlsConfig: tlsConfig, - } + // Run proxy server + if proxyConfig.Server { + log.Infof("Configuring socket proxy server: %v", proxyConfig) - grpcServer, err := givc_grpc.NewServer(cfgProxyServer, grpcProxyService) - if err != nil { - log.Errorf("Cannot create grpc proxy server config: %v", err) - } - err = grpcServer.ListenAndServe(ctx, proxyServerStarted) - if err != nil { - log.Errorf("Grpc proxy server failed: %v", err) - } + go func(proxyConfig givc_types.ProxyConfig) { + + // Socket proxy server config + cfgProxyServer := &givc_types.EndpointConfig{ + Transport: givc_types.TransportConfig{ + Name: cfgAgent.Transport.Name, + Address: cfgAgent.Transport.Address, + Port: proxyConfig.Transport.Port, + Protocol: proxyConfig.Transport.Protocol, + }, + TlsConfig: tlsConfig, + } + + var grpcProxyService []givc_types.GrpcServiceRegistration + grpcProxyService = append(grpcProxyService, socketProxyServer) + grpcServer, err := givc_grpc.NewServer(cfgProxyServer, grpcProxyService) + if err != nil { + log.Errorf("Cannot create grpc proxy server config: %v", err) + } + err = grpcServer.ListenAndServe(context.Background(), make(chan struct{})) + if err != nil { + log.Errorf("Grpc socket proxy server failed: %v", err) + } - }(proxyConfig) + }(proxyConfig) + } } // Create and start main grpc server diff --git a/internal/pkgs/applications/applications.go b/internal/pkgs/applications/applications.go index 9ee05ea..13b49a2 100644 --- a/internal/pkgs/applications/applications.go +++ b/internal/pkgs/applications/applications.go @@ -1,3 +1,5 @@ +// Copyright 2024 TII (SSRC) and the Ghaf contributors +// SPDX-License-Identifier: Apache-2.0 package applications import ( diff --git a/internal/pkgs/applications/applications_test.go b/internal/pkgs/applications/applications_test.go index f3bffcc..d94d3a0 100644 --- a/internal/pkgs/applications/applications_test.go +++ b/internal/pkgs/applications/applications_test.go @@ -1,3 +1,5 @@ +// Copyright 2024 TII (SSRC) and the Ghaf contributors +// SPDX-License-Identifier: Apache-2.0 package applications import ( diff --git a/internal/pkgs/socketproxy/controller.go b/internal/pkgs/socketproxy/controller.go index 40ea1ab..de0144c 100644 --- a/internal/pkgs/socketproxy/controller.go +++ b/internal/pkgs/socketproxy/controller.go @@ -1,9 +1,12 @@ +// Copyright 2024 TII (SSRC) and the Ghaf contributors +// SPDX-License-Identifier: Apache-2.0 package socketproxy import ( "fmt" "net" "os" + "time" log "github.com/sirupsen/logrus" ) @@ -17,12 +20,10 @@ type SocketProxyController struct { func NewSocketProxyController(socket string, runAsServer bool) (*SocketProxyController, error) { var listener net.Listener + var err error if !runAsServer { // Remove socket file if it exists - _, err := os.Stat(socket) - if err == nil { - os.Remove(socket) - } + os.Remove(socket) // Listen on unix socket listener, err = net.Listen("unix", socket) @@ -32,8 +33,15 @@ func NewSocketProxyController(socket string, runAsServer bool) (*SocketProxyCont } } + // Block until the socket is created + _, err = os.Stat(socket) + for err != nil { + time.Sleep(500 * time.Millisecond) + _, err = os.Stat(socket) + } + // Change socket owner and permissions to allow any users in group 'users' (gid: 100) - err := os.Chown(socket, os.Getuid(), 100) + err = os.Chown(socket, -1, 100) if err != nil { log.Errorf("Unable to change socket file ownership: %v", err) } @@ -47,10 +55,6 @@ func NewSocketProxyController(socket string, runAsServer bool) (*SocketProxyCont func (s *SocketProxyController) Dial() (net.Conn, error) { - if !s.runAsServer { - return nil, fmt.Errorf("socket proxy runs as client") - } - // Dial to the unix socket conn, err := net.Dial("unix", s.socket) if err != nil { @@ -62,9 +66,6 @@ func (s *SocketProxyController) Dial() (net.Conn, error) { func (s *SocketProxyController) Accept() (net.Conn, error) { - if s.runAsServer { - return nil, fmt.Errorf("socket proxy runs as server") - } // Accept new connection conn, err := s.listener.Accept() if err != nil { @@ -85,23 +86,21 @@ func (s *SocketProxyController) Close() error { } func (s *SocketProxyController) Write(conn net.Conn, data []byte) error { - _, err := conn.Write(data) + n, err := conn.Write(data) if err != nil { return err } + if n != len(data) { + return fmt.Errorf("unable to write all data to socket") + } return nil } func (s *SocketProxyController) Read(conn net.Conn) ([]byte, error) { - - var data []byte buf := make([]byte, 1024) - n, err := conn.Read(buf) if err != nil { return nil, err } - data = append(data, buf[:n]...) - - return data, nil + return buf[:n], nil } diff --git a/internal/pkgs/socketproxy/transport.go b/internal/pkgs/socketproxy/transport.go index 8058ad3..d23573f 100644 --- a/internal/pkgs/socketproxy/transport.go +++ b/internal/pkgs/socketproxy/transport.go @@ -1,3 +1,26 @@ +// Copyright 2024 TII (SSRC) and the Ghaf contributors +// SPDX-License-Identifier: Apache-2.0 + +/* + SocketProxyServer is a GRPC service that proxies data between a local socket and a remote GRPC server. + + It can run in two modes, server or client: + + 1. As a server: The server waits for a remote client to connect. + Once connected, it dials to a local socket and proxies data between the remote client and the local socket. + + 2. As a client: The client creates a socket listener and waits for a connection to the local socket. + Once a client (application) connects to the socket, it initiates the connection to the server. + + Both client and server run a GRPC server, and the main routine 'StreamToRemote' which must be run in a different go routine + than the GRPC server itself. + + As the socket read() function is blocking, the end of a socket connection must be forwarded to the remote, and locally + closed (here, by closing the socket connection) on both ends. This is done by sending an EOF message to the remote counterpart. + + Both ends unwind and close both socket and GRPC connections when any socket read error occurs, EOF or otherwise. +*/ + package socketproxy import ( @@ -12,77 +35,54 @@ import ( givc_types "givc/internal/pkgs/types" "golang.org/x/net/context" + "golang.org/x/sync/errgroup" "google.golang.org/grpc" log "github.com/sirupsen/logrus" ) type SocketProxyServer struct { - socketProxy *SocketProxyController // Socket proxy controller - conn net.Conn // Socket connection - streamConnected bool // Stream connection status; used to sync grpc stream - socketConnected bool // Socket connection status; used to indicate that socket is connected - clientConnected bool // Client connection status; used to indicate that grpc client is connected + socketController *SocketProxyController + conn net.Conn socket_api.UnimplementedSocketStreamServer } +type DataStream interface { + Recv() (*socket_api.BytePacket, error) + Send(*socket_api.BytePacket) error + Context() context.Context +} + func (s *SocketProxyServer) Name() string { - return "Socket Proxy Server" + return "Socket Proxy" } func (s *SocketProxyServer) RegisterGrpcService(srv *grpc.Server) { socket_api.RegisterSocketStreamServer(srv, s) } -/* - SocketProxyServer is a GRPC service that proxies data between a local socket and a remote GRPC server. - - It can run in two modes, server or client: - - 1. As a server: The server waits for a remote client to connect. - Once connected, it dials to a local socket and proxies data between the remote client and the local socket. - - 2. As a client: The client creates a socket listener and waits for a connection to the local socket. - Once a client (application) connects to the socket, it initiates the connection to the server. - - Both client and server run a GRPC server, and the main routine 'StreamToRemote' which must be run in a different go routine - than the GRPC server itself. - - When the client is connected, the server sends a 'PROXY_CLIENT_CONNECTED' message to the remote server. The server awaits - this message and then connects to the local socket via 'dial()'. The client repeats the request until the server signals - that the socket is connected and the GRPC stream is initiated. - - As the socket read() function is blocking, the end of a socket connection must be forwarded to the remote, and locally - closed (here, by closing the socket connection) on both ends. This is done by sending an EOF message to the remote counterpart. - - Both ends unwind and close both socket and GRPC connections when any socket read error occurs, EOF or otherwise. -*/ - func NewSocketProxyServer(socket string, runAsServer bool) (*SocketProxyServer, error) { // Create a new socket proxy controller var err error - socketProxy, err := NewSocketProxyController(socket, runAsServer) + socketController, err := NewSocketProxyController(socket, runAsServer) if err != nil { return nil, err } return &SocketProxyServer{ - socketProxy: socketProxy, - conn: nil, - streamConnected: false, - socketConnected: false, - clientConnected: false, + socketController: socketController, + conn: nil, }, nil } func (s *SocketProxyServer) Close() error { - return s.socketProxy.Close() + return s.socketController.Close() } func (s *SocketProxyServer) StreamToRemote(ctx context.Context, cfg *givc_types.EndpointConfig) error { - defer s.socketProxy.Close() + defer s.socketController.Close() // Setup and dial GRPC client grpcClientConn, err := givc_grpc.NewClient(cfg, true) @@ -106,143 +106,132 @@ func (s *SocketProxyServer) StreamToRemote(ctx context.Context, cfg *givc_types. // Stream data to remote default: - // Wait for local socket connection - if !s.socketProxy.runAsServer { + // Wait for new connection to socket; blocking + s.conn, err = s.socketController.Accept() + if err != nil { + return err + } - // Wait for new connection to socket; blocking - s.conn, err = s.socketProxy.Accept() - if err != nil { - return err - } - s.socketConnected = true + // Create new GRPC stream + stream, err := socketStreamClient.TransferData(ctx) + for err != nil { + time.Sleep(1 * time.Second) + stream, err = socketStreamClient.TransferData(ctx) + } - // Tell remote server that client is connected and wait for server connection - status, err := socketStreamClient.Sync(ctx, &socket_api.SyncData{Status: givc_types.PROXY_CLIENT_CONNECTED}) - for err != nil || status.GetStatus() != givc_types.PROXY_SERVER_CONNECTED { - time.Sleep(1 * time.Second) - status, err = socketStreamClient.Sync(ctx, &socket_api.SyncData{Status: givc_types.PROXY_CLIENT_CONNECTED}) - } + err = s.StreamData(stream) + if err != nil { + log.Warnf("StreamData exited with: %v", err) + } + + // Close stream connection + if stream != nil { + stream.CloseSend() } + } + } + +} + +func (s *SocketProxyServer) TransferData(stream socket_api.SocketStream_TransferDataServer) error { + + if !s.socketController.runAsServer { + return fmt.Errorf("socket proxy runs as client") + } + + // Dial to the unix socket + var err error + s.conn, err = s.socketController.Dial() + if err != nil { + return err + } + + return s.StreamData(stream) +} - // Wait for client connection - if s.socketProxy.runAsServer { +func (s *SocketProxyServer) StreamData(stream DataStream) error { - // Wait for remote client to make connection; blocking - for !s.clientConnected { - time.Sleep(500 * time.Millisecond) + group, ctx := errgroup.WithContext(stream.Context()) + + // Routine to read from grpc stream and write to socket + group.Go(func() error { + + for { + select { + case <-ctx.Done(): + return nil + default: + + // Read data from grpc stream + data, err := stream.Recv() + if err != nil { + log.Warnf(">> GRPC failure: %v", err) + return err + } + log.Infof("Recv data: %s", data.GetData()) + + // Check for EOF; and close socket connection + if bytes.Equal(data.GetData(), []byte(io.EOF.Error())) { + if s.conn != nil { + s.conn.Close() + } + return fmt.Errorf("EOF received") } - // Connect to socket - s.conn, err = s.socketProxy.Dial() + // Write data to socket + err = s.socketController.Write(s.conn, data.GetData()) if err != nil { + log.Warnf("Error writing to socket: %v", err) return err } - s.socketConnected = true } + } + }) - // Create new GRPC stream - stream, err := socketStreamClient.ReceiveData(ctx) - if err != nil { - log.Warnf("GRPC stream connection failed: %v", err) - return err - } - s.streamConnected = true + // Routine to read from socket and write to grpc stream + group.Go(func() error { - // Proxy loop for active connection - for { + for { + select { + case <-ctx.Done(): + return nil + default: // Read data from socket - data, err := s.socketProxy.Read(s.conn) + data, err := s.socketController.Read(s.conn) if err != nil { // Forward any read error to terminate stream and socket connections on both ends log.Infof(">> Socket read error: %v", err) - message := &socket_api.SocketDataStream{ + message := &socket_api.BytePacket{ Data: []byte(io.EOF.Error()), } err = stream.Send(message) if err != nil { log.Errorf("failed to send EOF to remote: %v", err) } - break + return err } // Send data to grpc stream - message := &socket_api.SocketDataStream{ + message := &socket_api.BytePacket{ Data: data, } err = stream.Send(message) if err != nil { - break + return err } log.Infof("Sent data: %s", data) } - - // Close socket connection - if s.conn != nil { - s.conn.Close() - } - s.socketConnected = false - - // Close stream connection - if stream != nil { - stream.CloseSend() - } - s.streamConnected = false - - // Reset client connection status - s.clientConnected = false } - } - -} + }) -func (s *SocketProxyServer) ReceiveData(stream socket_api.SocketStream_ReceiveDataServer) error { - - for { - // Read data from grpc stream - data, err := stream.Recv() - if err != nil { - log.Warnf(">> GRPC failure: %v", err) - return err - } - log.Infof("Recv data: %s", data.GetData()) - - // Check for EOF; and close socket connection - if bytes.Equal(data.GetData(), []byte(io.EOF.Error())) { - if s.streamConnected { - if s.conn != nil { - s.conn.Close() - } - } - return fmt.Errorf("EOF received") - } - - // Write data to socket - err = s.socketProxy.Write(s.conn, data.GetData()) - if err != nil { - log.Warnf("Error writing to socket: %v", err) - return err - } + if err := group.Wait(); err != nil { + log.Infof("Stream exited with: %s", err) } -} -func (s *SocketProxyServer) Sync(ctx context.Context, status *socket_api.SyncData) (*socket_api.SyncData, error) { - - resp := givc_types.PROXY_NULL - - if s.socketProxy.runAsServer { - - if status.GetStatus() == givc_types.PROXY_CLIENT_CONNECTED { - s.clientConnected = true - } - if s.socketConnected { - resp = givc_types.PROXY_SERVER_CONNECTED - } - - } else { - if s.socketConnected { - resp = givc_types.PROXY_CLIENT_CONNECTED - } + // Close socket connection + if s.conn != nil { + s.conn.Close() } - return &socket_api.SyncData{Status: resp}, nil + return nil } diff --git a/nixos/modules/appvm.nix b/nixos/modules/appvm.nix index 2697e64..994f5da 100644 --- a/nixos/modules/appvm.nix +++ b/nixos/modules/appvm.nix @@ -115,6 +115,7 @@ in }); ''; }; + systemd.user.services."givc-${cfg.agent.name}" = { description = "GIVC remote service manager for application VMs"; enable = true; diff --git a/nixos/modules/dbus.nix b/nixos/modules/dbus.nix index ba8b8c0..ab47a35 100644 --- a/nixos/modules/dbus.nix +++ b/nixos/modules/dbus.nix @@ -199,12 +199,6 @@ in You need to specify a non-system user with UID set to run the session bus proxy. ''; } - { - assertion = cfg.session.enable -> !cfg.system.enable; - message = '' - You can only enable either system or session bus proxy at once. - ''; - } ]; environment.systemPackages = [ @@ -237,8 +231,8 @@ in { description = "GIVC local xdg-dbus-proxy system service"; enable = true; - before = [ "network-online.target" ]; - wantedBy = [ "network-online.target" ]; + before = [ "givc-setup.target" ]; + wantedBy = [ "givc-setup.target" ]; serviceConfig = { Type = "exec"; ExecStart = "${pkgs.xdg-dbus-proxy}/bin/xdg-dbus-proxy unix:path=/run/dbus/system_bus_socket ${cfg.system.socket} --filter ${args}"; diff --git a/nixos/modules/sysvm.nix b/nixos/modules/sysvm.nix index a353ad7..e4e2c30 100644 --- a/nixos/modules/sysvm.nix +++ b/nixos/modules/sysvm.nix @@ -134,12 +134,20 @@ in } ]; + systemd.targets.givc-setup = { + enable = true; + description = "Ghaf givc target"; + bindsTo = [ "network-online.target" ]; + after = [ "network-online.target" ]; + wantedBy = [ "network-online.target" ]; + }; + systemd.services."givc-${cfg.agent.name}" = { description = "GIVC remote service manager for system VMs"; enable = true; - after = [ "network-online.target" ]; - wants = [ "network-online.target" ]; - wantedBy = [ "multi-user.target" ]; + after = [ "givc-setup.target" ]; + partOf = [ "givc-setup.target" ]; + wantedBy = [ "givc-setup.target" ]; serviceConfig = { Type = "exec"; ExecStart = "${givc-agent}/bin/givc-agent"; diff --git a/nixos/tests/admin.nix b/nixos/tests/admin.nix index fe6b4cf..ab4d5f0 100644 --- a/nixos/tests/admin.nix +++ b/nixos/tests/admin.nix @@ -1,3 +1,5 @@ +# Copyright 2024 TII (SSRC) and the Ghaf contributors +# SPDX-License-Identifier: Apache-2.0 { self, lib, diff --git a/nixos/tests/dbus.nix b/nixos/tests/dbus.nix index dce97b4..3672671 100644 --- a/nixos/tests/dbus.nix +++ b/nixos/tests/dbus.nix @@ -1,3 +1,5 @@ +# Copyright 2024 TII (SSRC) and the Ghaf contributors +# SPDX-License-Identifier: Apache-2.0 { self, lib, @@ -11,8 +13,8 @@ let netvm = "192.168.101.1"; audiovm = "192.168.101.2"; guivm = "192.168.101.3"; - appvm = "192.168.101.100"; adminvm = "192.168.101.10"; + appvm = "192.168.101.100"; }; admin = { name = "admin-vm"; @@ -150,13 +152,22 @@ in } { transport = { - name = "chromium-vm"; - addr = addrs.appvm; + name = "audio-vm"; + addr = addrs.audiovm; port = "9012"; protocol = "tcp"; }; socket = "/tmp/.dbusproxy_app.sock"; } + { + transport = { + name = "chromium-vm"; + addr = addrs.appvm; + port = "9013"; + protocol = "tcp"; + }; + socket = "/tmp/.dbusproxy_app2.sock"; + } ]; debug = true; }; @@ -261,8 +272,10 @@ in # Service services.upower.enable = true; + services.playerctld.enable = true; # Setup users and keys + users.mutableUsers = false; users.groups.users = { }; users.users = { ghaf = { @@ -270,6 +283,7 @@ in group = "users"; uid = 1000; openssh.authorizedKeys.keys = [ snakeOilPublicKey ]; + linger = true; }; }; @@ -291,6 +305,15 @@ in }; socket = "/tmp/.dbusproxy_snd.sock"; } + { + transport = { + name = "gui-vm"; + addr = addrs.guivm; + port = "9012"; + protocol = "tcp"; + }; + socket = "/tmp/.dbusproxy_app.sock"; + } ]; debug = true; }; @@ -305,6 +328,14 @@ in "org.freedesktop.UPower.*" ]; }; + session = { + enable = true; + user = "ghaf"; + socket = "/tmp/.dbusproxy_app.sock"; + policy.talk = [ + "org.mpris.MediaPlayer2.playerctld.*" + ]; + }; }; }; @@ -332,6 +363,7 @@ in services.playerctld.enable = true; # Setup users and keys + users.mutableUsers = false; users.groups.users = { }; users.users = { ghaf = { @@ -342,7 +374,6 @@ in linger = true; }; }; - services.getty.autologinUser = "ghaf"; givc.appvm = { enable = true; @@ -352,22 +383,22 @@ in name = "chromium-vm"; }; tls = mkTls "chromium-vm"; - applications = [ - { - name = "test"; - command = "/bin/bash"; - args = [ ]; - } - ]; socketProxy = [ { transport = { name = "gui-vm"; addr = addrs.guivm; - port = "9012"; + port = "9013"; protocol = "tcp"; }; - socket = "/tmp/.dbusproxy_app.sock"; + socket = "/tmp/.dbusproxy_app2.sock"; + } + ]; + applications = [ + { + name = "dummy"; + command = "/bin/bash"; + args = [ ]; } ]; debug = true; @@ -378,64 +409,71 @@ in session = { enable = true; user = "ghaf"; - socket = "/tmp/.dbusproxy_app.sock"; + socket = "/tmp/.dbusproxy_app2.sock"; policy.talk = [ "org.mpris.MediaPlayer2.playerctld.*" ]; }; }; }; - }; testScript = _: '' - # import time with subtest("boot_completed"): - adminvm.wait_for_unit("multi-user.target") - audiovm.wait_for_unit("multi-user.target") - netvm.wait_for_unit("multi-user.target") - appvm.wait_for_unit("multi-user.target") - guivm.wait_for_unit("multi-user.target") + adminvm.wait_for_unit("multi-user.target") + audiovm.wait_for_unit("multi-user.target") + netvm.wait_for_unit("multi-user.target") + guivm.wait_for_unit("multi-user.target") + appvm.wait_for_unit("multi-user.target") + + with subtest("asd"): + print(appvm.succeed("ls -ahl /tmp/.dbusproxy_app2.sock")) + print(audiovm.succeed("ls -ahl /tmp/.dbusproxy_app.sock")) + print(audiovm.succeed("")) + with subtest("success_tests_systembus"): - # SUCCESS: remote access to netvms NetworkManager service; dbus-send - print(guivm.succeed("sudo -u ghaf dbus-send --bus=unix:path=/tmp/.dbusproxy_net.sock --print-reply --dest=org.freedesktop.NetworkManager /org/freedesktop/NetworkManager org.freedesktop.DBus.Properties.Get string:'org.freedesktop.NetworkManager' string:'ActiveConnections'")) + # SUCCESS: remote access to netvms NetworkManager service; dbus-send + print(guivm.succeed("sudo -u ghaf dbus-send --bus=unix:path=/tmp/.dbusproxy_net.sock --print-reply --dest=org.freedesktop.NetworkManager /org/freedesktop/NetworkManager org.freedesktop.DBus.Properties.Get string:'org.freedesktop.NetworkManager' string:'ActiveConnections'")) - # SUCCESS: remote access to netvms NetworkManager service; nmcli - print(guivm.succeed("sudo -u ghaf -- bash -c 'export DBUS_SYSTEM_BUS_ADDRESS=unix:path=/tmp/.dbusproxy_net.sock; nmcli d'")) + # SUCCESS: remote access to netvms NetworkManager service; nmcli + print(guivm.succeed("sudo -u ghaf -- bash -c 'export DBUS_SYSTEM_BUS_ADDRESS=unix:path=/tmp/.dbusproxy_net.sock; nmcli d'")) - # SUCCESS: access to additional specified netvm service - print(guivm.succeed("sudo -u ghaf dbus-send --bus=unix:path=/tmp/.dbusproxy_net.sock --print-reply --dest=org.freedesktop.Avahi /org/freedesktop/Avahi org.freedesktop.DBus.Introspectable.Introspect")) + # SUCCESS: access to additional specified netvm service + print(guivm.succeed("sudo -u ghaf dbus-send --bus=unix:path=/tmp/.dbusproxy_net.sock --print-reply --dest=org.freedesktop.Avahi /org/freedesktop/Avahi org.freedesktop.DBus.Introspectable.Introspect")) - # SUCCESS: 'call' method access to specified netvm service - print(guivm.succeed("sudo -u ghaf dbus-send --bus=unix:path=/tmp/.dbusproxy_net.sock --print-reply --dest=org.freedesktop.UPower /org/freedesktop/UPower org.freedesktop.UPower.EnumerateDevices")) + # SUCCESS: 'call' method access to specified netvm service + print(guivm.succeed("sudo -u ghaf dbus-send --bus=unix:path=/tmp/.dbusproxy_net.sock --print-reply --dest=org.freedesktop.UPower /org/freedesktop/UPower org.freedesktop.UPower.EnumerateDevices")) - # SUCCESS: connection to secondary system vm (audio) - print(guivm.succeed("sudo -u ghaf dbus-send --bus=unix:path=/tmp/.dbusproxy_snd.sock --print-reply --dest=org.freedesktop.UPower /org/freedesktop/UPower org.freedesktop.DBus.Introspectable.Introspect")) + # SUCCESS: connection to secondary system vm (audio) + print(guivm.succeed("sudo -u ghaf dbus-send --bus=unix:path=/tmp/.dbusproxy_snd.sock --print-reply --dest=org.freedesktop.UPower /org/freedesktop/UPower org.freedesktop.DBus.Introspectable.Introspect")) with subtest("failure_tests_systembus"): - # FAIL: 'call' access to non-specified netvm service - print(guivm.fail("sudo -u ghaf dbus-send --bus=unix:path=/tmp/.dbusproxy_net.sock --print-reply --dest=org.freedesktop.UPower /org/freedesktop/UPower org.freedesktop.UPower.GetCriticalAction")) + # FAIL: 'call' access to non-specified netvm service + print(guivm.fail("sudo -u ghaf dbus-send --bus=unix:path=/tmp/.dbusproxy_net.sock --print-reply --dest=org.freedesktop.UPower /org/freedesktop/UPower org.freedesktop.UPower.GetCriticalAction")) - # FAIL: root user access to netvm service - print(guivm.fail("dbus-send --bus=unix:path=/tmp/.dbusproxy_net.sock --print-reply --dest=org.freedesktop.UPower /org/freedesktop/UPower org.freedesktop.DBus.Introspectable.Introspect")) + # FAIL: root user access to netvm service + print(guivm.fail("dbus-send --bus=unix:path=/tmp/.dbusproxy_net.sock --print-reply --dest=org.freedesktop.UPower /org/freedesktop/UPower org.freedesktop.DBus.Introspectable.Introspect")) - # FAIL: evil1 user access to netvm service - print(guivm.fail("sudo -u evil1 dbus-send --bus=unix:path=/tmp/.dbusproxy_net.sock --print-reply --dest=org.freedesktop.UPower /org/freedesktop/UPower org.freedesktop.UPower.EnumerateDevices")) + # FAIL: evil1 user access to netvm service + print(guivm.fail("sudo -u evil1 dbus-send --bus=unix:path=/tmp/.dbusproxy_net.sock --print-reply --dest=org.freedesktop.UPower /org/freedesktop/UPower org.freedesktop.UPower.EnumerateDevices")) - # FAIL: evil2 user access to netvm service - print(guivm.fail("sudo -u evil2 dbus-send --bus=unix:path=/tmp/.dbusproxy_net.sock --print-reply --dest=org.freedesktop.Avahi /org/freedesktop/Avahi org.freedesktop.DBus.Introspectable.Introspect")) + # FAIL: evil2 user access to netvm service + print(guivm.fail("sudo -u evil2 dbus-send --bus=unix:path=/tmp/.dbusproxy_net.sock --print-reply --dest=org.freedesktop.Avahi /org/freedesktop/Avahi org.freedesktop.DBus.Introspectable.Introspect")) with subtest("remote_user_to_sesssionbus_access"): + appvm.wait_for_unit("multi-user.target") - # SUCCESS: ghaf user access to audiovm session bus + # SUCCESS: ghaf user access to audiovm/appvm session bus print(guivm.succeed("sudo -u ghaf dbus-send --bus=unix:path=/tmp/.dbusproxy_app.sock --print-reply --dest=org.mpris.MediaPlayer2.playerctld /org/mpris/MediaPlayer2 org.freedesktop.DBus.Introspectable.Introspect")) + print(guivm.succeed("sudo -u ghaf dbus-send --bus=unix:path=/tmp/.dbusproxy_app2.sock --print-reply --dest=org.mpris.MediaPlayer2.playerctld /org/mpris/MediaPlayer2 org.freedesktop.DBus.Introspectable.Introspect")) - # FAIL: root user access to audiovm session bus + # FAIL: root user access to audiovm/appvm session bus print(guivm.fail("dbus-send --bus=unix:path=/tmp/.dbusproxy_app.sock --print-reply --dest=org.mpris.MediaPlayer2.playerctld /org/freedesktop/MediaPlayer2 org.freedesktop.DBus.Introspectable.Introspect")) + print(guivm.fail("dbus-send --bus=unix:path=/tmp/.dbusproxy_app2.sock --print-reply --dest=org.mpris.MediaPlayer2.playerctld /org/freedesktop/MediaPlayer2 org.freedesktop.DBus.Introspectable.Introspect")) ''; }; diff --git a/nixos/tests/default.nix b/nixos/tests/default.nix index 9fc7bae..68d88c0 100644 --- a/nixos/tests/default.nix +++ b/nixos/tests/default.nix @@ -1,3 +1,5 @@ +# Copyright 2024 TII (SSRC) and the Ghaf contributors +# SPDX-License-Identifier: Apache-2.0 { imports = [ ./admin.nix diff --git a/nixos/tests/netvm.nix b/nixos/tests/netvm.nix index 17896a6..3ac5862 100644 --- a/nixos/tests/netvm.nix +++ b/nixos/tests/netvm.nix @@ -1,3 +1,5 @@ +# Copyright 2024 TII (SSRC) and the Ghaf contributors +# SPDX-License-Identifier: Apache-2.0 { self, lib, @@ -188,7 +190,7 @@ in grpcurl_cmd = "/run/current-system/sw/bin/grpcurl "; grpcurl_args = if tls then - "-cacert ${nodes.netvm.givc.sysvm.tls.caCertPath} -cert ${nodes.netvm.givc.sysvm.tls.certPath} -key ${nodes.netvm.givc.sysvm.tls.keyPath}" + "-cacert ${nodes.adminvm.givc.admin.tls.caCertPath} -cert ${nodes.adminvm.givc.admin.tls.certPath} -key ${nodes.adminvm.givc.admin.tls.keyPath}" else "-plaintext"; grpcurl_addr = "${nodes.netvm.givc.sysvm.agent.addr}:${nodes.netvm.givc.sysvm.agent.port} ";