665 lines
16 KiB
Go
665 lines
16 KiB
Go
package commonbackend
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"fmt"
|
|
"io"
|
|
"net"
|
|
)
|
|
|
|
func unmarshalIndividualConnectionStruct(conn io.Reader) (*ProxyClientConnection, error) {
|
|
serverIPVersion := make([]byte, 1)
|
|
|
|
if _, err := conn.Read(serverIPVersion); err != nil {
|
|
return nil, fmt.Errorf("couldn't read server IP version")
|
|
}
|
|
|
|
var serverIPSize uint8
|
|
|
|
if serverIPVersion[0] == 4 {
|
|
serverIPSize = IPv4Size
|
|
} else if serverIPVersion[0] == 6 {
|
|
serverIPSize = IPv6Size
|
|
} else if serverIPVersion[0] == '\n' {
|
|
return nil, fmt.Errorf("no data found")
|
|
} else {
|
|
return nil, fmt.Errorf("invalid server IP version recieved")
|
|
}
|
|
|
|
serverIP := make(net.IP, serverIPSize)
|
|
|
|
if _, err := conn.Read(serverIP); err != nil {
|
|
return nil, fmt.Errorf("couldn't read server IP")
|
|
}
|
|
|
|
sourcePort := make([]byte, 2)
|
|
|
|
if _, err := conn.Read(sourcePort); err != nil {
|
|
return nil, fmt.Errorf("couldn't read source port")
|
|
}
|
|
|
|
destinationPort := make([]byte, 2)
|
|
|
|
if _, err := conn.Read(destinationPort); err != nil {
|
|
return nil, fmt.Errorf("couldn't read source port")
|
|
}
|
|
|
|
clientIPVersion := make([]byte, 1)
|
|
|
|
if _, err := conn.Read(clientIPVersion); err != nil {
|
|
return nil, fmt.Errorf("couldn't read server IP version")
|
|
}
|
|
|
|
var clientIPSize uint8
|
|
|
|
if clientIPVersion[0] == 4 {
|
|
clientIPSize = IPv4Size
|
|
} else if clientIPVersion[0] == 6 {
|
|
clientIPSize = IPv6Size
|
|
} else {
|
|
return nil, fmt.Errorf("invalid server IP version recieved")
|
|
}
|
|
|
|
clientIP := make(net.IP, clientIPSize)
|
|
|
|
if _, err := conn.Read(clientIP); err != nil {
|
|
return nil, fmt.Errorf("couldn't read server IP")
|
|
}
|
|
|
|
clientPort := make([]byte, 2)
|
|
|
|
if _, err := conn.Read(clientPort); err != nil {
|
|
return nil, fmt.Errorf("couldn't read source port")
|
|
}
|
|
|
|
return &ProxyClientConnection{
|
|
SourceIP: serverIP.String(),
|
|
SourcePort: binary.BigEndian.Uint16(sourcePort),
|
|
DestPort: binary.BigEndian.Uint16(destinationPort),
|
|
ClientIP: clientIP.String(),
|
|
ClientPort: binary.BigEndian.Uint16(clientPort),
|
|
}, nil
|
|
}
|
|
|
|
func unmarshalIndividualProxyStruct(conn io.Reader) (*ProxyInstance, error) {
|
|
ipVersion := make([]byte, 1)
|
|
|
|
if _, err := conn.Read(ipVersion); err != nil {
|
|
return nil, fmt.Errorf("couldn't read ip version")
|
|
}
|
|
|
|
var ipSize uint8
|
|
|
|
if ipVersion[0] == 4 {
|
|
ipSize = IPv4Size
|
|
} else if ipVersion[0] == 6 {
|
|
ipSize = IPv6Size
|
|
} else if ipVersion[0] == '\n' {
|
|
return nil, fmt.Errorf("no data found")
|
|
} else {
|
|
return nil, fmt.Errorf("invalid IP version recieved")
|
|
}
|
|
|
|
ip := make(net.IP, ipSize)
|
|
|
|
if _, err := conn.Read(ip); err != nil {
|
|
return nil, fmt.Errorf("couldn't read source IP")
|
|
}
|
|
|
|
sourcePort := make([]byte, 2)
|
|
|
|
if _, err := conn.Read(sourcePort); err != nil {
|
|
return nil, fmt.Errorf("couldn't read source port")
|
|
}
|
|
|
|
destPort := make([]byte, 2)
|
|
|
|
if _, err := conn.Read(destPort); err != nil {
|
|
return nil, fmt.Errorf("couldn't read destination port")
|
|
}
|
|
|
|
protocolBytes := make([]byte, 1)
|
|
|
|
if _, err := conn.Read(protocolBytes); err != nil {
|
|
return nil, fmt.Errorf("couldn't read protocol")
|
|
}
|
|
|
|
var protocol string
|
|
|
|
if protocolBytes[0] == TCP {
|
|
protocol = "tcp"
|
|
} else if protocolBytes[0] == UDP {
|
|
protocol = "udp"
|
|
} else {
|
|
return nil, fmt.Errorf("invalid protocol")
|
|
}
|
|
|
|
return &ProxyInstance{
|
|
SourceIP: ip.String(),
|
|
SourcePort: binary.BigEndian.Uint16(sourcePort),
|
|
DestPort: binary.BigEndian.Uint16(destPort),
|
|
Protocol: protocol,
|
|
}, nil
|
|
}
|
|
|
|
func Unmarshal(conn io.Reader) (string, interface{}, error) {
|
|
commandType := make([]byte, 1)
|
|
|
|
if _, err := conn.Read(commandType); err != nil {
|
|
return "", nil, fmt.Errorf("couldn't read command")
|
|
}
|
|
|
|
switch commandType[0] {
|
|
case StartID:
|
|
argumentsLength := make([]byte, 2)
|
|
|
|
if _, err := conn.Read(argumentsLength); err != nil {
|
|
return "", nil, fmt.Errorf("couldn't read argument length")
|
|
}
|
|
|
|
arguments := make([]byte, binary.BigEndian.Uint16(argumentsLength))
|
|
|
|
if _, err := conn.Read(arguments); err != nil {
|
|
return "", nil, fmt.Errorf("couldn't read arguments")
|
|
}
|
|
|
|
return "start", &Start{
|
|
Type: "start",
|
|
Arguments: arguments,
|
|
}, nil
|
|
case StopID:
|
|
return "stop", &Stop{
|
|
Type: "stop",
|
|
}, nil
|
|
case AddProxyID:
|
|
ipVersion := make([]byte, 1)
|
|
|
|
if _, err := conn.Read(ipVersion); err != nil {
|
|
return "", nil, fmt.Errorf("couldn't read ip version")
|
|
}
|
|
|
|
var ipSize uint8
|
|
|
|
if ipVersion[0] == 4 {
|
|
ipSize = IPv4Size
|
|
} else if ipVersion[0] == 6 {
|
|
ipSize = IPv6Size
|
|
} else {
|
|
return "", nil, fmt.Errorf("invalid IP version recieved")
|
|
}
|
|
|
|
ip := make(net.IP, ipSize)
|
|
|
|
if _, err := conn.Read(ip); err != nil {
|
|
return "", nil, fmt.Errorf("couldn't read source IP")
|
|
}
|
|
|
|
sourcePort := make([]byte, 2)
|
|
|
|
if _, err := conn.Read(sourcePort); err != nil {
|
|
return "", nil, fmt.Errorf("couldn't read source port")
|
|
}
|
|
|
|
destPort := make([]byte, 2)
|
|
|
|
if _, err := conn.Read(destPort); err != nil {
|
|
return "", nil, fmt.Errorf("couldn't read destination port")
|
|
}
|
|
|
|
protocolBytes := make([]byte, 1)
|
|
|
|
if _, err := conn.Read(protocolBytes); err != nil {
|
|
return "", nil, fmt.Errorf("couldn't read protocol")
|
|
}
|
|
|
|
var protocol string
|
|
|
|
if protocolBytes[0] == TCP {
|
|
protocol = "tcp"
|
|
} else if protocolBytes[1] == UDP {
|
|
protocol = "udp"
|
|
} else {
|
|
return "", nil, fmt.Errorf("invalid protocol")
|
|
}
|
|
|
|
return "addProxy", &AddProxy{
|
|
Type: "addProxy",
|
|
SourceIP: ip.String(),
|
|
SourcePort: binary.BigEndian.Uint16(sourcePort),
|
|
DestPort: binary.BigEndian.Uint16(destPort),
|
|
Protocol: protocol,
|
|
}, nil
|
|
case RemoveProxyID:
|
|
ipVersion := make([]byte, 1)
|
|
|
|
if _, err := conn.Read(ipVersion); err != nil {
|
|
return "", nil, fmt.Errorf("couldn't read ip version")
|
|
}
|
|
|
|
var ipSize uint8
|
|
|
|
if ipVersion[0] == 4 {
|
|
ipSize = IPv4Size
|
|
} else if ipVersion[0] == 6 {
|
|
ipSize = IPv6Size
|
|
} else {
|
|
return "", nil, fmt.Errorf("invalid IP version recieved")
|
|
}
|
|
|
|
ip := make(net.IP, ipSize)
|
|
|
|
if _, err := conn.Read(ip); err != nil {
|
|
return "", nil, fmt.Errorf("couldn't read source IP")
|
|
}
|
|
|
|
sourcePort := make([]byte, 2)
|
|
|
|
if _, err := conn.Read(sourcePort); err != nil {
|
|
return "", nil, fmt.Errorf("couldn't read source port")
|
|
}
|
|
|
|
destPort := make([]byte, 2)
|
|
|
|
if _, err := conn.Read(destPort); err != nil {
|
|
return "", nil, fmt.Errorf("couldn't read destination port")
|
|
}
|
|
|
|
protocolBytes := make([]byte, 1)
|
|
|
|
if _, err := conn.Read(protocolBytes); err != nil {
|
|
return "", nil, fmt.Errorf("couldn't read protocol")
|
|
}
|
|
|
|
var protocol string
|
|
|
|
if protocolBytes[0] == TCP {
|
|
protocol = "tcp"
|
|
} else if protocolBytes[1] == UDP {
|
|
protocol = "udp"
|
|
} else {
|
|
return "", nil, fmt.Errorf("invalid protocol")
|
|
}
|
|
|
|
return "removeProxy", &RemoveProxy{
|
|
Type: "removeProxy",
|
|
SourceIP: ip.String(),
|
|
SourcePort: binary.BigEndian.Uint16(sourcePort),
|
|
DestPort: binary.BigEndian.Uint16(destPort),
|
|
Protocol: protocol,
|
|
}, nil
|
|
case ProxyConnectionsResponseID:
|
|
connections := []*ProxyClientConnection{}
|
|
delimiter := make([]byte, 1)
|
|
var errorReturn error
|
|
|
|
// Infinite loop because we don't know the length
|
|
for {
|
|
connection, err := unmarshalIndividualConnectionStruct(conn)
|
|
|
|
if err != nil {
|
|
if err.Error() == "no data found" {
|
|
break
|
|
}
|
|
|
|
return "", nil, err
|
|
}
|
|
|
|
connections = append(connections, connection)
|
|
|
|
if _, err := conn.Read(delimiter); err != nil {
|
|
return "", nil, fmt.Errorf("couldn't read delimiter")
|
|
}
|
|
|
|
if delimiter[0] == '\r' {
|
|
continue
|
|
} else if delimiter[0] == '\n' {
|
|
break
|
|
} else {
|
|
// WTF? This shouldn't happen. Break out and return, but give an error
|
|
errorReturn = fmt.Errorf("invalid delimiter recieved while processing stream")
|
|
break
|
|
}
|
|
}
|
|
|
|
return "proxyConnectionsResponse", &ProxyConnectionsResponse{
|
|
Type: "proxyConnectionsResponse",
|
|
Connections: connections,
|
|
}, errorReturn
|
|
case CheckClientParametersID:
|
|
ipVersion := make([]byte, 1)
|
|
|
|
if _, err := conn.Read(ipVersion); err != nil {
|
|
return "", nil, fmt.Errorf("couldn't read ip version")
|
|
}
|
|
|
|
var ipSize uint8
|
|
|
|
if ipVersion[0] == 4 {
|
|
ipSize = IPv4Size
|
|
} else if ipVersion[0] == 6 {
|
|
ipSize = IPv6Size
|
|
} else {
|
|
return "", nil, fmt.Errorf("invalid IP version recieved")
|
|
}
|
|
|
|
ip := make(net.IP, ipSize)
|
|
|
|
if _, err := conn.Read(ip); err != nil {
|
|
return "", nil, fmt.Errorf("couldn't read source IP")
|
|
}
|
|
|
|
sourcePort := make([]byte, 2)
|
|
|
|
if _, err := conn.Read(sourcePort); err != nil {
|
|
return "", nil, fmt.Errorf("couldn't read source port")
|
|
}
|
|
|
|
destPort := make([]byte, 2)
|
|
|
|
if _, err := conn.Read(destPort); err != nil {
|
|
return "", nil, fmt.Errorf("couldn't read destination port")
|
|
}
|
|
|
|
protocolBytes := make([]byte, 1)
|
|
|
|
if _, err := conn.Read(protocolBytes); err != nil {
|
|
return "", nil, fmt.Errorf("couldn't read protocol")
|
|
}
|
|
|
|
var protocol string
|
|
|
|
if protocolBytes[0] == TCP {
|
|
protocol = "tcp"
|
|
} else if protocolBytes[1] == UDP {
|
|
protocol = "udp"
|
|
} else {
|
|
return "", nil, fmt.Errorf("invalid protocol")
|
|
}
|
|
|
|
return "checkClientParameters", &CheckClientParameters{
|
|
Type: "checkClientParameters",
|
|
SourceIP: ip.String(),
|
|
SourcePort: binary.BigEndian.Uint16(sourcePort),
|
|
DestPort: binary.BigEndian.Uint16(destPort),
|
|
Protocol: protocol,
|
|
}, nil
|
|
case CheckServerParametersID:
|
|
argumentsLength := make([]byte, 2)
|
|
|
|
if _, err := conn.Read(argumentsLength); err != nil {
|
|
return "", nil, fmt.Errorf("couldn't read argument length")
|
|
}
|
|
|
|
arguments := make([]byte, binary.BigEndian.Uint16(argumentsLength))
|
|
|
|
if _, err := conn.Read(arguments); err != nil {
|
|
return "", nil, fmt.Errorf("couldn't read arguments")
|
|
}
|
|
|
|
return "checkServerParameters", &CheckServerParameters{
|
|
Type: "checkServerParameters",
|
|
Arguments: arguments,
|
|
}, nil
|
|
case CheckParametersResponseID:
|
|
checkMethodByte := make([]byte, 1)
|
|
|
|
if _, err := conn.Read(checkMethodByte); err != nil {
|
|
return "", nil, fmt.Errorf("couldn't read check method byte")
|
|
}
|
|
|
|
var checkMethod string
|
|
|
|
if checkMethodByte[0] == CheckClientParametersID {
|
|
checkMethod = "checkClientParameters"
|
|
} else if checkMethodByte[0] == CheckServerParametersID {
|
|
checkMethod = "checkServerParameters"
|
|
} else {
|
|
return "", nil, fmt.Errorf("invalid check method recieved")
|
|
}
|
|
|
|
isValid := make([]byte, 1)
|
|
|
|
if _, err := conn.Read(isValid); err != nil {
|
|
return "", nil, fmt.Errorf("couldn't read isValid byte")
|
|
}
|
|
|
|
messageLengthBytes := make([]byte, 2)
|
|
|
|
if _, err := conn.Read(messageLengthBytes); err != nil {
|
|
return "", nil, fmt.Errorf("couldn't read message length")
|
|
}
|
|
|
|
messageLength := binary.BigEndian.Uint16(messageLengthBytes)
|
|
var message string
|
|
|
|
if messageLength != 0 {
|
|
messageBytes := make([]byte, messageLength)
|
|
|
|
if _, err := conn.Read(messageBytes); err != nil {
|
|
return "", nil, fmt.Errorf("couldn't read message")
|
|
}
|
|
|
|
message = string(messageBytes)
|
|
}
|
|
|
|
return "checkParametersResponse", &CheckParametersResponse{
|
|
Type: "checkParametersResponse",
|
|
InResponseTo: checkMethod,
|
|
IsValid: isValid[0] == 1,
|
|
Message: message,
|
|
}, nil
|
|
case BackendStatusResponseID:
|
|
isRunning := make([]byte, 1)
|
|
|
|
if _, err := conn.Read(isRunning); err != nil {
|
|
return "", nil, fmt.Errorf("couldn't read isRunning field")
|
|
}
|
|
|
|
statusCode := make([]byte, 1)
|
|
|
|
if _, err := conn.Read(statusCode); err != nil {
|
|
return "", nil, fmt.Errorf("couldn't read status code field")
|
|
}
|
|
|
|
messageLengthBytes := make([]byte, 2)
|
|
|
|
if _, err := conn.Read(messageLengthBytes); err != nil {
|
|
return "", nil, fmt.Errorf("couldn't read message length")
|
|
}
|
|
|
|
messageLength := binary.BigEndian.Uint16(messageLengthBytes)
|
|
var message string
|
|
|
|
if messageLength != 0 {
|
|
messageBytes := make([]byte, messageLength)
|
|
|
|
if _, err := conn.Read(messageBytes); err != nil {
|
|
return "", nil, fmt.Errorf("couldn't read message")
|
|
}
|
|
|
|
message = string(messageBytes)
|
|
}
|
|
|
|
return "backendStatusResponse", &BackendStatusResponse{
|
|
Type: "backendStatusResponse",
|
|
IsRunning: isRunning[0] == 1,
|
|
StatusCode: int(statusCode[0]),
|
|
Message: message,
|
|
}, nil
|
|
case BackendStatusRequestID:
|
|
return "backendStatusRequest", &BackendStatusRequest{
|
|
Type: "backendStatusRequest",
|
|
}, nil
|
|
case ProxyStatusRequestID:
|
|
ipVersion := make([]byte, 1)
|
|
|
|
if _, err := conn.Read(ipVersion); err != nil {
|
|
return "", nil, fmt.Errorf("couldn't read ip version")
|
|
}
|
|
|
|
var ipSize uint8
|
|
|
|
if ipVersion[0] == 4 {
|
|
ipSize = IPv4Size
|
|
} else if ipVersion[0] == 6 {
|
|
ipSize = IPv6Size
|
|
} else {
|
|
return "", nil, fmt.Errorf("invalid IP version recieved")
|
|
}
|
|
|
|
ip := make(net.IP, ipSize)
|
|
|
|
if _, err := conn.Read(ip); err != nil {
|
|
return "", nil, fmt.Errorf("couldn't read source IP")
|
|
}
|
|
|
|
sourcePort := make([]byte, 2)
|
|
|
|
if _, err := conn.Read(sourcePort); err != nil {
|
|
return "", nil, fmt.Errorf("couldn't read source port")
|
|
}
|
|
|
|
destPort := make([]byte, 2)
|
|
|
|
if _, err := conn.Read(destPort); err != nil {
|
|
return "", nil, fmt.Errorf("couldn't read destination port")
|
|
}
|
|
|
|
protocolBytes := make([]byte, 1)
|
|
|
|
if _, err := conn.Read(protocolBytes); err != nil {
|
|
return "", nil, fmt.Errorf("couldn't read protocol")
|
|
}
|
|
|
|
var protocol string
|
|
|
|
if protocolBytes[0] == TCP {
|
|
protocol = "tcp"
|
|
} else if protocolBytes[1] == UDP {
|
|
protocol = "udp"
|
|
} else {
|
|
return "", nil, fmt.Errorf("invalid protocol")
|
|
}
|
|
|
|
return "proxyStatusRequest", &ProxyStatusRequest{
|
|
Type: "proxyStatusRequest",
|
|
SourceIP: ip.String(),
|
|
SourcePort: binary.BigEndian.Uint16(sourcePort),
|
|
DestPort: binary.BigEndian.Uint16(destPort),
|
|
Protocol: protocol,
|
|
}, nil
|
|
case ProxyStatusResponseID:
|
|
ipVersion := make([]byte, 1)
|
|
|
|
if _, err := conn.Read(ipVersion); err != nil {
|
|
return "", nil, fmt.Errorf("couldn't read ip version")
|
|
}
|
|
|
|
var ipSize uint8
|
|
|
|
if ipVersion[0] == 4 {
|
|
ipSize = IPv4Size
|
|
} else if ipVersion[0] == 6 {
|
|
ipSize = IPv6Size
|
|
} else {
|
|
return "", nil, fmt.Errorf("invalid IP version recieved")
|
|
}
|
|
|
|
ip := make(net.IP, ipSize)
|
|
|
|
if _, err := conn.Read(ip); err != nil {
|
|
return "", nil, fmt.Errorf("couldn't read source IP")
|
|
}
|
|
|
|
sourcePort := make([]byte, 2)
|
|
|
|
if _, err := conn.Read(sourcePort); err != nil {
|
|
return "", nil, fmt.Errorf("couldn't read source port")
|
|
}
|
|
|
|
destPort := make([]byte, 2)
|
|
|
|
if _, err := conn.Read(destPort); err != nil {
|
|
return "", nil, fmt.Errorf("couldn't read destination port")
|
|
}
|
|
|
|
protocolBytes := make([]byte, 1)
|
|
|
|
if _, err := conn.Read(protocolBytes); err != nil {
|
|
return "", nil, fmt.Errorf("couldn't read protocol")
|
|
}
|
|
|
|
var protocol string
|
|
|
|
if protocolBytes[0] == TCP {
|
|
protocol = "tcp"
|
|
} else if protocolBytes[1] == UDP {
|
|
protocol = "udp"
|
|
} else {
|
|
return "", nil, fmt.Errorf("invalid protocol")
|
|
}
|
|
|
|
isActive := make([]byte, 1)
|
|
|
|
if _, err := conn.Read(isActive); err != nil {
|
|
return "", nil, fmt.Errorf("couldn't read isActive field")
|
|
}
|
|
|
|
return "proxyStatusResponse", &ProxyStatusResponse{
|
|
Type: "proxyStatusResponse",
|
|
SourceIP: ip.String(),
|
|
SourcePort: binary.BigEndian.Uint16(sourcePort),
|
|
DestPort: binary.BigEndian.Uint16(destPort),
|
|
Protocol: protocol,
|
|
IsActive: isActive[0] == 1,
|
|
}, nil
|
|
case ProxyInstanceRequestID:
|
|
return "proxyInstanceRequest", &ProxyInstanceRequest{
|
|
Type: "proxyInstanceRequest",
|
|
}, nil
|
|
case ProxyInstanceResponseID:
|
|
proxies := []*ProxyInstance{}
|
|
delimiter := make([]byte, 1)
|
|
var errorReturn error
|
|
|
|
// Infinite loop because we don't know the length
|
|
for {
|
|
proxy, err := unmarshalIndividualProxyStruct(conn)
|
|
|
|
if err != nil {
|
|
if err.Error() == "no data found" {
|
|
break
|
|
}
|
|
|
|
return "", nil, err
|
|
}
|
|
|
|
proxies = append(proxies, proxy)
|
|
|
|
if _, err := conn.Read(delimiter); err != nil {
|
|
return "", nil, fmt.Errorf("couldn't read delimiter")
|
|
}
|
|
|
|
if delimiter[0] == '\r' {
|
|
continue
|
|
} else if delimiter[0] == '\n' {
|
|
break
|
|
} else {
|
|
// WTF? This shouldn't happen. Break out and return, but give an error
|
|
errorReturn = fmt.Errorf("invalid delimiter recieved while processing stream")
|
|
break
|
|
}
|
|
}
|
|
|
|
return "proxyInstanceResponse", &ProxyInstanceResponse{
|
|
Type: "proxyInstanceResponse",
|
|
Proxies: proxies,
|
|
}, errorReturn
|
|
case ProxyConnectionsRequestID:
|
|
return "proxyConnectionsRequest", &ProxyConnectionsRequest{
|
|
Type: "proxyConnectionsRequest",
|
|
}, nil
|
|
}
|
|
|
|
return "", nil, fmt.Errorf("couldn't match command ID")
|
|
}
|