diff --git a/altwfc.cfg b/altwfc.cfg index 326948f..4a6cdfc 100755 --- a/altwfc.cfg +++ b/altwfc.cfg @@ -16,6 +16,7 @@ LoggerOutputFile = ON [NasServer] IP = 127.0.0.1 Port = 9000 +SvcHost = dls1.nintendowifi.net LoggerName = NasServer LoggerFilename = nas_server.log LoggerLevel = -1 @@ -40,6 +41,15 @@ LoggerLevel = -1 LoggerOutputConsole = ON LoggerOutputFile = ON +[Dls1Server] +IP = 127.0.0.1 +Port = 9003 +LoggerName = Dls1Server +LoggerFilename = dls1_server.log +LoggerLevel = -1 +LoggerOutputConsole = ON +LoggerOutputFile = ON + [AdminPage] IP = 127.0.0.1 Port = 9009 diff --git a/altwfc_nas.cfg b/altwfc_nas.cfg index 5995a09..d4996c2 100644 --- a/altwfc_nas.cfg +++ b/altwfc_nas.cfg @@ -12,6 +12,7 @@ LoggerOutputFile = ON [NasServer] IP = 127.0.0.1 Port = 80 +SvcHost = dls1.nintendowifi.net LoggerName = NasServer LoggerFilename = nas_server.log LoggerLevel = -1 @@ -36,6 +37,15 @@ LoggerLevel = -1 LoggerOutputConsole = ON LoggerOutputFile = ON +[Dls1Server] +IP = 127.0.0.1 +Port = 9003 +LoggerName = Dls1Server +LoggerFilename = dls1_server.log +LoggerLevel = -1 +LoggerOutputConsole = ON +LoggerOutputFile = ON + [AdminPage] IP = 127.0.0.1 Port = 9009 diff --git a/dls1_server.py b/dls1_server.py new file mode 100644 index 0000000..4539c54 --- /dev/null +++ b/dls1_server.py @@ -0,0 +1,161 @@ +"""DWC Network Server Emulator + + Copyright (C) 2014 polaris- + Copyright (C) 2014 ToadKing + Copyright (C) 2014 AdmiralCurtiss + Copyright (C) 2014 msoucy + Copyright (C) 2015 Sepalani + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as + published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +""" + +import logging +import BaseHTTPServer +import SocketServer +import os +import traceback + +from other import dlc, utils +import dwc_config + +logger = dwc_config.get_logger('Dls1Server') + + +def handle_post(handler, addr, post): + """Handle unknown path.""" + logger.log(logging.WARNING, "Unknown path request %s from %s:%d!", + handler.path, *addr) + handler.send_response(404) + return None + + +def handle_download_action(handler, dlc_path, post): + """Handle unknown download action request.""" + logger.log(logging.WARNING, "Unknown download action: %s", handler.path) + handler.send_response(200) + return None + + +def handle_download_count(handler, dlc_path, post): + """Handle download count request.""" + ret = dlc.download_count(dlc_path, post) + handler.send_response(200) + handler.send_header("Content-type", "text/plain") + handler.send_header("X-DLS-Host", "http://127.0.0.1/") + return ret + + +def handle_download_list(handler, dlc_path, post): + """Handle download list request.""" + ret = dlc.download_list(dlc_path, post) + handler.send_response(200) + handler.send_header("Content-type", "text/plain") + handler.send_header("X-DLS-Host", "http://127.0.0.1/") + return ret + + +def handle_download_contents(handler, dlc_path, post): + """Handle download contents request.""" + ret = dlc.download_contents(dlc_path, post) + + if ret is None: + handler.send_response(404) + else: + handler.send_response(200) + handler.send_header("Content-type", "application/x-dsdl") + handler.send_header("Content-Disposition", + 'attachment; filename="%s"' % post["contents"]) + handler.send_header("X-DLS-Host", "http://127.0.0.1/") + return ret + + +def handle_download(handler, addr, post): + """Handle download POST request.""" + logger.log(logging.DEBUG, "Download request to %s from %s:%d", + handler.path, *addr) + logger.log(logging.DEBUG, "%s", post) + + action = str(post["action"]).lower() + dlc_dir = os.path.abspath("dlc") + dlc_path = os.path.abspath(os.path.join("dlc", post["gamecd"])) + + if os.path.commonprefix([dlc_dir, dlc_path]) != dlc_dir: + logging.log(logging.WARNING, + 'Attempted directory traversal attack "%s",' + ' cancelling.', dlc_path) + handler.send_response(403) + return + + command = handler.download_actions.get(action, handle_download_action) + ret = command(handler, dlc_path, post) + + logger.log(logging.DEBUG, "Download response to %s:%d", *addr) + return ret + + +class Dls1HTTPServerHandler(BaseHTTPServer.BaseHTTPRequestHandler): + """Nintendo Dls1 server handler.""" + + post_paths = { + "/download": handle_download + } + + download_actions = { + "count": handle_download_count, + "list": handle_download_list, + "contents": handle_download_contents, + } + + def version_string(self): + return "Nintendo Wii (http)" + + def do_POST(self): + try: + length = int(self.headers['content-length']) + post = utils.qs_to_dict(self.rfile.read(length)) + client_address = ( + self.headers.get('x-forwarded-for', self.client_address[0]), + self.client_address[1] + ) + post['ipaddr'] = client_address[0] + + command = self.post_paths.get(self.path, handle_post) + ret = command(self, client_address, post) + + if ret is not None: + self.send_header("Content-Length", str(len(ret))) + self.end_headers() + self.wfile.write(ret) + except: + logger.log(logging.ERROR, "Exception occurred on POST request!") + logger.log(logging.ERROR, "%s", traceback.format_exc()) + + +class Dls1HTTPServer(SocketServer.ThreadingMixIn, BaseHTTPServer.HTTPServer): + """Threading HTTP server.""" + pass + + +class Dls1Server(object): + def start(self): + address = dwc_config.get_ip_port('Dls1Server') + httpd = Dls1HTTPServer(address, Dls1HTTPServerHandler) + logger.log(logging.INFO, "Now listening for connections on %s:%d...", + *address) + httpd.serve_forever() + + +if __name__ == "__main__": + dls1 = Dls1Server() + dls1.start() diff --git a/dwc_config.py b/dwc_config.py index dddc956..75ff139 100755 --- a/dwc_config.py +++ b/dwc_config.py @@ -75,3 +75,10 @@ def get_logger(section, filename='altwfc.cfg'): config.getboolean(section, 'LoggerOutputConsole'), config.getboolean(section, 'LoggerOutputFile') ) + + +def get_svchost(section, filename='altwfc.cfg'): + """Return the svchost of the corresponding section.""" + config = ConfigParser.RawConfigParser(allow_no_value=True) + config.read(get_config_filename(filename)) + return config.get(section, 'SvcHost') diff --git a/dwc_network_server_emulator.pyproj b/dwc_network_server_emulator.pyproj index 89b2580..a703b96 100644 --- a/dwc_network_server_emulator.pyproj +++ b/dwc_network_server_emulator.pyproj @@ -42,6 +42,7 @@ + diff --git a/master_server.py b/master_server.py index 954c123..f2d336b 100644 --- a/master_server.py +++ b/master_server.py @@ -28,6 +28,7 @@ from gamespy_qr_server import GameSpyQRServer from gamespy_server_browser_server import GameSpyServerBrowserServer from gamespy_gamestats_server import GameSpyGamestatsServer from nas_server import NasServer +from dls1_server import Dls1Server from internal_stats_server import InternalStatsServer from admin_page_server import AdminPageServer from storage_server import StorageServer @@ -59,6 +60,7 @@ if __name__ == "__main__": # GameSpyServerBrowserServer, GameSpyNatNegServer, NasServer, + Dls1Server, InternalStatsServer, AdminPageServer, RegPageServer, diff --git a/nas_server.py b/nas_server.py index fa5ca30..dd43837 100644 --- a/nas_server.py +++ b/nas_server.py @@ -22,14 +22,12 @@ import logging import time -import urlparse import BaseHTTPServer import SocketServer -import os import traceback from gamespy import gs_database -from other import dlc, utils +from other import utils import dwc_config logger = dwc_config.get_logger('NasServer') @@ -134,7 +132,9 @@ def handle_ac_svcloc(handler, db, addr, post): # DLC host = 9000 # In case the client's DNS isn't redirecting to # dls1.nintendowifi.net - ret["svchost"] = handler.headers['host'] + # NB: NAS config overrides this if set + svchost = dwc_config.get_svchost('NasServer') + ret["svchost"] = svchost if svchost else handler.headers['host'] # Brawl has 2 host headers which Apache chokes # on, so only return the first one or else it @@ -205,77 +205,12 @@ def handle_pr(handler, addr, post): return utils.dict_to_qs(ret) -def handle_download_action(handler, dlc_path, post): - """Handle unknown download action request.""" - logger.log(logging.WARNING, "Unknown download action: %s", handler.path) - handler.send_response(200) - return None - - -def handle_download_count(handler, dlc_path, post): - """Handle download count request.""" - ret = dlc.download_count(dlc_path, post) - handler.send_response(200) - handler.send_header("Content-type", "text/plain") - handler.send_header("X-DLS-Host", "http://127.0.0.1/") - return ret - - -def handle_download_list(handler, dlc_path, post): - """Handle download list request.""" - ret = dlc.download_list(dlc_path, post) - handler.send_response(200) - handler.send_header("Content-type", "text/plain") - handler.send_header("X-DLS-Host", "http://127.0.0.1/") - return ret - - -def handle_download_contents(handler, dlc_path, post): - """Handle download contents request.""" - ret = dlc.download_contents(dlc_path, post) - - if ret is None: - handler.send_response(404) - else: - handler.send_response(200) - handler.send_header("Content-type", "application/x-dsdl") - handler.send_header("Content-Disposition", - 'attachment; filename="%s"' % post["contents"]) - handler.send_header("X-DLS-Host", "http://127.0.0.1/") - return ret - - -def handle_download(handler, addr, post): - """Handle download POST request.""" - logger.log(logging.DEBUG, "Download request to %s from %s:%d", - handler.path, *addr) - logger.log(logging.DEBUG, "%s", post) - - action = str(post["action"]).lower() - dlc_dir = os.path.abspath("dlc") - dlc_path = os.path.abspath(os.path.join("dlc", post["gamecd"])) - - if os.path.commonprefix([dlc_dir, dlc_path]) != dlc_dir: - logging.log(logging.WARNING, - 'Attempted directory traversal attack "%s",' - ' cancelling.', dlc_path) - handler.send_response(403) - return - - command = handler.download_actions.get(action, handle_download_action) - ret = command(handler, dlc_path, post) - - logger.log(logging.DEBUG, "Download response to %s:%d", *addr) - return ret - - class NasHTTPServerHandler(BaseHTTPServer.BaseHTTPRequestHandler): """Nintendo NAS server handler.""" post_paths = { "/ac": handle_ac, "/pr": handle_pr, - "/download": handle_download } ac_actions = { @@ -284,12 +219,6 @@ class NasHTTPServerHandler(BaseHTTPServer.BaseHTTPRequestHandler): "svcloc": handle_ac_svcloc, } - download_actions = { - "count": handle_download_count, - "list": handle_download_list, - "contents": handle_download_contents, - } - def version_string(self): return "Nintendo Wii (http)" diff --git a/tools/apache-hosts/dls1.nintendowifi.net.conf b/tools/apache-hosts/dls1.nintendowifi.net.conf new file mode 100644 index 0000000..fda65ea --- /dev/null +++ b/tools/apache-hosts/dls1.nintendowifi.net.conf @@ -0,0 +1,9 @@ + + ServerAdmin webmaster@localhost + ServerName dls1.nintendowifi.net + ServerAlias "dls1.nintendowifi.net" + ServerAlias "dls1.nintendowifi.net, dls1.nintendowifi.net" + ProxyPreserveHost On + ProxyPass / http://127.0.0.1:9003/ + ProxyPassReverse / http://127.0.0.1:9003/ + diff --git a/tools/apache-hosts/nas-naswii-dls1-conntest.nintendowifi.net.conf b/tools/apache-hosts/nas-naswii-conntest.nintendowifi.net.conf similarity index 82% rename from tools/apache-hosts/nas-naswii-dls1-conntest.nintendowifi.net.conf rename to tools/apache-hosts/nas-naswii-conntest.nintendowifi.net.conf index f7f5537..94da24c 100644 --- a/tools/apache-hosts/nas-naswii-dls1-conntest.nintendowifi.net.conf +++ b/tools/apache-hosts/nas-naswii-conntest.nintendowifi.net.conf @@ -4,8 +4,6 @@ ServerAlias "naswii.nintendowifi.net, naswii.nintendowifi.net" ServerAlias "nas.nintendowifi.net" ServerAlias "nas.nintendowifi.net, nas.nintendowifi.net" - ServerAlias "dls1.nintendowifi.net" - ServerAlias "dls1.nintendowifi.net, dls1.nintendowifi.net" ServerAlias "conntest.nintendowifi.net" ServerAlias "conntest.nintendowifi.net, conntest.nintendowifi.net" ProxyPreserveHost On