t7x/src/client/component/network.cpp

349 lines
9.0 KiB
C++
Raw Normal View History

2022-10-19 15:07:07 -04:00
#include <std_include.hpp>
#include "loader/component_loader.hpp"
2022-10-24 13:57:33 -04:00
#include "scheduler.hpp"
2022-10-19 15:07:07 -04:00
#include "game/game.hpp"
#include <utils/hook.hpp>
2022-10-24 13:57:33 -04:00
#include <utils/string.hpp>
#include <utils/finally.hpp>
2022-10-23 13:56:03 -04:00
#include "network.hpp"
2023-04-11 14:48:14 -04:00
#include "game/fragment_handler.hpp"
2022-10-19 15:07:07 -04:00
namespace network
{
namespace
{
utils::hook::detour handle_packet_internal_hook{};
2022-10-23 13:56:03 -04:00
std::unordered_map<std::string, callback>& get_callbacks()
2022-10-19 15:07:07 -04:00
{
2022-10-23 13:56:03 -04:00
static std::unordered_map<std::string, callback> callbacks{};
return callbacks;
}
2022-12-09 12:23:23 -05:00
uint64_t handle_command(const game::netadr_t* address, const char* command, const game::msg_t* message)
2022-10-23 13:56:03 -04:00
{
2022-10-24 13:57:33 -04:00
const auto cmd_string = utils::string::to_lower(command);
2022-10-23 13:56:03 -04:00
auto& callbacks = get_callbacks();
const auto handler = callbacks.find(cmd_string);
const auto offset = cmd_string.size() + 5;
2022-10-24 13:57:33 -04:00
if (message->cursize < 0 || static_cast<size_t>(message->cursize) < offset || handler == callbacks.end())
2022-10-19 15:07:07 -04:00
{
2022-12-09 12:23:23 -05:00
return 1;
2022-10-19 15:07:07 -04:00
}
2022-10-23 13:56:03 -04:00
2022-10-24 13:57:33 -04:00
const std::basic_string_view data(message->data + offset, message->cursize - offset);
2022-10-19 15:07:07 -04:00
2023-04-03 13:03:54 -04:00
try
{
handler->second(*address, data);
}
catch (const std::exception& e)
{
printf("Error: %s\n", e.what());
}
catch (...)
{
}
2022-12-09 12:23:23 -05:00
return 0;
2022-10-19 15:07:07 -04:00
}
2022-10-23 13:56:03 -04:00
void handle_command_stub(utils::hook::assembler& a)
2022-10-19 15:07:07 -04:00
{
2023-01-02 07:57:00 -05:00
const auto sv = game::is_server();
2022-10-23 13:56:03 -04:00
a.pushad64();
2023-03-12 09:55:58 -04:00
a.mov(rdx, rcx); // command
a.mov(r8, sv ? r15 : r12); // msg
2023-01-02 07:57:00 -05:00
a.mov(rcx, sv ? r14 : r15); // address
2022-10-23 13:56:03 -04:00
a.call_aligned(handle_command);
a.mov(qword_ptr(rsp, 0x78), rax);
a.popad64();
2023-01-02 07:57:00 -05:00
a.ret();
2022-10-19 15:07:07 -04:00
}
2022-10-23 14:57:44 -04:00
bool socket_set_blocking(const SOCKET s, const bool blocking)
{
unsigned long mode = blocking ? 0 : 1;
return ioctlsocket(s, FIONBIO, &mode) == 0;
}
void create_ip_socket()
{
auto& s = *game::ip_socket;
if (s)
{
return;
}
s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
2022-10-24 13:57:33 -04:00
if (s == INVALID_SOCKET)
{
throw std::runtime_error("Unable to create socket");
}
2022-10-23 14:57:44 -04:00
2023-02-26 07:26:41 -05:00
constexpr char broadcast = 1;
setsockopt(s, SOL_SOCKET, SO_BROADCAST, &broadcast, sizeof(broadcast));
2022-10-23 14:57:44 -04:00
socket_set_blocking(s, false);
const auto address = htonl(INADDR_ANY);
auto port = static_cast<uint16_t>(game::Dvar_FindVar("net_port")->current.value.integer);
2022-10-23 14:57:44 -04:00
sockaddr_in server_addr{};
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = address;
2022-10-25 15:09:38 -04:00
int retries = 0;
do
2022-10-23 14:57:44 -04:00
{
server_addr.sin_port = htons(port++);
2022-10-25 15:09:38 -04:00
if (++retries > 10) return;
}
while (bind(s, reinterpret_cast<sockaddr*>(&server_addr), sizeof(server_addr)) ==
SOCKET_ERROR);
2022-10-23 14:57:44 -04:00
}
2022-10-28 10:15:00 -04:00
bool& socket_byte_missing()
{
static thread_local bool was_missing{false};
return was_missing;
}
uint8_t read_socket_byte_stub(game::msg_t* msg)
{
auto& byte_missing = socket_byte_missing();
byte_missing = msg->cursize >= 4 && *reinterpret_cast<int*>(msg->data) == -1;
if (byte_missing)
{
return game::NS_SERVER | (game::NS_SERVER << 4);
}
const auto _ = utils::finally([msg]
{
++msg->data;
});
return game::MSG_ReadByte(msg);
}
2022-10-28 10:15:00 -04:00
int verify_checksum_stub(void* /*data*/, const int length)
{
return length + (socket_byte_missing() ? 1 : 0);
2022-10-28 10:15:00 -04:00
}
2023-01-09 10:53:51 -05:00
2023-03-12 09:55:58 -04:00
void con_restricted_execute_buf_stub(int local_client_num, game::ControllerIndex_t controller_index,
const char* buffer)
2023-01-09 10:53:51 -05:00
{
2023-01-09 16:51:37 -05:00
game::Cbuf_ExecuteBuffer(local_client_num, controller_index, buffer);
2023-01-09 10:53:51 -05:00
}
2023-03-12 09:55:58 -04:00
uint64_t handle_packet_internal_stub(const game::ControllerIndex_t controller_index,
const game::netadr_t from_adr, const game::XUID from_xuid,
const game::LobbyType lobby_type, const uint64_t dest_module,
game::msg_t* msg)
{
if (from_adr.type != game::NA_LOOPBACK)
{
return 0;
}
2023-03-12 09:55:58 -04:00
return handle_packet_internal_hook.invoke<bool>(controller_index, from_adr, from_xuid, lobby_type,
dest_module, msg)
? 1
: 0;
}
uint64_t ret2()
{
return 2;
}
int bind_stub(SOCKET /*s*/, const sockaddr* /*addr*/, int /*namelen*/)
{
return 0;
}
2022-10-24 15:00:22 -04:00
}
2022-10-24 13:57:33 -04:00
2022-10-24 15:00:22 -04:00
void on(const std::string& command, const callback& callback)
{
get_callbacks()[utils::string::to_lower(command)] = callback;
}
void send(const game::netadr_t& address, const std::string& command, const std::string& data, const char separator)
{
std::string packet = "\xFF\xFF\xFF\xFF";
packet.append(command);
packet.push_back(separator);
packet.append(data);
send_data(address, packet);
}
sockaddr_in convert_to_sockaddr(const game::netadr_t& address)
{
sockaddr_in to{};
to.sin_family = AF_INET;
to.sin_port = htons(address.port);
2022-10-29 14:05:22 -04:00
to.sin_addr.S_un.S_addr = address.addr;
return to;
}
2023-02-05 10:15:29 -05:00
void send_data(const game::netadr_t& address, const void* data, const size_t length)
2022-10-24 15:00:22 -04:00
{
//game::NET_SendPacket(game::NS_CLIENT1, static_cast<int>(size), data, &address);
const auto to = convert_to_sockaddr(address);
2023-02-05 10:15:29 -05:00
sendto(*game::ip_socket, static_cast<const char*>(data), static_cast<int>(length), 0,
reinterpret_cast<const sockaddr*>(&to), sizeof(to));
2022-10-24 15:00:22 -04:00
}
void send_data(const game::netadr_t& address, const std::string& data)
{
send_data(address, data.data(), data.size());
2022-10-19 15:07:07 -04:00
}
2022-10-28 14:34:10 -04:00
game::netadr_t address_from_string(const std::string& address)
{
game::netadr_t addr{};
addr.localNetID = game::NS_SERVER;
if (!game::NET_StringToAdr(address.data(), &addr))
{
addr.type = game::NA_BAD;
return addr;
}
if (addr.type == game::NA_IP)
{
addr.type = game::NA_RAWIP;
}
return addr;
}
2022-10-29 14:05:22 -04:00
game::netadr_t address_from_ip(const uint32_t ip, const uint16_t port)
{
game::netadr_t addr{};
addr.localNetID = game::NS_SERVER;
addr.type = game::NA_RAWIP;
addr.port = port;
addr.addr = ip;
return addr;
}
2022-10-28 16:16:14 -04:00
bool are_addresses_equal(const game::netadr_t& a, const game::netadr_t& b)
{
if (a.type != b.type)
{
return false;
}
if (a.type != game::NA_RAWIP && a.type != game::NA_IP)
{
return true;
}
2022-10-29 14:05:22 -04:00
return a.port == b.port && a.addr == b.addr;
2022-10-28 16:16:14 -04:00
}
2023-04-10 09:05:23 -04:00
int net_sendpacket_stub(const game::netsrc_t sock, const int length, const char* data, const game::netadr_t* to)
{
2023-04-10 11:14:16 -04:00
//printf("Sending packet of size: %X\n", length);
2023-04-10 09:05:23 -04:00
if (to->type != game::NA_RAWIP)
{
printf("NET_SendPacket: bad address type\n");
return 0;
}
const auto s = *game::ip_socket;
if (!s || sock > game::NS_MAXCLIENTS)
{
return 0;
}
sockaddr_in address{};
address.sin_family = AF_INET;
address.sin_port = htons(to->port);
address.sin_addr.s_addr = htonl(((to->ipv4.c | ((to->ipv4.b | (to->ipv4.a << 8)) << 8)) << 8) | to->ipv4.d);
const auto size = static_cast<size_t>(length);
std::vector<char> buffer{};
buffer.resize(size + 1);
buffer[0] = static_cast<char>((static_cast<uint32_t>(sock) & 0xF) | ((to->localNetID & 0xF) << 4));
memcpy(buffer.data() + 1, data, size);
return sendto(s, buffer.data(), static_cast<int>(buffer.size()), 0, reinterpret_cast<sockaddr*>(&address),
sizeof(address));
}
2023-01-02 07:57:00 -05:00
struct component final : generic_component
2022-10-19 15:07:07 -04:00
{
void post_unpack() override
{
2023-04-11 14:48:14 -04:00
scheduler::loop(game::fragment_handler::clean, scheduler::async, 5s);
2023-03-12 09:55:58 -04:00
utils::hook::nop(game::select(0x1423322B6, 0x140596DF6), 4);
// don't increment data pointer to optionally skip socket byte
utils::hook::call(game::select(0x142332283, 0x140596DC3), read_socket_byte_stub);
// optionally read socket byte
utils::hook::call(game::select(0x1423322C1, 0x140596E01), verify_checksum_stub);
// skip checksum verification
2023-03-04 09:42:31 -05:00
utils::hook::set<uint8_t>(game::select(0x14233249E, 0x140596F2E), 0); // don't add checksum to packet
2022-10-19 15:07:07 -04:00
2023-04-10 09:05:23 -04:00
// Recreate NET_SendPacket to increase max packet size
//utils::hook::jump(game::select(0x1423323B0, 0x140596E40), net_sendpacket_stub);
2023-04-10 09:05:23 -04:00
2023-03-12 09:55:58 -04:00
utils::hook::set<uint32_t>(game::select(0x14134C6E0, 0x14018E574), 5);
// set initial connection state to challenging
2022-10-23 14:57:44 -04:00
2022-10-23 13:56:03 -04:00
// intercept command handling
2023-01-02 07:57:00 -05:00
utils::hook::call(game::select(0x14134D146, 0x14018EED0), utils::hook::assemble(handle_command_stub));
2022-10-19 15:07:07 -04:00
2023-03-12 09:55:58 -04:00
utils::hook::set<uint8_t>(game::select(0x14224DEAD, 0x1405315F9), 0xEB);
// don't kick clients without dw handle
2022-10-24 13:57:33 -04:00
2023-02-21 12:00:59 -05:00
// Skip DW stuff in NetAdr_ToString
2023-03-04 09:42:31 -05:00
utils::hook::set<uint8_t>(game::select(0x142172EF2, 0x140515881), 0xEB);
2023-02-21 12:00:59 -05:00
// NA_IP -> NA_RAWIP in NetAdr_ToString
2023-03-04 09:42:31 -05:00
utils::hook::set<uint8_t>(game::select(0x142172ED4, 0x140515864), game::NA_RAWIP);
2023-02-21 12:00:59 -05:00
2023-01-09 16:51:37 -05:00
if (game::is_server())
{
// Remove restrictions for rcon commands
2023-02-26 04:05:00 -05:00
utils::hook::call(0x140538D5C_g, &con_restricted_execute_buf_stub); // SVC_RemoteCommand
2023-01-09 16:51:37 -05:00
}
2023-01-09 10:53:51 -05:00
2022-10-24 13:57:33 -04:00
// TODO: Fix that
2022-10-25 02:35:58 -04:00
scheduler::once(create_ip_socket, scheduler::main);
// Kill lobby system
2023-03-04 09:42:31 -05:00
handle_packet_internal_hook.create(game::select(0x141EF7FE0, 0x1404A5B90), &handle_packet_internal_stub);
2023-03-07 10:59:19 -05:00
// Kill voice chat
2023-03-07 11:01:51 -05:00
utils::hook::set<uint32_t>(game::select(0x141359310, 0x14018FE40), 0xC3C03148);
// Don't let the game bind sockets anymore
utils::hook::set(game::select(0x15AAE9344, 0x14B4BD828), bind_stub);
2023-03-17 16:02:40 -04:00
// Set cl_maxpackets to 100
utils::hook::set<uint8_t>(game::select(0x1412FF342, 0x140177A32), 100 - 15);
2022-10-23 13:56:03 -04:00
}
2022-10-19 15:07:07 -04:00
};
}
REGISTER_COMPONENT(network::component)