Final commit before archive

This commit is contained in:
2020-03-29 18:45:38 +02:00
parent 2166a30aa9
commit 0e2bc4f886
31 changed files with 74 additions and 54 deletions

View File

@@ -0,0 +1,5 @@
from . import mainHandler
from . import serverQueryHandler
from . import handshakeHandler
from . import unknownHandler
from . import queueHandler

View File

@@ -0,0 +1,18 @@
import logging
import struct
from ..network.enums import types as TYPE
from .. import glob
logger = logging.getLogger(__name__)
def handle(client: "Client", data: bytes) -> bytes:
challenge = (client.ip_uint ^ glob.challenge_short) & TYPE.MAX_USHORT
challenge_solution = challenge ^ 0x6969 # 0x6969 being client_version?
challenge_answer = struct.unpack_from(b">H", data, 1)[0]
if challenge_answer != challenge_solution:
return struct.pack(b">BH", 0x1A, challenge)
client.state = 1 # CHALLENGE_PASSED
return b"\x19\x00" # 0x19: Valid_challenge; leading 0x00 byte due to some routers shitting itself if only 1 byte is sent/received

View File

@@ -0,0 +1,31 @@
from importlib import reload
import random
import logging
import struct
from . import handshakeHandler
from . import unknownHandler
from . import queueHandler
from ..helpers.byteFormater import readable_bytes
logger = logging.getLogger(__name__)
HANDLERS = {
0x18: handshakeHandler.handle,
0x00: unknownHandler.handle,
0xe3: queueHandler.handle
}
def handle(client: "Client", data: bytes) -> bytes:
out: bytes = HANDLERS.get(data[0], unimplemented)(client, data)
return out
def unimplemented(client: "Client", data: bytes) -> bytes:
logger.debug("[%s] sent unhandled data: %s" % (client.addr, readable_bytes(data)))
return bytes([x for x in range(1,32,1)])
def restart():
reload(handshakeHandler)

View File

@@ -0,0 +1,53 @@
"""
if client.state == 0: # Perform handshake if possible
client.state = 1
return b"\x1a\x1e\xd1\xd1"
if client.state == 1:
client.state = 2
return b"\x19\x00"
if client.state == 2:
client.state = 3
return b"\xe3\x00\x00", b"\x00\x00\x42\x98\x0c\x11\x33\x45\x30\x42\x33\x33\x35\x32\x37\x34\x46\x39\x31\x43\x39\x39\x00"
if client.state == 3:
client.state = 4
return
if client.state == 4:
client.state = 5
return b"\xe3\x01\x00", b"\x00\x80\x42\x68\x22\xc0\xa8\x02\x87\xfb\xaa\x00\x00\x04\x41\x00\x00"
if client.state <= 7:
client.state += 1
return
if client.state == 8:
client.state = 9
return b"\xe5\x02\x00\x02\x00\x02\x80\x00"
if client.state == 9:
client.state = 10
return b"\x01\x00\x32\x28\x06\xbf\xf9\xca\x0f\x03\x00\x87\x00\x29\x04\x00\x64\x90\x09\xaa\xf9\xca\x0f\xbf\xf9\xca\x0f\x05\x00\x87\x00\x17", b"\x03\x00\x32\x28\x06\xc5\xf9\xca\x0f"
if client.state == 10:
client.state = 11
return b"\x03\x80\x32\x48\x09\xb0\xf9\xca\x0f\xd1\xf9\xca\x0f"
if client.state == 11:
client.state = 12
return b"\xe3\x07\x00"
if client.state == 12:
client.state = 13
return b"\x04\x00\x48\x80\x00\x11\xe0\x14\x3c\xe2\x0e\x2f\x9c\xa0\xf0\x09\x00\x91\x00\x80\x0f\xc1\x00\x14\x8b\xcb\x61\x00\x00\x80\x38\x8d\x00\x00\x8c\x42\x40\x20\x00\x00\x00\x00\x10\x10\x00\x00\x00\xc0\x16\xf1\x20\x33\xc0\x00\x00\x00\x00\xa0\x00\x00\x00\xa0\x00\x00\x00\xa0\x00\x00\x00\x08\x00\x00\x00\x04\x00\x00\x00\x05\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
if client.state == 13:
client.state = 14
return
if client.state == 14:
client.state = 15
return b"\xe3\x0a\x00", b"\x05\x00\x48\x80\x80\x13\xe0\x14\x0c\xe6\x01\xbc\xcf\x44\x40\x8e\x5a\x74\x45\xdf\xe7\x54\x10\x0b\x00\x91\x01\x80\x27\xc0\x14\x9d\xe6\x01\xbc\xcf\x44\x40\x8e\x5a\x74\x45\xdf\xe7\x54\x10\x0c\x00\x91\x02\x00\x28\x40\x14\x9e\xe6\x81\xbc\xcf\x44\x40\x8e\x5a\x74\x45\xdf\xe7\x54\x10\x20\x0d\x00\x82\x6c\x04\x14\x80\xcf\x00\x20\x3f\xe0\x00\x00\x00\x00\x03\x79\x9e\x88\x81\x1c\xb4\xe8\x8b\xbf\xce\xa8\x27\xb2\x50\xc8\x60\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
if client.state == 15:
client.state = 16
return
if client.state == 16:
client.state = 17
return b"\xe3\x0b\x00", b"\x07\x00\x42\x20\x14\x81\xf8\x01"
if client.state == 17:
client.state = 18
return
if client.state == 18:
#client.state = 19
return b"\xe3\x0c\x00", b"\x07\x80\x38\x40\x00\x11\x40\xd0\x00\x00\x00\x00"
"""

