mirror of
https://github.com/barronwaffles/dwc_network_server_emulator.git
synced 2026-04-26 00:57:39 -05:00
Added some exception catching for debugging
This commit is contained in:
parent
7ff0467d2a
commit
5a2bca3a57
|
|
@ -1,5 +1,6 @@
|
||||||
import logging
|
import logging
|
||||||
import time
|
import time
|
||||||
|
import traceback
|
||||||
|
|
||||||
from twisted.internet.protocol import Factory
|
from twisted.internet.protocol import Factory
|
||||||
from twisted.internet.endpoints import serverFromString
|
from twisted.internet.endpoints import serverFromString
|
||||||
|
|
@ -75,52 +76,58 @@ class Gamestats(LineReceiver):
|
||||||
logger.log(level, "[%s:%d | %s | %s] %s", self.address.host, self.address.port, self.session, self.gameid, message)
|
logger.log(level, "[%s:%d | %s | %s] %s", self.address.host, self.address.port, self.session, self.gameid, message)
|
||||||
|
|
||||||
def connectionMade(self):
|
def connectionMade(self):
|
||||||
self.log(logging.INFO, "Received connection from %s:%d" % (self.address.host, self.address.port))
|
try:
|
||||||
|
self.log(logging.INFO, "Received connection from %s:%d" % (self.address.host, self.address.port))
|
||||||
|
|
||||||
# Generate a random challenge string
|
# Generate a random challenge string
|
||||||
self.challenge = utils.generate_random_str(10, "ABCDEFGHIJKLMNOPQRSTUVWXYZ")
|
self.challenge = utils.generate_random_str(10, "ABCDEFGHIJKLMNOPQRSTUVWXYZ")
|
||||||
|
|
||||||
# The first command sent to the client is always a login challenge containing the server challenge key.
|
# The first command sent to the client is always a login challenge containing the server challenge key.
|
||||||
msg = gs_query.create_gamespy_message([
|
msg = gs_query.create_gamespy_message([
|
||||||
('__cmd__', "lc"),
|
('__cmd__', "lc"),
|
||||||
('__cmd_val__', "1"),
|
('__cmd_val__', "1"),
|
||||||
('challenge', self.challenge),
|
('challenge', self.challenge),
|
||||||
('id', "1"),
|
('id', "1"),
|
||||||
])
|
])
|
||||||
|
|
||||||
self.log(logging.DEBUG, "SENDING: '%s'..." % msg)
|
self.log(logging.DEBUG, "SENDING: '%s'..." % msg)
|
||||||
|
|
||||||
msg = self.crypt(msg)
|
msg = self.crypt(msg)
|
||||||
self.transport.write(bytes(msg))
|
self.transport.write(bytes(msg))
|
||||||
|
except:
|
||||||
|
self.log(logging.ERROR, "Unknown exception: %s" % traceback.format_exc())
|
||||||
|
|
||||||
def connectionLost(self, reason):
|
def connectionLost(self, reason):
|
||||||
return
|
return
|
||||||
|
|
||||||
def rawDataReceived(self, data):
|
def rawDataReceived(self, data):
|
||||||
# Decrypt packet
|
try:
|
||||||
msg = self.remaining_message + str(self.crypt(data))
|
# Decrypt packet
|
||||||
self.data = msg
|
msg = self.remaining_message + str(self.crypt(data))
|
||||||
|
self.data = msg
|
||||||
|
|
||||||
commands, self.remaining_message = gs_query.parse_gamespy_message(msg)
|
commands, self.remaining_message = gs_query.parse_gamespy_message(msg)
|
||||||
#logger.log(logging.DEBUG, "STATS RESPONSE: %s" % msg)
|
#logger.log(logging.DEBUG, "STATS RESPONSE: %s" % msg)
|
||||||
|
|
||||||
cmds = {
|
cmds = {
|
||||||
"auth": self.perform_auth,
|
"auth": self.perform_auth,
|
||||||
"authp": self.perform_authp,
|
"authp": self.perform_authp,
|
||||||
"ka": self.perform_ka,
|
"ka": self.perform_ka,
|
||||||
"setpd": self.perform_setpd,
|
"setpd": self.perform_setpd,
|
||||||
"getpd": self.perform_getpd,
|
"getpd": self.perform_getpd,
|
||||||
"newgame": self.perform_newgame,
|
"newgame": self.perform_newgame,
|
||||||
"updgame": self.perform_updgame,
|
"updgame": self.perform_updgame,
|
||||||
}
|
}
|
||||||
|
|
||||||
def cmd_err(data_parsed):
|
def cmd_err(data_parsed):
|
||||||
logger.log(logging.DEBUG, "Found unknown command, don't know how to handle '%s'.", data_parsed['__cmd__'])
|
logger.log(logging.DEBUG, "Found unknown command, don't know how to handle '%s'.", data_parsed['__cmd__'])
|
||||||
|
|
||||||
for data_parsed in commands:
|
for data_parsed in commands:
|
||||||
print(data_parsed)
|
print(data_parsed)
|
||||||
|
|
||||||
cmds.get(data_parsed['__cmd__'], cmd_err)(data_parsed)
|
cmds.get(data_parsed['__cmd__'], cmd_err)(data_parsed)
|
||||||
|
except:
|
||||||
|
self.log(logging.ERROR, "Unknown exception: %s" % traceback.format_exc())
|
||||||
|
|
||||||
def perform_auth(self, data_parsed):
|
def perform_auth(self, data_parsed):
|
||||||
self.log(logging.DEBUG, "Parsing 'auth'...")
|
self.log(logging.DEBUG, "Parsing 'auth'...")
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ import time
|
||||||
import Queue
|
import Queue
|
||||||
import gamespy.gs_utility as gs_utils
|
import gamespy.gs_utility as gs_utils
|
||||||
import other.utils as utils
|
import other.utils as utils
|
||||||
|
import traceback
|
||||||
|
|
||||||
from multiprocessing.managers import BaseManager
|
from multiprocessing.managers import BaseManager
|
||||||
|
|
||||||
|
|
@ -43,21 +44,24 @@ class GameSpyNatNegServer(object):
|
||||||
self.server_manager.connect()
|
self.server_manager.connect()
|
||||||
|
|
||||||
def start(self):
|
def start(self):
|
||||||
# Start natneg server
|
try:
|
||||||
address = ('0.0.0.0', 27901) # accessible to outside connections (use this if you don't know what you're doing)
|
# Start natneg server
|
||||||
|
address = ('0.0.0.0', 27901) # accessible to outside connections (use this if you don't know what you're doing)
|
||||||
|
|
||||||
self.socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
self.socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||||
self.socket.bind(address)
|
self.socket.bind(address)
|
||||||
|
|
||||||
self.write_queue = Queue.Queue();
|
self.write_queue = Queue.Queue();
|
||||||
|
|
||||||
logger.log(logging.INFO, "Server is now listening on %s:%s..." % (address[0], address[1]))
|
logger.log(logging.INFO, "Server is now listening on %s:%s..." % (address[0], address[1]))
|
||||||
threading.Thread(target=self.write_queue_worker).start()
|
threading.Thread(target=self.write_queue_worker).start()
|
||||||
|
|
||||||
while 1:
|
while 1:
|
||||||
recv_data, addr = self.socket.recvfrom(2048)
|
recv_data, addr = self.socket.recvfrom(2048)
|
||||||
|
|
||||||
self.handle_packet(recv_data, addr)
|
self.handle_packet(recv_data, addr)
|
||||||
|
except:
|
||||||
|
logger.log(logging.ERROR, "Unknown exception: %s" % traceback.format_exc())
|
||||||
|
|
||||||
def write_queue_send(self, data, address):
|
def write_queue_send(self, data, address):
|
||||||
time.sleep(0.05)
|
time.sleep(0.05)
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import logging
|
import logging
|
||||||
|
import traceback
|
||||||
|
|
||||||
from twisted.internet.protocol import Factory
|
from twisted.internet.protocol import Factory
|
||||||
from twisted.internet.endpoints import serverFromString
|
from twisted.internet.endpoints import serverFromString
|
||||||
|
|
@ -57,18 +58,21 @@ class PlayerSearch(LineReceiver):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def rawDataReceived(self, data):
|
def rawDataReceived(self, data):
|
||||||
logger.log(logging.DEBUG, "SEARCH RESPONSE: %s" % data)
|
try:
|
||||||
|
logger.log(logging.DEBUG, "SEARCH RESPONSE: %s" % data)
|
||||||
|
|
||||||
data = self.leftover + data
|
data = self.leftover + data
|
||||||
commands, self.leftover = gs_query.parse_gamespy_message(data)
|
commands, self.leftover = gs_query.parse_gamespy_message(data)
|
||||||
|
|
||||||
for data_parsed in commands:
|
for data_parsed in commands:
|
||||||
print data_parsed
|
print data_parsed
|
||||||
|
|
||||||
if data_parsed['__cmd__'] == "otherslist":
|
if data_parsed['__cmd__'] == "otherslist":
|
||||||
self.perform_otherslist(data_parsed)
|
self.perform_otherslist(data_parsed)
|
||||||
else:
|
else:
|
||||||
logger.log(logging.DEBUG, "Found unknown search command, don't know how to handle '%s'." % data_parsed['__cmd__'])
|
logger.log(logging.DEBUG, "Found unknown search command, don't know how to handle '%s'." % data_parsed['__cmd__'])
|
||||||
|
except:
|
||||||
|
logger.log(logging.ERROR, "Unknown exception: %s" % traceback.format_exc())
|
||||||
|
|
||||||
def perform_otherslist(self, data_parsed):
|
def perform_otherslist(self, data_parsed):
|
||||||
# Reference: http://wiki.tockdom.com/wiki/MKWii_Network_Protocol/Server/gpsp.gs.nintendowifi.net
|
# Reference: http://wiki.tockdom.com/wiki/MKWii_Network_Protocol/Server/gpsp.gs.nintendowifi.net
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
import logging
|
import logging
|
||||||
import time
|
import time
|
||||||
|
import traceback
|
||||||
|
|
||||||
from twisted.internet.protocol import Factory
|
from twisted.internet.protocol import Factory
|
||||||
from twisted.internet.endpoints import serverFromString
|
from twisted.internet.endpoints import serverFromString
|
||||||
|
|
@ -89,79 +90,88 @@ class PlayerSession(LineReceiver):
|
||||||
return ipaddress
|
return ipaddress
|
||||||
|
|
||||||
def connectionMade(self):
|
def connectionMade(self):
|
||||||
self.transport.setTcpKeepAlive(1)
|
try:
|
||||||
|
self.transport.setTcpKeepAlive(1)
|
||||||
|
|
||||||
self.log(logging.INFO, "Received connection from %s:%d" % (self.address.host, self.address.port))
|
self.log(logging.INFO, "Received connection from %s:%d" % (self.address.host, self.address.port))
|
||||||
|
|
||||||
# Create new session id
|
# Create new session id
|
||||||
self.session = ""
|
self.session = ""
|
||||||
|
|
||||||
# Generate a random challenge string
|
# Generate a random challenge string
|
||||||
self.challenge = utils.generate_random_str(10, "ABCDEFGHIJKLMNOPQRSTUVWXYZ")
|
self.challenge = utils.generate_random_str(10, "ABCDEFGHIJKLMNOPQRSTUVWXYZ")
|
||||||
|
|
||||||
# The first command sent to the client is always a login challenge containing the server challenge key.
|
# The first command sent to the client is always a login challenge containing the server challenge key.
|
||||||
msg = gs_query.create_gamespy_message([
|
msg = gs_query.create_gamespy_message([
|
||||||
('__cmd__', "lc"),
|
('__cmd__', "lc"),
|
||||||
('__cmd_val__', "1"),
|
('__cmd_val__', "1"),
|
||||||
('challenge', self.challenge),
|
('challenge', self.challenge),
|
||||||
('id', "1"),
|
('id', "1"),
|
||||||
])
|
])
|
||||||
|
|
||||||
self.log(logging.DEBUG, "SENDING: '%s'..." % msg)
|
self.log(logging.DEBUG, "SENDING: '%s'..." % msg)
|
||||||
self.transport.write(bytes(msg))
|
self.transport.write(bytes(msg))
|
||||||
|
except:
|
||||||
|
self.log(logging.ERROR, "Unknown exception: %s" % traceback.format_exc())
|
||||||
|
|
||||||
def connectionLost(self, reason):
|
def connectionLost(self, reason):
|
||||||
self.log(logging.INFO, "Client disconnected")
|
try:
|
||||||
|
self.log(logging.INFO, "Client disconnected")
|
||||||
|
|
||||||
self.status = "0"
|
self.status = "0"
|
||||||
self.statstring = "Offline"
|
self.statstring = "Offline"
|
||||||
self.locstring = ""
|
self.locstring = ""
|
||||||
self.send_status_to_friends()
|
self.send_status_to_friends()
|
||||||
|
|
||||||
if self.profileid in self.sessions:
|
if self.profileid in self.sessions:
|
||||||
del self.sessions[self.profileid]
|
del self.sessions[self.profileid]
|
||||||
|
|
||||||
self.db.delete_session(self.session)
|
self.db.delete_session(self.session)
|
||||||
self.log(logging.INFO, "Deleted session " + self.session)
|
self.log(logging.INFO, "Deleted session " + self.session)
|
||||||
|
except:
|
||||||
|
self.log(logging.ERROR, "Unknown exception: %s" % traceback.format_exc())
|
||||||
|
|
||||||
def rawDataReceived(self, data):
|
def rawDataReceived(self, data):
|
||||||
self.log(logging.DEBUG, "RESPONSE: '%s'..." % data)
|
try:
|
||||||
|
self.log(logging.DEBUG, "RESPONSE: '%s'..." % data)
|
||||||
|
|
||||||
# In the case where command string is too big to fit into one read, any parts that could not be successfully
|
# In the case where command string is too big to fit into one read, any parts that could not be successfully
|
||||||
# parsed are stored in the variable remaining_message. On the next rawDataReceived command, the remaining
|
# parsed are stored in the variable remaining_message. On the next rawDataReceived command, the remaining
|
||||||
# message and the data are combined to create a full command.
|
# message and the data are combined to create a full command.
|
||||||
data = self.remaining_message + data
|
data = self.remaining_message + data
|
||||||
|
|
||||||
# Check to make sure the data buffer starts with a valid command.
|
# Check to make sure the data buffer starts with a valid command.
|
||||||
if len(data) > 0 and data[0] != '\\':
|
if len(data) > 0 and data[0] != '\\':
|
||||||
# There is data in the buffer but it doesn't start with a \ so there's no chance of it being valid.
|
# There is data in the buffer but it doesn't start with a \ so there's no chance of it being valid.
|
||||||
# Look for the first instance of \final\ and remove everything before it.
|
# Look for the first instance of \final\ and remove everything before it.
|
||||||
# If \final\ is not in the command string then ignore it.
|
# If \final\ is not in the command string then ignore it.
|
||||||
final = "\\final\\"
|
final = "\\final\\"
|
||||||
data = data[data.index(final) + len(final):] if final in data else ""
|
data = data[data.index(final) + len(final):] if final in data else ""
|
||||||
|
|
||||||
commands, self.remaining_message = gs_query.parse_gamespy_message(data)
|
commands, self.remaining_message = gs_query.parse_gamespy_message(data)
|
||||||
|
|
||||||
cmds = {
|
cmds = {
|
||||||
"login": self.perform_login,
|
"login": self.perform_login,
|
||||||
"logout": self.perform_logout,
|
"logout": self.perform_logout,
|
||||||
"getprofile": self.perform_getprofile,
|
"getprofile": self.perform_getprofile,
|
||||||
"updatepro": self.perform_updatepro,
|
"updatepro": self.perform_updatepro,
|
||||||
"ka": self.perform_ka,
|
"ka": self.perform_ka,
|
||||||
"status": self.perform_status,
|
"status": self.perform_status,
|
||||||
"bm": self.perform_bm,
|
"bm": self.perform_bm,
|
||||||
"addbuddy": self.perform_addbuddy,
|
"addbuddy": self.perform_addbuddy,
|
||||||
"delbuddy": self.perform_delbuddy,
|
"delbuddy": self.perform_delbuddy,
|
||||||
"authadd": self.perform_authadd,
|
"authadd": self.perform_authadd,
|
||||||
}
|
}
|
||||||
def cmd_err(data_parsed):
|
def cmd_err(data_parsed):
|
||||||
# Maybe write unknown commands to a separate file later so new data can be collected more easily?
|
# Maybe write unknown commands to a separate file later so new data can be collected more easily?
|
||||||
self.log(logging.ERROR, "Found unknown command, don't know how to handle '%s'." % data_parsed['__cmd__'])
|
self.log(logging.ERROR, "Found unknown command, don't know how to handle '%s'." % data_parsed['__cmd__'])
|
||||||
|
|
||||||
for data_parsed in commands:
|
for data_parsed in commands:
|
||||||
#self.log(-1, data_parsed)
|
#self.log(-1, data_parsed)
|
||||||
self.log(logging.DEBUG, data_parsed)
|
self.log(logging.DEBUG, data_parsed)
|
||||||
cmds.get(data_parsed['__cmd__'], cmd_err)(data_parsed)
|
cmds.get(data_parsed['__cmd__'], cmd_err)(data_parsed)
|
||||||
|
except:
|
||||||
|
self.log(logging.ERROR, "Unknown exception: %s" % traceback.format_exc())
|
||||||
|
|
||||||
def perform_login(self, data_parsed):
|
def perform_login(self, data_parsed):
|
||||||
authtoken_parsed = gs_utils.parse_authtoken(data_parsed['authtoken'], self.db)
|
authtoken_parsed = gs_utils.parse_authtoken(data_parsed['authtoken'], self.db)
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ import threading
|
||||||
import time
|
import time
|
||||||
import ctypes
|
import ctypes
|
||||||
import Queue
|
import Queue
|
||||||
|
import traceback
|
||||||
|
|
||||||
from multiprocessing.managers import BaseManager
|
from multiprocessing.managers import BaseManager
|
||||||
|
|
||||||
|
|
@ -60,38 +61,41 @@ class GameSpyQRServer(object):
|
||||||
logger.log(level, "[%s:%d] %s", address[0], address[1], message)
|
logger.log(level, "[%s:%d] %s", address[0], address[1], message)
|
||||||
|
|
||||||
def start(self):
|
def start(self):
|
||||||
manager_address = ("127.0.0.1", 27500)
|
try:
|
||||||
manager_password = ""
|
manager_address = ("127.0.0.1", 27500)
|
||||||
|
manager_password = ""
|
||||||
|
|
||||||
self.server_manager = GameSpyServerDatabase(address = manager_address, authkey= manager_password)
|
self.server_manager = GameSpyServerDatabase(address = manager_address, authkey= manager_password)
|
||||||
self.server_manager.connect()
|
self.server_manager.connect()
|
||||||
|
|
||||||
# Start QR server
|
# Start QR server
|
||||||
address = ('0.0.0.0', 27900) # accessible to outside connections (use this if you don't know what you're doing)
|
address = ('0.0.0.0', 27900) # accessible to outside connections (use this if you don't know what you're doing)
|
||||||
|
|
||||||
self.socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
self.socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||||
self.socket.bind(address)
|
self.socket.bind(address)
|
||||||
self.socket.setblocking(0)
|
self.socket.setblocking(0)
|
||||||
|
|
||||||
logger.log(logging.INFO, "Server is now listening on %s:%s..." % (address[0], address[1]))
|
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.
|
# 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 = GameSpyServerBrowserServer(self)
|
||||||
server_browser_server_thread = threading.Thread(target=server_browser_server.start)
|
server_browser_server_thread = threading.Thread(target=server_browser_server.start)
|
||||||
server_browser_server_thread.start()
|
server_browser_server_thread.start()
|
||||||
|
|
||||||
self.write_queue = Queue.Queue();
|
self.write_queue = Queue.Queue()
|
||||||
self.db = gs_database.GamespyDatabase()
|
self.db = gs_database.GamespyDatabase()
|
||||||
threading.Thread(target=self.write_queue_worker).start()
|
threading.Thread(target=self.write_queue_worker).start()
|
||||||
|
|
||||||
while 1:
|
while 1:
|
||||||
ready = select.select([self.socket], [], [], 15)
|
ready = select.select([self.socket], [], [], 15)
|
||||||
|
|
||||||
if ready[0]:
|
if ready[0]:
|
||||||
recv_data, address = self.socket.recvfrom(2048)
|
recv_data, address = self.socket.recvfrom(2048)
|
||||||
self.handle_packet(self.socket, recv_data, address)
|
self.handle_packet(self.socket, recv_data, address)
|
||||||
|
|
||||||
self.keepalive_check()
|
self.keepalive_check()
|
||||||
|
except:
|
||||||
|
logger.log(logging.ERROR, "Unknown exception: %s" % traceback.format_exc())
|
||||||
|
|
||||||
def write_queue_send(self, data, address):
|
def write_queue_send(self, data, address):
|
||||||
time.sleep(0.05)
|
time.sleep(0.05)
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
import logging
|
import logging
|
||||||
import socket
|
import socket
|
||||||
import ctypes
|
import ctypes
|
||||||
|
import traceback
|
||||||
|
|
||||||
from twisted.internet.protocol import Factory
|
from twisted.internet.protocol import Factory
|
||||||
from twisted.internet.endpoints import serverFromString
|
from twisted.internet.endpoints import serverFromString
|
||||||
|
|
@ -97,143 +98,146 @@ class Session(LineReceiver):
|
||||||
logger.log(level, "[%s:%d] %s", self.address.host, self.address.port,message)
|
logger.log(level, "[%s:%d] %s", self.address.host, self.address.port,message)
|
||||||
|
|
||||||
def rawDataReceived(self, data):
|
def rawDataReceived(self, data):
|
||||||
# First 2 bytes are the packet size.
|
try:
|
||||||
#
|
# First 2 bytes are the packet size.
|
||||||
# Third byte is the command byte.
|
#
|
||||||
# According to Openspy-Core:
|
# Third byte is the command byte.
|
||||||
# 0x00 - Server list request
|
# According to Openspy-Core:
|
||||||
# 0x01 - Server info request
|
# 0x00 - Server list request
|
||||||
# 0x02 - Send message request
|
# 0x01 - Server info request
|
||||||
# 0x03 - Keep alive reply
|
# 0x02 - Send message request
|
||||||
# 0x04 - Map loop request (?)
|
# 0x03 - Keep alive reply
|
||||||
# 0x05 - Player search request
|
# 0x04 - Map loop request (?)
|
||||||
#
|
# 0x05 - Player search request
|
||||||
# For Tetris DS, at the very least 0x00 and 0x02 need to be implemented.
|
#
|
||||||
if self.forward_to_client:
|
# For Tetris DS, at the very least 0x00 and 0x02 need to be implemented.
|
||||||
if self.forward_packet == None:
|
if self.forward_to_client:
|
||||||
self.forward_packet = data
|
if self.forward_packet == None:
|
||||||
|
self.forward_packet = data
|
||||||
|
else:
|
||||||
|
self.forward_packet += data
|
||||||
|
|
||||||
|
if self.header_length + len(self.forward_packet) >= self.expected_packet_length:
|
||||||
|
# Is it possible that multiple packets will need to be waited for?
|
||||||
|
# Is it possible that more data will be in the last packet than expected?
|
||||||
|
self.forward_data_to_client(self.forward_packet, self.forward_client)
|
||||||
|
|
||||||
|
self.forward_to_client = False
|
||||||
|
self.forward_client = None
|
||||||
|
self.header_length = 0
|
||||||
|
self.expected_packet_length = 0
|
||||||
|
self.forward_packet = None
|
||||||
|
return
|
||||||
|
|
||||||
|
if data[2] == '\x00': # Server list request
|
||||||
|
self.log(logging.DEBUG, "Received server list request from %s:%s..." % (self.address.host, self.address.port))
|
||||||
|
|
||||||
|
# This code is so... not python. The C programmer in me is coming out strong.
|
||||||
|
# TODO: Rewrite this section later?
|
||||||
|
idx = 3
|
||||||
|
list_version = ord(data[idx])
|
||||||
|
idx += 1
|
||||||
|
encoding_version = ord(data[idx])
|
||||||
|
idx += 1
|
||||||
|
game_version = utils.get_int(data, idx)
|
||||||
|
idx += 4
|
||||||
|
|
||||||
|
query_game = utils.get_string(data, idx)
|
||||||
|
idx += len(query_game) + 1
|
||||||
|
game_name = utils.get_string(data, idx)
|
||||||
|
idx += len(game_name) + 1
|
||||||
|
|
||||||
|
challenge = data[idx:idx+8]
|
||||||
|
idx += 8
|
||||||
|
|
||||||
|
filter = utils.get_string(data, idx)
|
||||||
|
idx += len(filter) + 1
|
||||||
|
fields = utils.get_string(data, idx)
|
||||||
|
idx += len(fields) + 1
|
||||||
|
|
||||||
|
options = utils.get_int_be(data, idx)
|
||||||
|
idx += 4
|
||||||
|
|
||||||
|
source_ip = 0
|
||||||
|
max_servers = 0
|
||||||
|
|
||||||
|
NO_SERVER_LIST = 0x02
|
||||||
|
ALTERNATE_SOURCE_IP = 0x08
|
||||||
|
LIMIT_RESULT_COUNT = 0x80
|
||||||
|
|
||||||
|
send_ip = False
|
||||||
|
if (options & LIMIT_RESULT_COUNT):
|
||||||
|
max_servers = utils.get_int(data, idx)
|
||||||
|
elif (options & ALTERNATE_SOURCE_IP):
|
||||||
|
source_ip = utils.get_int(data, idx)
|
||||||
|
elif (options & NO_SERVER_LIST):
|
||||||
|
send_ip = True
|
||||||
|
|
||||||
|
if '\\' in fields:
|
||||||
|
fields = [x for x in fields.split('\\') if x and not x.isspace()]
|
||||||
|
|
||||||
|
#print "%02x %02x %08x" % (list_version, encoding_version, game_version)
|
||||||
|
#print "%s" % query_game
|
||||||
|
#print "%s" % game_name
|
||||||
|
#print "%s" % challenge
|
||||||
|
#print "%s" % filter
|
||||||
|
#print "%s" % fields
|
||||||
|
|
||||||
|
#print "%08x" % options
|
||||||
|
#print "%d %08x" % (max_servers, source_ip)
|
||||||
|
|
||||||
|
self.log(logging.DEBUG, "list version: %02x / encoding version: %02x / game version: %08x / query game: %s / game name: %s / challenge: %s / filter: %s / fields: %s / options: %08x / max servers: %d / source ip: %08x" % (list_version, encoding_version, game_version, query_game, game_name, challenge, filter, fields, options, max_servers, source_ip))
|
||||||
|
|
||||||
|
# Requesting ip and port of client, not server
|
||||||
|
if filter == "" or fields == "" or send_ip == True:
|
||||||
|
output = bytearray([int(x) for x in self.address.host.split('.')])
|
||||||
|
output += utils.get_bytes_from_short_be(6500) # Does this ever change?
|
||||||
|
|
||||||
|
enc = gs_utils.EncTypeX()
|
||||||
|
output_enc = enc.encrypt(self.secret_key_list[game_name], challenge, output)
|
||||||
|
|
||||||
|
self.transport.write(bytes(output_enc))
|
||||||
|
|
||||||
|
self.log(logging.DEBUG, "Responding with own IP and game port...")
|
||||||
|
self.log(logging.DEBUG, utils.pretty_print_hex(output))
|
||||||
|
else:
|
||||||
|
self.find_server(query_game, filter, fields, max_servers, game_name, challenge)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
elif data[2] == '\x02': # Send message request
|
||||||
|
packet_len = utils.get_short_be(data, 0)
|
||||||
|
dest_addr = '.'.join(["%d" % ord(x) for x in data[3:7]])
|
||||||
|
dest_port = utils.get_short_be(data, 7) # What's the pythonic way to do this? unpack?
|
||||||
|
dest = (dest_addr, dest_port)
|
||||||
|
|
||||||
|
self.log(logging.DEBUG, "Received send message request from %s:%s to %s:%d... expecting %d byte packet." % (self.address.host, self.address.port, dest_addr, dest_port, packet_len))
|
||||||
|
self.log(logging.DEBUG, utils.pretty_print_hex(bytearray(data)))
|
||||||
|
|
||||||
|
if packet_len == len(data):
|
||||||
|
# Contains entire packet, send immediately.
|
||||||
|
self.forward_data_to_client(data[3:], dest)
|
||||||
|
|
||||||
|
self.forward_to_client = False
|
||||||
|
self.forward_client = None
|
||||||
|
self.header_length = 0
|
||||||
|
self.expected_packet_length = 0
|
||||||
|
self.forward_packet = None
|
||||||
|
else:
|
||||||
|
self.forward_to_client = True
|
||||||
|
self.forward_client = dest
|
||||||
|
self.header_length = len(data)
|
||||||
|
self.expected_packet_length = packet_len
|
||||||
|
|
||||||
|
elif data[2] == '\x03': # Keep alive reply
|
||||||
|
self.log(logging.DEBUG, "Received keep alive from %s:%s..." % (self.address.host, self.address.port))
|
||||||
|
|
||||||
else:
|
else:
|
||||||
self.forward_packet += data
|
self.log(logging.DEBUG, "Received unknown command (%02x) from %s:%s..." % (ord(data[2]), self.address.host, self.address.port))
|
||||||
|
self.log(logging.DEBUG, utils.pretty_print_hex(bytearray(data)))
|
||||||
if self.header_length + len(self.forward_packet) >= self.expected_packet_length:
|
self.log(logging.DEBUG, utils.pretty_print_hex(data))
|
||||||
# Is it possible that multiple packets will need to be waited for?
|
except:
|
||||||
# Is it possible that more data will be in the last packet than expected?
|
self.log(logging.ERROR, "Unknown exception: %s" % traceback.format_exc())
|
||||||
self.forward_data_to_client(self.forward_packet, self.forward_client)
|
|
||||||
|
|
||||||
self.forward_to_client = False
|
|
||||||
self.forward_client = None
|
|
||||||
self.header_length = 0
|
|
||||||
self.expected_packet_length = 0
|
|
||||||
self.forward_packet = None
|
|
||||||
return
|
|
||||||
|
|
||||||
if data[2] == '\x00': # Server list request
|
|
||||||
self.log(logging.DEBUG, "Received server list request from %s:%s..." % (self.address.host, self.address.port))
|
|
||||||
|
|
||||||
# This code is so... not python. The C programmer in me is coming out strong.
|
|
||||||
# TODO: Rewrite this section later?
|
|
||||||
idx = 3
|
|
||||||
list_version = ord(data[idx])
|
|
||||||
idx += 1
|
|
||||||
encoding_version = ord(data[idx])
|
|
||||||
idx += 1
|
|
||||||
game_version = utils.get_int(data, idx)
|
|
||||||
idx += 4
|
|
||||||
|
|
||||||
query_game = utils.get_string(data, idx)
|
|
||||||
idx += len(query_game) + 1
|
|
||||||
game_name = utils.get_string(data, idx)
|
|
||||||
idx += len(game_name) + 1
|
|
||||||
|
|
||||||
challenge = data[idx:idx+8]
|
|
||||||
idx += 8
|
|
||||||
|
|
||||||
filter = utils.get_string(data, idx)
|
|
||||||
idx += len(filter) + 1
|
|
||||||
fields = utils.get_string(data, idx)
|
|
||||||
idx += len(fields) + 1
|
|
||||||
|
|
||||||
options = utils.get_int_be(data, idx)
|
|
||||||
idx += 4
|
|
||||||
|
|
||||||
source_ip = 0
|
|
||||||
max_servers = 0
|
|
||||||
|
|
||||||
NO_SERVER_LIST = 0x02
|
|
||||||
ALTERNATE_SOURCE_IP = 0x08
|
|
||||||
LIMIT_RESULT_COUNT = 0x80
|
|
||||||
|
|
||||||
send_ip = False
|
|
||||||
if (options & LIMIT_RESULT_COUNT):
|
|
||||||
max_servers = utils.get_int(data, idx)
|
|
||||||
elif (options & ALTERNATE_SOURCE_IP):
|
|
||||||
source_ip = utils.get_int(data, idx)
|
|
||||||
elif (options & NO_SERVER_LIST):
|
|
||||||
send_ip = True
|
|
||||||
|
|
||||||
if '\\' in fields:
|
|
||||||
fields = [x for x in fields.split('\\') if x and not x.isspace()]
|
|
||||||
|
|
||||||
#print "%02x %02x %08x" % (list_version, encoding_version, game_version)
|
|
||||||
#print "%s" % query_game
|
|
||||||
#print "%s" % game_name
|
|
||||||
#print "%s" % challenge
|
|
||||||
#print "%s" % filter
|
|
||||||
#print "%s" % fields
|
|
||||||
|
|
||||||
#print "%08x" % options
|
|
||||||
#print "%d %08x" % (max_servers, source_ip)
|
|
||||||
|
|
||||||
self.log(logging.DEBUG, "list version: %02x / encoding version: %02x / game version: %08x / query game: %s / game name: %s / challenge: %s / filter: %s / fields: %s / options: %08x / max servers: %d / source ip: %08x" % (list_version, encoding_version, game_version, query_game, game_name, challenge, filter, fields, options, max_servers, source_ip))
|
|
||||||
|
|
||||||
# Requesting ip and port of client, not server
|
|
||||||
if filter == "" or fields == "" or send_ip == True:
|
|
||||||
output = bytearray([int(x) for x in self.address.host.split('.')])
|
|
||||||
output += utils.get_bytes_from_short_be(6500) # Does this ever change?
|
|
||||||
|
|
||||||
enc = gs_utils.EncTypeX()
|
|
||||||
output_enc = enc.encrypt(self.secret_key_list[game_name], challenge, output)
|
|
||||||
|
|
||||||
self.transport.write(bytes(output_enc))
|
|
||||||
|
|
||||||
self.log(logging.DEBUG, "Responding with own IP and game port...")
|
|
||||||
self.log(logging.DEBUG, utils.pretty_print_hex(output))
|
|
||||||
else:
|
|
||||||
self.find_server(query_game, filter, fields, max_servers, game_name, challenge)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
elif data[2] == '\x02': # Send message request
|
|
||||||
packet_len = utils.get_short_be(data, 0)
|
|
||||||
dest_addr = '.'.join(["%d" % ord(x) for x in data[3:7]])
|
|
||||||
dest_port = utils.get_short_be(data, 7) # What's the pythonic way to do this? unpack?
|
|
||||||
dest = (dest_addr, dest_port)
|
|
||||||
|
|
||||||
self.log(logging.DEBUG, "Received send message request from %s:%s to %s:%d... expecting %d byte packet." % (self.address.host, self.address.port, dest_addr, dest_port, packet_len))
|
|
||||||
self.log(logging.DEBUG, utils.pretty_print_hex(bytearray(data)))
|
|
||||||
|
|
||||||
if packet_len == len(data):
|
|
||||||
# Contains entire packet, send immediately.
|
|
||||||
self.forward_data_to_client(data[3:], dest)
|
|
||||||
|
|
||||||
self.forward_to_client = False
|
|
||||||
self.forward_client = None
|
|
||||||
self.header_length = 0
|
|
||||||
self.expected_packet_length = 0
|
|
||||||
self.forward_packet = None
|
|
||||||
else:
|
|
||||||
self.forward_to_client = True
|
|
||||||
self.forward_client = dest
|
|
||||||
self.header_length = len(data)
|
|
||||||
self.expected_packet_length = packet_len
|
|
||||||
|
|
||||||
elif data[2] == '\x03': # Keep alive reply
|
|
||||||
self.log(logging.DEBUG, "Received keep alive from %s:%s..." % (self.address.host, self.address.port))
|
|
||||||
|
|
||||||
else:
|
|
||||||
self.log(logging.DEBUG, "Received unknown command (%02x) from %s:%s..." % (ord(data[2]), self.address.host, self.address.port))
|
|
||||||
self.log(logging.DEBUG, utils.pretty_print_hex(bytearray(data)))
|
|
||||||
self.log(logging.DEBUG, utils.pretty_print_hex(data))
|
|
||||||
|
|
||||||
def get_game_id(self, data):
|
def get_game_id(self, data):
|
||||||
game_id = data[5: -1]
|
game_id = data[5: -1]
|
||||||
|
|
|
||||||
329
nas_server.py
329
nas_server.py
|
|
@ -6,6 +6,7 @@ import urlparse
|
||||||
import BaseHTTPServer
|
import BaseHTTPServer
|
||||||
import os
|
import os
|
||||||
import random
|
import random
|
||||||
|
import traceback
|
||||||
|
|
||||||
import gamespy.gs_database as gs_database
|
import gamespy.gs_database as gs_database
|
||||||
import gamespy.gs_utility as gs_utils
|
import gamespy.gs_utility as gs_utils
|
||||||
|
|
@ -40,208 +41,214 @@ class NasHTTPServerHandler(BaseHTTPServer.BaseHTTPRequestHandler):
|
||||||
return "Nintendo Wii (http)"
|
return "Nintendo Wii (http)"
|
||||||
|
|
||||||
def do_GET(self):
|
def do_GET(self):
|
||||||
# conntest server
|
try:
|
||||||
self.send_response(200)
|
# conntest server
|
||||||
self.send_header("Content-type", "text/html")
|
self.send_response(200)
|
||||||
self.send_header("X-Organization", "Nintendo")
|
self.send_header("Content-type", "text/html")
|
||||||
self.send_header("Server", "BigIP")
|
self.send_header("X-Organization", "Nintendo")
|
||||||
self.end_headers()
|
self.send_header("Server", "BigIP")
|
||||||
self.wfile.write("ok")
|
self.end_headers()
|
||||||
|
self.wfile.write("ok")
|
||||||
|
except:
|
||||||
|
logger.log(logging.ERROR, "Unknown exception: %s" % traceback.format_exc())
|
||||||
|
|
||||||
def do_POST(self):
|
def do_POST(self):
|
||||||
length = int(self.headers['content-length'])
|
try:
|
||||||
post = self.str_to_dict(self.rfile.read(length))
|
length = int(self.headers['content-length'])
|
||||||
ret = ''
|
post = self.str_to_dict(self.rfile.read(length))
|
||||||
|
ret = ''
|
||||||
|
|
||||||
if self.path == "/ac":
|
if self.path == "/ac":
|
||||||
logger.log(logging.DEBUG, "Request to %s from %s", self.path, self.client_address)
|
logger.log(logging.DEBUG, "Request to %s from %s", self.path, self.client_address)
|
||||||
logger.log(logging.DEBUG, post)
|
logger.log(logging.DEBUG, post)
|
||||||
ret = {}
|
ret = {}
|
||||||
ret["datetime"] = time.strftime("%Y%m%d%H%M%S")
|
ret["datetime"] = time.strftime("%Y%m%d%H%M%S")
|
||||||
ret["retry"] = "0"
|
ret["retry"] = "0"
|
||||||
action = post["action"]
|
action = post["action"]
|
||||||
self.send_response(200)
|
self.send_response(200)
|
||||||
self.send_header("Content-type", "text/plain")
|
self.send_header("Content-type", "text/plain")
|
||||||
self.send_header("NODE", "wifiappe1")
|
self.send_header("NODE", "wifiappe1")
|
||||||
|
|
||||||
if action == "acctcreate":
|
if action == "acctcreate":
|
||||||
# TODO: test for duplicate accounts
|
# TODO: test for duplicate accounts
|
||||||
ret["returncd"] = "002"
|
ret["returncd"] = "002"
|
||||||
|
|
||||||
logger.log(logging.DEBUG, "acctcreate response to %s", self.client_address)
|
logger.log(logging.DEBUG, "acctcreate response to %s", self.client_address)
|
||||||
logger.log(logging.DEBUG, ret)
|
logger.log(logging.DEBUG, ret)
|
||||||
|
|
||||||
ret = self.dict_to_str(ret)
|
ret = self.dict_to_str(ret)
|
||||||
|
|
||||||
elif action == "login":
|
elif action == "login":
|
||||||
ret["returncd"] = "001"
|
ret["returncd"] = "001"
|
||||||
ret["locator"] = "gamespy.com"
|
ret["locator"] = "gamespy.com"
|
||||||
challenge = utils.generate_random_str(8)
|
challenge = utils.generate_random_str(8)
|
||||||
ret["challenge"] = challenge
|
ret["challenge"] = challenge
|
||||||
post["challenge"] = challenge
|
post["challenge"] = challenge
|
||||||
authtoken = self.server.db.generate_authtoken(post["userid"], post)
|
authtoken = self.server.db.generate_authtoken(post["userid"], post)
|
||||||
ret["token"] = authtoken
|
ret["token"] = authtoken
|
||||||
|
|
||||||
logger.log(logging.DEBUG, "login response to %s", self.client_address)
|
logger.log(logging.DEBUG, "login response to %s", self.client_address)
|
||||||
logger.log(logging.DEBUG, ret)
|
logger.log(logging.DEBUG, ret)
|
||||||
|
|
||||||
ret = self.dict_to_str(ret)
|
ret = self.dict_to_str(ret)
|
||||||
|
|
||||||
elif action == "SVCLOC" or action == "svcloc": # Get service based on service id number
|
elif action == "SVCLOC" or action == "svcloc": # Get service based on service id number
|
||||||
ret["returncd"] = "007"
|
ret["returncd"] = "007"
|
||||||
ret["statusdata"] = "Y"
|
ret["statusdata"] = "Y"
|
||||||
authtoken = self.server.db.generate_authtoken(post["userid"], post)
|
authtoken = self.server.db.generate_authtoken(post["userid"], post)
|
||||||
|
|
||||||
if 'svc' in post:
|
if 'svc' in post:
|
||||||
if post["svc"] in ("9000", "9001"): # DLC host = 9000
|
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
|
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
|
# 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]
|
ret["svchost"] = ret["svchost"].split(',')[0]
|
||||||
|
|
||||||
if post["svc"] == 9000:
|
if post["svc"] == 9000:
|
||||||
ret["token"] = authtoken
|
ret["token"] = authtoken
|
||||||
else:
|
else:
|
||||||
|
ret["servicetoken"] = authtoken
|
||||||
|
elif post["svc"] == "0000": # Pokemon requests this for some things
|
||||||
ret["servicetoken"] = authtoken
|
ret["servicetoken"] = authtoken
|
||||||
elif post["svc"] == "0000": # Pokemon requests this for some things
|
ret["svchost"] = "n/a"
|
||||||
ret["servicetoken"] = authtoken
|
|
||||||
ret["svchost"] = "n/a"
|
|
||||||
|
|
||||||
logger.log(logging.DEBUG, "svcloc response to %s", self.client_address)
|
logger.log(logging.DEBUG, "svcloc response to %s", self.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, self.client_address)
|
||||||
|
ret = ''
|
||||||
|
|
||||||
|
|
||||||
|
elif self.path == "/pr":
|
||||||
|
logger.log(logging.DEBUG, "Request to %s from %s", self.path, self.client_address)
|
||||||
|
logger.log(logging.DEBUG, post)
|
||||||
|
ret = {}
|
||||||
|
|
||||||
|
words = len(post["words"].split('\t'))
|
||||||
|
wordsret = "0" * words
|
||||||
|
ret["prwords"] = wordsret
|
||||||
|
ret["prwordsA"] = wordsret
|
||||||
|
ret["prwordsC"] = wordsret
|
||||||
|
ret["prwordsE"] = wordsret
|
||||||
|
ret["prwordsJ"] = wordsret
|
||||||
|
ret["prwordsK"] = wordsret
|
||||||
|
ret["prwordsP"] = wordsret
|
||||||
|
ret["returncd"] = "000"
|
||||||
|
ret["datetime"] = time.strftime("%Y%m%d%H%M%S")
|
||||||
|
|
||||||
|
self.send_response(200)
|
||||||
|
self.send_header("Content-type", "text/plain")
|
||||||
|
self.send_header("NODE", "wifiappe1")
|
||||||
|
|
||||||
|
logger.log(logging.DEBUG, "pr response to %s", self.client_address)
|
||||||
logger.log(logging.DEBUG, ret)
|
logger.log(logging.DEBUG, ret)
|
||||||
|
|
||||||
ret = self.dict_to_str(ret)
|
ret = self.dict_to_str(ret)
|
||||||
else:
|
|
||||||
logger.log(logging.WARNING, "Unknown action request %s from %s!", self.path, self.client_address)
|
|
||||||
ret = ''
|
|
||||||
|
|
||||||
|
elif self.path == "/download":
|
||||||
|
logger.log(logging.DEBUG, "Request to %s from %s", self.path, self.client_address)
|
||||||
|
logger.log(logging.DEBUG, post)
|
||||||
|
|
||||||
elif self.path == "/pr":
|
action = post["action"]
|
||||||
logger.log(logging.DEBUG, "Request to %s from %s", self.path, self.client_address)
|
|
||||||
logger.log(logging.DEBUG, post)
|
|
||||||
ret = {}
|
|
||||||
|
|
||||||
words = len(post["words"].split('\t'))
|
ret = ""
|
||||||
wordsret = "0" * words
|
dlcdir = os.path.abspath('dlc')
|
||||||
ret["prwords"] = wordsret
|
dlcpath = os.path.abspath("dlc/" + post["gamecd"])
|
||||||
ret["prwordsA"] = wordsret
|
dlc_contenttype = False
|
||||||
ret["prwordsC"] = wordsret
|
|
||||||
ret["prwordsE"] = wordsret
|
|
||||||
ret["prwordsJ"] = wordsret
|
|
||||||
ret["prwordsK"] = wordsret
|
|
||||||
ret["prwordsP"] = wordsret
|
|
||||||
ret["returncd"] = "000"
|
|
||||||
ret["datetime"] = time.strftime("%Y%m%d%H%M%S")
|
|
||||||
|
|
||||||
self.send_response(200)
|
if os.path.commonprefix([dlcdir, dlcpath]) != dlcdir:
|
||||||
self.send_header("Content-type", "text/plain")
|
logging.log(logging.WARNING, 'Attempted directory traversal attack "%s", cancelling.', dlcpath)
|
||||||
self.send_header("NODE", "wifiappe1")
|
self.send_response(403)
|
||||||
|
return
|
||||||
|
|
||||||
logger.log(logging.DEBUG, "pr response to %s", self.client_address)
|
def safeloadfi(fn, mode='rb'):
|
||||||
logger.log(logging.DEBUG, ret)
|
'''
|
||||||
|
safeloadfi : string -> string
|
||||||
|
|
||||||
ret = self.dict_to_str(ret)
|
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()
|
||||||
|
|
||||||
elif self.path == "/download":
|
if action == "count":
|
||||||
logger.log(logging.DEBUG, "Request to %s from %s", self.path, self.client_address)
|
if post["gamecd"] in gamecodes_return_random_file:
|
||||||
logger.log(logging.DEBUG, post)
|
ret = "1"
|
||||||
|
else:
|
||||||
|
count = 0
|
||||||
|
|
||||||
action = post["action"]
|
if os.path.exists(dlcpath):
|
||||||
|
count = len(os.listdir(dlcpath))
|
||||||
|
|
||||||
ret = ""
|
if os.path.isfile(dlcpath + "/_list.txt"):
|
||||||
dlcdir = os.path.abspath('dlc')
|
attr1 = None
|
||||||
dlcpath = os.path.abspath("dlc/" + post["gamecd"])
|
if "attr1" in post:
|
||||||
dlc_contenttype = False
|
attr1 = post["attr1"]
|
||||||
|
attr2 = None
|
||||||
if os.path.commonprefix([dlcdir, dlcpath]) != dlcdir:
|
if "attr2" in post:
|
||||||
logging.log(logging.WARNING, 'Attempted directory traversal attack "%s", cancelling.', dlcpath)
|
attr2 = post["attr2"]
|
||||||
self.send_response(403)
|
attr3 = None
|
||||||
return
|
if "attr3" in post:
|
||||||
|
attr3 = post["attr3"]
|
||||||
|
|
||||||
def safeloadfi(fn, mode='rb'):
|
dlcfi = safeloadfi("_list.txt")
|
||||||
'''
|
lst = self.filter_list(dlcfi, attr1, attr2, attr3)
|
||||||
safeloadfi : string -> string
|
count = self.get_file_count(lst)
|
||||||
|
|
||||||
Safely load contents of a file, given a filename, and closing the file afterward
|
ret = "%d" % count
|
||||||
'''
|
|
||||||
with open(os.path.join(dlcpath, fn), mode) as fi:
|
|
||||||
return fi.read()
|
|
||||||
|
|
||||||
if action == "count":
|
if action == "list":
|
||||||
if post["gamecd"] in gamecodes_return_random_file:
|
num = int(post["num"])
|
||||||
ret = "1"
|
offset = int(post["offset"])
|
||||||
else:
|
|
||||||
count = 0
|
attr1 = None
|
||||||
|
if "attr1" in post:
|
||||||
|
attr1 = post["attr1"]
|
||||||
|
attr2 = None
|
||||||
|
if "attr2" in post:
|
||||||
|
attr2 = post["attr2"]
|
||||||
|
attr3 = None
|
||||||
|
if "attr3" in post:
|
||||||
|
attr3 = post["attr3"]
|
||||||
|
|
||||||
if os.path.exists(dlcpath):
|
if os.path.exists(dlcpath):
|
||||||
count = len(os.listdir(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")):
|
||||||
|
ret = self.filter_list(safeloadfi("_list.txt"), attr1, attr2, attr3)
|
||||||
|
|
||||||
if os.path.isfile(dlcpath + "/_list.txt"):
|
if post["gamecd"] in gamecodes_return_random_file:
|
||||||
attr1 = None
|
ret = self.filter_list_random_files(ret, 1)
|
||||||
if "attr1" in post:
|
|
||||||
attr1 = post["attr1"]
|
|
||||||
attr2 = None
|
|
||||||
if "attr2" in post:
|
|
||||||
attr2 = post["attr2"]
|
|
||||||
attr3 = None
|
|
||||||
if "attr3" in post:
|
|
||||||
attr3 = post["attr3"]
|
|
||||||
|
|
||||||
dlcfi = safeloadfi("_list.txt")
|
if action == "contents":
|
||||||
lst = self.filter_list(dlcfi, attr1, attr2, attr3)
|
# Get only the base filename just in case there is a path involved somewhere in the filename string.
|
||||||
count = self.get_file_count(lst)
|
dlc_contenttype = True
|
||||||
|
contents = os.path.basename(post["contents"])
|
||||||
|
ret = safeloadfi(contents)
|
||||||
|
|
||||||
ret = "%d" % count
|
self.send_response(200)
|
||||||
|
|
||||||
if action == "list":
|
if dlc_contenttype == True:
|
||||||
num = int(post["num"])
|
self.send_header("Content-type", "application/x-dsdl")
|
||||||
offset = int(post["offset"])
|
self.send_header("Content-Disposition", "attachment; filename=\"" + post["contents"] + "\"")
|
||||||
|
else:
|
||||||
|
self.send_header("Content-type", "text/plain")
|
||||||
|
|
||||||
attr1 = None
|
self.send_header("X-DLS-Host", "http://127.0.0.1/")
|
||||||
if "attr1" in post:
|
|
||||||
attr1 = post["attr1"]
|
|
||||||
attr2 = None
|
|
||||||
if "attr2" in post:
|
|
||||||
attr2 = post["attr2"]
|
|
||||||
attr3 = None
|
|
||||||
if "attr3" in post:
|
|
||||||
attr3 = post["attr3"]
|
|
||||||
|
|
||||||
if os.path.exists(dlcpath):
|
logger.log(logging.DEBUG, "download response to %s", self.client_address)
|
||||||
# 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")):
|
|
||||||
ret = self.filter_list(safeloadfi("_list.txt"), attr1, attr2, attr3)
|
|
||||||
|
|
||||||
if post["gamecd"] in gamecodes_return_random_file:
|
#if dlc_contenttype == False:
|
||||||
ret = self.filter_list_random_files(ret, 1)
|
# logger.log(logging.DEBUG, ret)
|
||||||
|
|
||||||
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:
|
else:
|
||||||
self.send_header("Content-type", "text/plain")
|
logger.log(logging.WARNING, "Unknown path request %s from %s!", self.path, self.client_address)
|
||||||
|
|
||||||
self.send_header("X-DLS-Host", "http://127.0.0.1/")
|
self.send_header("Content-Length", str(len(ret)))
|
||||||
|
self.end_headers()
|
||||||
logger.log(logging.DEBUG, "download response to %s", self.client_address)
|
self.wfile.write(ret)
|
||||||
|
except:
|
||||||
#if dlc_contenttype == False:
|
logger.log(logging.ERROR, "Unknown exception: %s" % traceback.format_exc())
|
||||||
# logger.log(logging.DEBUG, ret)
|
|
||||||
else:
|
|
||||||
logger.log(logging.WARNING, "Unknown path request %s from %s!", self.path, self.client_address)
|
|
||||||
|
|
||||||
self.send_header("Content-Length", str(len(ret)))
|
|
||||||
self.end_headers()
|
|
||||||
self.wfile.write(ret)
|
|
||||||
|
|
||||||
def str_to_dict(self, str):
|
def str_to_dict(self, str):
|
||||||
ret = urlparse.parse_qs(str)
|
ret = urlparse.parse_qs(str)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user