diff --git a/api/gosrc/commonbackend/constants.go b/api/gosrc/commonbackend/constants.go index 4a726e2..6aada61 100644 --- a/api/gosrc/commonbackend/constants.go +++ b/api/gosrc/commonbackend/constants.go @@ -1,13 +1,5 @@ package commonbackend -// Not all of these structs are implemented commands. -// Currently unimplemented commands: -// GetAllConnectionsRequest -// BackendStatusResponse -// BackendStatusRequest -// ProxyStatusRequest -// ProxyStatusResponse - // TODO (imterah): Rename AddConnectionCommand/RemoveConnectionCommand to AddProxyCommand/RemoveProxyCommand // and their associated function calls @@ -37,7 +29,7 @@ type RemoveConnectionCommand struct { } type ProxyStatusRequest struct { - Type string // Will be 'getProxyStatus' always + Type string // Will be 'proxyStatusRequest' always SourceIP string SourcePort uint16 DestPort uint16 @@ -61,20 +53,23 @@ type ProxyConnection struct { } type ProxyConnectionResponse struct { - Type string // Will be 'proxyConnectionResponse' always - Connections []*ProxyConnection // List of connections + Type string // Will be 'proxyConnectionResponse' always + Proxies []*ProxyConnection // List of connections +} + +type ProxyConnectionRequest struct { + Type string // Will be 'proxyConnectionRequest' always } type BackendStatusResponse struct { - Type string // Will be 'backendStatusResponse' always - InResponseTo string // Can be either for 'start' or 'stop' - StatusCode int // Either the 'Success' or 'Failure' constant - Message string // String message from the client (ex. failed to dial TCP) + Type string // Will be 'backendStatusResponse' always + IsRunning bool // Can be either for 'start' or 'stop' + StatusCode int // Either the 'Success' or 'Failure' constant + Message string // String message from the client (ex. failed to dial TCP) } type BackendStatusRequest struct { - Type string // Will be 'backendStatusRequest' always - ForProperty string // Can be either for 'start' or 'stop' + Type string // Will be 'backendStatusRequest' always } type GetAllConnectionsRequest struct { @@ -130,6 +125,8 @@ const ( BackendStatusRequestID ProxyStatusRequestID ProxyStatusResponseID + ProxyConnectionResponseID + ProxyConnectionRequestID ) const ( diff --git a/api/gosrc/commonbackend/marshal.go b/api/gosrc/commonbackend/marshal.go index 405f60d..cc02756 100644 --- a/api/gosrc/commonbackend/marshal.go +++ b/api/gosrc/commonbackend/marshal.go @@ -36,6 +36,7 @@ func marshalIndividualConnectionStruct(conn *ClientConnection) []byte { connectionBlock[0] = serverIPVer copy(connectionBlock[1:len(sourceIP)+1], sourceIP) + binary.BigEndian.PutUint16(connectionBlock[1+len(sourceIP):3+len(sourceIP)], conn.SourcePort) binary.BigEndian.PutUint16(connectionBlock[3+len(sourceIP):5+len(sourceIP)], conn.DestPort) @@ -46,6 +47,43 @@ func marshalIndividualConnectionStruct(conn *ClientConnection) []byte { return connectionBlock } +func marshalIndividualProxyStruct(conn *ProxyConnection) ([]byte, error) { + sourceIPOriginal := net.ParseIP(conn.SourceIP) + + var sourceIPVer uint8 + var sourceIP []byte + + if sourceIPOriginal.To4() == nil { + sourceIPVer = IPv6 + sourceIP = sourceIPOriginal.To16() + } else { + sourceIPVer = IPv4 + sourceIP = sourceIPOriginal.To4() + } + + proxyBlock := make([]byte, 6+len(sourceIP)) + + proxyBlock[0] = sourceIPVer + copy(proxyBlock[1:len(sourceIP)+1], sourceIP) + + binary.BigEndian.PutUint16(proxyBlock[1+len(sourceIP):3+len(sourceIP)], conn.SourcePort) + binary.BigEndian.PutUint16(proxyBlock[3+len(sourceIP):5+len(sourceIP)], conn.DestPort) + + var protocolVersion uint8 + + if conn.Protocol == "tcp" { + protocolVersion = TCP + } else if conn.Protocol == "udp" { + protocolVersion = UDP + } else { + return proxyBlock, fmt.Errorf("invalid protocol recieved") + } + + proxyBlock[5+len(sourceIP)] = protocolVersion + + return proxyBlock, nil +} + func Marshal(commandType string, command interface{}) ([]byte, error) { switch commandType { case "start": @@ -68,10 +106,7 @@ func Marshal(commandType string, command interface{}) ([]byte, error) { return nil, fmt.Errorf("failed to typecast") } - stopCommandBytes := make([]byte, 1) - stopCommandBytes[0] = StopCommandID - - return stopCommandBytes, nil + return []byte{StopCommandID}, nil case "addConnection": addConnectionCommand, ok := command.(*AddConnectionCommand) @@ -273,6 +308,190 @@ func Marshal(commandType string, command interface{}) ([]byte, error) { } return checkResponseBytes, nil + case "backendStatusResponse": + backendStatusResponse, ok := command.(*BackendStatusResponse) + + if !ok { + return nil, fmt.Errorf("failed to typecast") + } + + var isRunning uint8 + + if backendStatusResponse.IsRunning { + isRunning = 1 + } else { + isRunning = 0 + } + + statusResponseBytes := make([]byte, 3+2+len(backendStatusResponse.Message)) + statusResponseBytes[0] = BackendStatusResponseID + statusResponseBytes[1] = isRunning + statusResponseBytes[2] = byte(backendStatusResponse.StatusCode) + + binary.BigEndian.PutUint16(statusResponseBytes[3:5], uint16(len(backendStatusResponse.Message))) + + if len(backendStatusResponse.Message) != 0 { + copy(statusResponseBytes[5:], []byte(backendStatusResponse.Message)) + } + + return statusResponseBytes, nil + case "backendStatusRequest": + _, ok := command.(*BackendStatusRequest) + + if !ok { + return nil, fmt.Errorf("failed to typecast") + } + + statusRequestBytes := make([]byte, 2) + statusRequestBytes[0] = BackendStatusRequestID + + return statusRequestBytes, nil + case "proxyStatusRequest": + proxyStatusRequest, ok := command.(*ProxyStatusRequest) + + if !ok { + return nil, fmt.Errorf("failed to typecast") + } + + sourceIP := net.ParseIP(proxyStatusRequest.SourceIP) + + var ipVer uint8 + var ipBytes []byte + + if sourceIP.To4() == nil { + ipBytes = sourceIP.To16() + ipVer = IPv6 + } else { + ipBytes = sourceIP.To4() + ipVer = IPv4 + } + + proxyStatusRequestBytes := make([]byte, 1+1+len(ipBytes)+2+2+1) + + proxyStatusRequestBytes[0] = ProxyStatusRequestID + proxyStatusRequestBytes[1] = ipVer + + copy(proxyStatusRequestBytes[2:2+len(ipBytes)], ipBytes) + + binary.BigEndian.PutUint16(proxyStatusRequestBytes[2+len(ipBytes):4+len(ipBytes)], proxyStatusRequest.SourcePort) + binary.BigEndian.PutUint16(proxyStatusRequestBytes[4+len(ipBytes):6+len(ipBytes)], proxyStatusRequest.DestPort) + + var protocol uint8 + + if proxyStatusRequest.Protocol == "tcp" { + protocol = TCP + } else if proxyStatusRequest.Protocol == "udp" { + protocol = UDP + } else { + return nil, fmt.Errorf("invalid protocol") + } + + proxyStatusRequestBytes[6+len(ipBytes)] = protocol + + return proxyStatusRequestBytes, nil + case "proxyStatusResponse": + proxyStatusResponse, ok := command.(*ProxyStatusResponse) + + if !ok { + return nil, fmt.Errorf("failed to typecast") + } + + sourceIP := net.ParseIP(proxyStatusResponse.SourceIP) + + var ipVer uint8 + var ipBytes []byte + + if sourceIP.To4() == nil { + ipBytes = sourceIP.To16() + ipVer = IPv6 + } else { + ipBytes = sourceIP.To4() + ipVer = IPv4 + } + + proxyStatusResponseBytes := make([]byte, 1+1+len(ipBytes)+2+2+1+1) + + proxyStatusResponseBytes[0] = ProxyStatusResponseID + proxyStatusResponseBytes[1] = ipVer + + copy(proxyStatusResponseBytes[2:2+len(ipBytes)], ipBytes) + + binary.BigEndian.PutUint16(proxyStatusResponseBytes[2+len(ipBytes):4+len(ipBytes)], proxyStatusResponse.SourcePort) + binary.BigEndian.PutUint16(proxyStatusResponseBytes[4+len(ipBytes):6+len(ipBytes)], proxyStatusResponse.DestPort) + + var protocol uint8 + + if proxyStatusResponse.Protocol == "tcp" { + protocol = TCP + } else if proxyStatusResponse.Protocol == "udp" { + protocol = UDP + } else { + return nil, fmt.Errorf("invalid protocol") + } + + proxyStatusResponseBytes[6+len(ipBytes)] = protocol + + var isActive uint8 + + if proxyStatusResponse.IsActive { + isActive = 1 + } else { + isActive = 0 + } + + proxyStatusResponseBytes[7+len(ipBytes)] = isActive + + return proxyStatusResponseBytes, nil + case "proxyConnectionResponse": + proxyConectionResponse, ok := command.(*ProxyConnectionResponse) + + if !ok { + return nil, fmt.Errorf("failed to typecast") + } + + proxyArray := make([][]byte, len(proxyConectionResponse.Proxies)) + totalSize := 0 + + for proxyIndex, proxy := range proxyConectionResponse.Proxies { + var err error + proxyArray[proxyIndex], err = marshalIndividualProxyStruct(proxy) + + if err != nil { + return nil, err + } + + totalSize += len(proxyArray[proxyIndex]) + 1 + } + + connectionCommandArray := make([]byte, totalSize+1) + connectionCommandArray[0] = ProxyConnectionResponseID + + currentPosition := 1 + + for _, connection := range proxyArray { + copy(connectionCommandArray[currentPosition:currentPosition+len(connection)], connection) + connectionCommandArray[currentPosition+len(connection)] = '\r' + currentPosition += len(connection) + 1 + } + + connectionCommandArray[totalSize] = '\n' + return connectionCommandArray, nil + case "proxyConnectionRequest": + _, ok := command.(*ProxyConnectionRequest) + + if !ok { + return nil, fmt.Errorf("failed to typecast") + } + + return []byte{ProxyConnectionRequestID}, nil + case "getAllConnectionsRequest": + _, ok := command.(*GetAllConnectionsRequest) + + if !ok { + return nil, fmt.Errorf("failed to typecast") + } + + return []byte{GetAllConnectionsRequestID}, nil } return nil, fmt.Errorf("couldn't match command") diff --git a/api/gosrc/commonbackend/marshalling_test.go b/api/gosrc/commonbackend/marshalling_test.go index f339809..61644e5 100644 --- a/api/gosrc/commonbackend/marshalling_test.go +++ b/api/gosrc/commonbackend/marshalling_test.go @@ -292,17 +292,17 @@ func TestGetAllConnectionsCommandMarshalSupport(t *testing.T) { log.Printf("(in #%d) SourcePort's are not equal (orig: %d, unmsh: %d)", commandIndex, originalConnection.SourcePort, remoteConnection.SourcePort) } - if originalConnection.SourcePort != remoteConnection.SourcePort { + if originalConnection.DestPort != remoteConnection.DestPort { t.Fail() log.Printf("(in #%d) DestPort's are not equal (orig: %d, unmsh: %d)", commandIndex, originalConnection.DestPort, remoteConnection.DestPort) } - if originalConnection.SourcePort != remoteConnection.SourcePort { + if originalConnection.ClientIP != remoteConnection.ClientIP { t.Fail() log.Printf("(in #%d) ClientIP's are not equal (orig: %s, unmsh: %s)", commandIndex, originalConnection.ClientIP, remoteConnection.ClientIP) } - if originalConnection.SourcePort != remoteConnection.SourcePort { + if originalConnection.ClientPort != remoteConnection.ClientPort { t.Fail() log.Printf("(in #%d) ClientPort's are not equal (orig: %d, unmsh: %d)", commandIndex, originalConnection.ClientPort, remoteConnection.ClientPort) } @@ -472,3 +472,353 @@ func TestCheckParametersResponseMarshalSupport(t *testing.T) { log.Printf("Messages are not equal (orig: %s, unmsh: %s)", commandInput.Message, commandUnmarshalled.Message) } } + +func TestBackendStatusRequestMarshalSupport(t *testing.T) { + commandInput := &BackendStatusRequest{ + Type: "backendStatusRequest", + } + + commandMarshalled, err := Marshal(commandInput.Type, commandInput) + + if logLevel == "debug" { + log.Printf("Generated array contents: %v", commandMarshalled) + } + + if err != nil { + t.Fatalf(err.Error()) + } + + buf := bytes.NewBuffer(commandMarshalled) + commandType, commandUnmarshalledRaw, err := Unmarshal(buf) + + if err != nil { + t.Fatal(err.Error()) + } + + if commandType != commandInput.Type { + t.Fail() + log.Print("command type does not match up!") + } + + commandUnmarshalled, ok := commandUnmarshalledRaw.(*BackendStatusRequest) + + if !ok { + t.Fatal("failed typecast") + } + + if commandInput.Type != commandUnmarshalled.Type { + t.Fail() + log.Printf("Types are not equal (orig: %s, unmsh: %s)", commandInput.Type, commandUnmarshalled.Type) + } +} + +func TestBackendStatusResponseMarshalSupport(t *testing.T) { + commandInput := &BackendStatusResponse{ + Type: "backendStatusResponse", + IsRunning: true, + StatusCode: StatusFailure, + Message: "Hello from automated testing", + } + + commandMarshalled, err := Marshal(commandInput.Type, commandInput) + + if logLevel == "debug" { + log.Printf("Generated array contents: %v", commandMarshalled) + } + + if err != nil { + t.Fatalf(err.Error()) + } + + buf := bytes.NewBuffer(commandMarshalled) + commandType, commandUnmarshalledRaw, err := Unmarshal(buf) + + if err != nil { + t.Fatal(err.Error()) + } + + if commandType != commandInput.Type { + t.Fail() + log.Print("command type does not match up!") + } + + commandUnmarshalled, ok := commandUnmarshalledRaw.(*BackendStatusResponse) + + if !ok { + t.Fatal("failed typecast") + } + + if commandInput.Type != commandUnmarshalled.Type { + t.Fail() + log.Printf("Types are not equal (orig: %s, unmsh: %s)", commandInput.Type, commandUnmarshalled.Type) + } + + if commandInput.IsRunning != commandUnmarshalled.IsRunning { + t.Fail() + log.Printf("IsRunning's are not equal (orig: %t, unmsh: %t)", commandInput.IsRunning, commandUnmarshalled.IsRunning) + } + + if commandInput.StatusCode != commandUnmarshalled.StatusCode { + t.Fail() + log.Printf("StatusCodes are not equal (orig: %d, unmsh: %d)", commandInput.StatusCode, commandUnmarshalled.StatusCode) + } + + if commandInput.Message != commandUnmarshalled.Message { + t.Fail() + log.Printf("Messages are not equal (orig: %s, unmsh: %s)", commandInput.Message, commandUnmarshalled.Message) + } +} + +func TestProxyStatusRequestMarshalSupport(t *testing.T) { + commandInput := &ProxyStatusRequest{ + Type: "proxyStatusRequest", + SourceIP: "192.168.0.139", + SourcePort: 19132, + DestPort: 19132, + Protocol: "tcp", + } + + commandMarshalled, err := Marshal(commandInput.Type, commandInput) + + if err != nil { + t.Fatalf(err.Error()) + } + + if logLevel == "debug" { + log.Printf("Generated array contents: %v", commandMarshalled) + } + + buf := bytes.NewBuffer(commandMarshalled) + commandType, commandUnmarshalledRaw, err := Unmarshal(buf) + + if err != nil { + t.Fatal(err.Error()) + } + + if commandType != commandInput.Type { + t.Fail() + log.Print("command type does not match up!") + } + + commandUnmarshalled, ok := commandUnmarshalledRaw.(*ProxyStatusRequest) + + if !ok { + t.Fatal("failed typecast") + } + + if commandInput.Type != commandUnmarshalled.Type { + t.Fail() + log.Printf("Types are not equal (orig: %s, unmsh: %s)", commandInput.Type, commandUnmarshalled.Type) + } + + if commandInput.SourceIP != commandUnmarshalled.SourceIP { + t.Fail() + log.Printf("SourceIP's are not equal (orig: %s, unmsh: %s)", commandInput.SourceIP, commandUnmarshalled.SourceIP) + } + + if commandInput.SourcePort != commandUnmarshalled.SourcePort { + t.Fail() + log.Printf("SourcePort's are not equal (orig: %d, unmsh: %d)", commandInput.SourcePort, commandUnmarshalled.SourcePort) + } + + if commandInput.DestPort != commandUnmarshalled.DestPort { + t.Fail() + log.Printf("DestPort's are not equal (orig: %d, unmsh: %d)", commandInput.DestPort, commandUnmarshalled.DestPort) + } + + if commandInput.Protocol != commandUnmarshalled.Protocol { + t.Fail() + log.Printf("Protocols are not equal (orig: %s, unmsh: %s)", commandInput.Protocol, commandUnmarshalled.Protocol) + } +} + +func TestProxyStatusResponseMarshalSupport(t *testing.T) { + commandInput := &ProxyStatusResponse{ + Type: "proxyStatusResponse", + SourceIP: "192.168.0.139", + SourcePort: 19132, + DestPort: 19132, + Protocol: "tcp", + IsActive: true, + } + + commandMarshalled, err := Marshal(commandInput.Type, commandInput) + + if err != nil { + t.Fatalf(err.Error()) + } + + if logLevel == "debug" { + log.Printf("Generated array contents: %v", commandMarshalled) + } + + buf := bytes.NewBuffer(commandMarshalled) + commandType, commandUnmarshalledRaw, err := Unmarshal(buf) + + if err != nil { + t.Fatal(err.Error()) + } + + if commandType != commandInput.Type { + t.Fail() + log.Print("command type does not match up!") + } + + commandUnmarshalled, ok := commandUnmarshalledRaw.(*ProxyStatusResponse) + + if !ok { + t.Fatal("failed typecast") + } + + if commandInput.Type != commandUnmarshalled.Type { + t.Fail() + log.Printf("Types are not equal (orig: %s, unmsh: %s)", commandInput.Type, commandUnmarshalled.Type) + } + + if commandInput.SourceIP != commandUnmarshalled.SourceIP { + t.Fail() + log.Printf("SourceIP's are not equal (orig: %s, unmsh: %s)", commandInput.SourceIP, commandUnmarshalled.SourceIP) + } + + if commandInput.SourcePort != commandUnmarshalled.SourcePort { + t.Fail() + log.Printf("SourcePort's are not equal (orig: %d, unmsh: %d)", commandInput.SourcePort, commandUnmarshalled.SourcePort) + } + + if commandInput.DestPort != commandUnmarshalled.DestPort { + t.Fail() + log.Printf("DestPort's are not equal (orig: %d, unmsh: %d)", commandInput.DestPort, commandUnmarshalled.DestPort) + } + + if commandInput.Protocol != commandUnmarshalled.Protocol { + t.Fail() + log.Printf("Protocols are not equal (orig: %s, unmsh: %s)", commandInput.Protocol, commandUnmarshalled.Protocol) + } + + if commandInput.IsActive != commandUnmarshalled.IsActive { + t.Fail() + log.Printf("IsActive's are not equal (orig: %t, unmsh: %t)", commandInput.IsActive, commandUnmarshalled.IsActive) + } +} + +func TestProxyConnectionRequestMarshalSupport(t *testing.T) { + commandInput := &ProxyConnectionRequest{ + Type: "proxyConnectionRequest", + } + + commandMarshalled, err := Marshal(commandInput.Type, commandInput) + + if logLevel == "debug" { + log.Printf("Generated array contents: %v", commandMarshalled) + } + + if err != nil { + t.Fatalf(err.Error()) + } + + buf := bytes.NewBuffer(commandMarshalled) + commandType, commandUnmarshalledRaw, err := Unmarshal(buf) + + if err != nil { + t.Fatal(err.Error()) + } + + if commandType != commandInput.Type { + t.Fail() + log.Print("command type does not match up!") + } + + commandUnmarshalled, ok := commandUnmarshalledRaw.(*ProxyConnectionRequest) + + if !ok { + t.Fatal("failed typecast") + } + + if commandInput.Type != commandUnmarshalled.Type { + t.Fail() + log.Printf("Types are not equal (orig: %s, unmsh: %s)", commandInput.Type, commandUnmarshalled.Type) + } +} + +func TestProxyConnectionResponseMarshalSupport(t *testing.T) { + commandInput := &ProxyConnectionResponse{ + Type: "proxyConnectionResponse", + Proxies: []*ProxyConnection{ + { + SourceIP: "192.168.0.168", + SourcePort: 25565, + DestPort: 25565, + Protocol: "tcp", + }, + { + SourceIP: "127.0.0.1", + SourcePort: 19132, + DestPort: 19132, + Protocol: "udp", + }, + { + SourceIP: "68.42.203.47", + SourcePort: 22, + DestPort: 2222, + Protocol: "tcp", + }, + }, + } + + commandMarshalled, err := Marshal(commandInput.Type, commandInput) + + if err != nil { + t.Fatalf(err.Error()) + } + + if logLevel == "debug" { + log.Printf("Generated array contents: %v", commandMarshalled) + } + + buf := bytes.NewBuffer(commandMarshalled) + commandType, commandUnmarshalledRaw, err := Unmarshal(buf) + + if err != nil { + t.Fatal(err.Error()) + } + + if commandType != commandInput.Type { + t.Fail() + log.Print("command type does not match up!") + } + + commandUnmarshalled, ok := commandUnmarshalledRaw.(*ProxyConnectionResponse) + + if !ok { + t.Fatal("failed typecast") + } + + if commandInput.Type != commandUnmarshalled.Type { + t.Fail() + log.Printf("Types are not equal (orig: %s, unmsh: %s)", commandInput.Type, commandUnmarshalled.Type) + } + + for proxyIndex, originalProxy := range commandInput.Proxies { + remoteProxy := commandUnmarshalled.Proxies[proxyIndex] + + if originalProxy.SourceIP != remoteProxy.SourceIP { + t.Fail() + log.Printf("(in #%d) SourceIP's are not equal (orig: %s, unmsh: %s)", proxyIndex, originalProxy.SourceIP, remoteProxy.SourceIP) + } + + if originalProxy.SourcePort != remoteProxy.SourcePort { + t.Fail() + log.Printf("(in #%d) SourcePort's are not equal (orig: %d, unmsh: %d)", proxyIndex, originalProxy.SourcePort, remoteProxy.SourcePort) + } + + if originalProxy.DestPort != remoteProxy.DestPort { + t.Fail() + log.Printf("(in #%d) DestPort's are not equal (orig: %d, unmsh: %d)", proxyIndex, originalProxy.DestPort, remoteProxy.DestPort) + } + + if originalProxy.Protocol != remoteProxy.Protocol { + t.Fail() + log.Printf("(in #%d) ClientIP's are not equal (orig: %s, unmsh: %s)", proxyIndex, originalProxy.Protocol, remoteProxy.Protocol) + } + } +} diff --git a/api/gosrc/commonbackend/unmarshal.go b/api/gosrc/commonbackend/unmarshal.go index bab6949..ce53238 100644 --- a/api/gosrc/commonbackend/unmarshal.go +++ b/api/gosrc/commonbackend/unmarshal.go @@ -79,6 +79,65 @@ func unmarshalIndividualConnectionStruct(conn io.Reader) (*ClientConnection, err }, nil } +func unmarshalIndividualProxyStruct(conn io.Reader) (*ProxyConnection, 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 { + 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 &ProxyConnection{ + 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) @@ -381,6 +440,213 @@ func Unmarshal(conn io.Reader) (string, interface{}, error) { 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 ProxyConnectionRequestID: + return "proxyConnectionRequest", &ProxyConnectionRequest{ + Type: "proxyConnectionRequest", + }, nil + case ProxyConnectionResponseID: + proxies := []*ProxyConnection{} + delimiter := make([]byte, 1) + var errorReturn error + + // Infinite loop because we don't know the length + for { + proxy, err := unmarshalIndividualProxyStruct(conn) + + if err != nil { + 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 "proxyConnectionResponse", &ProxyConnectionResponse{ + Type: "proxyConnectionResponse", + Proxies: proxies, + }, errorReturn + case GetAllConnectionsRequestID: + return "getAllConnectionsRequest", &GetAllConnectionsRequest{ + Type: "getAllConnectionsRequest", + }, nil } return "", nil, fmt.Errorf("couldn't match command")