Skip to content

Commit

Permalink
chore: Adds basic commands and protocol.
Browse files Browse the repository at this point in the history
  • Loading branch information
imterah committed Dec 2, 2024
1 parent 7b5ec36 commit 28d25c9
Show file tree
Hide file tree
Showing 9 changed files with 1,421 additions and 0 deletions.
18 changes: 18 additions & 0 deletions api/gosrc/backendlauncher/backendlauncher.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package backendlauncher

import (
"fmt"
"math/rand/v2"
"net"
)

func GetUnixSocket(folder string) (string, net.Listener, error) {
socketPath := fmt.Sprintf("%s/sock-%d.sock", folder, rand.Uint())
listener, err := net.Listen("unix", socketPath)

if err != nil {
return "", nil, err
}

return socketPath, listener, nil
}
1 change: 1 addition & 0 deletions api/gosrc/backendparser/backendparser.go
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
package backendparser
83 changes: 83 additions & 0 deletions api/gosrc/commonbackend/constants.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package commonbackend

type StartCommand struct {
Type string // Will be 'start' always
Arguments []byte
}

type StopCommand struct {
Type string // Will be 'stop' always
}

type AddConnectionCommand struct {
Type string // Will be 'addConnection' always
SourceIP string
SourcePort uint16
DestPort uint16
Protocol string // Will be either 'tcp' or 'udp'
}

type RemoveConnectionCommand struct {
Type string // Will be 'removeConnection' always
SourceIP string
SourcePort uint16
DestPort uint16
Protocol string // Will be either 'tcp' or 'udp'
}

type ClientConnection struct {
SourceIP string
SourcePort uint16
DestPort uint16
ClientIP string
ClientPort uint16
}

type GetAllConnections struct {
Type string // Will be 'getAllConnections' always
Connections []*ClientConnection // List of connections
}

type CheckClientParameters struct {
Type string // Will be 'checkClientParameters' always
SourceIP string
SourcePort uint16
DestPort uint16
Protocol string // Will be either 'tcp' or 'udp'
}

type CheckServerParameters struct {
Type string // Will be 'checkServerParameters' always
Arguments []byte
}

// Sent as a response to either CheckClientParameters or CheckBackendParameters
type CheckParametersResponse struct {
Type string // Will be 'checkParametersResponse' always
InReplyTo string // Will be either 'checkClientParameters' or 'checkServerParameters'
IsValid bool // If true, valid, and if false, invalid
Message string // String message from the client (ex. failed to unmarshal JSON: x is not defined)
}

const (
StartCommandID = iota
StopCommandID
AddConnectionCommandID
RemoveConnectionCommandID
ClientConnectionID
GetAllConnectionsID
CheckClientParametersID
CheckServerParametersID
CheckParametersResponseID
)

const (
TCP = iota
UDP

IPv4 = 4
IPv6 = 6

IPv4Size = 4
IPv6Size = 16
)
279 changes: 279 additions & 0 deletions api/gosrc/commonbackend/marshal.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,279 @@
package commonbackend

import (
"encoding/binary"
"fmt"
"net"
)

func marshalIndividualConnectionStruct(conn *ClientConnection) []byte {
sourceIPOriginal := net.ParseIP(conn.SourceIP)
clientIPOriginal := net.ParseIP(conn.ClientIP)

var serverIPVer uint8
var sourceIP []byte

if sourceIPOriginal.To4() == nil {
serverIPVer = IPv6
sourceIP = sourceIPOriginal.To16()
} else {
serverIPVer = IPv4
sourceIP = sourceIPOriginal.To4()
}

var clientIPVer uint8
var clientIP []byte

if clientIPOriginal.To4() == nil {
clientIPVer = IPv6
clientIP = clientIPOriginal.To16()
} else {
clientIPVer = IPv4
clientIP = clientIPOriginal.To4()
}

connectionBlock := make([]byte, 8+len(sourceIP)+len(clientIP))

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)

