Don't authenticate loopback

This commit is contained in:
momo5502 2016-08-07 22:14:30 +02:00
parent 9e9967b9d1
commit 4fc7de502a
3 changed files with 178 additions and 166 deletions

View File

@ -63,86 +63,93 @@ namespace Components
return; return;
} }
#if DEBUG if (address.IsLoopback()
// Simply connect, if we're in debug mode, we ignore all security checks // Simply connect, if we're in debug mode, we ignore all security checks
if (!connectData.infostring().empty()) #ifdef DEBUG
|| true
#endif
)
{ {
Game::SV_Cmd_EndTokenizedString(); if (!connectData.infostring().empty())
Game::SV_Cmd_TokenizeString(connectData.infostring().data()); {
Game::SV_DirectConnect(*address.Get()); 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 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<unsigned int>(~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<uint32_t>(Dvar::Var("sv_securityLevel").Get<int>());
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<unsigned int>(~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<uint32_t>(Dvar::Var("sv_securityLevel").Get<int>());
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() void __declspec(naked) Auth::DirectConnectStub()

View File

@ -107,6 +107,10 @@ namespace Components
return false; return false;
} }
bool Network::Address::IsLoopback()
{
return Game::NET_IsLocalAddress(this->address);
}
bool Network::Address::IsValid() bool Network::Address::IsValid()
{ {
return (this->GetType() != Game::netadrtype_t::NA_BAD); return (this->GetType() != Game::netadrtype_t::NA_BAD);

View File

@ -1,91 +1,92 @@
#define NETWORK_MAX_PACKETS_PER_SECOND 100'000 #define NETWORK_MAX_PACKETS_PER_SECOND 100'000
namespace Components namespace Components
{ {
class Network : public Component class Network : public Component
{ {
public: public:
class Address class Address
{ {
public: public:
Address() { this->SetType(Game::netadrtype_t::NA_BAD); }; Address() { this->SetType(Game::netadrtype_t::NA_BAD); };
Address(std::string addrString); Address(std::string addrString);
Address(sockaddr* addr); Address(sockaddr* addr);
Address(sockaddr addr) : Address(&addr) {} Address(sockaddr addr) : Address(&addr) {}
Address(sockaddr_in addr) : Address(&addr) {} Address(sockaddr_in addr) : Address(&addr) {}
Address(sockaddr_in* addr) : Address(reinterpret_cast<sockaddr*>(addr)) {} Address(sockaddr_in* addr) : Address(reinterpret_cast<sockaddr*>(addr)) {}
Address(Game::netadr_t addr) : address(addr) {} Address(Game::netadr_t addr) : address(addr) {}
Address(Game::netadr_t* addr) : Address(*addr) {} Address(Game::netadr_t* addr) : Address(*addr) {}
Address(const Address& obj) : address(obj.address) {}; Address(const Address& obj) : address(obj.address) {};
Address(const Proto::Network::Address& addr) { this->Deserialize(addr); }; Address(const Proto::Network::Address& addr) { this->Deserialize(addr); };
bool operator!=(const Address &obj) { return !(*this == obj); }; bool operator!=(const Address &obj) { return !(*this == obj); };
bool operator==(const Address &obj); bool operator==(const Address &obj);
void SetPort(unsigned short port); void SetPort(unsigned short port);
unsigned short GetPort(); unsigned short GetPort();
void SetIP(DWORD ip); void SetIP(DWORD ip);
void SetIP(Game::netIP_t ip); void SetIP(Game::netIP_t ip);
Game::netIP_t GetIP(); Game::netIP_t GetIP();
void SetType(Game::netadrtype_t type); void SetType(Game::netadrtype_t type);
Game::netadrtype_t GetType(); Game::netadrtype_t GetType();
sockaddr GetSockAddr(); sockaddr GetSockAddr();
void ToSockAddr(sockaddr* addr); void ToSockAddr(sockaddr* addr);
void ToSockAddr(sockaddr_in* addr); void ToSockAddr(sockaddr_in* addr);
Game::netadr_t* Get(); Game::netadr_t* Get();
const char* GetCString(); const char* GetCString();
std::string GetString(); std::string GetString();
bool IsLocal(); bool IsLocal();
bool IsSelf(); bool IsSelf();
bool IsValid(); bool IsValid();
bool IsLoopback();
void Serialize(Proto::Network::Address* protoAddress);
void Deserialize(const Proto::Network::Address& protoAddress); void Serialize(Proto::Network::Address* protoAddress);
void Deserialize(const Proto::Network::Address& protoAddress);
private:
Game::netadr_t address; private:
}; Game::netadr_t address;
};
typedef void(Callback)(Address address, std::string data);
typedef void(CallbackRaw)(); typedef void(Callback)(Address address, std::string data);
typedef void(CallbackRaw)();
Network();
~Network(); Network();
const char* GetName() { return "Network"; }; ~Network();
const char* GetName() { return "Network"; };
static void Handle(std::string packet, Callback* callback);
static void OnStart(CallbackRaw* callback); 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); // Send quake-styled binary data
static void Send(Game::netsrc_t type, Address target, std::string 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); // Allows sending raw data without quake header
static void SendRaw(Game::netsrc_t type, Address target, std::string data); 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 = ""); // Send quake-style command using binary data
static void SendCommand(Game::netsrc_t type, Address target, std::string command, std::string 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 Broadcast(unsigned short port, std::string data);
static void BroadcastAll(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; private:
static std::string SelectedPacket; static SOCKET TcpSocket;
static wink::signal<wink::slot<CallbackRaw>> StartupSignal; static std::string SelectedPacket;
static std::map<std::string, wink::slot<Callback>> PacketHandlers; static wink::signal<wink::slot<CallbackRaw>> StartupSignal;
static std::map<std::string, wink::slot<Callback>> PacketHandlers;
static int PacketInterceptionHandler(const char* packet);
static void DeployPacket(Game::netadr_t* from, Game::msg_t* msg); static int PacketInterceptionHandler(const char* packet);
static void DeployPacketStub(); static void DeployPacket(Game::netadr_t* from, Game::msg_t* msg);
static void DeployPacketStub();
static void NetworkStart();
static void NetworkStartStub(); static void NetworkStart();
}; static void NetworkStartStub();
} };
}