mirror of
https://github.com/SphereServer/Source-X
synced 2026-08-13 10:23:05 -04:00
147 lines
4.4 KiB
C++
147 lines
4.4 KiB
C++
//#include "../common/CScriptParserBufs.h" // included in the precompiled header via CExpression.h
|
|
#include "../game/CServer.h"
|
|
#include "../game/CServerConfig.h"
|
|
#include "../game/CWorldGameTime.h"
|
|
#include "CIPHistoryManager.h"
|
|
#include <algorithm>
|
|
|
|
|
|
/***************************************************************************
|
|
*
|
|
*
|
|
* struct HistoryIP Simple interface for IP history maintainence
|
|
*
|
|
*
|
|
***************************************************************************/
|
|
|
|
void HistoryIP::update(void)
|
|
{
|
|
// reset ttl
|
|
m_iTTLSeconds = g_Cfg.m_iNetHistoryTTLSeconds;
|
|
}
|
|
|
|
bool HistoryIP::checkPing(void)
|
|
{
|
|
// ip is pinging, check if blocked
|
|
update();
|
|
|
|
return (m_fBlocked || (m_iPings++ >= g_Cfg.m_iNetMaxPings));
|
|
}
|
|
|
|
void HistoryIP::setBlocked(bool isBlocked, int64 timeoutSeconds)
|
|
{
|
|
// block ip
|
|
ADDTOCALLSTACK("HistoryIP:setBlocked");
|
|
if (isBlocked == true)
|
|
{
|
|
CScriptTriggerArgsPtr pScriptArgs = CScriptParserBufs::GetCScriptTriggerArgsPtr();
|
|
pScriptArgs->Init(m_ip.GetAddrStr());
|
|
pScriptArgs->m_iN1 = timeoutSeconds;
|
|
g_Serv.r_Call("f_onserver_blockip", pScriptArgs, &g_Serv );
|
|
timeoutSeconds = pScriptArgs->m_iN1;
|
|
}
|
|
|
|
m_fBlocked = isBlocked;
|
|
|
|
if (isBlocked && timeoutSeconds >= 0)
|
|
m_iBlockExpireMs = CWorldGameTime::GetCurrentTime().GetTimeRaw() + (timeoutSeconds * MSECS_PER_SEC);
|
|
else
|
|
m_iBlockExpireMs = 0;
|
|
}
|
|
|
|
/***************************************************************************
|
|
*
|
|
*
|
|
* class IPHistoryManager Holds IP records (bans, pings, etc)
|
|
*
|
|
*
|
|
***************************************************************************/
|
|
IPHistoryManager::IPHistoryManager(void)
|
|
{
|
|
m_lastDecayTime = 0;
|
|
}
|
|
|
|
IPHistoryManager::~IPHistoryManager(void)
|
|
{
|
|
m_ips.clear();
|
|
}
|
|
|
|
void IPHistoryManager::tick(void)
|
|
{
|
|
// periodic events
|
|
ADDTOCALLSTACK("IPHistoryManager::tick");
|
|
|
|
// check if ttl should decay (only do this once every second)
|
|
const bool decayTTL = (!(m_lastDecayTime > 0) || CWorldGameTime::GetCurrentTime().GetTimeDiff(m_lastDecayTime) > 1 * MSECS_PER_SEC);
|
|
if (decayTTL)
|
|
m_lastDecayTime = CWorldGameTime::GetCurrentTime().GetTimeRaw();
|
|
|
|
for (IPHistoryList::iterator it = m_ips.begin(), end = m_ips.end(); it != end; ++it)
|
|
{
|
|
if (it->m_fBlocked)
|
|
{
|
|
// blocked ips don't decay, but check if the ban has expired
|
|
if (it->m_iBlockExpireMs > 0 && (CWorldGameTime::GetCurrentTime().GetTimeRaw() > it->m_iBlockExpireMs))
|
|
it->setBlocked(false);
|
|
}
|
|
else if (decayTTL)
|
|
{
|
|
if (it->m_iAliveSuccessfulConnections == 0 && it->m_iPendingConnectionRequests == 0)
|
|
{
|
|
// start to forget about clients who aren't connected
|
|
if (it->m_iTTLSeconds >= 0)
|
|
--it->m_iTTLSeconds;
|
|
}
|
|
|
|
// wait a 5th of TTL between each ping decay, but do not wait less than 30 seconds
|
|
if (it->m_iPings > 0 && --it->m_iPingDecay < 0)
|
|
{
|
|
--it->m_iPings;
|
|
it->m_iPingDecay = std::max(30, g_Cfg.m_iNetHistoryTTLSeconds / 5);
|
|
}
|
|
}
|
|
}
|
|
|
|
// clear old ip history
|
|
std::erase_if(m_ips, [](HistoryIP const& elem) {
|
|
return elem.m_iTTLSeconds < 0;
|
|
});
|
|
}
|
|
|
|
HistoryIP& IPHistoryManager::getHistoryForIP(const CSocketAddressIP& ip) noexcept
|
|
{
|
|
// get history for an ip
|
|
|
|
// find existing entry
|
|
for (IPHistoryList::iterator it = m_ips.begin(), end = m_ips.end(); it != end; ++it)
|
|
{
|
|
if (it->m_ip == ip)
|
|
return *it;
|
|
}
|
|
|
|
// create a new entry
|
|
HistoryIP hist = {
|
|
.m_ip = ip,
|
|
.m_fBlocked = 0,
|
|
.m_iPingDecay = 30,
|
|
.m_iPings = 0,
|
|
.m_iConnectionRequests = 0,
|
|
.m_iPendingConnectionRequests = 0,
|
|
.m_iAliveSuccessfulConnections = 0,
|
|
.m_iTTLSeconds = 0, // updated by update() method
|
|
.m_iTimeLastConnectedMs = 0, // set by the caller, if needed
|
|
.m_iBlockExpireMs = 0,
|
|
};
|
|
hist.update();
|
|
|
|
return m_ips.emplace_back(std::move(hist));
|
|
}
|
|
|
|
HistoryIP& IPHistoryManager::getHistoryForIP(const char* ip)
|
|
{
|
|
// get history for an ip
|
|
ADDTOCALLSTACK("IPHistoryManager::getHistoryForIP");
|
|
|
|
CSocketAddressIP me(ip);
|
|
return getHistoryForIP(me);
|
|
}
|