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))
Example #2
0
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))
Example #3
0
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))
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))