323 lines
7.8 KiB
Go
323 lines
7.8 KiB
Go
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(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")
|
|
}
|
|
}
|