[management,proxy,client] Add L4 capabilities (TLS/TCP/UDP) (#5530)

This commit is contained in:
Viktor Liu
2026-03-14 01:36:44 +08:00
committed by GitHub
parent fe9b844511
commit 3e6baea405
90 changed files with 9611 additions and 1397 deletions

View File

@@ -2,6 +2,7 @@ package grpc
import (
"context"
"fmt"
pb "github.com/golang/protobuf/proto" // nolint
log "github.com/sirupsen/logrus"
@@ -39,23 +40,38 @@ func (s *Server) CreateExpose(ctx context.Context, req *proto.EncryptedMessage)
return nil, status.Errorf(codes.Internal, "reverse proxy manager not available")
}
if exposeReq.Port > 65535 {
return nil, status.Errorf(codes.InvalidArgument, "port out of range: %d", exposeReq.Port)
}
if exposeReq.ListenPort > 65535 {
return nil, status.Errorf(codes.InvalidArgument, "listen_port out of range: %d", exposeReq.ListenPort)
}
mode, err := exposeProtocolToString(exposeReq.Protocol)
if err != nil {
return nil, status.Errorf(codes.InvalidArgument, "%v", err)
}
created, err := reverseProxyMgr.CreateServiceFromPeer(ctx, accountID, peer.ID, &rpservice.ExposeServiceRequest{
NamePrefix: exposeReq.NamePrefix,
Port: int(exposeReq.Port),
Protocol: exposeProtocolToString(exposeReq.Protocol),
Domain: exposeReq.Domain,
Pin: exposeReq.Pin,
Password: exposeReq.Password,
UserGroups: exposeReq.UserGroups,
NamePrefix: exposeReq.NamePrefix,
Port: uint16(exposeReq.Port), //nolint:gosec // validated above
Mode: mode,
TargetProtocol: exposeTargetProtocol(exposeReq.Protocol),
Domain: exposeReq.Domain,
Pin: exposeReq.Pin,
Password: exposeReq.Password,
UserGroups: exposeReq.UserGroups,
ListenPort: uint16(exposeReq.ListenPort), //nolint:gosec // validated above
})
if err != nil {
return nil, mapExposeError(ctx, err)
}
return s.encryptResponse(peerKey, &proto.ExposeServiceResponse{
ServiceName: created.ServiceName,
ServiceUrl: created.ServiceURL,
Domain: created.Domain,
ServiceName: created.ServiceName,
ServiceUrl: created.ServiceURL,
Domain: created.Domain,
PortAutoAssigned: created.PortAutoAssigned,
})
}
@@ -77,7 +93,12 @@ func (s *Server) RenewExpose(ctx context.Context, req *proto.EncryptedMessage) (
return nil, status.Errorf(codes.Internal, "reverse proxy manager not available")
}
if err := reverseProxyMgr.RenewServiceFromPeer(ctx, accountID, peer.ID, renewReq.Domain); err != nil {
serviceID, err := s.resolveServiceID(ctx, renewReq.Domain)
if err != nil {
return nil, mapExposeError(ctx, err)
}
if err := reverseProxyMgr.RenewServiceFromPeer(ctx, accountID, peer.ID, serviceID); err != nil {
return nil, mapExposeError(ctx, err)
}
@@ -102,7 +123,12 @@ func (s *Server) StopExpose(ctx context.Context, req *proto.EncryptedMessage) (*
return nil, status.Errorf(codes.Internal, "reverse proxy manager not available")
}
if err := reverseProxyMgr.StopServiceFromPeer(ctx, accountID, peer.ID, stopReq.Domain); err != nil {
serviceID, err := s.resolveServiceID(ctx, stopReq.Domain)
if err != nil {
return nil, mapExposeError(ctx, err)
}
if err := reverseProxyMgr.StopServiceFromPeer(ctx, accountID, peer.ID, serviceID); err != nil {
return nil, mapExposeError(ctx, err)
}
@@ -180,13 +206,46 @@ func (s *Server) SetReverseProxyManager(mgr rpservice.Manager) {
s.reverseProxyManager = mgr
}
func exposeProtocolToString(p proto.ExposeProtocol) string {
// resolveServiceID looks up the service by its globally unique domain.
func (s *Server) resolveServiceID(ctx context.Context, domain string) (string, error) {
if domain == "" {
return "", status.Errorf(codes.InvalidArgument, "domain is required")
}
svc, err := s.accountManager.GetStore().GetServiceByDomain(ctx, domain)
if err != nil {
return "", err
}
return svc.ID, nil
}
func exposeProtocolToString(p proto.ExposeProtocol) (string, error) {
switch p {
case proto.ExposeProtocol_EXPOSE_HTTP:
return "http"
case proto.ExposeProtocol_EXPOSE_HTTPS:
return "https"
case proto.ExposeProtocol_EXPOSE_HTTP, proto.ExposeProtocol_EXPOSE_HTTPS:
return "http", nil
case proto.ExposeProtocol_EXPOSE_TCP:
return "tcp", nil
case proto.ExposeProtocol_EXPOSE_UDP:
return "udp", nil
case proto.ExposeProtocol_EXPOSE_TLS:
return "tls", nil
default:
return "http"
return "", fmt.Errorf("unsupported expose protocol: %v", p)
}
}
// exposeTargetProtocol returns the target protocol for the given expose protocol.
// For HTTP mode, this is http or https (the scheme used to connect to the backend).
// For L4 modes, this is tcp or udp (the transport used to connect to the backend).
func exposeTargetProtocol(p proto.ExposeProtocol) string {
switch p {
case proto.ExposeProtocol_EXPOSE_HTTPS:
return rpservice.TargetProtoHTTPS
case proto.ExposeProtocol_EXPOSE_TCP, proto.ExposeProtocol_EXPOSE_TLS:
return rpservice.TargetProtoTCP
case proto.ExposeProtocol_EXPOSE_UDP:
return rpservice.TargetProtoUDP
default:
return rpservice.TargetProtoHTTP
}
}