Add DoS protection to server info requests

Only allow 10 requests per second before falling back to smaller server
info responses.
This commit is contained in:
heinrich5991 2016-01-22 16:02:40 +01:00
parent 8636e6004a
commit b29a733c4f
2 changed files with 54 additions and 7 deletions

View file

@ -317,6 +317,10 @@ CServer::CServer()
m_RconRestrict = -1;
m_GeneratedRconPassword = 0;
m_ServerInfoFirstRequest = 0;
m_ServerInfoNumRequests = 0;
m_ServerInfoHighLoad = false;
Init();
}
@ -1266,12 +1270,35 @@ void CServer::ProcessClientPacket(CNetChunk *pPacket)
}
}
void CServer::SendServerInfo(const NETADDR *pAddr, int Token, bool Extended, int Offset)
void CServer::SendServerInfoConnless(const NETADDR *pAddr, int Token, bool Extended)
{
static const int MAX_REQUESTS_PER_SECOND = 10;
int64 Now = Tick();
if(Now <= m_ServerInfoFirstRequest + TickSpeed())
{
m_ServerInfoNumRequests++;
}
else
{
m_ServerInfoHighLoad = m_ServerInfoNumRequests > MAX_REQUESTS_PER_SECOND;
m_ServerInfoNumRequests = 1;
m_ServerInfoFirstRequest = Now;
}
bool Short = m_ServerInfoNumRequests > MAX_REQUESTS_PER_SECOND || m_ServerInfoHighLoad;
SendServerInfo(pAddr, Token, Extended, 0, Short);
}
void CServer::SendServerInfo(const NETADDR *pAddr, int Token, bool Extended, int Offset, bool Short)
{
CNetChunk Packet;
CPacker p;
char aBuf[128];
Packet.m_ClientID = -1;
Packet.m_Address = *pAddr;
Packet.m_Flags = NETSENDFLAG_CONNLESS;
// count the players
int PlayerCount = 0, ClientCount = 0;
for(int i = 0; i < MAX_CLIENTS; i++)
@ -1346,6 +1373,14 @@ void CServer::SendServerInfo(const NETADDR *pAddr, int Token, bool Extended, int
if (Extended)
p.AddInt(Offset);
if(Short)
{
Packet.m_DataSize = p.Size();
Packet.m_pData = p.Data();
m_NetServer.Send(&Packet);
return;
}
int ClientsPerPacket = Extended ? 24 : VANILLA_MAX_CLIENTS;
int Skip = Offset;
int Take = ClientsPerPacket;
@ -1368,9 +1403,6 @@ void CServer::SendServerInfo(const NETADDR *pAddr, int Token, bool Extended, int
}
}
Packet.m_ClientID = -1;
Packet.m_Address = *pAddr;
Packet.m_Flags = NETSENDFLAG_CONNLESS;
Packet.m_DataSize = p.Size();
Packet.m_pData = p.Data();
m_NetServer.Send(&Packet);
@ -1406,15 +1438,25 @@ void CServer::PumpNetwork()
// stateless
if(!m_Register.RegisterProcessPacket(&Packet))
{
bool ServerInfo = false;
bool Extended = false;
if(Packet.m_DataSize == sizeof(SERVERBROWSE_GETINFO)+1 &&
mem_comp(Packet.m_pData, SERVERBROWSE_GETINFO, sizeof(SERVERBROWSE_GETINFO)) == 0)
{
SendServerInfo(&Packet.m_Address, ((unsigned char *)Packet.m_pData)[sizeof(SERVERBROWSE_GETINFO)]);
ServerInfo = true;
Extended = false;
}
else if(Packet.m_DataSize == sizeof(SERVERBROWSE_GETINFO64)+1 &&
mem_comp(Packet.m_pData, SERVERBROWSE_GETINFO64, sizeof(SERVERBROWSE_GETINFO64)) == 0)
{
SendServerInfo(&Packet.m_Address, ((unsigned char *)Packet.m_pData)[sizeof(SERVERBROWSE_GETINFO64)], true);
ServerInfo = true;
Extended = true;
}
if(ServerInfo)
{
int Token = ((unsigned char *)Packet.m_pData)[sizeof(SERVERBROWSE_GETINFO)];
SendServerInfoConnless(&Packet.m_Address, Token, Extended);
}
}
}

View file

@ -184,6 +184,10 @@ public:
int m_RconRestrict;
bool m_ServerInfoHighLoad;
int64 m_ServerInfoFirstRequest;
int m_ServerInfoNumRequests;
CServer();
int TrySetClientName(int ClientID, const char *pName);
@ -238,7 +242,8 @@ public:
void ProcessClientPacket(CNetChunk *pPacket);
void SendServerInfo(const NETADDR *pAddr, int Token, bool Extended=false, int Offset=0);
void SendServerInfoConnless(const NETADDR *pAddr, int Token, bool Extended);
void SendServerInfo(const NETADDR *pAddr, int Token, bool Extended=false, int Offset=0, bool Short=false);
void UpdateServerInfo();
void PumpNetwork();