allow proxy handlers to override command/flag

This commit is contained in:
Martin Michelsen
2022-07-13 17:40:37 -07:00
parent ff7031544a
commit 2590a2f24b
+81 -63
View File
@@ -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<ServerState>,
ProxyServer::LinkedSession&, uint16_t, uint32_t, string&) {
return HandlerResult::FORWARD;
return HandlerResult::Type::FORWARD;
}
static HandlerResult process_server_97(shared_ptr<ServerState>,
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<ServerState>,
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<ServerState>,
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<ServerState> s,
@@ -177,7 +188,7 @@ static HandlerResult process_server_pc_gc_patch_02_17(shared_ptr<ServerState> 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<ServerState> 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<ServerState> 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<ServerState> 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<ServerState> 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<ServerState> 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<ServerState>,
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<uint64_t>() & 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<ServerState>,
@@ -363,10 +376,10 @@ static HandlerResult process_server_dc_pc_gc_06(shared_ptr<ServerState>,
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 <typename CmdT>
@@ -384,7 +397,7 @@ static HandlerResult process_server_41(shared_ptr<ServerState>,
modified = true;
}
}
return modified ? HandlerResult::MODIFIED : HandlerResult::FORWARD;
return modified ? HandlerResult::Type::MODIFIED : HandlerResult::Type::FORWARD;
}
template <typename CmdT>
@@ -402,7 +415,7 @@ static HandlerResult process_server_81(shared_ptr<ServerState>,
modified = true;
}
}
return modified ? HandlerResult::MODIFIED : HandlerResult::FORWARD;
return modified ? HandlerResult::Type::MODIFIED : HandlerResult::Type::FORWARD;
}
static HandlerResult process_server_88(shared_ptr<ServerState>,
@@ -419,7 +432,7 @@ static HandlerResult process_server_88(shared_ptr<ServerState>,
}
}
}
return modified ? HandlerResult::MODIFIED : HandlerResult::FORWARD;
return modified ? HandlerResult::Type::MODIFIED : HandlerResult::Type::FORWARD;
}
static HandlerResult process_server_B2(shared_ptr<ServerState>,
@@ -488,9 +501,9 @@ static HandlerResult process_server_B2(shared_ptr<ServerState>,
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<ServerState>,
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 <typename CmdT>
@@ -520,7 +533,7 @@ static HandlerResult process_server_C4(shared_ptr<ServerState>,
}
}
}
return modified ? HandlerResult::MODIFIED : HandlerResult::FORWARD;
return modified ? HandlerResult::Type::MODIFIED : HandlerResult::Type::FORWARD;
}
static HandlerResult process_server_gc_E4(shared_ptr<ServerState>,
@@ -533,7 +546,7 @@ static HandlerResult process_server_gc_E4(shared_ptr<ServerState>,
modified = true;
}
}
return modified ? HandlerResult::MODIFIED : HandlerResult::FORWARD;
return modified ? HandlerResult::Type::MODIFIED : HandlerResult::Type::FORWARD;
}
static HandlerResult process_server_bb_22(shared_ptr<ServerState>,
@@ -552,7 +565,7 @@ static HandlerResult process_server_bb_22(shared_ptr<ServerState>,
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<ServerState>,
@@ -589,7 +602,7 @@ static HandlerResult process_server_game_19_patch_14(shared_ptr<ServerState>,
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<ServerState>,
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<ServerState>,
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<ServerState>,
(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<ServerState>,
@@ -656,7 +669,7 @@ static HandlerResult process_server_60_62_6C_6D_C9_CB(shared_ptr<ServerState>,
}
}
return HandlerResult::FORWARD;
return HandlerResult::Type::FORWARD;
}
template <typename T>
@@ -684,7 +697,7 @@ static HandlerResult process_server_44_A6(shared_ptr<ServerState>,
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<ServerState>,
@@ -698,7 +711,7 @@ static HandlerResult process_server_13_A7(shared_ptr<ServerState>,
} 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<ServerState>,
session.saving_files.erase(cmd.filename);
}
}
return HandlerResult::FORWARD;
return HandlerResult::Type::FORWARD;
}
static HandlerResult process_server_gc_B8(shared_ptr<ServerState>,
@@ -729,21 +742,21 @@ static HandlerResult process_server_gc_B8(shared_ptr<ServerState>,
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 <typename CmdT>
@@ -797,7 +810,7 @@ static HandlerResult process_server_65_67_68(shared_ptr<ServerState>,
modified = true;
}
return modified ? HandlerResult::MODIFIED : HandlerResult::FORWARD;
return modified ? HandlerResult::Type::MODIFIED : HandlerResult::Type::FORWARD;
}
template <typename CmdT>
@@ -846,7 +859,7 @@ static HandlerResult process_server_64(shared_ptr<ServerState>,
modified = true;
}
return modified ? HandlerResult::MODIFIED : HandlerResult::FORWARD;
return modified ? HandlerResult::Type::MODIFIED : HandlerResult::Type::FORWARD;
}
static HandlerResult process_server_66_69(shared_ptr<ServerState>,
@@ -860,7 +873,7 @@ static HandlerResult process_server_66_69(shared_ptr<ServerState>,
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<ServerState> s,
@@ -877,7 +890,7 @@ static HandlerResult process_client_06(shared_ptr<ServerState> 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<ServerState> 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<ServerState>,
modified = true;
}
}
return modified ? HandlerResult::MODIFIED : HandlerResult::FORWARD;
return modified ? HandlerResult::Type::MODIFIED : HandlerResult::Type::FORWARD;
}
template <typename CmdT>
@@ -937,7 +950,7 @@ static HandlerResult process_client_81(shared_ptr<ServerState>,
}
// 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 <typename SendGuildCardCmdT>
@@ -1000,13 +1013,13 @@ HandlerResult process_client_60_62_6C_6D_C9_CB<void>(shared_ptr<ServerState>,
}
}
return HandlerResult::FORWARD;
return HandlerResult::Type::FORWARD;
}
static HandlerResult process_client_dc_pc_gc_A0_A1(shared_ptr<ServerState> 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<ServerState> 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 {