diff --git a/src/Components/Modules/Auth.cpp b/src/Components/Modules/Auth.cpp index 09d70aba..628238c4 100644 --- a/src/Components/Modules/Auth.cpp +++ b/src/Components/Modules/Auth.cpp @@ -63,86 +63,93 @@ namespace Components return; } -#if DEBUG - // Simply connect, if we're in debug mode, we ignore all security checks - if (!connectData.infostring().empty()) + if (address.IsLoopback() +// Simply connect, if we're in debug mode, we ignore all security checks +#ifdef DEBUG + || true +#endif + ) { - Game::SV_Cmd_EndTokenizedString(); - Game::SV_Cmd_TokenizeString(connectData.infostring().data()); - Game::SV_DirectConnect(*address.Get()); + if (!connectData.infostring().empty()) + { + Game::SV_Cmd_EndTokenizedString(); + Game::SV_Cmd_TokenizeString(connectData.infostring().data()); + Game::SV_DirectConnect(*address.Get()); + } + else + { + Network::Send(address, "error\nInvalid infostring data!"); + } } else { - Network::Send(address, "error\nInvalid infostring data!"); + // Validate proto data + if (connectData.signature().empty() || connectData.publickey().empty() || connectData.token().empty() || connectData.infostring().empty()) + { + Network::Send(address, "error\nInvalid connect data!"); + return; + } + + // Setup new cmd params + Game::SV_Cmd_EndTokenizedString(); + Game::SV_Cmd_TokenizeString(connectData.infostring().data()); + + // Access the params + Command::Params params(true); + + // Ensure there are enough params + if (params.Length() < 3) + { + Network::Send(address, "error\nInvalid connect string!"); + return; + } + + // Parse the infostring + Utils::InfoString infostr(params[2]); + + // Read the required data + std::string steamId = infostr.Get("xuid"); + std::string challenge = infostr.Get("challenge"); + + if (steamId.empty() || challenge.empty()) + { + Network::Send(address, "error\nInvalid connect data!"); + return; + } + + // Parse the id + unsigned __int64 xuid = strtoull(steamId.data(), nullptr, 16); + unsigned int id = static_cast(~0x110000100000000 & xuid); + + if ((xuid & 0xFFFFFFFF00000000) != 0x110000100000000 || id != (Utils::Cryptography::JenkinsOneAtATime::Compute(connectData.publickey()) & ~0x80000000)) + { + Network::Send(address, "error\nXUID doesn't match the certificate!"); + return; + } + + // Verify the signature + Utils::Cryptography::ECC::Key key; + key.Set(connectData.publickey()); + + if (!key.IsValid() || !Utils::Cryptography::ECC::VerifyMessage(key, challenge, connectData.signature())) + { + Network::Send(address, "error\nChallenge signature was invalid!"); + return; + } + + // Verify the security level + uint32_t ourLevel = static_cast(Dvar::Var("sv_securityLevel").Get()); + uint32_t userLevel = Auth::GetZeroBits(connectData.token(), connectData.publickey()); + + if (userLevel < ourLevel) + { + Network::Send(address, fmt::sprintf("error\nYour security level (%d) is lower than the server's security level (%d)", userLevel, ourLevel)); + return; + } + + Logger::Print("Verified XUID %llX (%d) from %s\n", xuid, userLevel, address.GetCString()); + Game::SV_DirectConnect(*address.Get()); } -#else - // Validate proto data - if (connectData.signature().empty() || connectData.publickey().empty() || connectData.token().empty() || connectData.infostring().empty()) - { - Network::Send(address, "error\nInvalid connect data!"); - return; - } - - // Setup new cmd params - Game::SV_Cmd_EndTokenizedString(); - Game::SV_Cmd_TokenizeString(connectData.infostring().data()); - - // Access the params - Command::Params params(true); - - // Ensure there are enough params - if (params.Length() < 3) - { - Network::Send(address, "error\nInvalid connect string!"); - return; - } - - // Parse the infostring - Utils::InfoString infostr(params[2]); - - // Read the required data - std::string steamId = infostr.Get("xuid"); - std::string challenge = infostr.Get("challenge"); - - if (steamId.empty() || challenge.empty()) - { - Network::Send(address, "error\nInvalid connect data!"); - return; - } - - // Parse the id - unsigned __int64 xuid = strtoull(steamId.data(), nullptr, 16); - unsigned int id = static_cast(~0x110000100000000 & xuid); - - if ((xuid & 0xFFFFFFFF00000000) != 0x110000100000000 || id != (Utils::Cryptography::JenkinsOneAtATime::Compute(connectData.publickey()) & ~0x80000000)) - { - Network::Send(address, "error\nXUID doesn't match the certificate!"); - return; - } - - // Verify the signature - Utils::Cryptography::ECC::Key key; - key.Set(connectData.publickey()); - - if (!key.IsValid() || !Utils::Cryptography::ECC::VerifyMessage(key, challenge, connectData.signature())) - { - Network::Send(address, "error\nChallenge signature was invalid!"); - return; - } - - // Verify the security level - uint32_t ourLevel = static_cast(Dvar::Var("sv_securityLevel").Get()); - uint32_t userLevel = Auth::GetZeroBits(connectData.token(), connectData.publickey()); - - if (userLevel < ourLevel) - { - Network::Send(address, fmt::sprintf("error\nYour security level (%d) is lower than the server's security level (%d)", userLevel, ourLevel)); - return; - } - - Logger::Print("Verified XUID %llX (%d) from %s\n", xuid, userLevel, address.GetCString()); - Game::SV_DirectConnect(*address.Get()); -#endif } void __declspec(naked) Auth::DirectConnectStub() diff --git a/src/Components/Modules/Network.cpp b/src/Components/Modules/Network.cpp index c4b5dda0..8ec561ab 100644 --- a/src/Components/Modules/Network.cpp +++ b/src/Components/Modules/Network.cpp @@ -107,6 +107,10 @@ namespace Components return false; } + bool Network::Address::IsLoopback() + { + return Game::NET_IsLocalAddress(this->address); + } bool Network::Address::IsValid() { return (this->GetType() != Game::netadrtype_t::NA_BAD); diff --git a/src/Components/Modules/Network.hpp b/src/Components/Modules/Network.hpp index 488c3f3f..aef42803 100644 --- a/src/Components/Modules/Network.hpp +++ b/src/Components/Modules/Network.hpp @@ -1,91 +1,92 @@ -#define NETWORK_MAX_PACKETS_PER_SECOND 100'000 - -namespace Components -{ - class Network : public Component - { - public: - class Address - { - public: - Address() { this->SetType(Game::netadrtype_t::NA_BAD); }; - Address(std::string addrString); - Address(sockaddr* addr); - Address(sockaddr addr) : Address(&addr) {} - Address(sockaddr_in addr) : Address(&addr) {} - Address(sockaddr_in* addr) : Address(reinterpret_cast(addr)) {} - Address(Game::netadr_t addr) : address(addr) {} - Address(Game::netadr_t* addr) : Address(*addr) {} - Address(const Address& obj) : address(obj.address) {}; - Address(const Proto::Network::Address& addr) { this->Deserialize(addr); }; - bool operator!=(const Address &obj) { return !(*this == obj); }; - bool operator==(const Address &obj); - - void SetPort(unsigned short port); - unsigned short GetPort(); - - void SetIP(DWORD ip); - void SetIP(Game::netIP_t ip); - Game::netIP_t GetIP(); - - void SetType(Game::netadrtype_t type); - Game::netadrtype_t GetType(); - - sockaddr GetSockAddr(); - void ToSockAddr(sockaddr* addr); - void ToSockAddr(sockaddr_in* addr); - Game::netadr_t* Get(); - const char* GetCString(); - std::string GetString(); - - bool IsLocal(); - bool IsSelf(); - bool IsValid(); - - void Serialize(Proto::Network::Address* protoAddress); - void Deserialize(const Proto::Network::Address& protoAddress); - - private: - Game::netadr_t address; - }; - - typedef void(Callback)(Address address, std::string data); - typedef void(CallbackRaw)(); - - Network(); - ~Network(); - const char* GetName() { return "Network"; }; - - static void Handle(std::string packet, Callback* callback); - static void OnStart(CallbackRaw* callback); - - // Send quake-styled binary data - static void Send(Address target, std::string data); - static void Send(Game::netsrc_t type, Address target, std::string data); - - // Allows sending raw data without quake header - static void SendRaw(Address target, std::string data); - static void SendRaw(Game::netsrc_t type, Address target, std::string data); - - // Send quake-style command using binary data - static void SendCommand(Address target, std::string command, std::string data = ""); - static void SendCommand(Game::netsrc_t type, Address target, std::string command, std::string data = ""); - - static void Broadcast(unsigned short port, std::string data); - static void BroadcastRange(unsigned int min, unsigned int max, std::string data); - static void BroadcastAll(std::string data); - - private: - static SOCKET TcpSocket; - static std::string SelectedPacket; - static wink::signal> StartupSignal; - static std::map> PacketHandlers; - - static int PacketInterceptionHandler(const char* packet); - static void DeployPacket(Game::netadr_t* from, Game::msg_t* msg); - static void DeployPacketStub(); - - static void NetworkStart(); - static void NetworkStartStub(); - }; -} +#define NETWORK_MAX_PACKETS_PER_SECOND 100'000 + +namespace Components +{ + class Network : public Component + { + public: + class Address + { + public: + Address() { this->SetType(Game::netadrtype_t::NA_BAD); }; + Address(std::string addrString); + Address(sockaddr* addr); + Address(sockaddr addr) : Address(&addr) {} + Address(sockaddr_in addr) : Address(&addr) {} + Address(sockaddr_in* addr) : Address(reinterpret_cast(addr)) {} + Address(Game::netadr_t addr) : address(addr) {} + Address(Game::netadr_t* addr) : Address(*addr) {} + Address(const Address& obj) : address(obj.address) {}; + Address(const Proto::Network::Address& addr) { this->Deserialize(addr); }; + bool operator!=(const Address &obj) { return !(*this == obj); }; + bool operator==(const Address &obj); + + void SetPort(unsigned short port); + unsigned short GetPort(); + + void SetIP(DWORD ip); + void SetIP(Game::netIP_t ip); + Game::netIP_t GetIP(); + + void SetType(Game::netadrtype_t type); + Game::netadrtype_t GetType(); + + sockaddr GetSockAddr(); + void ToSockAddr(sockaddr* addr); + void ToSockAddr(sockaddr_in* addr); + Game::netadr_t* Get(); + const char* GetCString(); + std::string GetString(); + + bool IsLocal(); + bool IsSelf(); + bool IsValid(); + bool IsLoopback(); + + void Serialize(Proto::Network::Address* protoAddress); + void Deserialize(const Proto::Network::Address& protoAddress); + + private: + Game::netadr_t address; + }; + + typedef void(Callback)(Address address, std::string data); + typedef void(CallbackRaw)(); + + Network(); + ~Network(); + const char* GetName() { return "Network"; }; + + static void Handle(std::string packet, Callback* callback); + static void OnStart(CallbackRaw* callback); + + // Send quake-styled binary data + static void Send(Address target, std::string data); + static void Send(Game::netsrc_t type, Address target, std::string data); + + // Allows sending raw data without quake header + static void SendRaw(Address target, std::string data); + static void SendRaw(Game::netsrc_t type, Address target, std::string data); + + // Send quake-style command using binary data + static void SendCommand(Address target, std::string command, std::string data = ""); + static void SendCommand(Game::netsrc_t type, Address target, std::string command, std::string data = ""); + + static void Broadcast(unsigned short port, std::string data); + static void BroadcastRange(unsigned int min, unsigned int max, std::string data); + static void BroadcastAll(std::string data); + + private: + static SOCKET TcpSocket; + static std::string SelectedPacket; + static wink::signal> StartupSignal; + static std::map> PacketHandlers; + + static int PacketInterceptionHandler(const char* packet); + static void DeployPacket(Game::netadr_t* from, Game::msg_t* msg); + static void DeployPacketStub(); + + static void NetworkStart(); + static void NetworkStartStub(); + }; +}