diff --git a/protocol.py b/protocol.py index ad46c21..fbaa699 100644 --- a/protocol.py +++ b/protocol.py @@ -5,8 +5,6 @@ class MasterProtocol: # Server To Master challengeRequest = 'q' - addServer = '0' - removeServer = 'b' # Master To Client queryPacketHeader = b'\xff\xff\xff\xff\x66\x0a' diff --git a/pymaster.py b/pymaster.py index 1666ded..fd4539d 100755 --- a/pymaster.py +++ b/pymaster.py @@ -39,10 +39,6 @@ class PyMaster: self.client_query(data, addr) case MasterProtocol.challengeRequest: self.send_challenge_to_server(data, addr) - case MasterProtocol.addServer: - self.add_server_to_list(data, addr) - case MasterProtocol.removeServer: - self.remove_server_from_list(data, addr) case other: logging.debug("Unknown message: {0} from {1}:{2}".format(data, addr[0], addr[1])) @@ -89,85 +85,25 @@ class PyMaster: except IndexError: pass - if clver is None: # Probably an old vulnerable version - self.fake_info_for_old_versions(gamedir, addr) - return - packet = MasterProtocol.queryPacketHeader if key != None: # Required in latest Xash3D version packet += b'\x7F' + pack(' i.die: - logging.debug("Server removed by timeout") - self.serverList.remove(i) - continue - - if not i.check: - logging.debug("Invalid request") - continue - - if nat != i.nat: - logging.debug("NAT {0} mismatch {1}".format(i.nat, nat)) - continue - - if gamedir is not None and gamedir != i.gamedir: - logging.debug("Game dir {0} mismatch node settings: {1}".format(i.gamedir, gamedir)) - continue - - if nat: - reply = "\xff\xff\xff\xffc {0}:{1}".format(addr[0], addr[1]) - data = reply.encode("latin_1") - # Tell server to send info reply - self.sock.sendto(data, i.addr) # Use pregenerated address string packet += i.queryAddr packet += b"\0\0\0\0\0\0" # Fill last IP:Port with \0 - self.sock.sendto(packet, addr) - - - def _send_fake_info(sock, warnmsg, gamedir, addr): - baseReply = ( - b"\xff\xff\xff\xffinfo\n\host\\" - + warnmsg.encode("utf-8") - + b"\map\\update\dm\\0\\team\\0\coop\\0\\numcl\\32\maxcl\\32\\gamedir\\" - + gamedir.encode("latin-1") - + b"\\" - ) - sock.sendto(baseReply, addr) - - - def fake_info_for_old_versions(self, gamedir, addr): - error_message = [ - "This version is not", - "supported anymore", - "Please update Xash3DFWGS", - "From GooglePlay or GitHub", - "Эта версия", - "устарела", - "Обновите Xash3DFWGS c", - "GooglePlay или GitHub", - ] - - for string in error_message: - _send_fake_info(self.sock, string, gamedir, addr) + self.sock.sendto(packet, addr) - def remove_server_from_list(self, data, addr): - for server in self.serverList: - if server.addr == addr: - logging.debug("Remove Server: from {0}:{1}".format(addr[0], addr[1])) - self.serverList.remove(server) + def send_challenge_to_server(self, data, addr): + logging.debug("Challenge Request: {0}:{1}".format(addr[0], addr[1])) - def send_challenge_to_server(self, data, addr): - logging.debug("Challenge Request: from {0}:{1}".format(addr[0], addr[1])) # At first, remove old server- data from list - # self.removeServerFromList(None, addr) - count = 0 for i in self.serverList: if i.addr[0] == addr[0]: @@ -179,10 +115,12 @@ class PyMaster: logging.debug("Reached MAX_SERVERS_FOR_IP: {0}".format(MAX_SERVERS_FOR_IP)) return + # Add server + logging.debug("Add Server: {0}:{1}".format(addr[0], addr[1])) + challenge = random.randint(0, 2**32 - 1) # Add server to list - logging.debug("Added new server {0}:{1} with challenge {2}".format(addr[0], addr[1], challenge)) self.serverList.append(ServerEntry(addr, challenge)) # And send him a challenge @@ -190,21 +128,6 @@ class PyMaster: packet += pack("I", challenge) self.sock.sendto(packet, addr) - - def add_server_to_list(self, data, addr): - logging.debug("Add Server: from {0}:{1}".format(addr[0], addr[1])) - # Remove the header. Just for better parsing. - serverInfo = data.strip("\x30\x0a\x5c") - - # Find a server with same address - for serverEntry in self.serverList: - if serverEntry.addr == addr: - logging.debug("Skipped same server address: {0}:{1}".format(addr[0], addr[1])) - break - - serverEntry.setInfoString(serverInfo) - - def spawn_pymaster(verbose, ip, port): if verbose: logging.getLogger().addHandler(logging.StreamHandler()) diff --git a/server_entry.py b/server_entry.py index 51b2b2a..5260ef0 100644 --- a/server_entry.py +++ b/server_entry.py @@ -4,85 +4,26 @@ from struct import pack import ipaddress class ServerEntry: - challenge2 = 0 - gamedir = 'valve' - protocol = 0 - players = 0 - maxplayers = 0 - bots = 0 - gamemap = '' - version = '0' - servtype = 'd' - password = 0 - os = 'l' - secure = 0 - lan = 0 - region = 255 - product = '' - nat = 0 - key = None - def setInfoString(self, data): - infostring = data.replace('\n', '').replace('\r', '').replace('\0', '') - split = infostring.split('\\') - for i in range(0, len(split), 2): - try: - value = split[i + 1] - if( split[i] == 'challenge' ): - self.challenge2 = int(value) - elif( split[i] == 'gamedir' ): - self.gamedir = value.lower() # keep gamedir lowercase - elif( split[i] == 'protocol' ): - self.protocol = int(value) - elif( split[i] == 'players' ): - self.players = int(value) - elif( split[i] == 'max' ): - self.maxplayers = int(value.split('.')[0]) - elif( split[i] == 'bots' ): - self.bots = int(value) - elif( split[i] == 'map' ): - self.gamemap = value - elif( split[i] == 'version' ): - self.version = value - elif( split[i] == 'type' ): - self.servtype = value - elif( split[i] == 'password' ): - self.password = value - elif( split[i] == 'os' ): - self.os = value - elif( split[i] == 'secure' ): - self.secure = value - elif( split[i] == 'lan' ): - self.lan = value - elif( split[i] == 'region' ): - self.region = value - elif( split[i] == 'product' ): - self.product = value - elif( split[i] == 'nat' ): - self.nat = int(value) - elif split[i] == 'key': - self.key = int(value, 16) - except IndexError: - pass - self.check = self.challenge == self.challenge2 - return self.check + def __init__(self, addr, challenge): - def __init__(self, addr, challenge): - # Address - self.addr = addr - # Shortcuts for generating query - self.queryAddr = b'' - self.queryAddr += ipaddress.ip_address(addr[0]).packed - self.queryAddr += pack('!H', int(addr[1])) + # Address + self.addr = addr + # Shortcuts for generating query + self.queryAddr = b'' - # Random number that server must return - self.challenge = challenge - self.sentChallengeAt = time() + if ':' in addr[0]: + self.queryAddr += ipaddress.ip_address(addr[0]).packed + else: + for i in addr[0].split('.'): + self.queryAddr += pack('!B', int(i)) - # This server is not checked - # So it will not get into queries - self.check = False + self.queryAddr += pack('!H', int(addr[1])) - # Remove server after this time. - # This maybe not instant - self.die = self.sentChallengeAt + 600 + # Random number that server must return + self.challenge = challenge + self.sentChallengeAt = time() + + # Remove server after this time. + # This maybe not instant + self.die = self.sentChallengeAt + 600 \ No newline at end of file