def handle_natneg_address_check(nn, recv_data, addr, socket): """Command: 0x0A - NN_ADDRESS_CHECK. Send by the client during connection test. Example: fd fc 1e 66 6a b2 03 0a 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 Description: fd fc 1e 66 6a b2 - NATNEG magic 03 - NATNEG version 0a - NATNEG record type 00 00 00 00 - Session id 01 - Port type (between 0x00 and 0x03) - 60 bytes padding? 00 - Client index (0x00 - Client, 0x01 - Host) 00 - NATNEG result? 00 00 00 00 - NAT type? 00 00 00 00 - NAT mapping scheme? 00 (x50) - Game name? """ client_id = "%02x" % ord(recv_data[13]) logger.log(logging.DEBUG, "Received address check command from %s:%d...", *addr) logger.log(logging.DEBUG, "%s", utils.pretty_print_hex(recv_data)) output = bytearray(recv_data[0:15]) output += utils.get_bytes_from_ip_str(addr[0]) output += utils.get_bytes_from_short(addr[1], True) output += bytearray(recv_data[len(output):]) output[7] = 0x0b # NN_ADDRESS_REPLY nn.write_queue.put((output, addr, socket)) logger.log(logging.DEBUG, "Sent address check response to %s:%d...", *addr) logger.log(logging.DEBUG, "%s", utils.pretty_print_hex(output))
def handle_natneg_init(nn, recv_data, addr, socket): """Command: 0x00 - NN_INIT. Send by the client to initialize the connection. Example: fd fc 1e 66 6a b2 03 00 3d f1 00 71 00 00 01 0a 00 01 e2 00 00 6d 61 72 69 6f 6b 61 72 74 77 69 69 00 Description: fd fc 1e 66 6a b2 - NATNEG magic 03 - NATNEG version 00 - NATNEG record type 3d f1 00 71 - Session id 00 - Port type (between 0x00 and 0x03) 00 - Client index (0x00 - Client, 0x01 - Host) 01 - Use game port 0a 00 01 e2 - Local IP 00 00 - Local port GAME_NAME 00 - Game name """ logger.log(logging.DEBUG, "Received initialization from %s:%d...", *addr) session_id = utils.get_int(recv_data, 8) output = bytearray(recv_data[0:14]) # Checked with Tetris DS, Mario Kart DS, and Metroid Prime # Hunters, and this seems to be the standard response to 0x00 output += bytearray([0xff, 0xff, 0x6d, 0x16, 0xb5, 0x7d, 0xea]) output[7] = 0x01 # Initialization response nn.write_queue.put((output, addr, socket)) # Try to connect to the server gameid = utils.get_string(recv_data, 0x15) client_id = "%02x" % ord(recv_data[13]) localaddr = utils.get_local_addr(recv_data, 15) nn.session_list \ .setdefault(session_id, {}) \ .setdefault(client_id, { 'connected': False, 'addr': '', 'localaddr': None, 'serveraddr': None, 'gameid': None }) # In fact, it's a pointer client_id_session = nn.session_list[session_id][client_id] client_id_session['gameid'] = gameid client_id_session['addr'] = addr client_id_session['localaddr'] = localaddr for client in nn.session_list[session_id]: # Another pointer client_session = nn.session_list[session_id][client] if client_session['connected'] or client == client_id: continue # --- Send to requesting client # Get server info serveraddr = nn.get_server_addr(gameid, session_id, client) client_session['serveraddr'] = serveraddr logger.log(logging.DEBUG, "Found server from local ip/port: %s from %d", serveraddr, session_id) # Get public port if client_session['serveraddr'] is not None: publicport = int(client_session['serveraddr']['publicport']) else: publicport = \ client_session['localaddr'][1] or \ client_session['addr'][1] output = bytearray(recv_data[0:12]) output += utils.get_bytes_from_ip_str(client_session['addr'][0]) output += utils.get_bytes_from_short(publicport, True) # Unknown, always seems to be \x42\x00 output += bytearray([0x42, 0x00]) output[7] = 0x05 # NN_CONNECT nn.write_queue.put((output, client_id_session['addr'], socket)) logger.log(logging.DEBUG, "Sent connection request to %s:%d...", *client_id_session['addr']) logger.log(logging.DEBUG, "%s", utils.pretty_print_hex(output)) # --- Send to other client # Get server info serveraddr = nn.get_server_addr(gameid, session_id, client_id) client_id_session['serveraddr'] = serveraddr logger.log(logging.DEBUG, "Found server 2 from local ip/port: %s from %d", serveraddr, session_id) # Get public port if client_id_session['serveraddr'] is not None: publicport = int(client_id_session['serveraddr']['publicport']) else: publicport = \ client_id_session['localaddr'][1] or \ client_id_session['addr'][1] output = bytearray(recv_data[0:12]) output += utils.get_bytes_from_ip_str(client_id_session['addr'][0]) output += utils.get_bytes_from_short(publicport, True) # Unknown, always seems to be \x42\x00 output += bytearray([0x42, 0x00]) output[7] = 0x05 # NN_CONNECT nn.write_queue.put((output, client_session['addr'], socket)) logger.log(logging.DEBUG, "Sent connection request to %s:%d...", *client_session['addr']) logger.log(logging.DEBUG, "%s", utils.pretty_print_hex(output))