Preparement for rcon support

This commit is contained in:
Emily 2020-03-29 23:43:08 +02:00
parent c1ad95d233
commit f55275a627
4 changed files with 26 additions and 15 deletions

View File

@ -14,6 +14,7 @@
"port": 7777, "port": 7777,
"hostname": "Python > C", "hostname": "Python > C",
"password": "", "password": "",
"rcon_password": "changeme",
"max_players": 50, "max_players": 50,
"mode": "debug", "mode": "debug",
"language": "python" "language": "python"

View File

@ -16,24 +16,14 @@ class QueryClient(BaseClient):
b"i": self.query_i, b"i": self.query_i,
b"r": self.query_r, b"r": self.query_r,
b"c": self.query_c, b"c": self.query_c,
b"d": self.query_d b"d": self.query_d,
b"p": self.query_p,
b"x": self.query_x
} }
async def on_packet(self, packet: bytes): async def on_packet(self, packet: bytes):
logger.debug("on_packet(%s)" % packet) logger.debug("on_packet(%s)" % packet)
"""
if len(packet) != 11: # Just a ping with some random numbers at the end (14 bytes in total)
await self.send(packet)
return
"""
# ip ~~and port~~ the client connected to; (would be server ip ~~and port~~ if not though proxy)
# This could be used to check if client connected remotely in some way though a proxy
# SA:MP default server drops the connection if port does not match (when its client (not query protocol))
#server_ip = ".".join((str(x) for x in struct.unpack(b"<4B", packet[4:8])))
#server_port, = struct.unpack(b"<H", packet[8:10]) # This is not port, the wiki is wrong: https://wiki.sa-mp.com/wiki/Query
#logger.debug("[%s:%d] via %s:%d" % (self.ip, self.port, server_ip, server_port))
if len(packet) <= 10: # Invalid if len(packet) <= 10: # Invalid
return return
@ -110,3 +100,19 @@ class QueryClient(BaseClient):
async def query_p(self, packet: bytes) -> bytes: async def query_p(self, packet: bytes) -> bytes:
return packet return packet
async def query_x(self, packet: bytes) -> bytes:
len_pswd, = struct.unpack_from(b"<H", packet, 11)
pswd, len_cmd = struct.unpack_from(b"<%dsH" % len_pswd, packet, 13)
cmd = struct.unpack_from(b"<%ds" % len_cmd, packet, 15 + len_pswd)
if len(self.server.config.rcon_password) == 0:
msg = b"Remote Console is not enabled on this server."
elif self.server.config.rcon_password.encode() != pswd:
msg = b"Invalid RCON password."
logger.warning("BAD RCON ATTEMPT BY: %s:%d" % (self.ip, self.port))
else:
# TODO: Add rcon client to command stdouts
return b"" # No response as all is ok
return packet[:11] + struct.pack(b"<H%ds" % len(msg), len(msg), msg)

View File

@ -22,6 +22,7 @@ class Server:
async def on_command(self, cmd: str): async def on_command(self, cmd: str):
logger.debug("on_command(%s)" % cmd) logger.debug("on_command(%s)" % cmd)
# TODO: When commands return a reponse we also want to forward this to potential rcon clients
async def get_online_players(self): # TODO: Get data from server's client objects async def get_online_players(self): # TODO: Get data from server's client objects
return [ return [

View File

@ -4,6 +4,7 @@ class ServerConfig:
def __init__(self, def __init__(self,
host: str, port: int, host: str, port: int,
hostname: str, password: str, hostname: str, password: str,
rcon_password: str,
max_players: int, max_players: int,
mode: str, language: str): mode: str, language: str):
self.host = host self.host = host
@ -12,6 +13,8 @@ class ServerConfig:
self.hostname = hostname self.hostname = hostname
self.password = password self.password = password
self.rcon_password = rcon_password
self.max_players = max_players self.max_players = max_players
self.mode = mode self.mode = mode