diff --git a/src/ProxyCommands.cc b/src/ProxyCommands.cc index 06215a03..e03b8328 100644 --- a/src/ProxyCommands.cc +++ b/src/ProxyCommands.cc @@ -44,7 +44,6 @@ static void forward_command(ProxyServer::LinkedSession& session, bool to_server, if (!ch.connected()) { proxy_server_log.warning("No endpoint is present; dropping command"); } else { - // TODO: Don't print the command here (usually) ch.send(command, flag, data, print_contents); } } @@ -90,33 +89,45 @@ static void send_text_message_to_client( // function may have modified) is forwarded to the other end; if they return // false; it is not. -enum class HandlerResult { - FORWARD = 0, - SUPPRESS, - MODIFIED, +struct HandlerResult { + enum class Type { + FORWARD = 0, + SUPPRESS, + MODIFIED, + }; + Type type; + // These are only used if Type is MODIFIED. If either are -1, then the + // original command's value is used instead. + int32_t new_command; + int64_t new_flag; + + HandlerResult(Type type) : type(type), new_command(-1), new_flag(-1) { } + HandlerResult(Type type, uint16_t new_command, uint32_t new_flag) + : type(type), new_command(new_command), new_flag(new_flag) { } }; static HandlerResult process_default(shared_ptr, ProxyServer::LinkedSession&, uint16_t, uint32_t, string&) { - return HandlerResult::FORWARD; + return HandlerResult::Type::FORWARD; } static HandlerResult process_server_97(shared_ptr, - ProxyServer::LinkedSession& session, uint16_t, uint32_t, string&) { - // Trap 97 commands and always send 97 01 04 00. This protects the client from - // cheat detection - if the flag is 0, the client triggers cheat detection and - // deletes a bunch of data. - session.client_channel.send(0x97, 0x01); - // Also, update the newserv client config so we'll know not to show the - // programs menu if they return to newserv. + ProxyServer::LinkedSession& session, uint16_t, uint32_t flag, string&) { + // Update the newserv client config so we'll know not to show the Programs + // menu if they return to newserv session.newserv_client_config.cfg.flags |= Client::Flag::SAVE_ENABLED; - return HandlerResult::SUPPRESS; + // Trap any 97 command that would have triggered cheat protection, and always + // send 97 01 04 00 + if (flag == 0) { + return HandlerResult(HandlerResult::Type::MODIFIED, 0x97, 0x01); + } + return HandlerResult::Type::FORWARD; } static HandlerResult process_server_gc_9A(shared_ptr, ProxyServer::LinkedSession& session, uint16_t, uint32_t, string&) { if (!session.license) { - return HandlerResult::FORWARD; + return HandlerResult::Type::FORWARD; } C_LoginExtended_GC_9E cmd; @@ -144,7 +155,7 @@ static HandlerResult process_server_gc_9A(shared_ptr, session.server_channel.send( 0x9E, 0x01, &cmd, cmd.is_extended ? sizeof(C_LoginExtended_GC_9E) : sizeof(C_Login_GC_9E)); - return HandlerResult::SUPPRESS; + return HandlerResult::Type::SUPPRESS; } static HandlerResult process_server_pc_gc_patch_02_17(shared_ptr s, @@ -177,7 +188,7 @@ static HandlerResult process_server_pc_gc_patch_02_17(shared_ptr s, session.client_channel.crypt_out.reset(new PSOPCEncryption(cmd.server_key)); } - return HandlerResult::SUPPRESS; + return HandlerResult::Type::SUPPRESS; } session.log.info("Existing license in linked session"); @@ -199,7 +210,7 @@ static HandlerResult process_server_pc_gc_patch_02_17(shared_ptr s, // redirect). if (session.version == GameVersion::PATCH) { session.server_channel.send(0x02); - return HandlerResult::SUPPRESS; + return HandlerResult::Type::SUPPRESS; } else if (session.version == GameVersion::PC) { C_Login_PC_9D cmd; @@ -221,7 +232,7 @@ static HandlerResult process_server_pc_gc_patch_02_17(shared_ptr s, cmd.access_key2 = cmd.access_key; cmd.name = session.character_name; session.server_channel.send(0x9D, 0x00, &cmd, sizeof(cmd)); - return HandlerResult::SUPPRESS; + return HandlerResult::Type::SUPPRESS; } else if (session.version == GameVersion::GC) { if (command == 0x17) { @@ -234,7 +245,7 @@ static HandlerResult process_server_pc_gc_patch_02_17(shared_ptr s, cmd.access_key2 = cmd.access_key; cmd.password = session.license->gc_password; session.server_channel.send(0xDB, 0x00, &cmd, sizeof(cmd)); - return HandlerResult::SUPPRESS; + return HandlerResult::Type::SUPPRESS; } else { // For command 02, send the same as if we had received 9A from the server @@ -277,7 +288,7 @@ static HandlerResult process_server_bb_03(shared_ptr s, } session.server_channel.send(0x93, 0x00, session.login_command_bb); - return HandlerResult::SUPPRESS; + return HandlerResult::Type::SUPPRESS; // If there's no detector crypt, then the session is new and was linked // immediately at connect time, and an 03 was not yet sent to the client, so @@ -299,7 +310,7 @@ static HandlerResult process_server_bb_03(shared_ptr s, session.detector_crypt, cmd.client_key.data(), sizeof(cmd.client_key), false)); // We already forwarded the command, so don't do so again - return HandlerResult::SUPPRESS; + return HandlerResult::Type::SUPPRESS; } } @@ -349,11 +360,13 @@ static HandlerResult process_server_dc_pc_gc_04(shared_ptr, if (!had_guild_card_number) { // We don't actually have a client checksum, of course... hopefully just // random data will do (probably no private servers check this at all) + // TODO: Presumably we can save these values from the client when they + // connected to newserv originally, but I'm too lazy to do this right now le_uint64_t checksum = random_object() & 0x0000FFFFFFFFFFFF; session.server_channel.send(0x96, 0x00, &checksum, sizeof(checksum)); } - return session.license ? HandlerResult::MODIFIED : HandlerResult::FORWARD; + return session.license ? HandlerResult::Type::MODIFIED : HandlerResult::Type::FORWARD; } static HandlerResult process_server_dc_pc_gc_06(shared_ptr, @@ -363,10 +376,10 @@ static HandlerResult process_server_dc_pc_gc_06(shared_ptr, sizeof(SC_TextHeader_01_06_11_B0_EE), 0xFFFF); if (cmd.guild_card_number == session.remote_guild_card_number) { cmd.guild_card_number = session.license->serial_number; - return HandlerResult::MODIFIED; + return HandlerResult::Type::MODIFIED; } } - return HandlerResult::FORWARD; + return HandlerResult::Type::FORWARD; } template @@ -384,7 +397,7 @@ static HandlerResult process_server_41(shared_ptr, modified = true; } } - return modified ? HandlerResult::MODIFIED : HandlerResult::FORWARD; + return modified ? HandlerResult::Type::MODIFIED : HandlerResult::Type::FORWARD; } template @@ -402,7 +415,7 @@ static HandlerResult process_server_81(shared_ptr, modified = true; } } - return modified ? HandlerResult::MODIFIED : HandlerResult::FORWARD; + return modified ? HandlerResult::Type::MODIFIED : HandlerResult::Type::FORWARD; } static HandlerResult process_server_88(shared_ptr, @@ -419,7 +432,7 @@ static HandlerResult process_server_88(shared_ptr, } } } - return modified ? HandlerResult::MODIFIED : HandlerResult::FORWARD; + return modified ? HandlerResult::Type::MODIFIED : HandlerResult::Type::FORWARD; } static HandlerResult process_server_B2(shared_ptr, @@ -488,9 +501,9 @@ static HandlerResult process_server_B2(shared_ptr, cmd.return_value = session.function_call_return_value; cmd.checksum = 0; session.server_channel.send(0xB3, flag, &cmd, sizeof(cmd)); - return HandlerResult::SUPPRESS; + return HandlerResult::Type::SUPPRESS; } else { - return HandlerResult::FORWARD; + return HandlerResult::Type::FORWARD; } } @@ -501,7 +514,7 @@ static HandlerResult process_server_E7(shared_ptr, save_file(output_filename, data); session.log.info("Wrote player data to file %s", output_filename.c_str()); } - return HandlerResult::FORWARD; + return HandlerResult::Type::FORWARD; } template @@ -520,7 +533,7 @@ static HandlerResult process_server_C4(shared_ptr, } } } - return modified ? HandlerResult::MODIFIED : HandlerResult::FORWARD; + return modified ? HandlerResult::Type::MODIFIED : HandlerResult::Type::FORWARD; } static HandlerResult process_server_gc_E4(shared_ptr, @@ -533,7 +546,7 @@ static HandlerResult process_server_gc_E4(shared_ptr, modified = true; } } - return modified ? HandlerResult::MODIFIED : HandlerResult::FORWARD; + return modified ? HandlerResult::Type::MODIFIED : HandlerResult::Type::FORWARD; } static HandlerResult process_server_bb_22(shared_ptr, @@ -552,7 +565,7 @@ static HandlerResult process_server_bb_22(shared_ptr, session.log.info("Enabling remote IP CRC patch"); session.enable_remote_ip_crc_patch = true; } - return HandlerResult::FORWARD; + return HandlerResult::Type::FORWARD; } static HandlerResult process_server_game_19_patch_14(shared_ptr, @@ -589,7 +602,7 @@ static HandlerResult process_server_game_19_patch_14(shared_ptr, if (!session.client_channel.connected()) { session.log.warning("Received reconnect command with no destination present"); - return HandlerResult::SUPPRESS; + return HandlerResult::Type::SUPPRESS; } else if (command == 0x14) { // On the patch server, hide redirects from the client completely. The new @@ -605,7 +618,7 @@ static HandlerResult process_server_game_19_patch_14(shared_ptr, dest_sin->sin_addr.s_addr = cmd.address.load_raw(); dest_sin->sin_port = cmd.port; session.connect(); - return HandlerResult::SUPPRESS; + return HandlerResult::Type::SUPPRESS; } else { // If the client is on a virtual connection (fd < 0), only change @@ -623,7 +636,7 @@ static HandlerResult process_server_game_19_patch_14(shared_ptr, cmd.address.store_raw(sin->sin_addr.s_addr); cmd.port = ntohs(sin->sin_port); } - return HandlerResult::MODIFIED; + return HandlerResult::Type::MODIFIED; } } @@ -636,7 +649,7 @@ static HandlerResult process_server_gc_1A_D5(shared_ptr, (session.newserv_client_config.cfg.flags & Client::Flag::NO_MESSAGE_BOX_CLOSE_CONFIRMATION)) { session.server_channel.send(0xD6); } - return HandlerResult::FORWARD; + return HandlerResult::Type::FORWARD; } static HandlerResult process_server_60_62_6C_6D_C9_CB(shared_ptr, @@ -656,7 +669,7 @@ static HandlerResult process_server_60_62_6C_6D_C9_CB(shared_ptr, } } - return HandlerResult::FORWARD; + return HandlerResult::Type::FORWARD; } template @@ -684,7 +697,7 @@ static HandlerResult process_server_44_A6(shared_ptr, session.saving_files.emplace(cmd.filename, move(sf)); session.log.info("Opened file %s", output_filename.c_str()); } - return HandlerResult::FORWARD; + return HandlerResult::Type::FORWARD; } static HandlerResult process_server_13_A7(shared_ptr, @@ -698,7 +711,7 @@ static HandlerResult process_server_13_A7(shared_ptr, } catch (const out_of_range&) { string filename = cmd.filename; session.log.warning("Received data for non-open file %s", filename.c_str()); - return HandlerResult::FORWARD; + return HandlerResult::Type::FORWARD; } size_t bytes_to_write = cmd.data_size; @@ -721,7 +734,7 @@ static HandlerResult process_server_13_A7(shared_ptr, session.saving_files.erase(cmd.filename); } } - return HandlerResult::FORWARD; + return HandlerResult::Type::FORWARD; } static HandlerResult process_server_gc_B8(shared_ptr, @@ -729,21 +742,21 @@ static HandlerResult process_server_gc_B8(shared_ptr, if (session.save_files) { if (data.size() < 4) { session.log.warning("Card list data size is too small; not saving file"); - return HandlerResult::FORWARD; + return HandlerResult::Type::FORWARD; } StringReader r(data); size_t size = r.get_u32l(); if (r.remaining() < size) { session.log.warning("Card list data size extends beyond end of command; not saving file"); - return HandlerResult::FORWARD; + return HandlerResult::Type::FORWARD; } string output_filename = string_printf("cardupdate.%" PRIu64 ".mnr", now()); save_file(output_filename, r.read(size)); session.log.info("Wrote %zu bytes to %s", size, output_filename.c_str()); } - return HandlerResult::FORWARD; + return HandlerResult::Type::FORWARD; } template @@ -797,7 +810,7 @@ static HandlerResult process_server_65_67_68(shared_ptr, modified = true; } - return modified ? HandlerResult::MODIFIED : HandlerResult::FORWARD; + return modified ? HandlerResult::Type::MODIFIED : HandlerResult::Type::FORWARD; } template @@ -846,7 +859,7 @@ static HandlerResult process_server_64(shared_ptr, modified = true; } - return modified ? HandlerResult::MODIFIED : HandlerResult::FORWARD; + return modified ? HandlerResult::Type::MODIFIED : HandlerResult::Type::FORWARD; } static HandlerResult process_server_66_69(shared_ptr, @@ -860,7 +873,7 @@ static HandlerResult process_server_66_69(shared_ptr, session.lobby_players[index].name.clear(); session.log.info("Removed lobby player (%zu)", index); } - return HandlerResult::FORWARD; + return HandlerResult::Type::FORWARD; } static HandlerResult process_client_06(shared_ptr s, @@ -877,7 +890,7 @@ static HandlerResult process_client_06(shared_ptr s, strip_trailing_zeroes(text); if (text.empty()) { - return HandlerResult::SUPPRESS; + return HandlerResult::Type::SUPPRESS; } bool is_command = (text[0] == '$' || (text[0] == '\t' && text[1] != 'C' && text[2] == '$')); @@ -885,24 +898,24 @@ static HandlerResult process_client_06(shared_ptr s, text = text.substr((text[0] == '$') ? 0 : 2); if (text.size() >= 2 && text[1] == '$') { send_chat_message(session.server_channel, text.substr(1)); - return HandlerResult::SUPPRESS; + return HandlerResult::Type::SUPPRESS; } else { process_chat_command(s, session, text); - return HandlerResult::SUPPRESS; + return HandlerResult::Type::SUPPRESS; } } else if (session.enable_chat_filter) { add_color_inplace(data.data() + 8, data.size() - 8); // TODO: We should return MODIFIED here if the message was changed by // the add_color_inplace call - return HandlerResult::FORWARD; + return HandlerResult::Type::FORWARD; } else { - return HandlerResult::FORWARD; + return HandlerResult::Type::FORWARD; } } else { - return HandlerResult::FORWARD; + return HandlerResult::Type::FORWARD; } } @@ -920,7 +933,7 @@ static HandlerResult process_client_40(shared_ptr, modified = true; } } - return modified ? HandlerResult::MODIFIED : HandlerResult::FORWARD; + return modified ? HandlerResult::Type::MODIFIED : HandlerResult::Type::FORWARD; } template @@ -937,7 +950,7 @@ static HandlerResult process_client_81(shared_ptr, } // GC clients send uninitialized memory here; don't forward it cmd.text.clear_after(cmd.text.len()); - return HandlerResult::MODIFIED; + return HandlerResult::Type::MODIFIED; } template @@ -1000,13 +1013,13 @@ HandlerResult process_client_60_62_6C_6D_C9_CB(shared_ptr, } } - return HandlerResult::FORWARD; + return HandlerResult::Type::FORWARD; } static HandlerResult process_client_dc_pc_gc_A0_A1(shared_ptr s, ProxyServer::LinkedSession& session, uint16_t, uint32_t, string&) { if (!session.license) { - return HandlerResult::FORWARD; + return HandlerResult::Type::FORWARD; } // For licensed sessions, send them back to newserv's main menu instead of @@ -1063,7 +1076,7 @@ static HandlerResult process_client_dc_pc_gc_A0_A1(shared_ptr s, session.client_channel.send(0x19, 0x00, &reconnect_cmd, sizeof(reconnect_cmd)); - return HandlerResult::SUPPRESS; + return HandlerResult::Type::SUPPRESS; } @@ -1289,13 +1302,18 @@ void process_proxy_command( auto fn = get_handler(session.version, from_server, command); try { auto res = fn(s, session, command, flag, data); - if (res == HandlerResult::FORWARD) { + if (res.type == HandlerResult::Type::FORWARD) { forward_command(session, !from_server, command, flag, data, false); - } else if (res == HandlerResult::MODIFIED) { + } else if (res.type == HandlerResult::Type::MODIFIED) { session.log.info("The preceding command from the %s was modified in transit", from_server ? "server" : "client"); - forward_command(session, !from_server, command, flag, data); - } else if (res == HandlerResult::SUPPRESS) { + forward_command( + session, + !from_server, + res.new_command >= 0 ? res.new_command : command, + res.new_flag >= 0 ? res.new_flag : flag, + data); + } else if (res.type == HandlerResult::Type::SUPPRESS) { session.log.info("The preceding command from the %s was not forwarded", from_server ? "server" : "client"); } else {