feature: Adds basic TCP support for SSHAppBackend.

This commit is contained in:
Tera << 8 2025-02-18 13:15:09 -05:00
parent 432d457ad7
commit 15176831e6
Signed by: imterah
GPG key ID: 8FA7DD57BA6CEA37
5 changed files with 622 additions and 172 deletions

View file

@ -0,0 +1,30 @@
package gaslighter
import "io"
type Gaslighter struct {
Byte byte
HasGaslit bool
ProxiedReader io.Reader
}
func (gaslighter *Gaslighter) Read(p []byte) (n int, err error) {
if gaslighter.HasGaslit {
return gaslighter.ProxiedReader.Read(p)
}
if len(p) == 0 {
return 0, nil
}
p[0] = gaslighter.Byte
gaslighter.HasGaslit = true
if len(p) > 1 {
n, err := gaslighter.ProxiedReader.Read(p[1:])
return n + 1, err
} else {
return 1, nil
}
}

View file

@ -5,19 +5,35 @@ import (
"crypto/md5"
"encoding/hex"
"encoding/json"
"errors"
"fmt"
"io"
"math/rand/v2"
"net"
"os"
"strings"
"sync"
"time"
"git.terah.dev/imterah/hermes/backend/backendutil"
"git.terah.dev/imterah/hermes/backend/commonbackend"
"git.terah.dev/imterah/hermes/backend/sshappbackend/datacommands"
"git.terah.dev/imterah/hermes/backend/sshappbackend/gaslighter"
"github.com/charmbracelet/log"
"github.com/go-playground/validator/v10"
"github.com/pkg/sftp"
"golang.org/x/crypto/ssh"
)
type TCPProxy struct {
proxyInformation *commonbackend.AddProxy
connections map[uint16]net.Conn
}
type UDPProxy struct {
proxyInformation *commonbackend.AddProxy
}
type SSHAppBackendData struct {
IP string `json:"ip" validate:"required"`
Port uint16 `json:"port" validate:"required"`
@ -27,14 +43,27 @@ type SSHAppBackendData struct {
}
type SSHAppBackend struct {
config *SSHAppBackendData
conn *ssh.Client
clients []*commonbackend.ProxyClientConnection
arrayPropMutex sync.Mutex
config *SSHAppBackendData
conn *ssh.Client
listener net.Listener
currentSock net.Conn
tcpProxies map[uint16]*TCPProxy
udpProxies map[uint16]*UDPProxy
// globalNonCriticalMessageLock: Locks all messages that don't need low-latency transmissions & high
// speed behind a lock. This ensures safety when it comes to handling messages correctly.
globalNonCriticalMessageLock sync.Mutex
// globalNonCriticalMessageChan: Channel for handling messages that need a reply / aren't critical.
globalNonCriticalMessageChan chan interface{}
}
func (backend *SSHAppBackend) StartBackend(configBytes []byte) (bool, error) {
log.Info("SSHAppBackend is initializing...")
backend.globalNonCriticalMessageChan = make(chan interface{})
backend.tcpProxies = map[uint16]*TCPProxy{}
backend.udpProxies = map[uint16]*UDPProxy{}
var backendData SSHAppBackendData
if err := json.Unmarshal(configBytes, &backendData); err != nil {
@ -77,8 +106,8 @@ func (backend *SSHAppBackend) StartBackend(configBytes []byte) (bool, error) {
backend.conn = conn
log.Info("SSHAppBackend has connected successfully.")
log.Info("Getting CPU architecture...")
log.Debug("SSHAppBackend has connected successfully.")
log.Debug("Getting CPU architecture...")
session, err := backend.conn.NewSession()
@ -125,7 +154,7 @@ func (backend *SSHAppBackend) StartBackend(configBytes []byte) (bool, error) {
return false, fmt.Errorf("CPU architecture not compiled/supported currently")
}
log.Info("Checking if we need to copy the application...")
log.Debug("Checking if we need to copy the application...")
var binary []byte
needsToCopyBinary := true
@ -187,7 +216,8 @@ func (backend *SSHAppBackend) StartBackend(configBytes []byte) (bool, error) {
}
if needsToCopyBinary {
log.Info("Copying binary...")
log.Debug("Copying binary...")
sftpInstance, err := sftp.NewClient(conn)
if err != nil {
@ -213,13 +243,13 @@ func (backend *SSHAppBackend) StartBackend(configBytes []byte) (bool, error) {
var file *sftp.File
if fileExists {
file, err = sftpInstance.Create("/tmp/sshappbackend.runtime")
} else {
file, err = sftpInstance.OpenFile("/tmp/sshappbackend.runtime", os.O_WRONLY)
} else {
file, err = sftpInstance.Create("/tmp/sshappbackend.runtime")
}
if err != nil {
log.Warnf("Failed to create file: %s", err.Error())
log.Warnf("Failed to create (or open) file: %s", err.Error())
conn.Close()
backend.conn = nil
return false, err
@ -234,7 +264,7 @@ func (backend *SSHAppBackend) StartBackend(configBytes []byte) (bool, error) {
return false, err
}
err = file.Chmod(775)
err = file.Chmod(0755)
if err != nil {
log.Warnf("Failed to change permissions on file: %s", err.Error())
@ -243,12 +273,25 @@ func (backend *SSHAppBackend) StartBackend(configBytes []byte) (bool, error) {
return false, err
}
log.Info("Done copying file.")
log.Debug("Done copying file.")
sftpInstance.Close()
} else {
log.Info("Skipping copying as there's a copy on disk already.")
log.Debug("Skipping copying as there's a copy on disk already.")
}
log.Info("Starting process...")
log.Debug("Initializing Unix socket...")
socketPath := fmt.Sprintf("/tmp/sock-%d.sock", rand.Uint())
listener, err := conn.ListenUnix(socketPath)
if err != nil {
log.Warnf("Failed to listen on socket: %s", err.Error())
conn.Close()
backend.conn = nil
return false, err
}
log.Debug("Starting process...")
session, err = backend.conn.NewSession()
@ -259,10 +302,56 @@ func (backend *SSHAppBackend) StartBackend(configBytes []byte) (bool, error) {
return false, err
}
backend.listener = listener
session.Stdout = WriteLogger{}
session.Stderr = WriteLogger{}
go session.Run("/tmp/sshappbackend.runtime")
go func() {
for {
err := session.Run(fmt.Sprintf("HERMES_LOG_LEVEL=\"%s\" HERMES_API_SOCK=\"%s\" /tmp/sshappbackend.runtime", os.Getenv("HERMES_LOG_LEVEL"), socketPath))
if err != nil && !errors.Is(err, &ssh.ExitError{}) && !errors.Is(err, &ssh.ExitMissingError{}) {
log.Errorf("Critically failed during execution of remote code: %s", err.Error())
return
} else {
log.Warn("Remote code failed for an unknown reason. Restarting...")
}
}
}()
go backend.sockServerHandler()
log.Debug("Started process. Waiting for Unix socket connection...")
for backend.currentSock == nil {
time.Sleep(10 * time.Millisecond)
}
log.Debug("Detected connection. Sending initialization command...")
proxyStatusRaw, err := backend.SendNonCriticalMessage(&commonbackend.Start{
Arguments: []byte{},
})
if err != nil {
return false, err
}
proxyStatus, ok := proxyStatusRaw.(*commonbackend.BackendStatusResponse)
if !ok {
return false, fmt.Errorf("recieved invalid response type: %T", proxyStatusRaw)
}
if proxyStatus.StatusCode == commonbackend.StatusFailure {
if proxyStatus.Message == "" {
return false, fmt.Errorf("failed to initialize backend in remote code")
} else {
return false, fmt.Errorf("failed to initialize backend in remote code: %s", proxyStatus.Message)
}
}
log.Info("SSHAppBackend has initialized successfully.")
return true, nil
@ -283,15 +372,117 @@ func (backend *SSHAppBackend) GetBackendStatus() (bool, error) {
}
func (backend *SSHAppBackend) StartProxy(command *commonbackend.AddProxy) (bool, error) {
proxyStatusRaw, err := backend.SendNonCriticalMessage(command)
if err != nil {
return false, err
}
proxyStatus, ok := proxyStatusRaw.(*datacommands.ProxyStatusResponse)
if !ok {
return false, fmt.Errorf("recieved invalid response type: %T", proxyStatusRaw)
}
if !proxyStatus.IsActive {
return false, fmt.Errorf("failed to initialize proxy in remote code")
}
if command.Protocol == "tcp" {
backend.tcpProxies[proxyStatus.ProxyID] = &TCPProxy{
proxyInformation: command,
}
backend.tcpProxies[proxyStatus.ProxyID].connections = map[uint16]net.Conn{}
} else if command.Protocol == "udp" {
backend.udpProxies[proxyStatus.ProxyID] = &UDPProxy{
proxyInformation: command,
}
}
return true, nil
}
func (backend *SSHAppBackend) StopProxy(command *commonbackend.RemoveProxy) (bool, error) {
if command.Protocol == "tcp" {
for proxyIndex, proxy := range backend.tcpProxies {
if proxy.proxyInformation.DestPort != command.DestPort {
continue
}
onDisconnect := &datacommands.TCPConnectionClosed{
ProxyID: proxyIndex,
}
for connectionIndex, connection := range proxy.connections {
connection.Close()
delete(proxy.connections, connectionIndex)
onDisconnect.ConnectionID = connectionIndex
disconnectionCommandMarshalled, err := datacommands.Marshal(onDisconnect)
if err != nil {
log.Errorf("failed to marshal disconnection message: %s", err.Error())
}
backend.currentSock.Write(disconnectionCommandMarshalled)
}
proxyStatusRaw, err := backend.SendNonCriticalMessage(&datacommands.RemoveProxy{
ProxyID: proxyIndex,
})
if err != nil {
return false, err
}
proxyStatus, ok := proxyStatusRaw.(*datacommands.ProxyStatusResponse)
if !ok {
log.Warn("Failed to stop proxy: typecast failed")
return true, fmt.Errorf("failed to stop proxy: typecast failed")
}
if proxyStatus.IsActive {
log.Warn("Failed to stop proxy: still running")
return true, fmt.Errorf("failed to stop proxy: still running")
}
}
} else if command.Protocol == "udp" {
for proxyIndex, proxy := range backend.udpProxies {
if proxy.proxyInformation.DestPort != command.DestPort {
continue
}
proxyStatusRaw, err := backend.SendNonCriticalMessage(&datacommands.RemoveProxy{
ProxyID: proxyIndex,
})
if err != nil {
return false, err
}
proxyStatus, ok := proxyStatusRaw.(*datacommands.ProxyStatusResponse)
if !ok {
log.Warn("Failed to stop proxy: typecast failed")
return true, fmt.Errorf("failed to stop proxy: typecast failed")
}
if proxyStatus.IsActive {
log.Warn("Failed to stop proxy: still running")
return true, fmt.Errorf("failed to stop proxy: still running")
}
// TODO: finish code for UDP
}
}
return false, fmt.Errorf("could not find the proxy")
}
func (backend *SSHAppBackend) GetAllClientConnections() []*commonbackend.ProxyClientConnection {
return backend.clients
return []*commonbackend.ProxyClientConnection{}
}
func (backend *SSHAppBackend) CheckParametersForConnections(clientParameters *commonbackend.CheckClientParameters) *commonbackend.CheckParametersResponse {
@ -322,6 +513,216 @@ func (backend *SSHAppBackend) CheckParametersForBackend(arguments []byte) *commo
}
}
func (backend *SSHAppBackend) OnTCPConnectionOpened(proxyID, connectionID uint16) {
conn, err := net.Dial("tcp", fmt.Sprintf("%s:%d", backend.tcpProxies[proxyID].proxyInformation.SourceIP, backend.tcpProxies[proxyID].proxyInformation.SourcePort))
if err != nil {
log.Warnf("failed to dial sock: %s", err.Error())
}
go func() {
dataBuf := make([]byte, 65535)
tcpData := &datacommands.TCPProxyData{
ProxyID: proxyID,
ConnectionID: connectionID,
}
for {
len, err := conn.Read(dataBuf)
if err != nil {
if errors.Is(err, net.ErrClosed) {
return
} else if err.Error() != "EOF" {
log.Warnf("failed to read from sock: %s", err.Error())
}
conn.Close()
break
}
tcpData.DataLength = uint16(len)
marshalledMessageCommand, err := datacommands.Marshal(tcpData)
if err != nil {
log.Warnf("failed to marshal message data: %s", err.Error())
conn.Close()
break
}
if _, err := backend.currentSock.Write(marshalledMessageCommand); err != nil {
log.Warnf("failed to send marshalled message data: %s", err.Error())
conn.Close()
break
}
if _, err := backend.currentSock.Write(dataBuf[:len]); err != nil {
log.Warnf("failed to send raw message data: %s", err.Error())
conn.Close()
break
}
}
onDisconnect := &datacommands.TCPConnectionClosed{
ProxyID: proxyID,
ConnectionID: connectionID,
}
disconnectionCommandMarshalled, err := datacommands.Marshal(onDisconnect)
if err != nil {
log.Errorf("failed to marshal disconnection message: %s", err.Error())
}
backend.currentSock.Write(disconnectionCommandMarshalled)
}()
backend.tcpProxies[proxyID].connections[connectionID] = conn
}
func (backend *SSHAppBackend) OnTCPConnectionClosed(proxyID, connectionID uint16) {
proxy, ok := backend.tcpProxies[proxyID]
if !ok {
log.Warn("Could not find TCP proxy")
}
connection, ok := proxy.connections[connectionID]
if !ok {
log.Warn("Could not find connection in TCP proxy")
}
connection.Close()
delete(proxy.connections, connectionID)
}
func (backend *SSHAppBackend) HandleTCPMessage(message *datacommands.TCPProxyData, data []byte) {
proxy, ok := backend.tcpProxies[message.ProxyID]
if !ok {
log.Warn("Could not find TCP proxy")
}
connection, ok := proxy.connections[message.ConnectionID]
if !ok {
log.Warn("Could not find connection in TCP proxy")
}
connection.Write(data)
}
func (backend *SSHAppBackend) HandleUDPMessage(message *datacommands.UDPProxyData, data []byte) {}
func (backend *SSHAppBackend) SendNonCriticalMessage(iface interface{}) (interface{}, error) {
if backend.currentSock == nil {
return nil, fmt.Errorf("socket connection not initialized yet")
}
bytes, err := datacommands.Marshal(iface)
if err != nil && err.Error() == "unsupported command type" {
bytes, err = commonbackend.Marshal(iface)
if err != nil {
return nil, err
}
} else if err != nil {
return nil, err
}
backend.globalNonCriticalMessageLock.Lock()
if _, err := backend.currentSock.Write(bytes); err != nil {
backend.globalNonCriticalMessageLock.Unlock()
return nil, fmt.Errorf("failed to write message: %s", err.Error())
}
reply, ok := <-backend.globalNonCriticalMessageChan
if !ok {
backend.globalNonCriticalMessageLock.Unlock()
return nil, fmt.Errorf("failed to get reply back: chan not OK")
}
backend.globalNonCriticalMessageLock.Unlock()
return reply, nil
}
func (backend *SSHAppBackend) sockServerHandler() {
for {
conn, err := backend.listener.Accept()
if err != nil {
log.Warnf("Failed to accept remote connection: %s", err.Error())
}
log.Debug("Successfully connected.")
backend.currentSock = conn
commandID := make([]byte, 1)
gaslighter := &gaslighter.Gaslighter{}
gaslighter.ProxiedReader = conn
dataBuffer := make([]byte, 65535)
var commandRaw interface{}
for {
if _, err := conn.Read(commandID); err != nil {
log.Warnf("Failed to read command ID: %s", err.Error())
return
}
gaslighter.Byte = commandID[0]
gaslighter.HasGaslit = false
if gaslighter.Byte > 100 {
commandRaw, err = datacommands.Unmarshal(gaslighter)
} else {
commandRaw, err = commonbackend.Unmarshal(gaslighter)
}
if err != nil {
log.Warnf("Failed to parse command: %s", err.Error())
}
switch command := commandRaw.(type) {
case *datacommands.TCPConnectionOpened:
backend.OnTCPConnectionOpened(command.ProxyID, command.ConnectionID)
case *datacommands.TCPConnectionClosed:
backend.OnTCPConnectionClosed(command.ProxyID, command.ConnectionID)
case *datacommands.TCPProxyData:
if _, err := io.ReadFull(conn, dataBuffer[:command.DataLength]); err != nil {
log.Warnf("Failed to read entire data buffer: %s", err.Error())
break
}
backend.HandleTCPMessage(command, dataBuffer[:command.DataLength])
case *datacommands.UDPProxyData:
if _, err := io.ReadFull(conn, dataBuffer[:command.DataLength]); err != nil {
log.Warnf("Failed to read entire data buffer: %s", err.Error())
break
}
backend.HandleUDPMessage(command, dataBuffer[:command.DataLength])
default:
select {
case backend.globalNonCriticalMessageChan <- command:
default:
}
}
}
}
}
func main() {
logLevel := os.Getenv("HERMES_LOG_LEVEL")

View file

@ -8,6 +8,7 @@ import (
"git.terah.dev/imterah/hermes/backend/backendutil"
"git.terah.dev/imterah/hermes/backend/commonbackend"
"git.terah.dev/imterah/hermes/backend/sshappbackend/datacommands"
"git.terah.dev/imterah/hermes/backend/sshappbackend/gaslighter"
"github.com/charmbracelet/log"
)
@ -38,10 +39,28 @@ func (helper *BackendApplicationHelper) Start() error {
log.Debug("Sucessfully connected")
for {
commandRaw, err := datacommands.Unmarshal(helper.socket)
gaslighter := &gaslighter.Gaslighter{}
gaslighter.ProxiedReader = helper.socket
if err != nil && err.Error() != "couldn't match command ID" {
commandID := make([]byte, 1)
for {
if _, err := helper.socket.Read(commandID); err != nil {
return err
}
gaslighter.Byte = commandID[0]
gaslighter.HasGaslit = false
var commandRaw interface{}
if gaslighter.Byte > 100 {
commandRaw, err = datacommands.Unmarshal(gaslighter)
} else {
commandRaw, err = commonbackend.Unmarshal(gaslighter)
}
if err != nil {
return err
}
@ -127,155 +146,146 @@ func (helper *BackendApplicationHelper) Start() error {
}
helper.Backend.HandleUDPMessage(command, bytes)
default:
commandRaw, err := commonbackend.Unmarshal(helper.socket)
case *commonbackend.Start:
ok, err := helper.Backend.StartBackend(command.Arguments)
var (
message string
statusCode int
)
if err != nil {
message = err.Error()
statusCode = commonbackend.StatusFailure
} else {
statusCode = commonbackend.StatusSuccess
}
response := &commonbackend.BackendStatusResponse{
IsRunning: ok,
StatusCode: statusCode,
Message: message,
}
responseMarshalled, err := commonbackend.Marshal(response)
if err != nil {
log.Error("failed to marshal response: %s", err.Error())
continue
}
helper.socket.Write(responseMarshalled)
case *commonbackend.Stop:
ok, err := helper.Backend.StopBackend()
var (
message string
statusCode int
)
if err != nil {
message = err.Error()
statusCode = commonbackend.StatusFailure
} else {
statusCode = commonbackend.StatusSuccess
}
response := &commonbackend.BackendStatusResponse{
IsRunning: !ok,
StatusCode: statusCode,
Message: message,
}
responseMarshalled, err := commonbackend.Marshal(response)
if err != nil {
log.Error("failed to marshal response: %s", err.Error())
continue
}
helper.socket.Write(responseMarshalled)
case *commonbackend.BackendStatusRequest:
ok, err := helper.Backend.GetBackendStatus()
var (
message string
statusCode int
)
if err != nil {
message = err.Error()
statusCode = commonbackend.StatusFailure
} else {
statusCode = commonbackend.StatusSuccess
}
response := &commonbackend.BackendStatusResponse{
IsRunning: ok,
StatusCode: statusCode,
Message: message,
}
responseMarshalled, err := commonbackend.Marshal(response)
if err != nil {
log.Error("failed to marshal response: %s", err.Error())
continue
}
helper.socket.Write(responseMarshalled)
case *commonbackend.AddProxy:
id, ok, err := helper.Backend.StartProxy(command)
var hasAnyFailed bool
if !ok {
log.Warnf("failed to add proxy (%s:%d -> remote:%d): StartProxy returned into failure state", command.SourceIP, command.SourcePort, command.DestPort)
hasAnyFailed = true
} else if err != nil {
log.Warnf("failed to add proxy (%s:%d -> remote:%d): %s", command.SourceIP, command.SourcePort, command.DestPort, err.Error())
hasAnyFailed = true
}
response := &datacommands.ProxyStatusResponse{
ProxyID: id,
IsActive: !hasAnyFailed,
}
responseMarshalled, err := datacommands.Marshal(response)
if err != nil {
log.Error("failed to marshal response: %s", err.Error())
continue
}
helper.socket.Write(responseMarshalled)
case *commonbackend.CheckClientParameters:
resp := helper.Backend.CheckParametersForConnections(command)
resp.InResponseTo = "checkClientParameters"
byteData, err := commonbackend.Marshal(resp)
if err != nil {
return err
}
switch command := commandRaw.(type) {
case *commonbackend.Start:
ok, err := helper.Backend.StartBackend(command.Arguments)
var (
message string
statusCode int
)
if err != nil {
message = err.Error()
statusCode = commonbackend.StatusFailure
} else {
statusCode = commonbackend.StatusSuccess
}
response := &commonbackend.BackendStatusResponse{
IsRunning: ok,
StatusCode: statusCode,
Message: message,
}
responseMarshalled, err := commonbackend.Marshal(response)
if err != nil {
log.Error("failed to marshal response: %s", err.Error())
continue
}
helper.socket.Write(responseMarshalled)
case *commonbackend.Stop:
ok, err := helper.Backend.StopBackend()
var (
message string
statusCode int
)
if err != nil {
message = err.Error()
statusCode = commonbackend.StatusFailure
} else {
statusCode = commonbackend.StatusSuccess
}
response := &commonbackend.BackendStatusResponse{
IsRunning: !ok,
StatusCode: statusCode,
Message: message,
}
responseMarshalled, err := commonbackend.Marshal(response)
if err != nil {
log.Error("failed to marshal response: %s", err.Error())
continue
}
helper.socket.Write(responseMarshalled)
case *commonbackend.BackendStatusRequest:
ok, err := helper.Backend.GetBackendStatus()
var (
message string
statusCode int
)
if err != nil {
message = err.Error()
statusCode = commonbackend.StatusFailure
} else {
statusCode = commonbackend.StatusSuccess
}
response := &commonbackend.BackendStatusResponse{
IsRunning: ok,
StatusCode: statusCode,
Message: message,
}
responseMarshalled, err := commonbackend.Marshal(response)
if err != nil {
log.Error("failed to marshal response: %s", err.Error())
continue
}
helper.socket.Write(responseMarshalled)
case *commonbackend.AddProxy:
id, ok, err := helper.Backend.StartProxy(command)
var hasAnyFailed bool
if !ok {
log.Warnf("failed to add proxy (%s:%d -> remote:%d): StartProxy returned into failure state", command.SourceIP, command.SourcePort, command.DestPort)
hasAnyFailed = true
} else if err != nil {
log.Warnf("failed to add proxy (%s:%d -> remote:%d): %s", command.SourceIP, command.SourcePort, command.DestPort, err.Error())
hasAnyFailed = true
}
response := &datacommands.ProxyStatusResponse{
ProxyID: id,
IsActive: !hasAnyFailed,
}
responseMarshalled, err := datacommands.Marshal(response)
if err != nil {
log.Error("failed to marshal response: %s", err.Error())
continue
}
helper.socket.Write(responseMarshalled)
case *commonbackend.CheckClientParameters:
resp := helper.Backend.CheckParametersForConnections(command)
resp.InResponseTo = "checkClientParameters"
byteData, err := commonbackend.Marshal(resp)
if err != nil {
return err
}
if _, err = helper.socket.Write(byteData); err != nil {
return err
}
case *commonbackend.CheckServerParameters:
resp := helper.Backend.CheckParametersForBackend(command.Arguments)
resp.InResponseTo = "checkServerParameters"
byteData, err := commonbackend.Marshal(resp)
if err != nil {
return err
}
if _, err = helper.socket.Write(byteData); err != nil {
return err
}
default:
log.Warnf("Unsupported command recieved: %T", command)
if _, err = helper.socket.Write(byteData); err != nil {
return err
}
case *commonbackend.CheckServerParameters:
resp := helper.Backend.CheckParametersForBackend(command.Arguments)
resp.InResponseTo = "checkServerParameters"
byteData, err := commonbackend.Marshal(resp)
if err != nil {
return err
}
if _, err = helper.socket.Write(byteData); err != nil {
return err
}
default:
log.Warnf("Unsupported command recieved: %T", command)
}
}
}

View file

@ -36,6 +36,8 @@ type SSHRemoteAppBackend struct {
tcpProxies map[uint16]*TCPProxy
udpProxies map[uint16]*UDPProxy
isRunning bool
sock net.Conn
}
@ -43,6 +45,8 @@ func (backend *SSHRemoteAppBackend) StartBackend(byte []byte) (bool, error) {
backend.tcpProxies = map[uint16]*TCPProxy{}
backend.udpProxies = map[uint16]*UDPProxy{}
backend.isRunning = true
return true, nil
}
@ -61,11 +65,12 @@ func (backend *SSHRemoteAppBackend) StopBackend() (bool, error) {
delete(backend.udpProxies, udpProxyIndex)
}
backend.isRunning = false
return true, nil
}
func (backend *SSHRemoteAppBackend) GetBackendStatus() (bool, error) {
return true, nil
return backend.isRunning, nil
}
func (backend *SSHRemoteAppBackend) StartProxy(command *commonbackend.AddProxy) (uint16, bool, error) {
@ -104,6 +109,8 @@ func (backend *SSHRemoteAppBackend) StartProxy(command *commonbackend.AddProxy)
backend.tcpProxies[proxyID].connectionIDIndex++
backend.tcpProxies[proxyID].connectionIDLock.Unlock()
backend.tcpProxies[proxyID].connections[connectionID] = conn
dataBuf := make([]byte, 65535)
onConnection := &datacommands.TCPConnectionOpened{
@ -372,12 +379,14 @@ func (backend *SSHRemoteAppBackend) HandleTCPMessage(message *datacommands.TCPPr
tcpProxy, ok := backend.tcpProxies[message.ProxyID]
if !ok {
log.Warnf("could not find tcp proxy (ID %d)", message.ProxyID)
return
}
connection, ok := tcpProxy.connections[message.ConnectionID]
if !ok {
log.Warnf("could not find tcp proxy (ID %d) with connection ID (%d)", message.ProxyID, message.ConnectionID)
return
}