306 lines
7.4 KiB
Go
306 lines
7.4 KiB
Go
package backendutil_custom
|
|
|
|
import (
|
|
"io"
|
|
"net"
|
|
"os"
|
|
|
|
"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"
|
|
)
|
|
|
|
type BackendApplicationHelper struct {
|
|
Backend BackendInterface
|
|
SocketPath string
|
|
|
|
socket net.Conn
|
|
}
|
|
|
|
func (helper *BackendApplicationHelper) Start() error {
|
|
log.Debug("BackendApplicationHelper is starting")
|
|
err := backendutil.ConfigureProfiling()
|
|
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
log.Debug("Currently waiting for Unix socket connection...")
|
|
|
|
helper.socket, err = net.Dial("unix", helper.SocketPath)
|
|
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
helper.Backend.OnSocketConnection(helper.socket)
|
|
|
|
log.Debug("Sucessfully connected")
|
|
|
|
gaslighter := &gaslighter.Gaslighter{}
|
|
gaslighter.ProxiedReader = helper.socket
|
|
|
|
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
|
|
}
|
|
|
|
switch command := commandRaw.(type) {
|
|
case *datacommands.ProxyConnectionsRequest:
|
|
connections := helper.Backend.GetAllClientConnections(command.ProxyID)
|
|
|
|
serverParams := &datacommands.ProxyConnectionsResponse{
|
|
Connections: connections,
|
|
}
|
|
|
|
byteData, err := datacommands.Marshal(serverParams)
|
|
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if _, err = helper.socket.Write(byteData); err != nil {
|
|
return err
|
|
}
|
|
case *datacommands.RemoveProxy:
|
|
ok, err := helper.Backend.StopProxy(command)
|
|
var hasAnyFailed bool
|
|
|
|
if !ok {
|
|
log.Warnf("failed to remove proxy (ID %d): RemoveProxy returned into failure state", command.ProxyID)
|
|
hasAnyFailed = true
|
|
} else if err != nil {
|
|
log.Warnf("failed to remove proxy (ID %d): %s", command.ProxyID, err.Error())
|
|
hasAnyFailed = true
|
|
}
|
|
|
|
response := &datacommands.ProxyStatusResponse{
|
|
ProxyID: command.ProxyID,
|
|
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 *datacommands.ProxyInformationRequest:
|
|
response := helper.Backend.ResolveProxy(command.ProxyID)
|
|
responseMarshalled, err := datacommands.Marshal(response)
|
|
|
|
if err != nil {
|
|
log.Error("failed to marshal response: %s", err.Error())
|
|
continue
|
|
}
|
|
|
|
helper.socket.Write(responseMarshalled)
|
|
case *datacommands.ProxyConnectionInformationRequest:
|
|
response := helper.Backend.ResolveConnection(command.ProxyID, command.ConnectionID)
|
|
responseMarshalled, err := datacommands.Marshal(response)
|
|
|
|
if err != nil {
|
|
log.Error("failed to marshal response: %s", err.Error())
|
|
continue
|
|
}
|
|
|
|
helper.socket.Write(responseMarshalled)
|
|
case *datacommands.TCPConnectionClosed:
|
|
helper.Backend.OnTCPConnectionClosed(command.ProxyID, command.ConnectionID)
|
|
case *datacommands.TCPProxyData:
|
|
bytes := make([]byte, command.DataLength)
|
|
_, err := io.ReadFull(helper.socket, bytes)
|
|
|
|
if err != nil {
|
|
log.Warn("failed to read TCP data")
|
|
}
|
|
|
|
helper.Backend.HandleTCPMessage(command, bytes)
|
|
case *datacommands.UDPProxyData:
|
|
bytes := make([]byte, command.DataLength)
|
|
_, err := io.ReadFull(helper.socket, bytes)
|
|
|
|
if err != nil {
|
|
log.Warn("failed to read TCP data")
|
|
}
|
|
|
|
helper.Backend.HandleUDPMessage(command, bytes)
|
|
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)
|
|
}
|
|
}
|
|
}
|
|
|
|
func NewHelper(backend BackendInterface) *BackendApplicationHelper {
|
|
socketPath, ok := os.LookupEnv("HERMES_API_SOCK")
|
|
|
|
if !ok {
|
|
log.Warn("HERMES_API_SOCK is not defined! This will cause an issue unless the backend manually overwrites it")
|
|
}
|
|
|
|
helper := &BackendApplicationHelper{
|
|
Backend: backend,
|
|
SocketPath: socketPath,
|
|
}
|
|
|
|
return helper
|
|
}
|