From 2c6b5eb5b9b030f42d2428d8fc0c22c4faae125f Mon Sep 17 00:00:00 2001 From: imterah Date: Sun, 12 Jan 2025 11:35:26 -0500 Subject: [PATCH] chore: Mostly ports SSHBackend. --- backend/api/backendruntime/runtime.go | 1 + backend/backendutil/structure.go | 19 ++++- backend/dummybackend/main.go | 12 +-- backend/externalbackendlauncher/main.go | 26 ++---- backend/sshbackend/main.go | 102 ++++++++++++++++-------- 5 files changed, 98 insertions(+), 62 deletions(-) diff --git a/backend/api/backendruntime/runtime.go b/backend/api/backendruntime/runtime.go index a65c077..10ddec2 100644 --- a/backend/api/backendruntime/runtime.go +++ b/backend/api/backendruntime/runtime.go @@ -229,6 +229,7 @@ func (runtime *Runtime) goRoutineHandler() error { } } case *commonbackend.ProxyStatusRequest: + command.Message() err := handleCommand("proxyStatusRequest", command, sock, messageData.Channel) if err != nil { diff --git a/backend/backendutil/structure.go b/backend/backendutil/structure.go index 0eb7116..55f9746 100644 --- a/backend/backendutil/structure.go +++ b/backend/backendutil/structure.go @@ -1,6 +1,9 @@ package backendutil -import "git.terah.dev/imterah/hermes/backend/commonbackend" +import ( + "capnproto.org/go/capnp/v3" + "git.terah.dev/imterah/hermes/backend/commonbackend" +) type BackendInterface interface { StartBackend(arguments []byte) (bool, error) @@ -8,7 +11,15 @@ type BackendInterface interface { GetBackendStatus() (bool, error) StartProxy(command *commonbackend.AddProxy) (bool, error) StopProxy(command *commonbackend.RemoveProxy) (bool, error) - GetAllClientConnections() []*commonbackend.ProxyClientConnection - CheckParametersForConnections(clientParameters *commonbackend.CheckClientParameters) *commonbackend.CheckParametersResponse - CheckParametersForBackend(arguments []byte) *commonbackend.CheckParametersResponse + GetAllClientConnections(seg *capnp.Segment) []*commonbackend.Connection + CheckParametersForConnections(clientParameters *commonbackend.CheckClientParameters) *CheckParametersResponse + CheckParametersForBackend(arguments []byte) *CheckParametersResponse +} + +// Sent as a response to either CheckClientParameters or CheckBackendParameters +type CheckParametersResponse struct { + Type string // Will be 'checkParametersResponse' always + InResponseTo string // Will be either 'checkClientParameters' or 'checkServerParameters' + IsValid bool // If true, valid, and if false, invalid + Message string // String message from the client (ex. failed to unmarshal JSON: x is not defined) } diff --git a/backend/dummybackend/main.go b/backend/dummybackend/main.go index f28615c..c504b1c 100644 --- a/backend/dummybackend/main.go +++ b/backend/dummybackend/main.go @@ -31,23 +31,23 @@ func (backend *DummyBackend) StopProxy(command *commonbackend.RemoveProxy) (bool return true, nil } -func (backend *DummyBackend) GetAllClientConnections() []*commonbackend.ProxyClientConnection { - return []*commonbackend.ProxyClientConnection{} +func (backend *DummyBackend) GetAllClientConnections() []*commonbackend.Connection { + return []*commonbackend.Connection{} } -func (backend *DummyBackend) CheckParametersForConnections(clientParameters *commonbackend.CheckClientParameters) *commonbackend.CheckParametersResponse { +func (backend *DummyBackend) CheckParametersForConnections(clientParameters *commonbackend.CheckClientParameters) *backendutil.CheckParametersResponse { // You don't have to specify Type and InReplyTo. Those will be handled for you. // Message is optional. - return &commonbackend.CheckParametersResponse{ + return &backendutil.CheckParametersResponse{ IsValid: true, Message: "Valid!", } } -func (backend *DummyBackend) CheckParametersForBackend(arguments []byte) *commonbackend.CheckParametersResponse { +func (backend *DummyBackend) CheckParametersForBackend(arguments []byte) *backendutil.CheckParametersResponse { // You don't have to specify Type and InReplyTo. Those will be handled for you. // Message is optional. - return &commonbackend.CheckParametersResponse{ + return &backendutil.CheckParametersResponse{ IsValid: true, Message: "Valid!", } diff --git a/backend/externalbackendlauncher/main.go b/backend/externalbackendlauncher/main.go index 4c66c6a..e067ded 100644 --- a/backend/externalbackendlauncher/main.go +++ b/backend/externalbackendlauncher/main.go @@ -21,11 +21,8 @@ type ProxyInstance struct { Protocol string `json:"protocol"` } -type WriteLogger struct { - UseError bool -} +type WriteLogger struct{} -// TODO: deprecate UseError switching func (writer WriteLogger) Write(p []byte) (n int, err error) { logSplit := strings.Split(string(p), "\n") @@ -34,11 +31,7 @@ func (writer WriteLogger) Write(p []byte) (n int, err error) { continue } - if writer.UseError { - log.Errorf("application: %s", line) - } else { - log.Infof("application: %s", line) - } + log.Infof("application: %s", line) } return len(p), err @@ -157,7 +150,7 @@ func entrypoint(cCtx *cli.Context) error { if !command.IsRunning { var status string - if command.StatusCode == commonbackend.StatusSuccess { + if command.StatusCode() == commonbackend.StatusCode_success { status = "Success" } else { status = "Failure" @@ -236,19 +229,14 @@ func entrypoint(cCtx *cli.Context) error { log.Debug("entering infinite keepalive loop...") for { + time.Sleep(1 * time.Second) } } }() log.Debug("entering execution loop (in main goroutine)...") - stdout := WriteLogger{ - UseError: false, - } - - stderr := WriteLogger{ - UseError: true, - } + logger := WriteLogger{} for { log.Info("starting process...") @@ -257,9 +245,7 @@ func entrypoint(cCtx *cli.Context) error { cmd := exec.Command(executablePath) cmd.Env = append(cmd.Env, fmt.Sprintf("HERMES_API_SOCK=%s", sockPath), fmt.Sprintf("HERMES_LOG_LEVEL=%s", logLevel)) - cmd.Stdout = stdout - cmd.Stderr = stderr - + cmd.Stdout, cmd.Stderr = logger, logger err := cmd.Run() if err != nil { diff --git a/backend/sshbackend/main.go b/backend/sshbackend/main.go index baf1994..f3343f3 100644 --- a/backend/sshbackend/main.go +++ b/backend/sshbackend/main.go @@ -22,14 +22,14 @@ type SSHListener struct { SourceIP string SourcePort uint16 DestPort uint16 - Protocol string // Will be either 'tcp' or 'udp' + Protocol commonbackend.Protocol Listeners []net.Listener } type SSHBackend struct { config *SSHBackendData conn *ssh.Client - clients []*commonbackend.ProxyClientConnection + clients []*commonbackend.Connection proxies []*SSHListener arrayPropMutex sync.Mutex } @@ -105,18 +105,31 @@ func (backend *SSHBackend) GetBackendStatus() (bool, error) { } func (backend *SSHBackend) StartProxy(command *commonbackend.AddProxy) (bool, error) { + sourceIPBytes, err := command.SourceIP() + + if err != nil { + return false, err + } + + // YOLO. + sourceIP, err := commonbackend.IPBytesToIPSafe(sourceIPBytes) + + if err != nil { + return false, err + } + listenerObject := &SSHListener{ - SourceIP: command.SourceIP, - SourcePort: command.SourcePort, - DestPort: command.DestPort, - Protocol: command.Protocol, + SourceIP: sourceIP.String(), + SourcePort: command.SourcePort(), + DestPort: command.DestPort(), + Protocol: command.Protocol(), Listeners: []net.Listener{}, } for _, ipListener := range backend.config.ListenOnIPs { ip := net.TCPAddr{ IP: net.ParseIP(ipListener), - Port: int(command.DestPort), + Port: int(command.DestPort()), } listener, err := backend.conn.ListenTCP(&ip) @@ -158,7 +171,7 @@ func (backend *SSHBackend) StartProxy(command *commonbackend.AddProxy) (bool, er } clientIPAndPort := forwardedConn.RemoteAddr().String() - clientIP := clientIPAndPort[:strings.LastIndex(clientIPAndPort, ":")] + clientIPString := clientIPAndPort[:strings.LastIndex(clientIPAndPort, ":")] clientPort, err := strconv.Atoi(clientIPAndPort[strings.LastIndex(clientIPAndPort, ":")+1:]) if err != nil { @@ -166,17 +179,21 @@ func (backend *SSHBackend) StartProxy(command *commonbackend.AddProxy) (bool, er continue } - advertisedConn := &commonbackend.ProxyClientConnection{ - SourceIP: command.SourceIP, - SourcePort: command.SourcePort, - DestPort: command.DestPort, - ClientIP: clientIP, - ClientPort: uint16(clientPort), + clientIP, err := commonbackend.IPStringToIPBytes(clientIPString) - // FIXME (imterah): shouldn't protocol be in here? - // Protocol: command.Protocol, + if err != nil { + log.Warnf("failed to parse client IP: %s", err.Error()) + continue } + advertisedConn := &commonbackend.Connection{} + + advertisedConn.SetSourceIP(sourceIPBytes) + advertisedConn.SetSourcePort(command.SourcePort()) + advertisedConn.SetDestPort(command.DestPort()) + advertisedConn.SetClientIP(clientIP) + advertisedConn.SetClientPort(uint16(clientPort)) + backend.arrayPropMutex.Lock() backend.clients = append(backend.clients, advertisedConn) backend.arrayPropMutex.Unlock() @@ -278,7 +295,20 @@ func (backend *SSHBackend) StopProxy(command *commonbackend.RemoveProxy) (bool, backend.arrayPropMutex.Lock() for proxyIndex, proxy := range backend.proxies { - if command.SourceIP == proxy.SourceIP && command.SourcePort == proxy.SourcePort && command.DestPort == proxy.DestPort && command.Protocol == proxy.Protocol { + sourceIPBytes, err := command.SourceIP() + + if err != nil { + log.Warnf("failed to get source IP: %s", err.Error()) + continue + } + + sourceIP, err := commonbackend.IPBytesToIPSafe(sourceIPBytes) + + if err != nil { + log.Warnf("failed to get source IP: %s", err.Error()) + } + + if sourceIP.String() == proxy.SourceIP && command.SourcePort() == proxy.SourcePort && command.DestPort() == proxy.DestPort && command.Protocol() == proxy.Protocol { for _, listener := range proxy.Listeners { err := listener.Close() @@ -299,44 +329,44 @@ func (backend *SSHBackend) StopProxy(command *commonbackend.RemoveProxy) (bool, return false, fmt.Errorf("could not find the proxy") } -func (backend *SSHBackend) GetAllClientConnections() []*commonbackend.ProxyClientConnection { +func (backend *SSHBackend) GetAllClientConnections() []*commonbackend.Connection { defer backend.arrayPropMutex.Unlock() backend.arrayPropMutex.Lock() return backend.clients } -func (backend *SSHBackend) CheckParametersForConnections(clientParameters *commonbackend.CheckClientParameters) *commonbackend.CheckParametersResponse { - if clientParameters.Protocol != "tcp" { - return &commonbackend.CheckParametersResponse{ +func (backend *SSHBackend) CheckParametersForConnections(clientParameters *commonbackend.CheckClientParameters) *backendutil.CheckParametersResponse { + if clientParameters.Protocol() != commonbackend.Protocol_tcp { + return &backendutil.CheckParametersResponse{ IsValid: false, Message: "Only TCP is supported for SSH", } } - return &commonbackend.CheckParametersResponse{ + return &backendutil.CheckParametersResponse{ IsValid: true, } } -func (backend *SSHBackend) CheckParametersForBackend(arguments []byte) *commonbackend.CheckParametersResponse { +func (backend *SSHBackend) CheckParametersForBackend(arguments []byte) *backendutil.CheckParametersResponse { var backendData SSHBackendData if err := json.Unmarshal(arguments, &backendData); err != nil { - return &commonbackend.CheckParametersResponse{ + return &backendutil.CheckParametersResponse{ IsValid: false, Message: fmt.Sprintf("could not read json: %s", err.Error()), } } if err := validator.New().Struct(&backendData); err != nil { - return &commonbackend.CheckParametersResponse{ + return &backendutil.CheckParametersResponse{ IsValid: false, Message: fmt.Sprintf("failed validation of parameters: %s", err.Error()), } } - return &commonbackend.CheckParametersResponse{ + return &backendutil.CheckParametersResponse{ IsValid: true, } } @@ -388,12 +418,20 @@ func (backend *SSHBackend) backendDisconnectHandler() { log.Info("SSHBackend has reconnected successfully. Attempting to set up proxies again...") for _, proxy := range backend.proxies { - ok, err := backend.StartProxy(&commonbackend.AddProxy{ - SourceIP: proxy.SourceIP, - SourcePort: proxy.SourcePort, - DestPort: proxy.DestPort, - Protocol: proxy.Protocol, - }) + sourceIP, err := commonbackend.IPStringToIPBytes(proxy.SourceIP) + + if err != nil { + log.Warnf("Failed to parse IP address: %s", err.Error()) + } + + proxyStartCommand := &commonbackend.AddProxy{} + + proxyStartCommand.SetSourceIP(sourceIP) + proxyStartCommand.SetSourcePort(proxy.SourcePort) + proxyStartCommand.SetDestPort(proxy.DestPort) + proxyStartCommand.SetProtocol(proxy.Protocol) + + ok, err := backend.StartProxy(proxyStartCommand) if err != nil { log.Errorf("Failed to set up proxy: %s", err.Error())