MASTER: Fix Sketch's silly heartbeat mistake

This commit is contained in:
TheLordScruffy 2023-09-18 19:10:03 -04:00
parent 382073e432
commit 2acc87dba2
5 changed files with 116 additions and 46 deletions

View File

@ -91,6 +91,7 @@ func handleRequest(conn net.Conn) {
if err != nil {
if errors.Is(err, io.EOF) {
// Client closed connection, terminate.
logging.Notice("GPCM", "Client closed connection")
return
}
}

View File

@ -2,11 +2,8 @@ package master
import (
"encoding/binary"
"fmt"
"net"
"strconv"
"strings"
"wwfc/common"
"wwfc/logging"
)
@ -24,34 +21,10 @@ func heartbeat(conn net.PacketConn, addr net.Addr, buffer []byte) {
payload[values[i]] = values[i+1]
}
// Generate challenge and send to server
var hexIP string
for _, i := range strings.Split(payload["localip0"], ".") {
val, err := strconv.ParseUint(i, 10, 64)
if err != nil {
panic(err)
}
hexIP += fmt.Sprintf("%02X", val)
publicip, ok := payload["publicip"]
if ok && publicip != "0" {
return
}
port, err := strconv.ParseUint(payload["localport"], 10, 64)
if err != nil {
panic(err)
}
hexPort := fmt.Sprintf("%04X", port)
challenge := common.RandomString(6) + "00" + hexIP + hexPort
mutex.Lock()
session := sessions[sessionId]
session.Challenge = challenge
mutex.Unlock()
response := []byte{0xfe, 0xfd, 0x01}
response = binary.BigEndian.AppendUint32(response, sessionId)
response = append(response, []byte(challenge)...)
response = append(response, 0)
conn.WriteTo(response, addr)
sendChallenge(conn, addr, sessionId)
}

View File

@ -2,9 +2,16 @@ package master
import (
"encoding/binary"
"fmt"
"log"
"net"
"strconv"
"strings"
"sync"
"wwfc/common"
"wwfc/logging"
"github.com/logrusorgru/aurora/v3"
)
var (
@ -13,6 +20,20 @@ var (
mutex = sync.RWMutex{}
)
const (
Command_QUERY = 0x00
Command_CHALLENGE = 0x01
Command_ECHO = 0x02
Command_HEARTBEAT = 0x03
Command_ADDERROR = 0x04
Command_ECHO_RESPONSE = 0x05
Command_CLIENT_MESSAGE = 0x06
Command_CLIENT_MESSAGE_ACK = 0x07
Command_KEEPALIVE = 0x08
Command_AVAILABLE = 0x09
Command_CLIENT_REGISTERED = 0x0A
)
func StartServer() {
conn, err := net.ListenPacket("udp", ":27900")
if err != nil {
@ -38,20 +59,94 @@ func handleConnection(conn net.PacketConn, addr net.Addr, buffer []byte) {
}
switch buffer[0] {
case 1:
// Challenge
sessionId := binary.BigEndian.Uint32(buffer[1:5])
response := []byte{0xfe, 0xfd, 0x0a}
response = binary.BigEndian.AppendUint32(response, sessionId)
conn.WriteTo(response, addr)
case Command_QUERY:
logging.Notice("MASTER", "Command:", aurora.Yellow("QUERY").String())
break
case 3:
case Command_CHALLENGE:
logging.Notice("MASTER", "Command:", aurora.Yellow("CHALLENGE").String())
// sessionId := binary.BigEndian.Uint32(buffer[1:5])
// conn.WriteTo(createResponseHeader(Command_CLIENT_REGISTERED, sessionId), addr)
break
case Command_ECHO:
logging.Notice("MASTER", "Command:", aurora.Yellow("ECHO").String())
break
case Command_HEARTBEAT:
logging.Notice("MASTER", "Command:", aurora.Yellow("HEARTBEAT").String())
heartbeat(conn, addr, buffer)
break
case 9:
conn.WriteTo([]byte{0xfe, 0xfd, 0x09, 0x00, 0x00, 0x00, 0x00}, addr)
case Command_ADDERROR:
logging.Notice("MASTER", "Command:", aurora.Yellow("ADDERROR").String())
break
case Command_ECHO_RESPONSE:
logging.Notice("MASTER", "Command:", aurora.Yellow("ECHO_RESPONSE").String())
break
case Command_CLIENT_MESSAGE:
logging.Notice("MASTER", "Command:", aurora.Yellow("CLIENT_MESSAGE").String())
return
case Command_CLIENT_MESSAGE_ACK:
logging.Notice("MASTER", "Command:", aurora.Yellow("CLIENT_MESSAGE_ACK").String())
return
case Command_KEEPALIVE:
logging.Notice("MASTER", "Command:", aurora.Yellow("KEEPALIVE").String())
return
case Command_AVAILABLE:
logging.Notice("MASTER", "Command:", aurora.Yellow("AVAILABLE").String())
conn.WriteTo(createResponseHeader(Command_AVAILABLE, 0), addr)
break
case Command_CLIENT_REGISTERED:
logging.Notice("MASTER", "Command:", aurora.Yellow("QUERY").String())
break
default:
logging.Notice("MASTER", "Unknown command:", aurora.Yellow(buffer[0]).String())
return
}
}
func createResponseHeader(command byte, sessionId uint32) []byte {
return binary.BigEndian.AppendUint32([]byte{0xfe, 0xfd, command}, sessionId)
}
func sendChallenge(conn net.PacketConn, addr net.Addr, sessionId uint32) {
addrString := strings.Split(addr.String(), ":")
// Generate challenge and send to server
var hexIP string
for _, i := range strings.Split(addrString[0], ".") {
val, err := strconv.ParseUint(i, 10, 64)
if err != nil {
panic(err)
}
hexIP += fmt.Sprintf("%02X", val)
}
port, err := strconv.ParseUint(addrString[1], 10, 64)
if err != nil {
panic(err)
}
hexPort := fmt.Sprintf("%04X", port)
challenge := common.RandomString(6) + "00" + hexIP + hexPort
mutex.Lock()
session := sessions[sessionId]
session.Challenge = challenge
mutex.Unlock()
response := createResponseHeader(Command_CHALLENGE, sessionId)
response = append(response, []byte(challenge)...)
response = append(response, 0)
conn.WriteTo(response, addr)
}

View File

@ -5,7 +5,6 @@ import (
"context"
"errors"
"fmt"
"github.com/jackc/pgx/v4/pgxpool"
"io"
"log"
"net"
@ -13,6 +12,9 @@ import (
"time"
"wwfc/common"
"wwfc/logging"
"github.com/jackc/pgx/v4/pgxpool"
"github.com/logrusorgru/aurora/v3"
)
var (
@ -92,11 +94,14 @@ func handleRequest(conn net.Conn) {
}
}
logging.Notice(ModuleName, "Help me please")
switch buffer[2] {
case ServerList:
serverList(conn, buffer)
break
default:
logging.Notice(ModuleName, "Command:", aurora.Yellow(buffer[2]).String())
break
}
}
}

View File

@ -11,10 +11,6 @@ import (
func serverList(conn net.Conn, buffer []byte) {
logging.Notice(ModuleName, "Received server list command")
// TODO: Make a custom decoder for this? Go's binary decoder does not support strings as they are not a fixed width.
//listVersion := buffer[3]
//encodingVersion := buffer[4]
//gameVersion := binary.BigEndian.Uint32(buffer[5:])
index := 9
queryGame := common.GetString(buffer[index:])