View File

@@ -0,0 +1,11 @@
import logging
import struct
from ..network.enums import types as TYPE
from .. import glob
logger = logging.getLogger(__name__)
def handle(client: "Client", data: bytes) -> bytes:
return b""

View File

@@ -0,0 +1,120 @@
import struct
import logging
from .. import glob
from ..helpers import dataHelper
logger = logging.getLogger(__name__)
logger.propagate = False # Disable console logging
def handle(client, data):
ping_ip = ".".join((str(x) for x in struct.unpack(b"<4B", data[4:8])))
ping_port = struct.unpack(b"<H", data[9:11])[0]
logger.debug("[%s] -> Pinging to %s:%d" % (client.addr, ping_ip, ping_port))
if len(data) == 11: # We should add our data ontop
if data[-1:] in RESPONSE:
data += RESPONSE[data[-1:]]()
logger.debug("[%s] <- %s" % (client.addr, data))
return data
def query_i():
len_hostname = len(glob.config["server"]["hostname"])
len_mode = len(glob.config["server"]["mode"])
len_language = len(glob.config["server"]["language"])
packet = struct.pack(b"<?HHI%dsI%dsI%ds" % (len_hostname, len_mode, len_language),
False,
len(get_online_players()),
glob.config["server"]["max_players"],
len_hostname,
glob.config["server"]["hostname"].encode(),
len_mode,
glob.config["server"]["mode"].encode(),
len_language,
glob.config["server"]["language"].encode())
return packet
def query_r():
packet_data = []
rules = get_rules()
packet_data.append(len(rules)) # len_rules
for name, value in rules.items():
packet_data.append([
len(name), name,
len(value), value
])
flat_packet_data = dataHelper.flatten(packet_data)
packet = struct.pack(b"<H" + b"B%dsB%ds" * flat_packet_data[0] # using len_rules
% tuple(len(y) for x in rules.items() for y in x), # tuple of only rules entries
*flat_packet_data)
return packet
def query_c():
packet_data = []
players_scores = get_players_scores()
packet_data.append(len(players_scores))
for name, value in players_scores.items():
packet_data.append([
len(name), name,
value
])
flat_packet_data = dataHelper.flatten(packet_data)
packet = struct.pack(b"<H" + b"B%dsI" * flat_packet_data[0]
% tuple(len(x) for x in players_scores.keys()),
*flat_packet_data)
return packet
def query_d():
packet_data = []
players = get_online_players()
packet_data.append(len(players))
for player in players:
packet_data.append([
player["id"],
len(player["nick"]), player["nick"],
player["score"],
player["ping"]
])
flat_packet_data = dataHelper.flatten(packet_data)
packet = struct.pack(b"<H" + b"cc%dsII" * flat_packet_data[0]
% [len(player["nick"]) for player in players],
*flat_packet_data)
return packet
def get_online_players(): #TODO: Get data from server's client objects
return [
{"nick": b"Sunpy", "score": 64, "ping": 8, "id": 1} # replace id with function to get player's id
]
def get_rules(): #TODO
return {b"Rule name sample": b"Rule value", b"weburl": b"https://git.osufx.com/Sunpy/sampy"}
def get_players_scores(): #TODO
return {b"Sunpy": 64, b"username": 123}
RESPONSE = { #TODO?: p (https://wiki.sa-mp.com/wiki/Query_Mechanism) (We dont really need to do the last handler as it happens somewhat automatically)
b"i": query_i,
b"r": query_r,
b"c": query_c,
b"d": query_d
}

View File

@@ -0,0 +1,16 @@
import struct
index = 0
def handle(client: "Client", data: bytes) -> bytes:
global index
data = LOOKUP[index]
client.send_immediate(data[:3])
index = (index + 1) % 2
return data[3:]
LOOKUP = [
bytes([int(x,16) for x in "e3 00 00 00 00 42 98 0c 11 33 30 45 39 33 39 33 33 36 39 42 35 36 38 43 32 00".split(" ")]),
bytes([int(x,16) for x in "e3 01 00 00 80 42 68 22 c0 a8 02 85 dc f8 01 00 e0 57 00 00".split(" ")])
]