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

438 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;
std::unordered_map<std::string, Network::NetworkCallback> Network::SV_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);
}
2021-09-12 07:47:35 -04:00
bool Network::Address::operator==(const Network::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
}
2017-01-19 16:23:59 -05:00
bool Network::Address::isLocal()
{
// 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;
}
2017-01-19 16:23:59 -05:00
bool Network::Address::isSelf()
{
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;
}
2022-08-19 19:10:35 -04:00
bool Network::Address::isLoopback() const
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);
}
2022-08-19 19:10:35 -04:00
bool Network::Address::isValid() const
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
{
// NET_OutOfBandPrint only supports non-binary data!
//Game::NET_OutOfBandPrint(type, *target.Get(), data.data());
std::string rawData;
rawData.append("\xFF\xFF\xFF\xFF", 4);
rawData.append(data);
//rawData.append("\0", 1);
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;
2017-01-19 16:23:59 -05:00
// NET_OutOfBandData doesn't seem to work properly
//Game::NET_OutOfBandData(type, *target.Get(), data.data(), data.size());
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
}
unsigned short Network::GetPort()
{
return static_cast<unsigned short>(Dvar::Var(0x64A3004).get<unsigned int>());
}
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-06-12 17:07:53 -04:00
Logger::Print(Game::conChannel_t::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-19 19:10:35 -04:00
SendCommand(Game::NS_SERVER, client->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
void Network::OnServerPacket(const std::string& command, const NetworkCallback& callback)
{
SV_Callbacks[Utils::String::ToLower(command)] = callback;
}
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);
Address address_ = address;
handler->second(address_, data);
return true;
}
bool Network::SV_HandleCommand(Game::netadr_t* address, const char* command, const Game::msg_t* message)
{
const auto command_ = Utils::String::ToLower(command);
const auto handler = SV_Callbacks.find(command_);
const auto offset = command_.size() + 5;
if (static_cast<std::size_t>(message->cursize) < offset || handler == SV_Callbacks.end())
2022-05-20 18:12:46 -04:00
{
return false;
}
2022-08-13 11:19:45 -04:00
const std::string data(reinterpret_cast<char*>(message->data) + offset, message->cursize - offset);
2022-05-20 18:12:46 -04:00
Address address_ = address;
handler->second(address_, data);
return true;
}
__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
}
}
2022-08-19 19:10:35 -04:00
__declspec(naked) void Network::SV_HandleCommandStub()
{
__asm
{
lea eax, [esp + 0x408]
pushad
push esi // msg
push edi // command name
push eax // netadr_t pointer
call SV_HandleCommand
add esp, 0xC
test al, al
popad
jz unhandled
// Exit SV_ConnectionlessPacket
push 0x6267EB
retn
unhandled:
// Proceed
push 0x6266E0
retn
}
}
2017-01-19 16:23:59 -05:00
Network::Network()
{
AssertSize(Game::netadr_t, 20);
// maximum size in NET_OutOfBandPrint
Utils::Hook::Set<DWORD>(0x4AEF08, 0x1FFFC);
Utils::Hook::Set<DWORD>(0x4AEFA3, 0x1FFFC);
// increase max port binding attempts from 10 to 100
Utils::Hook::Set<BYTE>(0x4FD48A, 100);
// increase cl_maxpackets limit
Utils::Hook::Set<BYTE>(0x4050A1, 125);
2017-06-29 17:03:57 -04:00
// increase snaps
//Utils::Hook::Set<BYTE>(0x405357, 40);
// default maxpackets and snaps
Utils::Hook::Set<BYTE>(0x40535B, 30);
Utils::Hook::Set<BYTE>(0x4050A5, 125);
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();
Utils::Hook(0x6266CA, SV_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
Utils::Hook::Set<BYTE>(0x5AA5B6, 0xEB); // CL_SteamServerAuth
Utils::Hook::Set<BYTE>(0x5AA69F, 0xEB); // echo
Utils::Hook::Set<BYTE>(0x5AAA82, 0xEB); // SP
2022-08-13 11:19:45 -04:00
Utils::Hook::Set<BYTE>(0x5A9F18, 0xEB); // CL_VoiceConnectionTestPacket
Utils::Hook::Set<BYTE>(0x5A9FF3, 0xEB); // CL_HandleRelayPacket
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
});
}
}