iw4x-client/src/Components/Modules/Network.cpp

399 lines
10 KiB
C++
Raw Normal View History

2022-02-27 07:53:44 -05:00
#include <STDInclude.hpp>
2017-01-19 16:23:59 -05:00
namespace Components
{
Utils::Signal<Network::CallbackRaw> Network::StartupSignal;
2022-05-20 18:12:46 -04:00
// Packet interception
2022-08-19 19:10:35 -04:00
std::unordered_map<std::string, Network::NetworkCallback> Network::CL_Callbacks;
2017-01-19 16:23:59 -05:00
2018-12-17 08:29:18 -05:00
Network::Address::Address(const std::string& addrString)
2017-01-19 16:23:59 -05:00
{
Game::NET_StringToAdr(addrString.data(), &this->address);
}
2017-01-19 16:23:59 -05:00
Network::Address::Address(sockaddr* addr)
{
Game::SockadrToNetadr(addr, &this->address);
}
2022-11-16 12:25:21 -05:00
bool Network::Address::operator==(const Address& obj) const
2017-01-19 16:23:59 -05:00
{
return Game::NET_CompareAdr(this->address, obj.address);
}
2017-01-19 16:23:59 -05:00
void Network::Address::setPort(unsigned short port)
{
this->address.port = htons(port);
}
2022-08-19 19:10:35 -04:00
unsigned short Network::Address::getPort() const
2017-01-19 16:23:59 -05:00
{
return ntohs(this->address.port);
}
2017-01-19 16:23:59 -05:00
void Network::Address::setIP(DWORD ip)
{
this->address.ip.full = ip;
}
2017-01-19 16:23:59 -05:00
void Network::Address::setIP(Game::netIP_t ip)
{
this->address.ip = ip;
}
2022-08-19 19:10:35 -04:00
Game::netIP_t Network::Address::getIP() const
2017-01-19 16:23:59 -05:00
{
return this->address.ip;
}
2017-01-19 16:23:59 -05:00
void Network::Address::setType(Game::netadrtype_t type)
{
this->address.type = type;
}
2022-08-19 19:10:35 -04:00
Game::netadrtype_t Network::Address::getType() const
2017-01-19 16:23:59 -05:00
{
return this->address.type;
}
2017-01-19 16:23:59 -05:00
sockaddr Network::Address::getSockAddr()
{
sockaddr addr;
this->toSockAddr(&addr);
return addr;
}
2017-01-19 16:23:59 -05:00
void Network::Address::toSockAddr(sockaddr* addr)
{
if (addr)
{
Game::NetadrToSockadr(&this->address, addr);
}
}
2017-01-19 16:23:59 -05:00
void Network::Address::toSockAddr(sockaddr_in* addr)
{
this->toSockAddr(reinterpret_cast<sockaddr*>(addr));
}
2017-01-19 16:23:59 -05:00
Game::netadr_t* Network::Address::get()
{
return &this->address;
}
2017-06-25 15:54:35 -04:00
const char* Network::Address::getCString() const
2017-01-19 16:23:59 -05:00
{
return Game::NET_AdrToString(this->address);
}
2017-06-25 15:54:35 -04:00
std::string Network::Address::getString() const
2017-01-19 16:23:59 -05:00
{
2022-08-19 19:10:35 -04:00
return {this->getCString()};
2017-01-19 16:23:59 -05:00
}
2023-02-06 14:34:08 -05:00
bool Network::Address::isLocal() const noexcept
2017-01-19 16:23:59 -05:00
{
// According to: https://en.wikipedia.org/wiki/Private_network
// 10.X.X.X
if (this->getIP().bytes[0] == 10) return true;
// 192.168.X.X
if (this->getIP().bytes[0] == 192 && this->getIP().bytes[1] == 168) return true;
// 172.16.X.X - 172.31.X.X
if (this->getIP().bytes[0] == 172 && (this->getIP().bytes[1] >= 16) && (this->getIP().bytes[1] < 32)) return true;
// 127.0.0.1
if (this->getIP().full == 0x0100007F) return true;
// TODO: Maybe check for matching localIPs and subnet mask
return false;
}
2023-02-06 14:34:08 -05:00
bool Network::Address::isSelf() const noexcept
2017-01-19 16:23:59 -05:00
{
if (Game::NET_IsLocalAddress(this->address)) return true; // Loopback
2022-08-19 19:10:35 -04:00
if (this->getPort() != GetPort()) return false; // Port not equal
2017-01-19 16:23:59 -05:00
for (int i = 0; i < *Game::numIP; ++i)
{
if (this->getIP().full == Game::localIP[i].full)
{
return true;
}
}
return false;
}
2023-02-06 14:34:08 -05:00
bool Network::Address::isLoopback() const noexcept
2017-01-19 16:23:59 -05:00
{
if (this->getIP().full == 0x100007f) // 127.0.0.1
{
return true;
}
return Game::NET_IsLocalAddress(this->address);
}
2023-02-06 14:34:08 -05:00
bool Network::Address::isValid() const noexcept
2017-01-19 16:23:59 -05:00
{
2022-08-19 19:10:35 -04:00
return (this->getType() != Game::NA_BAD && this->getType() >= Game::NA_BOT && this->getType() <= Game::NA_IP);
2017-01-19 16:23:59 -05:00
}
2022-08-19 19:10:35 -04:00
void Network::OnStart(const Utils::Slot<CallbackRaw>& callback)
2017-01-19 16:23:59 -05:00
{
2022-08-19 19:10:35 -04:00
StartupSignal.connect(callback);
2017-01-19 16:23:59 -05:00
}
2022-08-19 19:10:35 -04:00
void Network::Send(Game::netsrc_t type, Address target, const std::string& data)
2017-01-19 16:23:59 -05:00
{
2022-11-16 12:25:21 -05:00
// Do not use NET_OutOfBandPrint. It only supports non-binary data!
2017-01-19 16:23:59 -05:00
std::string rawData;
rawData.append("\xFF\xFF\xFF\xFF", 4);
rawData.append(data);
2022-08-19 19:10:35 -04:00
SendRaw(type, target, rawData);
2017-01-19 16:23:59 -05:00
}
2022-08-19 19:10:35 -04:00
void Network::Send(Address target, const std::string& data)
2017-01-19 16:23:59 -05:00
{
2022-08-19 19:10:35 -04:00
Send(Game::netsrc_t::NS_CLIENT1, target, data);
2017-01-19 16:23:59 -05:00
}
2022-08-19 19:10:35 -04:00
void Network::SendRaw(Game::netsrc_t type, Address target, const std::string& data)
2017-01-19 16:23:59 -05:00
{
if (!target.isValid()) return;
2022-11-16 12:25:21 -05:00
// NET_OutOfBandData doesn't seem to work properly. Do not use it
2017-01-19 16:23:59 -05:00
Game::Sys_SendPacket(type, data.size(), data.data(), *target.get());
}
2022-08-19 19:10:35 -04:00
void Network::SendRaw(Address target, const std::string& data)
2017-01-19 16:23:59 -05:00
{
2022-08-19 19:10:35 -04:00
SendRaw(Game::NS_CLIENT1, target, data);
2017-01-19 16:23:59 -05:00
}
2022-08-19 19:10:35 -04:00
void Network::SendCommand(Game::netsrc_t type, Address target, const std::string& command, const std::string& data)
2017-01-19 16:23:59 -05:00
{
// Use space as separator (possible separators are '\n', ' ').
2017-01-31 16:02:08 -05:00
// Though, our handler only needs exactly 1 char as separator and doesn't care which char it is.
// EDIT: Most 3rd party tools expect a line break, so let's use that instead!
2017-01-19 16:23:59 -05:00
std::string packet;
packet.append(command);
2017-01-31 16:02:08 -05:00
packet.append("\n", 1);
2017-01-19 16:23:59 -05:00
packet.append(data);
2022-08-19 19:10:35 -04:00
Send(type, target, packet);
2017-01-19 16:23:59 -05:00
}
2022-08-19 19:10:35 -04:00
void Network::SendCommand(Address target, const std::string& command, const std::string& data)
2017-01-19 16:23:59 -05:00
{
2022-08-19 19:10:35 -04:00
SendCommand(Game::NS_CLIENT1, target, command, data);
2017-01-19 16:23:59 -05:00
}
2018-12-17 08:29:18 -05:00
void Network::Broadcast(unsigned short port, const std::string& data)
2017-01-19 16:23:59 -05:00
{
Address target;
target.setPort(port);
target.setIP(INADDR_BROADCAST);
target.setType(Game::netadrtype_t::NA_BROADCAST);
2022-08-19 19:10:35 -04:00
Send(Game::netsrc_t::NS_CLIENT1, target, data);
2017-01-19 16:23:59 -05:00
}
2018-12-17 08:29:18 -05:00
void Network::BroadcastRange(unsigned int min, unsigned int max, const std::string& data)
2017-01-19 16:23:59 -05:00
{
for (unsigned int i = min; i < max; ++i)
{
2022-08-19 19:10:35 -04:00
Broadcast(static_cast<unsigned short>(i & 0xFFFF), data);
2017-01-19 16:23:59 -05:00
}
}
2018-12-17 08:29:18 -05:00
void Network::BroadcastAll(const std::string& data)
2017-01-19 16:23:59 -05:00
{
2022-08-19 19:10:35 -04:00
BroadcastRange(100, 65536, data);
2017-01-19 16:23:59 -05:00
}
void Network::NetworkStart()
{
2022-08-19 19:10:35 -04:00
StartupSignal();
StartupSignal.clear();
2017-01-19 16:23:59 -05:00
}
2023-02-06 14:34:08 -05:00
std::uint16_t Network::GetPort()
{
2023-02-06 14:34:08 -05:00
assert((*Game::port));
assert((*Game::port)->current.unsignedInt <= std::numeric_limits<std::uint16_t>::max());
return static_cast<std::uint16_t>((*Game::port)->current.unsignedInt);
}
2017-01-19 16:23:59 -05:00
__declspec(naked) void Network::NetworkStartStub()
{
__asm
{
mov eax, 64D900h
call eax
2022-08-19 19:10:35 -04:00
jmp NetworkStart
2017-01-19 16:23:59 -05:00
}
}
__declspec(naked) void Network::PacketErrorCheck()
{
__asm
{
cmp eax, 2746h
jz returnIgnore
cmp eax, WSAENETRESET
jz returnIgnore
push 465325h
retn
returnIgnore:
push 4654C6h
retn
}
}
void Network::SV_ExecuteClientMessageStub(Game::client_t* client, Game::msg_t* msg)
2021-09-12 07:47:35 -04:00
{
if (client->reliableAcknowledge < 0)
{
2022-12-05 13:45:14 -05:00
Logger::Print(Game::CON_CHANNEL_NETWORK, "Negative reliableAcknowledge from {} - cl->reliableSequence is {}, reliableAcknowledge is {}\n",
2022-08-19 19:10:35 -04:00
client->name, client->reliableSequence, client->reliableAcknowledge);
client->reliableAcknowledge = client->reliableSequence;
2022-08-20 06:09:41 -04:00
SendCommand(Game::NS_SERVER, client->header.netchan.remoteAddress, "error", "EXE_LOSTRELIABLECOMMANDS");
return;
}
2021-09-12 07:47:35 -04:00
Utils::Hook::Call<void(Game::client_t*, Game::msg_t*)>(0x414D40)(client, msg);
}
2022-08-19 19:10:35 -04:00
void Network::OnClientPacket(const std::string& command, const NetworkCallback& callback)
2022-05-20 18:12:46 -04:00
{
2022-08-19 19:10:35 -04:00
CL_Callbacks[Utils::String::ToLower(command)] = callback;
2022-05-20 18:12:46 -04:00
}
2022-08-19 19:10:35 -04:00
bool Network::CL_HandleCommand(Game::netadr_t* address, const char* command, const Game::msg_t* message)
2022-05-20 18:12:46 -04:00
{
2022-06-25 12:21:12 -04:00
const auto command_ = Utils::String::ToLower(command);
2022-08-19 19:10:35 -04:00
const auto handler = CL_Callbacks.find(command_);
2022-05-20 18:12:46 -04:00
2022-06-25 12:21:12 -04:00
const auto offset = command_.size() + 5;
2022-08-19 19:10:35 -04:00
if (static_cast<std::size_t>(message->cursize) < offset || handler == CL_Callbacks.end())
{
return false;
}
const std::string data(reinterpret_cast<char*>(message->data) + offset, message->cursize - offset);
2022-11-16 12:25:21 -05:00
auto address_ = Address(address);
2022-08-19 19:10:35 -04:00
handler->second(address_, data);
return true;
}
2022-05-20 18:12:46 -04:00
__declspec(naked) void Network::CL_HandleCommandStub()
{
__asm
{
lea eax, [esp + 0xC54] // address
pushad
push ebp // msg_t
2022-08-19 19:10:35 -04:00
push edi // command name
2022-05-20 18:12:46 -04:00
push eax // netadr_t pointer
2022-08-19 19:10:35 -04:00
call CL_HandleCommand
2022-05-20 18:12:46 -04:00
add esp, 0xC
test al, al
popad
jz unhandled
// Exit CL_DispatchConnectionlessPacket
push 0x5A9E0E
retn
unhandled:
// Proceed
push 0x5AA719
retn
}
}
2017-01-19 16:23:59 -05:00
Network::Network()
{
AssertSize(Game::netadr_t, 20);
2023-01-11 14:37:35 -05:00
// Maximum size in NET_OutOfBandPrint
Utils::Hook::Set<std::uint32_t>(0x4AEF08, 0x1FFFC);
Utils::Hook::Set<std::uint32_t>(0x4AEFA3, 0x1FFFC);
2017-01-19 16:23:59 -05:00
2023-01-11 14:37:35 -05:00
// Increase max port binding attempts from 10 to 100
Utils::Hook::Set<std::uint8_t>(0x4FD48A, 100);
2017-01-19 16:23:59 -05:00
2023-01-11 14:37:35 -05:00
// Increase cl_maxpackets dvar limit
Utils::Hook::Set<std::uint8_t>(0x4050A1, 125);
2017-01-19 16:23:59 -05:00
2023-01-11 14:37:35 -05:00
// Increase snaps (disabled for unknown reasons)
2017-06-29 17:03:57 -04:00
//Utils::Hook::Set<BYTE>(0x405357, 40);
2023-01-11 14:37:35 -05:00
// Set default value of snaps and cl_maxpackets dvar
Utils::Hook::Set<std::uint8_t>(0x40535B, 30);
Utils::Hook::Set<std::uint8_t>(0x4050A5, 125);
2017-06-29 17:03:57 -04:00
2017-01-19 16:23:59 -05:00
// Parse port as short in Net_AddrToString
2020-12-09 14:13:34 -05:00
Utils::Hook::Set<const char*>(0x4698E3, "%u.%u.%u.%u:%hu");
2017-01-19 16:23:59 -05:00
// Install startup handler
2022-08-19 19:10:35 -04:00
Utils::Hook(0x4FD4D4, NetworkStartStub, HOOK_JUMP).install()->quick();
2017-01-19 16:23:59 -05:00
// Prevent recvfrom error spam
2022-08-19 19:10:35 -04:00
Utils::Hook(0x46531A, PacketErrorCheck, HOOK_JUMP).install()->quick();
2017-01-19 16:23:59 -05:00
// Fix server freezer exploit
2022-08-19 19:10:35 -04:00
Utils::Hook(0x626996, SV_ExecuteClientMessageStub, HOOK_CALL).install()->quick();
2022-05-20 18:12:46 -04:00
// Handle client packets
2022-08-19 19:10:35 -04:00
Utils::Hook(0x5AA703, CL_HandleCommandStub, HOOK_JUMP).install()->quick();
2021-09-12 07:47:35 -04:00
2022-06-27 07:09:10 -04:00
// Disable unused OOB packets handlers just to be sure
2023-01-11 14:37:35 -05:00
Utils::Hook::Set<std::uint8_t>(0x5AA5B6, 0xEB); // CL_SteamServerAuth
Utils::Hook::Set<std::uint8_t>(0x5AA69F, 0xEB); // echo
Utils::Hook::Set<std::uint8_t>(0x5AAA82, 0xEB); // SP
Utils::Hook::Set<std::uint8_t>(0x5A9F18, 0xEB); // CL_VoiceConnectionTestPacket
Utils::Hook::Set<std::uint8_t>(0x5A9FF3, 0xEB); // CL_HandleRelayPacket
// Com_GetProtocol
Utils::Hook::Set<std::uint32_t>(0x4FB501, PROTOCOL);
// Set the default, min and max of the protocol dvar
Utils::Hook::Set<std::uint32_t>(0x4D36A9, PROTOCOL);
Utils::Hook::Set<std::uint32_t>(0x4D36AE, PROTOCOL);
Utils::Hook::Set<std::uint32_t>(0x4D36B3, PROTOCOL);
// Internal version is 99, most servers should accept it
Utils::Hook::Set<std::uint32_t>(0x463C61, 208); // getBuildNumberAsInt
// LSP disabled
Utils::Hook::Set<std::uint8_t>(0x435950, 0xC3); // LSP HELLO
Utils::Hook::Set<std::uint8_t>(0x49C220, 0xC3); // We wanted to send a logging packet, but we haven't connected to LSP!
Utils::Hook::Set<std::uint8_t>(0x4BD900, 0xC3); // main LSP response func
Utils::Hook::Set<std::uint8_t>(0x682170, 0xC3); // Telling LSP that we're playing a private match
Utils::Hook::Nop(0x4FD448, 5); // Don't create lsp_socket
2022-06-27 07:09:10 -04:00
2022-08-19 19:10:35 -04:00
OnClientPacket("resolveAddress", [](const Address& address, [[maybe_unused]] const std::string& data)
2017-01-19 16:23:59 -05:00
{
2022-08-19 19:10:35 -04:00
SendRaw(address, address.getString());
2017-01-19 16:23:59 -05:00
});
}
}