feature: Adds basic data command support.
This commit is contained in:
parent
ede4d528aa
commit
17e1491f96
14 changed files with 2241 additions and 195 deletions
323
backend/sshappbackend/datacommands/marshal.go
Normal file
323
backend/sshappbackend/datacommands/marshal.go
Normal file
|
@ -0,0 +1,323 @@
|
|||
package datacommands
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"net"
|
||||
)
|
||||
|
||||
// Example size and protocol constants — adjust as needed.
|
||||
const (
|
||||
IPv4Size = 4
|
||||
IPv6Size = 16
|
||||
|
||||
TCP = 1
|
||||
UDP = 2
|
||||
)
|
||||
|
||||
// Marshal takes a command (pointer to one of our structs) and converts it to a byte slice.
|
||||
func Marshal(_ string, command interface{}) ([]byte, error) {
|
||||
switch cmd := command.(type) {
|
||||
// ProxyStatusRequest: 1 byte for the command ID + 2 bytes for the ProxyID.
|
||||
case *ProxyStatusRequest:
|
||||
buf := make([]byte, 1+2)
|
||||
|
||||
buf[0] = ProxyStatusRequestID
|
||||
binary.BigEndian.PutUint16(buf[1:], cmd.ProxyID)
|
||||
|
||||
return buf, nil
|
||||
|
||||
// ProxyStatusResponse: 1 byte for the command ID, 2 bytes for ProxyID, and 1 byte for IsActive.
|
||||
case *ProxyStatusResponse:
|
||||
buf := make([]byte, 1+2+1)
|
||||
|
||||
buf[0] = ProxyStatusResponseID
|
||||
binary.BigEndian.PutUint16(buf[1:], cmd.ProxyID)
|
||||
|
||||
if cmd.IsActive {
|
||||
buf[3] = 1
|
||||
} else {
|
||||
buf[3] = 0
|
||||
}
|
||||
|
||||
return buf, nil
|
||||
|
||||
// RemoveProxy: 1 byte for the command ID + 2 bytes for the ProxyID.
|
||||
case *RemoveProxy:
|
||||
buf := make([]byte, 1+2)
|
||||
|
||||
buf[0] = RemoveProxyID
|
||||
binary.BigEndian.PutUint16(buf[1:], cmd.ProxyID)
|
||||
|
||||
return buf, nil
|
||||
|
||||
// ProxyConnectionsRequest: 1 byte for the command ID + 2 bytes for the ProxyID.
|
||||
case *ProxyConnectionsRequest:
|
||||
buf := make([]byte, 1+2)
|
||||
|
||||
buf[0] = ProxyConnectionsRequestID
|
||||
binary.BigEndian.PutUint16(buf[1:], cmd.ProxyID)
|
||||
|
||||
return buf, nil
|
||||
|
||||
// ProxyConnectionsResponse: 1 byte for the command ID + 2 bytes length of the Connections + 2 bytes for each
|
||||
// number in the Connection array.
|
||||
case *ProxyConnectionsResponse:
|
||||
buf := make([]byte, 1+((len(cmd.Connections)+1)*2))
|
||||
|
||||
buf[0] = ProxyConnectionsResponseID
|
||||
binary.BigEndian.PutUint16(buf[1:], uint16(len(cmd.Connections)))
|
||||
|
||||
for connectionIndex, connection := range cmd.Connections {
|
||||
binary.BigEndian.PutUint16(buf[3+(connectionIndex*2):], connection)
|
||||
}
|
||||
|
||||
return buf, nil
|
||||
|
||||
// ProxyConnectionsResponse: 1 byte for the command ID + 2 bytes length of the Proxies + 2 bytes for each
|
||||
// number in the Proxies array.
|
||||
case *ProxyInstanceResponse:
|
||||
buf := make([]byte, 1+((len(cmd.Proxies)+1)*2))
|
||||
|
||||
buf[0] = ProxyInstanceResponseID
|
||||
binary.BigEndian.PutUint16(buf[1:], uint16(len(cmd.Proxies)))
|
||||
|
||||
for connectionIndex, connection := range cmd.Proxies {
|
||||
binary.BigEndian.PutUint16(buf[3+(connectionIndex*2):], connection)
|
||||
}
|
||||
|
||||
return buf, nil
|
||||
|
||||
// TCPConnectionOpened: 1 byte for the command ID + 2 bytes ProxyID + 2 bytes ConnectionID.
|
||||
case *TCPConnectionOpened:
|
||||
buf := make([]byte, 1+2+2)
|
||||
|
||||
buf[0] = TCPConnectionOpenedID
|
||||
binary.BigEndian.PutUint16(buf[1:], cmd.ProxyID)
|
||||
binary.BigEndian.PutUint16(buf[3:], cmd.ConnectionID)
|
||||
|
||||
return buf, nil
|
||||
|
||||
// TCPConnectionClosed: 1 byte for the command ID + 2 bytes ProxyID + 2 bytes ConnectionID.
|
||||
case *TCPConnectionClosed:
|
||||
buf := make([]byte, 1+2+2)
|
||||
|
||||
buf[0] = TCPConnectionClosedID
|
||||
binary.BigEndian.PutUint16(buf[1:], cmd.ProxyID)
|
||||
binary.BigEndian.PutUint16(buf[3:], cmd.ConnectionID)
|
||||
|
||||
return buf, nil
|
||||
|
||||
// TCPProxyData: 1 byte ID + 2 bytes ProxyID + 2 bytes ConnectionID + 2 bytes DataLength.
|
||||
case *TCPProxyData:
|
||||
buf := make([]byte, 1+2+2+2)
|
||||
|
||||
buf[0] = TCPProxyDataID
|
||||
binary.BigEndian.PutUint16(buf[1:], cmd.ProxyID)
|
||||
binary.BigEndian.PutUint16(buf[3:], cmd.ConnectionID)
|
||||
binary.BigEndian.PutUint16(buf[5:], cmd.DataLength)
|
||||
|
||||
return buf, nil
|
||||
|
||||
// UDPProxyData:
|
||||
// Format: 1 byte ID + 2 bytes ProxyID + 2 bytes ConnectionID +
|
||||
// 1 byte IP version + IP bytes + 2 bytes ClientPort + 2 bytes DataLength.
|
||||
case *UDPProxyData:
|
||||
ip := net.ParseIP(cmd.ClientIP)
|
||||
if ip == nil {
|
||||
return nil, fmt.Errorf("invalid client IP: %v", cmd.ClientIP)
|
||||
}
|
||||
|
||||
var ipVer uint8
|
||||
var ipBytes []byte
|
||||
|
||||
if ip4 := ip.To4(); ip4 != nil {
|
||||
ipBytes = ip4
|
||||
ipVer = 4
|
||||
} else if ip16 := ip.To16(); ip16 != nil {
|
||||
ipBytes = ip16
|
||||
ipVer = 6
|
||||
} else {
|
||||
return nil, fmt.Errorf("unable to detect IP version for: %v", cmd.ClientIP)
|
||||
}
|
||||
|
||||
totalSize := 1 + // id
|
||||
2 + // ProxyID
|
||||
1 + // IP version
|
||||
len(ipBytes) + // client IP bytes
|
||||
2 + // ClientPort
|
||||
2 // DataLength
|
||||
|
||||
buf := make([]byte, totalSize)
|
||||
offset := 0
|
||||
buf[offset] = UDPProxyDataID
|
||||
offset++
|
||||
|
||||
binary.BigEndian.PutUint16(buf[offset:], cmd.ProxyID)
|
||||
offset += 2
|
||||
|
||||
buf[offset] = ipVer
|
||||
offset++
|
||||
|
||||
copy(buf[offset:], ipBytes)
|
||||
offset += len(ipBytes)
|
||||
|
||||
binary.BigEndian.PutUint16(buf[offset:], cmd.ClientPort)
|
||||
offset += 2
|
||||
|
||||
binary.BigEndian.PutUint16(buf[offset:], cmd.DataLength)
|
||||
|
||||
return buf, nil
|
||||
|
||||
// ProxyInformationRequest: 1 byte ID + 2 bytes ProxyID.
|
||||
case *ProxyInformationRequest:
|
||||
buf := make([]byte, 1+2)
|
||||
buf[0] = ProxyInformationRequestID
|
||||
binary.BigEndian.PutUint16(buf[1:], cmd.ProxyID)
|
||||
return buf, nil
|
||||
|
||||
// ProxyInformationResponse:
|
||||
// Format: 1 byte ID + 1 byte Exists + (if exists:)
|
||||
// 1 byte IP version + IP bytes + 2 bytes SourcePort + 2 bytes DestPort + 1 byte Protocol.
|
||||
// (For simplicity, this marshaller always writes the IP and port info even if !Exists.)
|
||||
case *ProxyInformationResponse:
|
||||
if !cmd.Exists {
|
||||
buf := make([]byte, 1+1)
|
||||
buf[0] = ProxyInformationResponseID
|
||||
buf[1] = 0 /* false */
|
||||
|
||||
return buf, nil
|
||||
}
|
||||
|
||||
ip := net.ParseIP(cmd.SourceIP)
|
||||
|
||||
if ip == nil {
|
||||
return nil, fmt.Errorf("invalid source IP: %v", cmd.SourceIP)
|
||||
}
|
||||
|
||||
var ipVer uint8
|
||||
var ipBytes []byte
|
||||
|
||||
if ip4 := ip.To4(); ip4 != nil {
|
||||
ipBytes = ip4
|
||||
ipVer = 4
|
||||
} else if ip16 := ip.To16(); ip16 != nil {
|
||||
ipBytes = ip16
|
||||
ipVer = 6
|
||||
} else {
|
||||
return nil, fmt.Errorf("unable to detect IP version for: %v", cmd.SourceIP)
|
||||
}
|
||||
|
||||
totalSize := 1 + // id
|
||||
1 + // Exists flag
|
||||
1 + // IP version
|
||||
len(ipBytes) +
|
||||
2 + // SourcePort
|
||||
2 + // DestPort
|
||||
1 // Protocol
|
||||
|
||||
buf := make([]byte, totalSize)
|
||||
|
||||
offset := 0
|
||||
buf[offset] = ProxyInformationResponseID
|
||||
offset++
|
||||
|
||||
// We already handle this above
|
||||
buf[offset] = 1 /* true */
|
||||
offset++
|
||||
|
||||
buf[offset] = ipVer
|
||||
offset++
|
||||
|
||||
copy(buf[offset:], ipBytes)
|
||||
offset += len(ipBytes)
|
||||
|
||||
binary.BigEndian.PutUint16(buf[offset:], cmd.SourcePort)
|
||||
offset += 2
|
||||
|
||||
binary.BigEndian.PutUint16(buf[offset:], cmd.DestPort)
|
||||
offset += 2
|
||||
|
||||
// Encode protocol as 1 byte.
|
||||
switch cmd.Protocol {
|
||||
case "tcp":
|
||||
buf[offset] = TCP
|
||||
case "udp":
|
||||
buf[offset] = UDP
|
||||
default:
|
||||
return nil, fmt.Errorf("invalid protocol: %v", cmd.Protocol)
|
||||
}
|
||||
|
||||
// offset++ (not needed since we are at the end)
|
||||
return buf, nil
|
||||
|
||||
// ProxyConnectionInformationRequest: 1 byte ID + 2 bytes ProxyID + 2 bytes ConnectionID.
|
||||
case *ProxyConnectionInformationRequest:
|
||||
buf := make([]byte, 1+2+2)
|
||||
|
||||
buf[0] = ProxyConnectionInformationRequestID
|
||||
binary.BigEndian.PutUint16(buf[1:], cmd.ProxyID)
|
||||
binary.BigEndian.PutUint16(buf[3:], cmd.ConnectionID)
|
||||
|
||||
return buf, nil
|
||||
|
||||
// ProxyConnectionInformationResponse:
|
||||
// Format: 1 byte ID + 1 byte Exists + (if exists:)
|
||||
// 1 byte IP version + IP bytes + 2 bytes ClientPort.
|
||||
// This marshaller only writes the rest of the data if Exists.
|
||||
case *ProxyConnectionInformationResponse:
|
||||
if !cmd.Exists {
|
||||
buf := make([]byte, 1+1)
|
||||
buf[0] = ProxyConnectionInformationResponseID
|
||||
buf[1] = 0 /* false */
|
||||
|
||||
return buf, nil
|
||||
}
|
||||
|
||||
ip := net.ParseIP(cmd.ClientIP)
|
||||
|
||||
if ip == nil {
|
||||
return nil, fmt.Errorf("invalid client IP: %v", cmd.ClientIP)
|
||||
}
|
||||
|
||||
var ipVer uint8
|
||||
var ipBytes []byte
|
||||
if ip4 := ip.To4(); ip4 != nil {
|
||||
ipBytes = ip4
|
||||
ipVer = 4
|
||||
} else if ip16 := ip.To16(); ip16 != nil {
|
||||
ipBytes = ip16
|
||||
ipVer = 6
|
||||
} else {
|
||||
return nil, fmt.Errorf("unable to detect IP version for: %v", cmd.ClientIP)
|
||||
}
|
||||
|
||||
totalSize := 1 + // id
|
||||
1 + // Exists flag
|
||||
1 + // IP version
|
||||
len(ipBytes) +
|
||||
2 // ClientPort
|
||||
|
||||
buf := make([]byte, totalSize)
|
||||
offset := 0
|
||||
buf[offset] = ProxyConnectionInformationResponseID
|
||||
offset++
|
||||
|
||||
// We already handle this above
|
||||
buf[offset] = 1 /* true */
|
||||
offset++
|
||||
|
||||
buf[offset] = ipVer
|
||||
offset++
|
||||
|
||||
copy(buf[offset:], ipBytes)
|
||||
offset += len(ipBytes)
|
||||
|
||||
binary.BigEndian.PutUint16(buf[offset:], cmd.ClientPort)
|
||||
|
||||
return buf, nil
|
||||
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported command type")
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue