Skip to content

Instantly share code, notes, and snippets.

@alienelephant
Forked from mdhowle/realmserver.py
Last active November 27, 2015 09:01
Show Gist options
  • Save alienelephant/25c6c45a034f5d5eb09b to your computer and use it in GitHub Desktop.
Save alienelephant/25c6c45a034f5d5eb09b to your computer and use it in GitHub Desktop.
#!/usr/bin/python
'''
code forked from https://gist.github.com/mdhowle/4212b0116edfab37c545
'''
from sys import stdout
from twisted.python.log import startLogging
from twisted.internet import reactor
from twisted.internet.protocol import Factory, Protocol
import struct
# might be helpful later
class ServerConfig:
def __init__(self, server_name, server_ip, server_port, server_online_users=9999, server_status="up"):
# these are sane max length values for the fields. this should be changed to actual validation code
SERVER_NAME_MAX = 23
SERVER_IP_MAX = 15
SERVER_PORT_MAX = 5
SERVER_STAT_MAX = 4
SERVER_ONLINE_MAX = 4
self.server_name = server_name[:self.SERVER_NAME_MAX]
self.server_name_len = struct.pack('B', len(self.server_name))
self.server_ip = server_ip[:self.SERVER_IP_MAX]
self.server_ip_len = struct.pack('B', len(server_ip))
self.server_port = server_port[:self.SERVER_PORT_MAX]
self.server_port_len = struct.pack('B', len(server_port))
self.server_online_user = server_online_user[:SERVER_ONLINE_MAX]
self.server_online_users_len = struct.pack('B', len(server_online_users))
self.server_status = server_status[:self.SERVER_STAT_MAX]
self.server_status_len = struct.pack('B', len(server_status))
# unlikely to be using this anytime soon
class PatchServer(Protocol): # listens on port 6005
def connectionMade(self):
print 'PATCH: Client connected: %s' % self.transport.getPeer()
def connectionLost(self, reason):
print "PATCH: Client disconnected: %s" % self.transport.getPeer()
def dataReceived(self, data):
if data.startswith("\x04"):
self.transport.write('\x18\x00\x00\x00')
self.transport.write('\x19\x00\x00\x00')
self.transport.write('\x00\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')
elif data.startswith('\x08'):
self.transport.write('\x18\x00\x00\x00\x19\x00\x00\x00')
self.transport.write('\x00\x00\x00\x00\x00\x00\x00\x00\x08\x00\x00\x00\x60\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')
elif data.startswith('\x0c'): # start sending patches ?
pass
else:
print data.encode('hex')
# router server generally works well
class RouteServer(Protocol): # listens on port 7002
def connectionMade(self):
print "ROUTE: Client connected: %s" % self.transport.getPeer()
def connectionLost(self, reason):
print "ROUTE: Client disconnected: %s" % self.transport.getPeer()
##
# added some easy to config vars
def dataReceived(self, data):
server_version = '64'
#server_version = '52'
if data.startswith("\x14"): # patch server requested
self.transport.write('\x2c\x00\x00\x00')
self.transport.write('\x19\x00\x00\x00')
#self.transport.write('\x00\x00\x00\x00\x00\x00\x00\x00\x64\x00\x00\x00\x00\x00\x00\x00\x0d\x0050.247.16.101\x04\x006005\x00\x00\x02\x0046\x0d')
self.transport.write('\x00\x00\x00\x00\x00\x00\x00\x00\x64\x00\x00\x00\x00\x00\x00\x00\x0d\x0050.247.16.101\x04\x006005\x00\x00\x02\x00\x35\x38\x0d')
elif data.startswith("\x10"): # ROUTE server requested
head_data = '\x00\x00\x00\x19\x00\x00\x00' # not sure what this does, or what 0x19 is
head_data_2 = '\x00\x00\x00\x00\x00\x00\x00\x00\x64\x00\x00\x00\x00\x00\x00\x00' # not sure what this does, x64 seems to be the server version
end_data = '\x00\x00\x00\x00\x00\x00' # might be padding?
server_name_max = 23
server_name = "Private Realm Server" # this has a max length of 23
server_name_len = struct.pack('B', len(server_name[:server_name_max]))
server_ip = "192.168.1.100"
server_ip_len = struct.pack('B', len(server_ip))
server_port = "8001"
server_port_len = struct.pack('B', len(server_port))
server_online_users = "5555" # max of 4 (let's be realistic)
server_online_users_len = struct.pack('B', len(server_online_users[:4]))
server_status = "down"
server_status_len = struct.pack('B', len(server_status[:4]))
# create most of the packet
packet = head_data_2 \
+ '\x02' + server_name_len + '\x00' + server_name[:server_name_max] \
+ server_status_len + '\x00' + server_status \
+ server_online_users_len + '\x00' + server_online_users \
+ server_ip_len + '\x00' + server_ip \
+ server_port_len + '\x00' + server_port \
+ end_data
# complete packet creation
data_length = struct.pack('B', len(packet))
packet = data_length + head_data + packet
# finally write the packet
self.transport.write(packet)
'''
orig for ref
self.transport.write('\x00\x00\x00\x00\x00\x00\x00\x00\x64\x00\x00\x00\x00\x00\x00\x00'
'\x02\x10\x00Matthew\'s Realm\x02\x00up\x04\x009999\x0d\x0050.247.16.101\x04\x008001'
'\x10\x00The Mists - Test\x02\x00up\x01\x000\x0d\x0050.247.16.101\x04\x008000'
'\x00\x00\x00\x00\x00\x00')
'''
# need to figure out user login procedure
class GameServer(Protocol): #8001
def __init__(self, reactor):
self.reactor = reactor
def connectionMade(self):
print "GAME: Client connected: %s" % self.transport.getPeer()
# this is apparently the message size?
self.transport.write("\x78\x00\x00\x00")
self.transport.write("\x04\x00\x00\x00")
data = "\x70\xA7\x37\xA5\xF1\x02\x23\xEF\xEF\xCD\x8E\x2A\x8D\x02\x31\x2A\xAA\x00\x46\x22\x62\x7B\xBA\x66\xA0\x38\x20\xA1\x57\x77\x37\x9F\x9C\x18\x87\x9F\x9C\x77\x6A\xBD\x41\x6E\x5C\xF3\x9C\x77\x37\xA4\x9D\x77\x37\x9F\xCD\xBE\x33\x7F\x89\x1A\x87\x9F\x9C\x77\xC0\xBE\xFB\xD5\x92\xF7\xF9\x3A\x37\x9F\x9C\x77\x37\x9F\x9C\x77\x37\x9F\x9C\x77\x37\x9F\x7A\xEB\x2B\xB3\x8B\xF7\x38\x9F\x9C\x77\x37\x9F\x9C\x77\x37\x9F\x9F\x95\x37\xC6\x9C\xAD\x37\x9F\x9C\x77\x37\x9F\x9C\x77\x00\x00\x00\x00\x00\x00\xD0\x00\x00\x00\x04\x00\x00\x00\x09\x70\xD1\xE1\x58\xCB\xBC\x26\x56\x96\x27\x97\xEC\x42\x71\x66\x03\x40\xD0\x61\xF5\xCB\xEE\xCD\x28\xD4\xD0\xD6\x03\x45\xD1\xD6\x03\x40\x01\xDC\xFA\x65\x64\xD6\x03\x40\xD5\xD7\x03\x40\xD0\x07\x49\x44\x03\x34\x07\x37\xF5\x6A\x03\x40\xD0\xDB\x04\x40\xD0\xD6\x34\x86\xD8\x09\x61\x48\x73\x66\x03\x40\xD0\x59\xFC\x44\x4C\x13\xFA\x65\x64\xD6\x03\x40\xD5\xD7\x03\x40\xD0\x07\x49\x4C\x03\x34\x0F\xE3\x60\xD6\x03\x40\x53\xCF\x08\xBC\xF2\x59\xC9\x50\x53\xBF\x08\xB4\xD7\x09\x21\xC3\x96\xDA\xE3\x39\x0B\xF4\x77\x4F\x89\xE6\x03\x40\xD0\x90\x9B\x40\xD0\xD6\xEB\x40\xD0\xD6\x03\x9F\x2E\x31\x5B\x9D\x93\xD6\x50\x7B\xE0\x0A\xF2\xC0\xD1\xD6\x0B\x40\xD0\xD6\x03\x40\xD0\xD4\x05\x40\xD0\xD6\x03\x40\xD0\xD6\x03\x40\xD0\xD6\x03\x40\xD0\xD6\x0B\x4B\xD0\xEB\x03\x62\xD0\x09\x03\x83\xD0\x24\x03\x9E\xD0\x56\x03\x41\x55\xD6\x04\x40\x00\x00\x1A\x1C\x00\x40\x18\x00\x00\x00\xFD\xDC\x1A\xF4\xDD\x38\x6A\x30\x54\x96\x76\x88\x6C\x58\x34\x48\x00\x00\x00\x00\x00\x50\xEA\x1E\xFC\x8C\xF0\xEA"
# splitting up the data as show in winsock hook
self.transport.write(data[:120])
self.transport.write(data[120:124])
self.transport.write(data[124:336])
self.transport.write(data[336:340])
self.transport.write(data[340:])
def connectionLost(self, reason):
print "GAME: Client disconnected: %s" % self.transport.getPeer()
def dataReceived(self, data):
print "GAME: Data received: ", data.encode('hex')
class GameFactory(Factory):
def buildProtocol(self, addr):
p = self.protocol(self.reactor)
p.factory = self
return p
if __name__ == '__main__':
startLogging(stdout)
routefactory = Factory()
routefactory.protocol = RouteServer
reactor.listenTCP(7002, routefactory)
patchfactory = Factory()
patchfactory.protocol = PatchServer
reactor.listenTCP(6005, patchfactory)
gamefactory = GameFactory()
gamefactory.reactor = reactor
gamefactory.protocol = GameServer
reactor.listenTCP(8001, gamefactory)
reactor.run()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment