def __init__(self, sessions, address): self.setRawMode() # We're dealing with binary data so set to raw mode self.db = gs_database.GamespyDatabase() self.sessions = sessions self.address = address # Stores any unparsable/incomplete commands until the next # rawDataReceived self.remaining_message = "" self.profileid = 0 self.gameid = "" self.buddies = [] self.blocked = [] self.status = "" self.statstring = "" self.locstring = "" self.keepalive = int(time.time()) self.sesskey = "" self.sdkrevision = "0"
def __init__(self): self.sessions = {} # Generate a dictionary "secret_key_list" containing the secret game keys associated with their game IDs. # The dictionary key will be the game's ID, and the value will be the secret key. self.secret_key_list = gs_utils.generate_secret_keys("gslist.cfg") #self.log(logging.DEBUG, address, "Generated list of secret game keys...") self.db = gs_database.GamespyDatabase() GameSpyServerDatabase.register("update_server_list") GameSpyServerDatabase.register("delete_server")
def __init__(self, sessions, address): self.setRawMode() # We're dealing with binary data so set to raw mode self.db = gs_database.GamespyDatabase() self.sessions = sessions self.address = address self.remaining_message = "" # Stores any unparsable/incomplete commands until the next rawDataReceived self.session = "" self.gameid = "" self.lid = "0"
def do_GET(self): self.server = lambda:None self.server.db = gs_database.GamespyDatabase() try: # conntest server self.send_response(200) self.send_header("Content-type", "text/html") self.send_header("X-Organization", "Nintendo") self.send_header("Server", "BigIP") self.end_headers() self.wfile.write("ok") except: logger.log(logging.ERROR, "Unknown exception: %s" % traceback.format_exc())
def start(self): try: manager_address = dwc_config.get_ip_port('GameSpyManager') manager_password = "" self.server_manager = GameSpyServerDatabase( address=manager_address, authkey=manager_password) self.server_manager.connect() # Start QR server # Accessible to outside connections (use this if you don't know # what you're doing) address = dwc_config.get_ip_port('GameSpyQRServer') self.socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) self.socket.bind(address) self.socket.setblocking(0) logger.log(logging.INFO, "Server is now listening on %s:%s...", address[0], address[1]) # Dependencies! I don't really like this solution but it's easier # than trying to manage it another way. server_browser_server = GameSpyServerBrowserServer(self) server_browser_server_thread = threading.Thread( target=server_browser_server.start) server_browser_server_thread.start() self.write_queue = Queue.Queue() self.db = gs_database.GamespyDatabase() threading.Thread(target=self.write_queue_worker).start() while True: ready = select.select([self.socket], [], [], 15) if ready[0]: try: recv_data, address = self.socket.recvfrom(2048) self.handle_packet(self.socket, recv_data, address) except: logger.log(logging.ERROR, "Failed to handle client: %s", traceback.format_exc()) self.keepalive_check() except: logger.log(logging.ERROR, "Unknown exception: %s", traceback.format_exc())
def handle_ac(handler, addr, post): """Handle ac POST request.""" logger.log(logging.DEBUG, "Ac request to %s from %s:%d", handler.path, *addr) logger.log(logging.DEBUG, "%s", post) action = str(post["action"]).lower() command = handler.ac_actions.get(action, handle_ac_action) ret = command(handler, gs_database.GamespyDatabase(), addr, post) ret.update({"datetime": time.strftime("%Y%m%d%H%M%S")}) handler.send_response(200) handler.send_header("Content-type", "text/plain") handler.send_header("NODE", "wifiappe1") return utils.dict_to_qs(ret)
from gamestats_server_http import GameStatsServer from register_page import RegPageServer import gamespy.gs_database as gs_database import threading if __name__ == "__main__": """Let database initialize before starting any servers. This fixes any conflicts where two servers find an uninitialized database at the same time and both try to initialize it. """ db = gs_database.GamespyDatabase() db.initialize_database() db.close() servers = [ GameSpyBackendServer, GameSpyQRServer, GameSpyProfileServer, GameSpyPlayerSearchServer, GameSpyGamestatsServer, # GameSpyServerBrowserServer, GameSpyNatNegServer, NasServer, Dls1Server, InternalStatsServer, AdminPageServer,
def __init__(self, server_address, RequestHandlerClass): BaseHTTPServer.HTTPServer.__init__(self, server_address, RequestHandlerClass) self.gamespydb = gs_database.GamespyDatabase() self.db = sqlite3.connect('storage.db') self.tables = {} self.valid_sql_terms = ['LIKE', '=', 'AND', 'OR'] logger.log(logging.INFO, "Checking for and creating database tables...") cursor = self.db.cursor() if not self.table_exists('typedata'): cursor.execute( 'CREATE TABLE typedata (tbl TEXT, col TEXT, type TEXT)') if not self.table_exists('filepaths'): cursor.execute( 'CREATE TABLE filepaths (fileid INTEGER PRIMARY KEY AUTOINCREMENT, gameid INT, playerid INT, path TEXT)' ) PK = 'INTEGER PRIMARY KEY AUTOINCREMENT' self.create_or_alter_table_if_not_exists('g1443_bbdx_player', ['recordid', 'stat'], [PK, 'INT'], ['int', 'int']) self.create_or_alter_table_if_not_exists( 'g1443_bbdx_info', ['serialid', 'stat', 'message'], ['INT', 'INT', 'TEXT'], ['int', 'int', 'unicodeString']) self.create_or_alter_table_if_not_exists('g1443_bbdx_search', [ 'recordid', 'song_name', 'creator_name', 'average_rating', 'serialid', 'filestore', 'is_lyric', 'num_ratings', 'jasrac_code', 'artist_name' ], [ PK, 'TEXT', 'TEXT', 'REAL', 'INT', 'INT', 'INT', 'INT', 'TEXT', 'TEXT' ], [ 'int', 'asciiString', 'asciiString', 'float', 'int', 'int', 'boolean', 'int', 'asciiString', 'asciiString' ]) # Mario Kart Wii self.create_or_alter_table_if_not_exists( 'g1687_FriendInfo', ['recordid', 'ownerid', 'info'], [PK, 'INT', 'TEXT'], ['int', 'int', 'binaryData']) self.create_or_alter_table_if_not_exists( 'g1687_StoredGhostData', ['recordid', 'fileid', 'profile', 'region', 'gameid', 'course'], [PK, 'INT', 'INT', 'INT', 'INT', 'INT'], ['int', 'int', 'int', 'int', 'int', 'int']) # WarioWare DIY self.create_or_alter_table_if_not_exists( 'g2050_contest', ['recordid', 'ownerid', 'm_no', 'm_file_id'], [PK, 'INT', 'INT', 'INT'], ['int', 'int', 'int', 'int']) self.create_or_alter_table_if_not_exists( 'g2050_contest_eu', ['recordid', 'ownerid', 'm_no', 'm_file_id'], [PK, 'INT', 'INT', 'INT'], ['int', 'int', 'int', 'int']) self.create_or_alter_table_if_not_exists( 'g2050_contest_us', ['recordid', 'ownerid', 'm_no', 'm_file_id'], [PK, 'INT', 'INT', 'INT'], ['int', 'int', 'int', 'int']) self.create_or_alter_table_if_not_exists('g2050_box', [ 'recordid', 'ownerid', 'm_enable', 'm_type', 'm_index', 'm_file_id', 'm_header', 'm_file_id___size', 'm_file_id___create_time', 'm_file_id___downloads' ], [ PK, 'INT', 'INT', 'INT', 'INT', 'INT', 'TEXT', 'INT', 'DATETIME', 'INT' ], [ 'int', 'int', 'boolean', 'int', 'int', 'int', 'binaryData', 'int', 'dateAndTime', 'int' ]) cursor.execute( 'CREATE TRIGGER IF NOT EXISTS g2050ti_box AFTER INSERT ON g2050_box BEGIN UPDATE g2050_box SET m_file_id___create_time = strftime(\'%Y-%m-%dT%H:%M:%f\', \'now\'), m_file_id___size = 0, m_file_id___downloads = 0 WHERE recordid = NEW.recordid; END' ) cursor.execute( 'CREATE TRIGGER IF NOT EXISTS g2050tu_box AFTER UPDATE ON g2050_box BEGIN UPDATE g2050_box SET m_file_id___create_time = strftime(\'%Y-%m-%dT%H:%M:%f\', \'now\') WHERE recordid = NEW.recordid; END' ) self.create_or_alter_table_if_not_exists('g2050_box_us_eu', [ 'recordid', 'ownerid', 'm_enable', 'm_type', 'm_index', 'm_file_id', 'm_header', 'm_file_id___size', 'm_file_id___create_time', 'm_file_id___downloads' ], [ PK, 'INT', 'INT', 'INT', 'INT', 'INT', 'TEXT', 'INT', 'DATETIME', 'INT' ], [ 'int', 'int', 'boolean', 'int', 'int', 'int', 'binaryData', 'int', 'dateAndTime', 'int' ]) cursor.execute( 'CREATE TRIGGER IF NOT EXISTS g2050ti_box_us_eu AFTER INSERT ON g2050_box_us_eu BEGIN UPDATE g2050_box_us_eu SET m_file_id___create_time = strftime(\'%Y-%m-%dT%H:%M:%f\', \'now\'), m_file_id___size = 0, m_file_id___downloads = 0 WHERE recordid = NEW.recordid; END' ) cursor.execute( 'CREATE TRIGGER IF NOT EXISTS g2050tu_box_us_eu AFTER UPDATE ON g2050_box_us_eu BEGIN UPDATE g2050_box_us_eu SET m_file_id___create_time = strftime(\'%Y-%m-%dT%H:%M:%f\', \'now\') WHERE recordid = NEW.recordid; END' ) self.create_or_alter_table_if_not_exists('g2649_bbdx_player', ['recordid', 'stat'], [PK, 'INT'], ['int', 'int']) self.create_or_alter_table_if_not_exists( 'g2649_bbdx_info', ['serialid', 'stat', 'message'], ['INT', 'INT', 'TEXT'], ['int', 'int', 'unicodeString']) self.create_or_alter_table_if_not_exists('g2649_bbdx_search', [ 'recordid', 'song_name', 'creator_name', 'average_rating', 'serialid', 'filestore', 'is_lyric', 'num_ratings', 'song_code', 'artist_name' ], [ PK, 'TEXT', 'TEXT', 'REAL', 'INT', 'INT', 'INT', 'INT', 'TEXT', 'TEXT' ], [ 'int', 'asciiString', 'asciiString', 'float', 'int', 'int', 'boolean', 'int', 'asciiString', 'asciiString' ]) # Playground self.create_or_alter_table_if_not_exists( 'g2999_tblRegionInfo', ['recordid', 'region', 'allowed_regions', 'min_ratings'], [PK, 'INT', 'INT', 'INT'], ['int', 'byte', 'int', 'int']) # Super Smash Bros. Brawl self.create_or_alter_table_if_not_exists( 'g1658_submit', ['recordid', 'ownerid', 'data'], [PK, 'INT', 'INT'], ['int', 'int', 'int']) self.create_or_alter_table_if_not_exists( 'g1658_watching', ['recordid', 'ownerid', 'data'], [PK, 'INT', 'INT'], ['int', 'int', 'int']) # load column info into memory, unfortunately there's no simple way # to check for column-existence so get that data in advance cursor.execute("SELECT name FROM sqlite_master WHERE type='table'") tabledata = cursor.fetchall() for t in tabledata: cursor.execute( "PRAGMA table_info(%s)" % t[0] ) # yeah I know but parameters don't work in pragmas, and inserting table names like that should be safe columns = cursor.fetchall() self.tables[t[0]] = [c[1] for c in columns] self.db.commit()
def __init__(self, server_address, RequestHandlerClass): self.db = gs_database.GamespyDatabase() BaseHTTPServer.HTTPServer.__init__(self, server_address, RequestHandlerClass)
def __init__(self, server_address, RequestHandlerClass): BaseHTTPServer.HTTPServer.__init__(self, server_address, RequestHandlerClass) self.gamespydb = gs_database.GamespyDatabase() self.db = sqlite3.connect('storage.db') self.tables = {} cursor = self.db.cursor() if not self.table_exists('typedata'): cursor.execute( 'CREATE TABLE typedata (tbl TEXT, col TEXT, type TEXT)') if not self.table_exists('g2050_box_us_eu'): cursor.execute( 'CREATE TABLE g2050_box_us_eu (recordid INTEGER PRIMARY KEY AUTOINCREMENT, ownerid INT, m_enable INT, m_type INT, m_index INT, m_file_id INT, m_header TEXT, m_file_id___size INT, m_file_id___create_time DATETIME, m_file_id___downloads INT)' ) cursor.execute( 'INSERT INTO typedata VALUES ("g2050_box_us_eu", "recordid", "intValue"), ("g2050_box_us_eu", "ownerid", "intValue"), ("g2050_box_us_eu", "m_enable", "booleanValue"), ("g2050_box_us_eu", "m_type", "intValue"), ("g2050_box_us_eu", "m_index", "intValue"), ("g2050_box_us_eu", "m_file_id", "intValue"), ("g2050_box_us_eu", "m_header", "binaryDataValue"), ("g2050_box_us_eu", "m_file_id___size", "intValue"), ("g2050_box_us_eu", "m_file_id___create_time", "dateAndTimeValue"), ("g2050_box_us_eu", "m_file_id___downloads", "intValue")' ) cursor.execute( 'CREATE TRIGGER g2050ti_box_us_eu AFTER INSERT ON g2050_box_us_eu BEGIN UPDATE g2050_box_us_eu SET m_file_id___create_time = date(\'now\'), m_file_id___size = 0, m_file_id___downloads = 0 WHERE recordid = NEW.recordid; END' ) cursor.execute( 'CREATE TRIGGER g2050tu_box_us_eu AFTER UPDATE ON g2050_box_us_eu BEGIN UPDATE g2050_box_us_eu SET m_file_id___create_time = date(\'now\') WHERE recordid = NEW.recordid; END' ) if not self.table_exists('g2050_contest_us'): cursor.execute( 'CREATE TABLE g2050_contest_us (recordid INTEGER PRIMARY KEY AUTOINCREMENT, ownerid INT, m_no INT, m_file_id INT)' ) cursor.execute( 'INSERT INTO typedata VALUES ("g2050_contest_us", "recordid", "intValue"), ("g2050_contest_us", "ownerid", "intValue"), ("g2050_contest_us", "m_no", "intValue"), ("g2050_contest_us", "m_file_id", "intValue")' ) if not self.table_exists('g2649_bbdx_player'): cursor.execute( 'CREATE TABLE g2649_bbdx_player (recordid INTEGER PRIMARY KEY AUTOINCREMENT, stat INT)' ) cursor.execute( 'INSERT INTO typedata VALUES ("g2649_bbdx_player", "recordid", "intValue"), ("g2649_bbdx_player", "stat", "intValue")' ) if not self.table_exists('g2649_bbdx_info'): cursor.execute( 'CREATE TABLE g2649_bbdx_info (serialid INT, stat INT, message TEXT)' ) cursor.execute( 'INSERT INTO typedata VALUES ("g2649_bbdx_info", "serialid", "intValue"), ("g2649_bbdx_info", "stat", "intValue"), ("g2649_bbdx_info", "message", "unicodeStringValue")' ) if not self.table_exists('g2649_bbdx_search'): cursor.execute( 'CREATE TABLE g2649_bbdx_search (recordid INTEGER PRIMARY KEY AUTOINCREMENT, song_name TEXT, creator_name TEXT, average_rating REAL, serialid INT, filestore INT, is_lyric INT, num_ratings INT)' ) cursor.execute( 'INSERT INTO typedata VALUES ("g2649_bbdx_search", "recordid", "intValue"), ("g2649_bbdx_search", "song_name", "asciiStringValue"), ("g2649_bbdx_search", "creator_name", "asciiStringValue"), ("g2649_bbdx_search", "average_rating", "floatValue"), ("g2649_bbdx_search", "serialid", "intValue"), ("g2649_bbdx_search", "filestore", "intValue"), ("g2649_bbdx_search", "is_lyric", "booleanValue"), ("g2649_bbdx_search", "num_ratings", "intValue")' ) # load column info into memory, unfortunately there's no simple way # to check for column-existence so get that data in advance cursor.execute("SELECT name FROM sqlite_master WHERE type='table'") tabledata = cursor.fetchall() for t in tabledata: cursor.execute( "PRAGMA table_info(%s)" % t[0] ) # yeah I know but parameters don't work in pragmas, and inserting table names like that should be safe columns = cursor.fetchall() columndata = [] for c in columns: columndata.append(c[1]) self.tables[t[0]] = columndata self.db.commit()
def __init__(self, address): self.setRawMode() self.db = gs_database.GamespyDatabase() self.address = address self.leftover = ""
def handle_packet(self, socket, recv_data, address): db = gs_database.GamespyDatabase() time.sleep(0.05) # Tetris DS overlay 10 @ 02144184 - Handle responses back to server # Tetris DS overlay 10 @ 02144184 - Handle responses back to server # # After some more packet inspection, it seems the format goes something like this: # - All server messages seem to always start with \xfe\xfd. # - The first byte from the client (or third byte from the server) is a command. # - Bytes 2 - 5 from the client is some kind of ID. This will have to be inspected later. I believe it's a # session-like ID because the number changes between connections. Copying the client's ID might be enough. # # The above was as guessed. # The code in Tetris DS (overlay 10) @ 0216E974 handles the network command creation. # R1 contains the command to be sent to the server. # R2 contains a pointer to some unknown integer that gets written after the command. # # - Commands # Commands range from 0x00 to 0x09 (for client only at least?) (Tetris DS overlay 10 @ 0216DDCC) # # CLIENT: # 0x01 - Response (Tetris DS overlay 10 @ 216DCA4) # Sends back base64 of RC4 encrypted string that was gotten from the server's 0x01. # # 0x03 - Send client state? (Tetris DS overlay 10 @ 216DA30) # Data sent: # 1) Loop for each localip available on the system, write as localip%d\x00(local ip) # 2) localport\x00(local port) # 3) natneg (either 0 or 1) # 4) ONLY IF STATE CHANGED: statechanged\x00(state) (Possible values: 0, 1, 2, 3) # 5) gamename\x00(game name) # 6) ONLY IF PUBLIC IP AND PORT ARE AVAILABLE: publicip\x00(public ip) # 7) ONLY IF PUBLIC IP AND PORT ARE AVAILABLE: publicport\x00(public port) # # if statechanged != 2: # Write various other data described here: http://docs.poweredbygamespy.com/wiki/Query_and_Reporting_Implementation # # 0x07 - Unknown, related to server's 0x06 (returns value sent from server) # # 0x08 - Keep alive? Sent after 0x03 # # 0x09 - Availability check # # SERVER: # 0x01 - Unknown # Data sent: # 8 random ASCII characters (?) followed by the public IP and port of the client as a hex string # # 0x06 - Unknown # First 4 bytes is some kind of id? I believe it's a unique identifier for the data being sent, # seeing how the server can send the same IP information many times in a row. If the IP information has # already been parsed then it doesn't waste time handling it. # # After that is a "SBCM" section which is 0x14 bytes in total. # SBCM information gets parsed at 2141A0C in Tetris DS overlay 10. # Seems to contain IP address information. # # The SBCM seems to contain a little information that must be parsed before. # After the SBCM: # \x03\x00\x00\x00 - Always the same? # \x01 - Found player? # \x04 - Unknown # (2 bytes) - Unknown. Port? # (4 bytes) - Player's IP # (4 bytes) - Unknown. Some other IP? Remote server IP? # \x00\x00\x00\x00 - Unknown but seems to get checked # # Another SBCM, after a player has been found and attempting to start a game: # \x03\x00\x00\x00 - Always the same? # \x05 - Connecting to player? # \x00 - Unknown # (2 bytes) - Unknown. Port? Same as before. # (4 bytes) - Player's IP # (4 bytes) - Unknown. Some other IP? Remote server IP? # # 0x0a - Response to 0x01 # Gets sent after receiving 0x01 from the client. So, server 0x01 -> client 0x01 -> server 0x0a. # Has no other data besides the client ID. # # - \xfd\xfc commands get passed directly between the other player(s)? # # # Open source version of GameSpy found here: https://github.com/sfcspanky/Openspy-Core/tree/master/qr # Use as reference. if recv_data[0] != '\x09': # Don't add a session if the client is trying to check if the game is available or not session_id = struct.unpack("<I", recv_data[1:5])[0] session_id_raw = recv_data[1:5] if session_id not in self.sessions: # Found a new session, add to session list self.sessions[session_id] = self.Session(address) self.sessions[session_id].session = session_id self.sessions[session_id].keepalive = int(time.time()) # Handle commands if recv_data[0] == '\x00': # Query self.log(logging.DEBUG, address, "NOT IMPLEMENTED! Received query from %s:%s... %s" % (address[0], address[1], recv_data[5:])) elif recv_data[0] == '\x01': # Challenge self.log(logging.DEBUG, address, "Received challenge from %s:%s... %s" % (address[0], address[1], recv_data[5:])) # Prepare the challenge sent from the server to be compared challenge = gs_utils.prepare_rc4_base64(self.sessions[session_id].secretkey, self.sessions[session_id].challenge) # Compare challenge client_challenge = recv_data[5:-1] if client_challenge == challenge: # Challenge succeeded # Send message back to client saying it was accepted packet = bytearray([0xfe, 0xfd, 0x0a]) # Send client registered command packet.extend(session_id_raw) # Get the session ID socket.sendto(packet, address) self.log(logging.DEBUG, address, "Sent client registered to %s:%s..." % (address[0], address[1])) else: # Failed the challenge, request another during the next heartbeat self.sessions[session_id].sent_challenge = False elif recv_data[0] == '\x02': # Echo self.log(logging.DEBUG, address, "NOT IMPLEMENTED! Received echo from %s:%s... %s" % (address[0], address[1], recv_data[5:])) elif recv_data[0] == '\x03': # Heartbeat data = recv_data[5:] self.log(logging.DEBUG, address, "Received heartbeat from %s:%s... %s" % (address[0], address[1], data)) # Parse information from heartbeat here d = data.rstrip('\0').split('\0') # It may be safe to ignore "unknown" keys because the proper key names get filled in later... k = {} for i in range(0, len(d), 2): #self.log(logging.DEBUG, address, "%s = %s" % (d[i], d[i+1])) k[d[i]] = d[i+1] if "gamename" in k: self.sessions[session_id].secretkey = self.secret_key_list[k['gamename']] #print "Got secret key %s for %s" % (self.sessions[session_id].secretkey, k['gamename']) if self.sessions[session_id].playerid == 0 and "dwc_pid" in k: # Get the player's id and then query the profile to figure out what console they are on. # The endianness of some server data depends on the endianness of the console, so we must be able # to account for that. self.sessions[session_id].playerid = int(k['dwc_pid']) profile = db.get_profile_from_profileid(self.sessions[session_id].playerid) if "console" in profile: self.sessions[session_id].console = profile['console'] if self.sessions[session_id].sent_challenge == False: addr_hex = ''.join(["%02X" % int(x) for x in address[0].split('.')]) port_hex = "%04X" % int(address[1]) server_challenge = utils.generate_random_str(8) + addr_hex + port_hex self.sessions[session_id].challenge = server_challenge packet = bytearray([0xfe, 0xfd, 0x01]) # Send challenge command packet.extend(session_id_raw) # Get the session ID packet.extend(server_challenge) packet.extend('\x00') socket.sendto(packet, address) self.log(logging.DEBUG, address, "Sent challenge to %s:%s..." % (address[0], address[1])) self.sessions[session_id].sent_challenge = True if 'publicip' in k and k['publicip'] == "0": #and k['dwc_hoststate'] == "2": # When dwc_hoststate == 2 then it doesn't send an IP, so calculate it ourselves if self.sessions[session_id].console != 0: k['publicip'] = str(ctypes.c_int32(utils.get_int_be(bytearray([int(x) for x in address[0].split('.')]), 0)).value) # Wii else: k['publicip'] = str(ctypes.c_int32(utils.get_int(bytearray([int(x) for x in address[0].split('.')]), 0)).value) # DS if "statechanged" in k: if k['statechanged'] == "2": # Close server self.server_manager.delete_server(k['gamename'] , session_id) if session_id in self.sessions: self.sessions.pop(session_id) else: #if k['statechanged'] == "1": # Create server #if k['publicport'] != "0" and k['publicip'] != "0": # dwc_mtype controls what kind of server query we're looking for. # dwc_mtype = 0 is used when looking for a matchmaking game. # dwc_mtype = 1 is unknown. # dwc_mtype = 2 is used when hosting a friends only game (possibly other uses too). # dwc_mtype = 3 is used when looking for a friends only game (possibly other uses too). # Some memory could be saved by clearing out any unwanted fields from k before sending. self.server_manager.update_server_list(k['gamename'], session_id, k, self.sessions[session_id].console)._getvalue() if session_id in self.sessions: self.sessions[session_id].gamename = k['gamename'] elif recv_data[0] == '\x04': # Add Error self.log(logging.WARNING, address, "NOT IMPLEMENTED! Received add error from %s:%s... %s" % (address[0], address[1], recv_data[5:])) elif recv_data[0] == '\x05': # Echo Response self.log(logging.WARNING, address, "NOT IMPLEMENTED! Received echo response from %s:%s... %s" % (address[0], address[1], recv_data[5:])) elif recv_data[0] == '\x06': # Client Message self.log(logging.WARNING, address, "NOT IMPLEMENTED! Received echo from %s:%s... %s" % (address[0], address[1], recv_data[5:])) elif recv_data[0] == '\x07': # Client Message Ack #self.log(logging.WARNING, address, "NOT IMPLEMENTED! Received client message ack from %s:%s... %s" % (address[0], address[1], recv_data[5:])) self.log(logging.DEBUG, address, "Received client message ack from %s:%s..." % (address[0], address[1])) elif recv_data[0] == '\x08': # Keep Alive self.log(logging.DEBUG, address, "Received keep alive from %s:%s..." % (address[0], address[1])) self.sessions[session_id].keepalive = int(time.time()) elif recv_data[0] == '\x09': # Available # Availability check only sent to *.available.gs.nintendowifi.net self.log(logging.DEBUG, address, "Received availability request for '%s' from %s:%s..." % (recv_data[5: -1], address[0], address[1])) socket.sendto(bytearray([0xfe, 0xfd, 0x09, 0x00, 0x00, 0x00, 0x00]), address) elif recv_data[0] == '\x0a': # Client Registered # Only sent to client, never received? self.log(logging.WARNING, address, "NOT IMPLEMENTED! Received client registered from %s:%s... %s" % (address[0], address[1], recv_data[5:])) else: self.log(logging.ERROR, address, "Unknown request from %s:%s:" % (address[0], address[1])) self.log(logging.DEBUG, address, utils.pretty_print_hex(recv_data))
def do_POST(self): self.server = lambda: None self.server.db = gs_database.GamespyDatabase() try: length = int(self.headers['content-length']) post = self.str_to_dict(self.rfile.read(length)) if self.client_address[0] == '127.0.0.1': client_address = (self.headers.get('x-forwarded-for', self.client_address[0]), self.client_address[1]) else: client_address = self.client_address post['ipaddr'] = client_address[0] if self.path == "/ac": logger.log(logging.DEBUG, "Request to %s from %s", self.path, client_address) logger.log(logging.DEBUG, post) ret = {"datetime": time.strftime("%Y%m%d%H%M%S"), "retry": "0"} action = post["action"] self.send_response(200) self.send_header("Content-type", "text/plain") self.send_header("NODE", "wifiappe1") if action == "acctcreate": # TODO: test for duplicate accounts if self.server.db.is_ip_banned(post): logger.log( logging.DEBUG, "acctcreate denied for banned user " + str(post)) ret = { "datetime": time.strftime("%Y%m%d%H%M%S"), "returncd": "3913", "locator": "gamespy.com", "retry": "1", "reason": "User banned." } else: ret["returncd"] = "002" ret['userid'] = self.server.db.get_next_available_userid( ) logger.log(logging.DEBUG, "acctcreate response to %s", client_address) logger.log(logging.DEBUG, ret) ret = self.dict_to_str(ret) elif action == "login": if self.server.db.is_ip_banned(post): logger.log(logging.DEBUG, "login denied for banned user " + str(post)) ret = { "datetime": time.strftime("%Y%m%d%H%M%S"), "returncd": "3917", "locator": "gamespy.com", "retry": "1", "reason": "User banned." } elif self.server.db.is_console_macadr_banned(post): logger.log( logging.DEBUG, "login denied for banned console" + str(post)) ret = { "datetime": time.strftime("%Y%m%d%H%M%S"), "returncd": "3914", "locator": "gamespy.com", "retry": "1", "reason": "User's console is banned." } elif self.server.db.is_console_cfc_banned(post): logger.log( logging.DEBUG, "login denied for banned console" + str(post)) ret = { "datetime": time.strftime("%Y%m%d%H%M%S"), "returncd": "3915", "locator": "gamespy.com", "retry": "1", "reason": "User's console is banned." } elif self.server.db.is_console_csnum_banned(post): logger.log( logging.DEBUG, "login denied for banned console" + str(post)) ret = { "datetime": time.strftime("%Y%m%d%H%M%S"), "returncd": "3915", "locator": "gamespy.com", "retry": "1", "reason": "User's console is banned." } elif self.server.db.is_ingamesn_banned(post): logger.log( logging.DEBUG, "login denied for banned Mii name" + str(post)) ret = { "datetime": time.strftime("%Y%m%d%H%M%S"), "returncd": "3916", "locator": "gamespy.com", "retry": "1", "reason": "Mii name is black listed" } elif self.server.db.is_devname_banned(post): logger.log( logging.DEBUG, "login denied for banned device name" + str(post)) ret = { "datetime": time.strftime("%Y%m%d%H%M%S"), "returncd": "3916", "locator": "gamespy.com", "retry": "1", "reason": "device name is black listed" } #Un0comment the lines below to activate console registration elif not self.server.db.pending(post): logger.log( logging.DEBUG, "Login denied - Unknown console" + str(post)) ret = { "datetime": time.strftime("%Y%m%d%H%M%S"), "returncd": "3921", "locator": "gamespy.com", "retry": "1", } elif not self.server.db.registered(post): logger.log( logging.DEBUG, "Login denied - console pending" + str(post)) ret = { "datetime": time.strftime("%Y%m%d%H%M%S"), "returncd": "3888", "locator": "gamespy.com", "retry": "1", } else: challenge = utils.generate_random_str(8) post["challenge"] = challenge authtoken = self.server.db.generate_authtoken( post["userid"], post) ret.update({ "returncd": "001", "locator": "gamespy.com", "challenge": challenge, "token": authtoken, }) logger.log(logging.DEBUG, "login response to %s", client_address) logger.log(logging.DEBUG, ret) ret = self.dict_to_str(ret) elif action == "SVCLOC" or action == "svcloc": # Get service based on service id number ret["returncd"] = "007" ret["statusdata"] = "Y" authtoken = self.server.db.generate_authtoken( post["userid"], post) if 'svc' in post: if post["svc"] in ("9000", "9001"): # DLC host = 9000 ret["svchost"] = self.headers[ 'host'] # in case the client's DNS isn't redirecting dls1.nintendowifi.net # Brawl has 2 host headers which Apache chokes on, so only return the first one or else it won't work ret["svchost"] = ret["svchost"].split(',')[0] if post["svc"] == 9000: ret["token"] = authtoken else: ret["servicetoken"] = authtoken elif post[ "svc"] == "0000": # Pokemon requests this for some things ret["servicetoken"] = authtoken ret["svchost"] = "n/a" logger.log(logging.DEBUG, "svcloc response to %s", client_address) logger.log(logging.DEBUG, ret) ret = self.dict_to_str(ret) else: logger.log(logging.WARNING, "Unknown action request %s from %s!", self.path, client_address) elif self.path == "/pr": logger.log(logging.DEBUG, "Request to %s from %s", self.path, client_address) logger.log(logging.DEBUG, post) words = len(post["words"].split('\t')) wordsret = "0" * words ret = { "prwords": wordsret, "returncd": "000", "datetime": time.strftime("%Y%m%d%H%M%S") } for l in "ACEJKP": ret["prwords" + l] = wordsret self.send_response(200) self.send_header("Content-type", "text/plain") self.send_header("NODE", "wifiappe1") logger.log(logging.DEBUG, "pr response to %s", client_address) logger.log(logging.DEBUG, ret) ret = self.dict_to_str(ret) elif self.path == "/download": logger.log(logging.DEBUG, "Request to %s from %s", self.path, client_address) logger.log(logging.DEBUG, post) action = post["action"] ret = "" dlcdir = os.path.abspath('dlc') dlcpath = os.path.abspath("dlc/" + post["gamecd"]) dlc_contenttype = False if os.path.commonprefix([dlcdir, dlcpath]) != dlcdir: logging.log( logging.WARNING, 'Attempted directory traversal attack "%s", cancelling.', dlcpath) self.send_response(403) return def safeloadfi(fn, mode='rb'): ''' safeloadfi : string -> string Safely load contents of a file, given a filename, and closing the file afterward ''' with open(os.path.join(dlcpath, fn), mode) as fi: return fi.read() if action == "count": if post["gamecd"] in gamecodes_return_random_file: ret = "1" else: count = 0 if os.path.exists(dlcpath): count = len(os.listdir(dlcpath)) if os.path.isfile(dlcpath + "/_list.txt"): attr1 = post.get("attr1", None) attr2 = post.get("attr2", None) attr3 = post.get("attr3", None) dlcfi = safeloadfi("_list.txt") lst = self.filter_list(dlcfi, attr1, attr2, attr3) count = self.get_file_count(lst) ret = "%d" % count if action == "list": num = post.get("num", None) offset = post.get("offset", None) if num != None: num = int(num) if offset != None: offset = int(offset) attr1 = post.get("attr1", None) attr2 = post.get("attr2", None) attr3 = post.get("attr3", None) if os.path.exists(dlcpath): # Look for a list file first. # If the list file exists, send the entire thing back to the client. if os.path.isfile(os.path.join(dlcpath, "_list.txt")): if post["gamecd"].startswith( "IRA") and attr1.startswith("MYSTERY"): # Pokemon BW Mystery Gifts, until we have a better solution for that ret = self.filter_list(safeloadfi("_list.txt"), attr1, attr2, attr3) ret = self.filter_list_g5_mystery_gift( ret, post["rhgamecd"]) ret = self.filter_list_by_date( ret, post["token"]) elif post[ "gamecd"] in gamecodes_return_random_file: # Pokemon Gen 4 Mystery Gifts, same here ret = self.filter_list(safeloadfi("_list.txt"), attr1, attr2, attr3) ret = self.filter_list_by_date( ret, post["token"]) else: # default case for most games ret = self.filter_list(safeloadfi("_list.txt"), attr1, attr2, attr3, num, offset) if action == "contents": # Get only the base filename just in case there is a path involved somewhere in the filename string. dlc_contenttype = True contents = os.path.basename(post["contents"]) ret = safeloadfi(contents) self.send_response(200) if dlc_contenttype == True: self.send_header("Content-type", "application/x-dsdl") self.send_header( "Content-Disposition", "attachment; filename=\"" + post["contents"] + "\"") else: self.send_header("Content-type", "text/plain") self.send_header("X-DLS-Host", "http://127.0.0.1/") logger.log(logging.DEBUG, "download response to %s", client_address) #if dlc_contenttype == False: # logger.log(logging.DEBUG, ret) else: self.send_response(404) logger.log(logging.WARNING, "Unknown path request %s from %s!", self.path, client_address) return self.send_header("Content-Length", str(len(ret))) self.end_headers() self.wfile.write(ret) except: logger.log(logging.ERROR, "Unknown exception: %s" % traceback.format_exc())
from gamespy_gamestats_server import GameSpyGamestatsServer from nas_server import NasServer from internal_stats_server import InternalStatsServer from storage_server import StorageServer from gamestats_server_http import GameStatsServer import gamespy.gs_database as gs_database import threading if __name__ == "__main__": # Let database initialize before starting any servers. # This fixes any conflicts where two servers find an uninitialized database at the same time and both try to # initialize it. gs_database.GamespyDatabase().initialize_database() servers = [ GameSpyBackendServer, GameSpyQRServer, GameSpyProfileServer, GameSpyPlayerSearchServer, GameSpyGamestatsServer, #GameSpyServerBrowserServer, GameSpyNatNegServer, NasServer, InternalStatsServer, StorageServer, GameStatsServer, ] for server in servers: