mirror of
https://github.com/barronwaffles/dwc_network_server_emulator.git
synced 2026-09-29 21:36:37 -05:00
Fixed encryption, implemented more QR server stuff
- Fixed the RC4/Base64 encryption method (seems to be more commonly known as "gsmsalg"). - Implemented more of the query and reporting server.
This commit is contained in:
@@ -42,11 +42,12 @@ def rc4_encrypt(_key, _data):
|
||||
return data
|
||||
|
||||
# Tetris DS overlay 10 @ 0216E9B8
|
||||
# Used by the master server to send some data between the client and server
|
||||
# Used by the master server to send some data between the client and server.
|
||||
# This seems to be what Luigi Auriemma calls "Gsmsalg".
|
||||
def prepare_rc4_base64(_key, _data):
|
||||
data = rc4_encrypt(_key, _data)
|
||||
data.append(0)
|
||||
return base64_encode(buffer(data))
|
||||
return base64.b64encode(buffer(data))
|
||||
|
||||
# Parse my custom authtoken generated by the emulated nas.nintendowifi.net/ac
|
||||
def parse_authtoken(authtoken):
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
# Server emulator for *.available.gs.nintendowifi.net and *.master.gs.nintendowifi.net
|
||||
# Query and Reporting: http://docs.poweredbygamespy.com/wiki/Query_and_Reporting_Overview
|
||||
|
||||
# TODO: Refactor into a class
|
||||
|
||||
import socket
|
||||
import gamespy.gs_utility as gs_utils
|
||||
import other.utils as utils
|
||||
@@ -15,6 +19,11 @@ s.bind(address)
|
||||
|
||||
utils.print_log("Server is now listening on %s:%s..." % (address[0], address[1]))
|
||||
|
||||
# Temporarily make these global until everything is made into a client class.
|
||||
server_challenge = ""
|
||||
secretkey = "JJlSi8" # Parse gslist.cfg later
|
||||
sent_challenge = False
|
||||
|
||||
while 1:
|
||||
recv_data, addr = s.recvfrom(2048)
|
||||
|
||||
@@ -22,7 +31,7 @@ while 1:
|
||||
# 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\xfe.
|
||||
# - 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.
|
||||
@@ -37,7 +46,7 @@ while 1:
|
||||
#
|
||||
# CLIENT:
|
||||
# 0x01 - Response (Tetris DS overlay 10 @ 216DCA4)
|
||||
# Sends back base64 of RC4 encrypted string that was gotten from the server's 0x01. Server doesn't respond?
|
||||
# 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:
|
||||
@@ -96,21 +105,87 @@ while 1:
|
||||
#
|
||||
# - \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] == '\x01':
|
||||
utils.print_log("Response received from %s:%s... %s" % (addr[0], addr[1], recv_data[5:]))
|
||||
elif recv_data[0] == '\x03':
|
||||
utils.print_log("Received client state from %s:%s... %s" % (addr[0], addr[1], recv_data[5:]))
|
||||
elif recv_data[0] == '\x07':
|
||||
utils.print_log("Received unknown data from %s:%s... %s" % (addr[0], addr[1], recv_data[5:]))
|
||||
elif recv_data[0] == '\x08':
|
||||
if recv_data[0] == '\x00': # Query
|
||||
utils.print_log("NOT IMPLEMENTED! Received query from %s:%s... %s" % (addr[0], addr[1], recv_data[5:]))
|
||||
|
||||
elif recv_data[0] == '\x01': # Challenge
|
||||
utils.print_log("Received challenge from %s:%s... %s" % (addr[0], addr[1], recv_data[5:]))
|
||||
|
||||
# Prepare the challenge sent from the server to be compared
|
||||
challenge = gs_utils.prepare_rc4_base64(secretkey, server_challenge)
|
||||
|
||||
# Compare challenge
|
||||
client_challenge = recv_data[5:-1]
|
||||
if client_challenge == challenge:
|
||||
# Challenge succeeded
|
||||
sent_challenge = True
|
||||
|
||||
# Handle successful challenge stuff here
|
||||
packet = bytearray([0xfe, 0xfd, 0x0a]) # Send client registered command
|
||||
packet.extend(recv_data[1:5]) # Get the ID
|
||||
s.sendto(packet, addr)
|
||||
utils.print_log("Sent client registered to %s:%s..." % (addr[0], addr[1]))
|
||||
|
||||
elif recv_data[0] == '\x02': # Echo
|
||||
utils.print_log("NOT IMPLEMENTED! Received echo from %s:%s... %s" % (addr[0], addr[1], recv_data[5:]))
|
||||
|
||||
elif recv_data[0] == '\x03': # Heartbeat
|
||||
data = recv_data[5:]
|
||||
utils.print_log("Received heartbeat from %s:%s... %s" % (addr[0], addr[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(len(d) / 2):
|
||||
k[d[i]] = d[i+1]
|
||||
|
||||
# Store k per client
|
||||
|
||||
if sent_challenge == False:
|
||||
addr_hex = ''.join(["%02X" % int(x) for x in addr[0].split('.')])
|
||||
port_hex = "%04X" % int(addr[1])
|
||||
server_challenge = utils.generate_random_str(8) + addr_hex + port_hex
|
||||
|
||||
packet = bytearray([0xfe, 0xfd, 0x01]) # Send challenge command
|
||||
packet.extend(recv_data[1:5]) # Get the ID
|
||||
packet.extend(server_challenge)
|
||||
packet.extend('\x00')
|
||||
|
||||
s.sendto(packet, addr)
|
||||
utils.print_log("Sent challenge to %s:%s..." % (addr[0], addr[1]))
|
||||
|
||||
elif recv_data[0] == '\x04': # Add Error
|
||||
utils.print_log("NOT IMPLEMENTED! Received add error from %s:%s... %s" % (addr[0], addr[1], recv_data[5:]))
|
||||
|
||||
elif recv_data[0] == '\x05': # Echo Response
|
||||
utils.print_log("NOT IMPLEMENTED! Received echo response from %s:%s... %s" % (addr[0], addr[1], recv_data[5:]))
|
||||
|
||||
elif recv_data[0] == '\x06': # Client Message
|
||||
utils.print_log("NOT IMPLEMENTED! Received echo from %s:%s... %s" % (addr[0], addr[1], recv_data[5:]))
|
||||
|
||||
elif recv_data[0] == '\x07': # Client Message Ack
|
||||
utils.print_log("NOT IMPLEMENTED! Received client message ack from %s:%s... %s" % (addr[0], addr[1], recv_data[5:]))
|
||||
|
||||
elif recv_data[0] == '\x08': # Keep Alive
|
||||
utils.print_log("Received keep alive from %s:%s..." % (addr[0], addr[1]))
|
||||
elif recv_data[0] == '\x09':
|
||||
|
||||
elif recv_data[0] == '\x09': # Available
|
||||
# Availability check only sent to *.available.gs.nintendowifi.net
|
||||
utils.print_log("Received availability request for '%s' from %s:%s... %s" % (
|
||||
get_game_id(recv_data), addr[0], addr[1], [elem.encode("hex") for elem in recv_data]))
|
||||
|
||||
s.sendto(bytearray([0xfe, 0xfd, recv_data[0], recv_data[1], recv_data[2], recv_data[3], recv_data[4]]), addr)
|
||||
|
||||
elif recv_data[0] == '\x0a': # Client Registered
|
||||
# Only sent to client, never received?
|
||||
utils.print_log("NOT IMPLEMENTED! Received client registered from %s:%s... %s" % (addr[0], addr[1], recv_data[5:]))
|
||||
|
||||
else:
|
||||
utils.print_log(
|
||||
"Unknown request from %s:%s: %s" % (addr[0], addr[1], [elem.encode("hex") for elem in recv_data]))
|
||||
|
||||
34
server_browser.py
Normal file
34
server_browser.py
Normal file
@@ -0,0 +1,34 @@
|
||||
# I found an open source implemention of this exact server I'm trying to emulate here: https://github.com/sfcspanky/Openspy-Core/blob/master/serverbrowsing/
|
||||
# Use as reference later.
|
||||
|
||||
# Tetris DS won't let you search for a match unless this server exists, so just create an empty server for now.
|
||||
|
||||
import socket
|
||||
import gamespy.gs_utility as gs_utils
|
||||
import other.utils as utils
|
||||
import time
|
||||
|
||||
def get_game_id(data):
|
||||
game_id = data[5: -1]
|
||||
return game_id
|
||||
|
||||
#address = ('127.0.0.1', 28910) # accessible to only the local computer
|
||||
address = ('0.0.0.0', 28910) # accessible to outside connections (use this if you don't know what you're doing)
|
||||
backlog = 10
|
||||
size = 2048
|
||||
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
s.bind(address)
|
||||
s.listen(backlog)
|
||||
|
||||
utils.print_log("Server is now listening on %s:%s..." % (address[0], address[1]))
|
||||
|
||||
while 1:
|
||||
client, address = s.accept()
|
||||
|
||||
utils.print_log("Received connection from %s:%s" % (address[0], address[1]))
|
||||
|
||||
while 1:
|
||||
accept_connection = True
|
||||
data = client.recv(size).rstrip()
|
||||
utils.print_log("RESPONSE: %s" % data)
|
||||
Reference in New Issue
Block a user