2022-05-20 18:17:41 -04:00
|
|
|
#include "hooking.hpp"
|
2022-06-30 00:11:54 +02:00
|
|
|
#include "services/players/player_service.hpp"
|
2022-11-13 16:34:44 +00:00
|
|
|
#include "natives.hpp"
|
2022-09-12 18:44:47 +00:00
|
|
|
#include "gta_util.hpp"
|
2022-11-19 01:49:36 +00:00
|
|
|
#include "util/session.hpp"
|
2022-11-21 15:42:12 +00:00
|
|
|
#include "util/spam.hpp"
|
2022-12-22 21:23:32 +00:00
|
|
|
#include "backend/command.hpp"
|
|
|
|
#include "backend/context/chat_command_context.hpp"
|
|
|
|
#include "gta/net_game_event.hpp"
|
|
|
|
#include "gta/script_id.hpp"
|
|
|
|
#include "backend/player_command.hpp"
|
|
|
|
|
2022-11-13 16:34:44 +00:00
|
|
|
#include <network/Network.hpp>
|
2022-12-19 17:39:06 +00:00
|
|
|
#include <network/netTime.hpp>
|
2022-05-20 18:17:41 -04:00
|
|
|
|
|
|
|
namespace big
|
|
|
|
{
|
2022-07-05 16:54:45 -04:00
|
|
|
bool get_msg_type(rage::eNetMessage& msgType, rage::datBitBuffer& buffer)
|
2022-05-20 18:17:41 -04:00
|
|
|
{
|
|
|
|
uint32_t pos;
|
|
|
|
uint32_t magic;
|
|
|
|
uint32_t length;
|
|
|
|
uint32_t extended{};
|
|
|
|
if ((buffer.m_flagBits & 2) != 0 || (buffer.m_flagBits & 1) == 0 ? (pos = buffer.m_curBit) : (pos = buffer.m_maxBit),
|
2022-07-05 16:54:45 -04:00
|
|
|
buffer.m_bitsRead + 15 > pos || !buffer.ReadDword(&magic, 14) || magic != 0x3246 || !buffer.ReadDword(&extended, 1)) {
|
2022-11-12 18:35:28 +00:00
|
|
|
msgType = rage::eNetMessage::MsgInvalid;
|
2022-05-20 18:17:41 -04:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
length = extended ? 16 : 8;
|
2022-07-05 16:54:45 -04:00
|
|
|
if ((buffer.m_flagBits & 1) == 0 ? (pos = buffer.m_curBit) : (pos = buffer.m_maxBit), length + buffer.m_bitsRead <= pos && buffer.ReadDword((uint32_t*)&msgType, length))
|
2022-05-20 18:17:41 -04:00
|
|
|
return true;
|
|
|
|
else
|
|
|
|
return false;
|
|
|
|
}
|
2022-08-29 10:26:18 +00:00
|
|
|
|
2022-11-12 18:35:28 +00:00
|
|
|
void gamer_handle_deserialize(rage::rlGamerHandle& hnd, rage::datBitBuffer& buf)
|
|
|
|
{
|
|
|
|
constexpr int PC_PLATFORM = 3;
|
|
|
|
if ((hnd.m_platform = buf.Read<uint8_t>(8)) != PC_PLATFORM)
|
|
|
|
return;
|
|
|
|
|
|
|
|
buf.ReadInt64((int64_t*)&hnd.m_rockstar_id, 64);
|
|
|
|
hnd.unk_0009 = buf.Read<uint8_t>(8);
|
|
|
|
}
|
|
|
|
|
2022-12-08 12:23:57 +00:00
|
|
|
static void script_id_deserialize(CGameScriptId& id, rage::datBitBuffer& buffer)
|
|
|
|
{
|
|
|
|
id.m_hash = buffer.Read<uint32_t>(32);
|
|
|
|
id.m_timestamp = buffer.Read<uint32_t>(32);
|
|
|
|
|
|
|
|
if (buffer.Read<bool>(1))
|
|
|
|
id.m_position_hash = buffer.Read<uint32_t>(32);
|
|
|
|
|
|
|
|
if (buffer.Read<bool>(1))
|
|
|
|
id.m_instance_id = buffer.Read<int32_t>(8);
|
|
|
|
}
|
|
|
|
|
2022-05-20 18:17:41 -04:00
|
|
|
bool hooks::receive_net_message(void* netConnectionManager, void* a2, rage::netConnection::InFrame* frame)
|
|
|
|
{
|
2022-12-29 23:51:11 +00:00
|
|
|
if (frame->get_event_type() != rage::netConnection::InFrame::EventType::FrameReceived)
|
|
|
|
return g_hooking->get_original<hooks::receive_net_message>()(netConnectionManager, a2, frame);
|
|
|
|
|
|
|
|
rage::datBitBuffer buffer((uint8_t*)frame->m_data, frame->m_length);
|
|
|
|
buffer.m_flagBits = 1;
|
|
|
|
|
|
|
|
rage::eNetMessage msgType;
|
|
|
|
player_ptr player;
|
|
|
|
|
|
|
|
for (std::uint32_t i = 0; i < gta_util::get_network()->m_game_session_ptr->m_player_count; i++)
|
|
|
|
{
|
|
|
|
if (gta_util::get_network()->m_game_session_ptr->m_players[i]->m_player_data.m_peer_id_2 == frame->m_peer_id)
|
|
|
|
{
|
|
|
|
player = g_player_service->get_by_host_token(gta_util::get_network()->m_game_session_ptr->m_players[i]->m_player_data.m_host_token);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!get_msg_type(msgType, buffer))
|
|
|
|
return g_hooking->get_original<hooks::receive_net_message>()(netConnectionManager, a2, frame);
|
|
|
|
|
2022-12-31 00:47:01 +00:00
|
|
|
if ((msgType == rage::eNetMessage::MsgTransitionLaunchNotify && frame->m_connection_identifier != gta_util::get_network()->m_game_session.m_connection_identifier) ||
|
|
|
|
(msgType == rage::eNetMessage::MsgTransitionLaunch && frame->m_connection_identifier != gta_util::get_network()->m_transition_session.m_connection_identifier))
|
2022-05-20 18:17:41 -04:00
|
|
|
{
|
2022-12-31 00:47:01 +00:00
|
|
|
if (player)
|
2022-09-12 18:44:47 +00:00
|
|
|
{
|
2022-12-31 00:47:01 +00:00
|
|
|
g_notification_service->push_error("Protections", std::format("Blocked invalid transition launch crash from {}", player->get_name()));
|
2022-09-12 18:44:47 +00:00
|
|
|
}
|
2022-12-31 00:47:01 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
g_notification_service->push_error("Protections", "Blocked invalid transition launch remote crash");
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
2022-12-29 23:51:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (player)
|
|
|
|
{
|
|
|
|
switch (msgType)
|
2022-05-20 18:17:41 -04:00
|
|
|
{
|
2022-11-12 18:35:28 +00:00
|
|
|
case rage::eNetMessage::MsgTextMessage:
|
2022-11-21 15:42:12 +00:00
|
|
|
case rage::eNetMessage::MsgTextMessage2:
|
2022-11-12 03:17:22 +10:30
|
|
|
{
|
2022-11-21 15:42:12 +00:00
|
|
|
char message[256];
|
|
|
|
buffer.ReadString(message, 256);
|
|
|
|
|
|
|
|
if (player->is_spammer)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
if (spam::is_text_spam(message))
|
2022-11-12 03:17:22 +10:30
|
|
|
{
|
2022-12-18 23:15:52 +01:00
|
|
|
if (g.session.log_chat_messages)
|
2022-11-21 15:42:12 +00:00
|
|
|
spam::log_chat(message, player, true);
|
|
|
|
player->is_spammer = true;
|
2022-12-18 23:15:52 +01:00
|
|
|
if (g.session.kick_chat_spammers)
|
2022-12-22 21:23:32 +00:00
|
|
|
{
|
|
|
|
((player_command*)command::get(RAGE_JOAAT("breakup")))->call(player, {});
|
|
|
|
}
|
2022-11-21 15:42:12 +00:00
|
|
|
return true;
|
2022-11-12 03:17:22 +10:30
|
|
|
}
|
2022-11-21 15:42:12 +00:00
|
|
|
else
|
2022-11-12 03:17:22 +10:30
|
|
|
{
|
2022-12-18 23:15:52 +01:00
|
|
|
if (g.session.log_chat_messages)
|
2022-11-21 15:42:12 +00:00
|
|
|
spam::log_chat(message, player, false);
|
2022-12-22 21:23:32 +00:00
|
|
|
|
|
|
|
if (g.session.chat_commands && message[0] == g.session.chat_command_prefix)
|
|
|
|
command::process(std::string(message + 1), std::make_shared<chat_command_context>(player));
|
2022-11-12 03:17:22 +10:30
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2022-11-12 18:35:28 +00:00
|
|
|
case rage::eNetMessage::MsgScriptMigrateHost:
|
2022-08-29 10:26:18 +00:00
|
|
|
{
|
2022-11-21 15:42:12 +00:00
|
|
|
if (player->m_host_migration_rate_limit.process())
|
2022-05-20 18:17:41 -04:00
|
|
|
{
|
2022-11-21 15:42:12 +00:00
|
|
|
if (player->m_host_migration_rate_limit.exceeded_last_process())
|
2022-08-29 10:26:18 +00:00
|
|
|
{
|
2022-11-19 01:49:36 +00:00
|
|
|
session::add_infraction(player, Infraction::TRIED_KICK_PLAYER);
|
2022-10-24 14:08:37 +02:00
|
|
|
g_notification_service->push_error("Protections", std::format("{} tried to OOM kick you!", player->get_name()));
|
2022-08-29 10:26:18 +00:00
|
|
|
}
|
|
|
|
return true;
|
2022-05-20 18:17:41 -04:00
|
|
|
}
|
2022-08-29 10:26:18 +00:00
|
|
|
break;
|
|
|
|
}
|
2022-11-12 18:35:28 +00:00
|
|
|
case rage::eNetMessage::MsgRemoveGamersFromSessionCmd:
|
2022-09-12 18:44:47 +00:00
|
|
|
{
|
|
|
|
player_ptr pl;
|
|
|
|
uint64_t session_id;
|
|
|
|
buffer.ReadQWord(&session_id, 64);
|
|
|
|
uint32_t count;
|
|
|
|
buffer.ReadDword(&count, 6);
|
|
|
|
for (std::uint32_t i = 0; i < count; i++)
|
|
|
|
{
|
|
|
|
uint64_t peer_id;
|
2022-11-12 03:17:22 +10:30
|
|
|
buffer.ReadQWord(&peer_id, 64);
|
2022-09-12 18:44:47 +00:00
|
|
|
for (std::uint32_t i = 0; i < gta_util::get_network()->m_game_session_ptr->m_peer_count; i++)
|
|
|
|
{
|
|
|
|
if (gta_util::get_network()->m_game_session_ptr->m_peers[i]->m_peer_data.m_peer_id_2 == peer_id)
|
|
|
|
{
|
|
|
|
pl = g_player_service->get_by_host_token(gta_util::get_network()->m_game_session_ptr->m_peers[i]->m_peer_data.m_host_token);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-12-08 12:23:57 +00:00
|
|
|
|
2022-09-12 18:44:47 +00:00
|
|
|
if (player && pl && player->id() != pl->id() && count == 1 && frame->m_msg_id == -1)
|
|
|
|
{
|
2022-12-22 21:23:32 +00:00
|
|
|
if (g_player_service->get_self()->is_host())
|
|
|
|
{
|
|
|
|
g_notification_service->push_error("Warning!", std::format("{} tried to breakup kick {}!", player->get_name(), pl->get_name()));
|
|
|
|
session::add_infraction(player, Infraction::BREAKUP_KICK_DETECTED);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
g_notification_service->push_error("Warning!", std::format("{} breakup kicked {}!", player->get_name(), pl->get_name()));
|
|
|
|
session::add_infraction(player, Infraction::BREAKUP_KICK_DETECTED);
|
|
|
|
}
|
2022-09-12 18:44:47 +00:00
|
|
|
}
|
2022-12-08 12:23:57 +00:00
|
|
|
|
2022-09-12 18:44:47 +00:00
|
|
|
break;
|
|
|
|
}
|
2022-11-12 18:35:28 +00:00
|
|
|
case rage::eNetMessage::MsgLostConnectionToHost:
|
|
|
|
{
|
|
|
|
uint64_t session_id;
|
|
|
|
buffer.ReadQWord(&session_id, 64);
|
|
|
|
rage::rlGamerHandle handle;
|
|
|
|
gamer_handle_deserialize(handle, buffer);
|
|
|
|
|
|
|
|
auto self = g_player_service->get_self();
|
|
|
|
if (self->get_net_data() && self->get_net_data()->m_gamer_handle_2.m_rockstar_id == handle.m_rockstar_id)
|
|
|
|
{
|
2022-11-19 01:49:36 +00:00
|
|
|
session::add_infraction(player, Infraction::TRIED_KICK_PLAYER);
|
2022-11-12 18:35:28 +00:00
|
|
|
g_notification_service->push_error("Protections", std::format("{} tried to lost connection kick you!", player->get_name()));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (auto& [_, plyr] : g_player_service->players())
|
|
|
|
{
|
2022-12-29 23:51:11 +00:00
|
|
|
if (plyr->get_net_data() && plyr != player && plyr->get_net_data()->m_gamer_handle_2.m_rockstar_id == handle.m_rockstar_id)
|
2022-11-12 18:35:28 +00:00
|
|
|
{
|
2022-11-19 01:49:36 +00:00
|
|
|
session::add_infraction(player, Infraction::LOST_CONNECTION_KICK_DETECTED);
|
2022-11-12 18:35:28 +00:00
|
|
|
g_notification_service->push_error("Protections", std::format("{} tried to lost connection kick {}!", player->get_name(), plyr->get_name()));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
2022-11-19 01:49:36 +00:00
|
|
|
case rage::eNetMessage::MsgSessionEstablished:
|
|
|
|
{
|
|
|
|
rage::rlGamerHandle handle{ 0 };
|
|
|
|
if (player && player->get_net_data())
|
|
|
|
{
|
|
|
|
uint64_t session_id;
|
|
|
|
buffer.ReadQWord(&session_id, 64);
|
|
|
|
gamer_handle_deserialize(handle, buffer);
|
|
|
|
if (session_id == gta_util::get_network()->m_game_session_ptr->m_rline_session.m_session_id)
|
|
|
|
{
|
|
|
|
if (handle.m_rockstar_id != player->get_net_data()->m_gamer_handle_2.m_rockstar_id)
|
|
|
|
{
|
|
|
|
session::add_infraction(player, Infraction::SPOOFED_ROCKSTAR_ID); // TODO: store this RID
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case rage::eNetMessage::MsgNetComplaint:
|
|
|
|
{
|
|
|
|
uint64_t host_token{};
|
|
|
|
buffer.ReadQWord(&host_token, 64);
|
|
|
|
|
|
|
|
std::vector<CNetGamePlayer*> players;
|
|
|
|
|
|
|
|
uint32_t num_of_tokens{};
|
|
|
|
buffer.ReadDword(&num_of_tokens, 32);
|
|
|
|
|
2022-11-21 15:42:12 +00:00
|
|
|
if (player && host_token != player->get_net_data()->m_host_token && !player->exposed_desync_protection)
|
|
|
|
{
|
2022-11-19 01:49:36 +00:00
|
|
|
session::add_infraction(player, Infraction::DESYNC_PROTECTION);
|
2022-11-21 15:42:12 +00:00
|
|
|
player->exposed_desync_protection = true;
|
|
|
|
}
|
2022-11-19 01:49:36 +00:00
|
|
|
|
|
|
|
return true; // block desync kicks as host
|
|
|
|
}
|
|
|
|
case rage::eNetMessage::MsgRequestObjectIds:
|
|
|
|
{
|
|
|
|
if (player && player->block_join)
|
|
|
|
{
|
|
|
|
g_notification_service->push("Join Blocker", std::format("Trying to prevent {} from joining...", player->get_name()));
|
|
|
|
return true;
|
|
|
|
}
|
2022-12-08 12:23:57 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case rage::eNetMessage::MsgScriptHostRequest:
|
|
|
|
{
|
|
|
|
CGameScriptId script;
|
|
|
|
script_id_deserialize(script, buffer);
|
|
|
|
|
2022-12-18 23:15:52 +01:00
|
|
|
if (script.m_hash == RAGE_JOAAT("freemode") && g.session.force_script_host)
|
2022-12-08 12:23:57 +00:00
|
|
|
return true;
|
2022-12-29 23:51:11 +00:00
|
|
|
|
2022-12-08 12:23:57 +00:00
|
|
|
break;
|
2022-11-19 01:49:36 +00:00
|
|
|
}
|
2022-12-19 17:39:06 +00:00
|
|
|
case rage::eNetMessage::MsgNetTimeSync:
|
|
|
|
{
|
|
|
|
if (player)
|
|
|
|
{
|
|
|
|
int action = buffer.Read<int>(2);
|
|
|
|
uint32_t counter = buffer.Read<uint32_t>(32);
|
|
|
|
uint32_t token = buffer.Read<uint32_t>(32);
|
|
|
|
uint32_t timestamp = buffer.Read<uint32_t>(32);
|
|
|
|
uint32_t time_diff = (*g_pointers->m_network_time)->m_time_offset + frame->m_timestamp;
|
|
|
|
|
|
|
|
if (action == 0)
|
|
|
|
{
|
|
|
|
player->player_time_value = timestamp;
|
|
|
|
player->player_time_value_received_time = std::chrono::time_point_cast<std::chrono::milliseconds>(std::chrono::system_clock::now());
|
|
|
|
if (!player->time_difference || time_diff > player->time_difference.value())
|
|
|
|
player->time_difference = time_diff;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2022-12-29 23:51:11 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
switch (msgType)
|
|
|
|
{
|
|
|
|
case rage::eNetMessage::MsgLostConnectionToHost:
|
|
|
|
{
|
|
|
|
uint64_t session_id;
|
|
|
|
buffer.ReadQWord(&session_id, 64);
|
|
|
|
rage::rlGamerHandle handle;
|
|
|
|
gamer_handle_deserialize(handle, buffer);
|
|
|
|
|
|
|
|
auto self = g_player_service->get_self();
|
|
|
|
if (self->get_net_data() && self->get_net_data()->m_gamer_handle_2.m_rockstar_id == handle.m_rockstar_id)
|
|
|
|
{
|
|
|
|
g_notification_service->push_error("Warning!", "Someone tried to lost connection kick you remotely!");
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (auto& [_, plyr] : g_player_service->players())
|
|
|
|
{
|
|
|
|
if (plyr->get_net_data() && plyr->get_net_data()->m_gamer_handle_2.m_rockstar_id == handle.m_rockstar_id)
|
|
|
|
{
|
|
|
|
g_notification_service->push_error("Warning!", std::format("Someone tried to lost connection kick {} remotely!", plyr->get_name()));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case rage::eNetMessage::MsgRemoveGamersFromSessionCmd:
|
|
|
|
{
|
|
|
|
if (!g_player_service->get_self()->is_host())
|
|
|
|
break;
|
|
|
|
|
|
|
|
player_ptr target;
|
|
|
|
uint64_t session_id;
|
|
|
|
buffer.ReadQWord(&session_id, 64);
|
|
|
|
uint32_t count;
|
|
|
|
buffer.ReadDword(&count, 6);
|
|
|
|
for (std::uint32_t i = 0; i < count; i++)
|
|
|
|
{
|
|
|
|
uint64_t peer_id;
|
|
|
|
buffer.ReadQWord(&peer_id, 64);
|
|
|
|
|
|
|
|
if (g_player_service->get_self()->get_net_data() && g_player_service->get_self()->get_net_data()->m_peer_id_2 == peer_id)
|
|
|
|
{
|
|
|
|
target = g_player_service->get_self();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
for (std::uint32_t i = 0; i < gta_util::get_network()->m_game_session_ptr->m_peer_count; i++)
|
|
|
|
{
|
|
|
|
if (gta_util::get_network()->m_game_session_ptr->m_peers[i]->m_peer_data.m_peer_id_2 == peer_id)
|
|
|
|
{
|
|
|
|
target = g_player_service->get_by_host_token(gta_util::get_network()->m_game_session_ptr->m_peers[i]->m_peer_data.m_host_token);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (target && count == 1 && frame->m_msg_id == -1)
|
|
|
|
{
|
|
|
|
if (target->id() == g_player_service->get_self()->id())
|
|
|
|
g_notification_service->push_error("Warning!", "Someone tried to breakup kick you remotely!");
|
|
|
|
else
|
|
|
|
g_notification_service->push_error("Warning!", std::format("Someone tried to breakup kick {} remotely!", target->get_name()));
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
2022-05-20 18:17:41 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-12-29 23:51:11 +00:00
|
|
|
|
2022-05-20 18:17:41 -04:00
|
|
|
|
2022-10-30 19:32:51 +01:00
|
|
|
return g_hooking->get_original<hooks::receive_net_message>()(netConnectionManager, a2, frame);
|
2022-05-20 18:17:41 -04:00
|
|
|
}
|
2022-06-27 15:41:03 +02:00
|
|
|
}
|