connectionBlock[5+len(sourceIP)] = clientIPVer
copy(connectionBlock[6+len(sourceIP):6+len(sourceIP)+len(clientIP)], clientIP)
binary.BigEndian.PutUint16(connectionBlock[6+len(sourceIP)+len(clientIP):8+len(sourceIP)+len(clientIP)], conn.ClientPort)

return connectionBlock
}

func Marshal(commandType string, command interface{}) ([]byte, error) {
switch commandType {
case "start":
startCommand, ok := command.(*StartCommand)

if !ok {
return nil, fmt.Errorf("failed to typecast")
}

startCommandBytes := make([]byte, 1+2+len(startCommand.Arguments))
startCommandBytes[0] = StartCommandID
binary.BigEndian.PutUint16(startCommandBytes[1:3], uint16(len(startCommand.Arguments)))
copy(startCommandBytes[3:], startCommand.Arguments)

return startCommandBytes, nil
case "stop":
_, ok := command.(*StopCommand)

if !ok {
return nil, fmt.Errorf("failed to typecast")
}

stopCommandBytes := make([]byte, 1)
stopCommandBytes[0] = StopCommandID

return stopCommandBytes, nil
case "addConnection":
addConnectionCommand, ok := command.(*AddConnectionCommand)

if !ok {
return nil, fmt.Errorf("failed to typecast")
}

sourceIP := net.ParseIP(addConnectionCommand.SourceIP)

var ipVer uint8
var ipBytes []byte

if sourceIP.To4() == nil {
ipBytes = sourceIP.To16()
ipVer = IPv6
} else {
ipBytes = sourceIP.To4()
ipVer = IPv4
}

addConnectionBytes := make([]byte, 1+1+len(ipBytes)+2+2+1)

addConnectionBytes[0] = AddConnectionCommandID
addConnectionBytes[1] = ipVer

copy(addConnectionBytes[2:2+len(ipBytes)], ipBytes)

binary.BigEndian.PutUint16(addConnectionBytes[2+len(ipBytes):4+len(ipBytes)], addConnectionCommand.SourcePort)
binary.BigEndian.PutUint16(addConnectionBytes[4+len(ipBytes):6+len(ipBytes)], addConnectionCommand.DestPort)

var protocol uint8

if addConnectionCommand.Protocol == "tcp" {
protocol = TCP
} else if addConnectionCommand.Protocol == "udp" {
protocol = UDP
} else {
return nil, fmt.Errorf("invalid protocol")
}

addConnectionBytes[6+len(ipBytes)] = protocol

return addConnectionBytes, nil
case "removeConnection":
removeConnectionCommand, ok := command.(*RemoveConnectionCommand)

if !ok {
return nil, fmt.Errorf("failed to typecast")
}

sourceIP := net.ParseIP(removeConnectionCommand.SourceIP)

var ipVer uint8
var ipBytes []byte

if sourceIP.To4() == nil {
ipBytes = sourceIP.To16()
ipVer = IPv6
} else {
ipBytes = sourceIP.To4()
ipVer = IPv4
}

removeConnectionBytes := make([]byte, 1+1+len(ipBytes)+2+2+1)

removeConnectionBytes[0] = RemoveConnectionCommandID
removeConnectionBytes[1] = ipVer
copy(removeConnectionBytes[2:2+len(ipBytes)], ipBytes)
binary.BigEndian.PutUint16(removeConnectionBytes[2+len(ipBytes):4+len(ipBytes)], removeConnectionCommand.SourcePort)
binary.BigEndian.PutUint16(removeConnectionBytes[4+len(ipBytes):6+len(ipBytes)], removeConnectionCommand.DestPort)

var protocol uint8

if removeConnectionCommand.Protocol == "tcp" {
protocol = TCP
} else if removeConnectionCommand.Protocol == "udp" {
protocol = UDP
} else {
return nil, fmt.Errorf("invalid protocol")
}

removeConnectionBytes[6+len(ipBytes)] = protocol

return removeConnectionBytes, nil
case "getAllConnections":
allConnectionsCommand, ok := command.(*GetAllConnections)

if !ok {
return nil, fmt.Errorf("failed to typecast")
}

connectionsArray := make([][]byte, len(allConnectionsCommand.Connections))
totalSize := 0

for connIndex, conn := range allConnectionsCommand.Connections {
connectionsArray[connIndex] = marshalIndividualConnectionStruct(conn)
totalSize += len(connectionsArray[connIndex]) + 1
}

connectionCommandArray := make([]byte, totalSize+1)
connectionCommandArray[0] = GetAllConnectionsID

currentPosition := 1

for _, connection := range connectionsArray {
copy(connectionCommandArray[currentPosition:currentPosition+len(connection)], connection)
connectionCommandArray[currentPosition+len(connection)] = '\r'
currentPosition += len(connection) + 1
}

connectionCommandArray[totalSize] = '\n'
return connectionCommandArray, nil
case "checkClientParameters":
checkClientCommand, ok := command.(*CheckClientParameters)

if !ok {
return nil, fmt.Errorf("failed to typecast")
}

sourceIP := net.ParseIP(checkClientCommand.SourceIP)

var ipVer uint8
var ipBytes []byte

if sourceIP.To4() == nil {
ipBytes = sourceIP.To16()
ipVer = IPv6
} else {
ipBytes = sourceIP.To4()
ipVer = IPv4
}

checkClientBytes := make([]byte, 1+1+len(ipBytes)+2+2+1)

checkClientBytes[0] = CheckClientParametersID
checkClientBytes[1] = ipVer
copy(checkClientBytes[2:2+len(ipBytes)], ipBytes)
binary.BigEndian.PutUint16(checkClientBytes[2+len(ipBytes):4+len(ipBytes)], checkClientCommand.SourcePort)
binary.BigEndian.PutUint16(checkClientBytes[4+len(ipBytes):6+len(ipBytes)], checkClientCommand.DestPort)

var protocol uint8

if checkClientCommand.Protocol == "tcp" {
protocol = TCP
} else if checkClientCommand.Protocol == "udp" {
protocol = UDP
} else {
return nil, fmt.Errorf("invalid protocol")
}

checkClientBytes[6+len(ipBytes)] = protocol

return checkClientBytes, nil
case "checkServerParameters":
checkServerCommand, ok := command.(*CheckServerParameters)

if !ok {
return nil, fmt.Errorf("failed to typecast")
}

serverCommandBytes := make([]byte, 1+2+len(checkServerCommand.Arguments))
serverCommandBytes[0] = CheckServerParametersID
binary.BigEndian.PutUint16(serverCommandBytes[1:3], uint16(len(checkServerCommand.Arguments)))
copy(serverCommandBytes[3:], checkServerCommand.Arguments)

return serverCommandBytes, nil
case "checkParametersResponse":
checkParametersCommand, ok := command.(*CheckParametersResponse)

if !ok {
return nil, fmt.Errorf("failed to typecast")
}

var checkMethod uint8

if checkParametersCommand.InReplyTo == "checkClientParameters" {
checkMethod = CheckClientParametersID
} else if checkParametersCommand.InReplyTo == "checkServerParameters" {
checkMethod = CheckServerParametersID
} else {
return nil, fmt.Errorf("invalid mode recieved (must be either checkClientParameters or checkServerParameters)")
}

var isValid uint8

if checkParametersCommand.IsValid {
isValid = 1
}

checkResponseBytes := make([]byte, 3+2+len(checkParametersCommand.Message))
checkResponseBytes[0] = CheckParametersResponseID
checkResponseBytes[1] = checkMethod
checkResponseBytes[2] = isValid

binary.BigEndian.PutUint16(checkResponseBytes[3:5], uint16(len(checkParametersCommand.Message)))

if len(checkParametersCommand.Message) != 0 {
copy(checkResponseBytes[5:], []byte(checkParametersCommand.Message))
}

return checkResponseBytes, nil
}

return nil, fmt.Errorf("couldn't match command")
}
Loading

0 comments on commit 28d25c9

Please sign in to comment.