First blood

This commit is contained in:
a1batross 2016-01-20 00:32:16 +03:00
parent 138776d0db
commit d3bcda6268
3 changed files with 148 additions and 0 deletions

116
pymaster.py Normal file
View File

@ -0,0 +1,116 @@
import socket
import random
import struct
import sys
from server_entry import ServerEntry
from util import getAttrOrNone
UDP_IP = "127.0.0.1"
UDP_PORT = 27010
sock = []
def logPrint( msg ):
if DEBUG:
print( msg )
class PyMaster:
self.serverList = []
self.sock = []
def __init__(self):
sock = socket.socket( socket.AF_INET, socket.SOCK_DGRAM )
sock.bind( (UDP_IP, UDP_PORT) )
logprint("Welcome to PyMaster!")
logprint("I ask you again, are you my master?")
logprint("Running on %s:%i" % UDP_IP, UDP_PORT)
def serverLoop(self)
data, addr = sock.recvfrom(1024)4
logprint("received message: %s" % data)
if data[0] == '1':
self.clientQuery(data, addr);
elif data[0] == 'q'
self.sendChallengeToServer(data, addr);
elif data[0] == '0'
self.addServerToList(data, addr);
elif data[0] == 'b'
self.removeServerFromList(data, addr);
else
logprint("Unknown message: %s from %s" % data, addr)
def clientQuery(self, data, addr):
data = data.strip('1')
region = data[0]
queryAddr, rawFilter = data.split('\0')
rawFilter = rawFilter.split('\\')
queryFilter = namedtuple('QueryFilter', rawFilter[0::2])._make(rawFilter[1::2])
#nor = getAttrOrNone(queryFilter, 'nor')
#nand = getAttrOrNone(queryFilter, 'nand')
#dedicated = getAttrOrNone(queryFilter, 'dedicated')
#gamedir = getAttrOrNone(queryFilter, 'gamedir')
#gamemap = getAttrOrNone(queryFilter, 'map')
#linux = getAttrOrNone(queryFilter, 'linux')
#empty = getAttrOrNone(queryFilter, 'empty')
#full = getAttrOrNone(queryFilter, 'full')
#proxy = getAttrOrNone(queryFilter, 'proxy')
#noplayers = getAttrOrNone(queryFilter, 'noplayers')
#white = getAttrOrNone(queryFilter, 'white')
#name = getAttrOrNone(queryFilter, 'name')
#version = getAttrOrNone(queryFilter, 'version_match')
#gameaddr = getAttrOrNone(queryFilter, 'gameaddr')
secure = getAttrOrNone(queryFilter, 'secure')
packet = '\xff\xff\xff\xff\x66\x0a'
for i in self.serverList:
if( !i.check ):
continue
if( gamedir != None ):
if( gamedir != i.serverInfo.gamedir):
continue
# Use pregenerated address string
packet += self.queryAddr
def sendChallengeToServer(self, data, addr):
# Generate a 32 bit challenge number
challenge = random.randint(0, 2**32-1)
# Add server to list
self.serverList.append(ServerEntry(addr, challenge))
# And send him a challenge
packet = '\xff\xff\xff\xff\x73\x0a'
packet += struct.pack('I', challenge)
socket.sendto(packet, addr)
def addServerToList(self, data, addr):
# Remove the header
serverInfo = data.strip('\x30\x0a\x5c')
# Find a server with
for serverEntry in self.serverList:
if (serverEntry.addr == addr):
serverEntry.setInfoString(serverInfo)
def removeServerFromList(self, data, addr):
for i in self.serverList:
if (i.addr == addr):
self.serverList.remove(i)
def main( argv = None ):
if argv is None:
argv = sys.argv
masterMain = PyMaster()
while True:
masterMain.serverLoop()
if __name__ == "__main__":
sys.exit( main( ) )

30
server_entry.py Normal file
View File

@ -0,0 +1,30 @@
from collections import namedtuple
from time import time
class ServerEntry:
def setInfoString(self, data):
infostring = data.translate(None, '\n\r\0')
split = infostring.split('\\')
self.serverInfo = namedtuple('ServerInfo', split[0::2])._make(split[1::2])
self.check = int(self.serverInfo.challenge) == self.challenge
def __init__(self, addr, challenge):
# Address
self.addr = addr
# Shortcuts for generating query
self.queryAddr = ""
for i in addr[0].split('.'):
self.queryAddr += struct.pack('B', int(i))
self.queryAddr += struct.pack('H', addr[1])
# Random number that server must return
self.challenge = challenge
# This server is not checked
# So it will not get into queries
self.check = False
# Remove server after this time.
# This maybe not instant
self.die = time() + 600.0

2
util.py Normal file
View File

@ -0,0 +1,2 @@
def getAttrOrNone(obj, prop):
return getattr(obj, prop, None)