Merge pull request #544 from east/dnsbl

Basic DNSBL implementation
This commit is contained in:
Dennis Felsing 2016-09-19 11:57:07 +02:00 committed by GitHub
commit 5a29fa8fca
5 changed files with 135 additions and 1 deletions

View file

@ -166,6 +166,7 @@ public:
virtual int* GetIdMap(int ClientID) = 0;
virtual bool DnsblWhite(int ClientID) = 0;
};
class IGameServer : public IInterface

View file

@ -800,6 +800,9 @@ int CServer::ClientRejoinCallback(int ClientID, void *pUser)
int CServer::NewClientNoAuthCallback(int ClientID, bool Reset, void *pUser)
{
CServer *pThis = (CServer *)pUser;
pThis->m_aClients[ClientID].m_DnsblState = CClient::DNSBL_STATE_NONE;
if (Reset)
{
pThis->m_aClients[ClientID].m_State = CClient::STATE_CONNECTING;
@ -821,6 +824,7 @@ int CServer::NewClientCallback(int ClientID, void *pUser)
{
CServer *pThis = (CServer *)pUser;
pThis->m_aClients[ClientID].m_State = CClient::STATE_AUTH;
pThis->m_aClients[ClientID].m_DnsblState = CClient::DNSBL_STATE_NONE;
pThis->m_aClients[ClientID].m_aName[0] = 0;
pThis->m_aClients[ClientID].m_aClan[0] = 0;
pThis->m_aClients[ClientID].m_Country = -1;
@ -834,6 +838,27 @@ int CServer::NewClientCallback(int ClientID, void *pUser)
return 0;
}
void CServer::InitDnsbl(int ClientID)
{
NETADDR Addr = *m_NetServer.ClientAddr(ClientID);
//TODO: support ipv6
if (Addr.type != NETTYPE_IPV4)
return;
// build dnsbl host lookup
char aBuf[256];
if (g_Config.m_SvDnsblKey[0] == '\0')
// without key
str_format(aBuf, sizeof(aBuf), "%d.%d.%d.%d.%s", Addr.ip[3], Addr.ip[2], Addr.ip[1], Addr.ip[0], g_Config.m_SvDnsblHost);
else
// with key
str_format(aBuf, sizeof(aBuf), "%s.%d.%d.%d.%d.%s", g_Config.m_SvDnsblKey, Addr.ip[3], Addr.ip[2], Addr.ip[1], Addr.ip[0], g_Config.m_SvDnsblHost);
IEngine *pEngine = Kernel()->RequestInterface<IEngine>();
pEngine->HostLookup(&m_aClients[ClientID].m_DnsblLookup, aBuf, NETTYPE_IPV4);
}
int CServer::DelClientCallback(int ClientID, const char *pReason, void *pUser)
{
CServer *pThis = (CServer *)pUser;
@ -1742,6 +1767,50 @@ int CServer::Run()
}
}
// handle dnsbl
if (g_Config.m_SvDnsbl)
{
for (int c = 0; c < MAX_CLIENTS; c++)
{
if (m_aClients[c].m_State == CClient::STATE_EMPTY)
continue;
if (m_aClients[c].m_DnsblState == CClient::DNSBL_STATE_NONE)
{
// initiate dnsbl lookup
m_aClients[c].m_DnsblState = CClient::DNSBL_STATE_PENDING;
InitDnsbl(c);
}
else if (m_aClients[c].m_DnsblState == CClient::DNSBL_STATE_PENDING &&
m_aClients[c].m_DnsblLookup.m_Job.Status() == CJob::STATE_DONE)
{
if (m_aClients[c].m_DnsblLookup.m_Addr.type == NETTYPE_INVALID)
{
// entry not found -> whitelisted
m_aClients[c].m_DnsblState = CClient::DNSBL_STATE_WHITELISTED;
}
else
{
// entry found -> blacklisted
m_aClients[c].m_DnsblState = CClient::DNSBL_STATE_BLACKLISTED;
// console output
char aAddrStr[NETADDR_MAXSTRSIZE];
net_addr_str(m_NetServer.ClientAddr(c), aAddrStr, sizeof(aAddrStr), true);
char aBuf[256];
str_format(aBuf, sizeof(aBuf), "ClientID=%d addr=%s secure=%s blacklisted", c, aAddrStr, m_NetServer.HasSecurityToken(c)?"yes":"no");
Console()->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "dnsbl", aBuf);
}
}
if (m_aClients[c].m_DnsblState == CClient::DNSBL_STATE_BLACKLISTED &&
g_Config.m_SvDnsblBan)
m_NetServer.NetBan()->BanAddr(m_NetServer.ClientAddr(c), 60*10, "Blacklisted by DNSBL");
}
}
while(t > TickStartTime(m_CurrentGameTick+1))
{
m_CurrentGameTick++;
@ -1905,6 +1974,34 @@ void CServer::ConStatus(IConsole::IResult *pResult, void *pUser)
}
}
void CServer::ConDnsblStatus(IConsole::IResult *pResult, void *pUser)
{
// dump blacklisted clients
char aBuf[1024];
char aAddrStr[NETADDR_MAXSTRSIZE];
CServer* pThis = static_cast<CServer *>(pUser);
for(int i = 0; i < MAX_CLIENTS; i++)
{
if(pThis->m_aClients[i].m_State != CClient::STATE_EMPTY &&
pThis->m_aClients[i].m_DnsblState == CClient::DNSBL_STATE_BLACKLISTED)
{
net_addr_str(pThis->m_NetServer.ClientAddr(i), aAddrStr, sizeof(aAddrStr), true);
if(pThis->m_aClients[i].m_State == CClient::STATE_INGAME)
{
const char *pAuthStr = pThis->m_aClients[i].m_Authed == CServer::AUTHED_ADMIN ? "(Admin)" :
pThis->m_aClients[i].m_Authed == CServer::AUTHED_MOD ? "(Mod)" :
pThis->m_aClients[i].m_Authed == CServer::AUTHED_HELPER ? "(Helper)" : "";
str_format(aBuf, sizeof(aBuf), "id=%d addr=%s name='%s' score=%d client=%d secure=%s %s", i, aAddrStr,
pThis->m_aClients[i].m_aName, pThis->m_aClients[i].m_Score, ((CGameContext *)(pThis->GameServer()))->m_apPlayers[i]->m_ClientVersion, pThis->m_NetServer.HasSecurityToken(i) ? "yes":"no", pAuthStr);
}
else
str_format(aBuf, sizeof(aBuf), "id=%d addr=%s connecting", i, aAddrStr);
pThis->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "Server", aBuf);
}
}
}
void CServer::ConShutdown(IConsole::IResult *pResult, void *pUser)
{
((CServer *)pUser)->m_RunServer = 0;
@ -2240,6 +2337,8 @@ void CServer::RegisterCommands()
#endif
Console()->Register("dnsbl_status", "", CFGFLAG_SERVER, ConDnsblStatus, this, "List blacklisted players");
Console()->Chain("sv_name", ConchainSpecialInfoupdate, this);
Console()->Chain("password", ConchainSpecialInfoupdate, this);

View file

@ -3,6 +3,7 @@
#ifndef ENGINE_SERVER_SERVER_H
#define ENGINE_SERVER_SERVER_H
#include <engine/engine.h>
#include <engine/server.h>
#include <engine/map.h>
@ -116,7 +117,12 @@ public:
SNAPRATE_INIT=0,
SNAPRATE_FULL,
SNAPRATE_RECOVER
SNAPRATE_RECOVER,
DNSBL_STATE_NONE=0,
DNSBL_STATE_PENDING,
DNSBL_STATE_BLACKLISTED,
DNSBL_STATE_WHITELISTED,
};
class CInput
@ -156,6 +162,10 @@ public:
// DDRace
NETADDR m_Addr;
// DNSBL
int m_DnsblState;
CHostLookup m_DnsblLookup;
};
CClient m_aClients[MAX_CLIENTS];
@ -282,6 +292,7 @@ public:
static void ConStopRecord(IConsole::IResult *pResult, void *pUser);
static void ConMapReload(IConsole::IResult *pResult, void *pUser);
static void ConLogout(IConsole::IResult *pResult, void *pUser);
static void ConDnsblStatus(IConsole::IResult *pResult, void *pUser);
#if defined (CONF_SQL)
// console commands for sqlmasters
@ -320,6 +331,12 @@ public:
virtual int* GetIdMap(int ClientID);
void InitDnsbl(int ClientID);
bool DnsblWhite(int ClientID)
{
return m_aClients[ClientID].m_DnsblState == CClient::DNSBL_STATE_NONE ||
m_aClients[ClientID].m_DnsblState == CClient::DNSBL_STATE_WHITELISTED;
}
};
#endif

View file

@ -150,6 +150,12 @@ MACRO_CONFIG_INT(SvRconBantime, sv_rcon_bantime, 5, 0, 1440, CFGFLAG_SERVER, "Th
MACRO_CONFIG_INT(SvAutoDemoRecord, sv_auto_demo_record, 0, 0, 1, CFGFLAG_SERVER, "Automatically record demos")
MACRO_CONFIG_INT(SvAutoDemoMax, sv_auto_demo_max, 10, 0, 1000, CFGFLAG_SERVER, "Maximum number of automatically recorded demos (0 = no limit)")
MACRO_CONFIG_INT(SvVanillaAntiSpoof, sv_vanilla_antispoof, 1, 0, 1, CFGFLAG_SERVER, "Enable vanilla Antispoof")
MACRO_CONFIG_INT(SvDnsbl, sv_dnsbl, 0, 0, 1, CFGFLAG_SERVER, "Enable DNSBL (DNS-based Blackhole List)")
MACRO_CONFIG_STR(SvDnsblHost, sv_dnsbl_host, 128, "", CFGFLAG_SERVER, "Hostname of DNSBL provider to use for IP Verification")
MACRO_CONFIG_STR(SvDnsblKey, sv_dnsbl_key, 128, "", CFGFLAG_SERVER, "Optional Authentification Key for the specified DNSBL provider")
MACRO_CONFIG_INT(SvDnsblVote, sv_dnsbl_vote, 0, 0, 1, CFGFLAG_SERVER, "Block votes by blacklisted addresses")
MACRO_CONFIG_INT(SvDnsblBan, sv_dnsbl_ban, 0, 0, 1, CFGFLAG_SERVER, "Automatically ban blacklisted addresses")
MACRO_CONFIG_INT(SvPlayerDemoRecord, sv_player_demo_record, 0, 0, 1, CFGFLAG_SERVER, "Automatically record demos for each player")
MACRO_CONFIG_INT(SvDemoChat, sv_demo_chat, 0, 0, 1, CFGFLAG_SERVER, "Record chat for demos")

View file

@ -653,6 +653,10 @@ void CGameContext::OnTick()
if(m_apPlayers[i]->m_Afk && i != m_VoteCreator)
continue;
// don't count votes by blacklisted clients
if (g_Config.m_SvDnsblVote && !m_pServer->DnsblWhite(i))
continue;
int ActVote = m_apPlayers[i]->m_Vote;
int ActVotePos = m_apPlayers[i]->m_VotePos;
@ -1151,6 +1155,13 @@ void CGameContext::OnMessage(int MsgID, CUnpacker *pUnpacker, int ClientID)
int64 Now = Server()->Tick();
int64 TickSpeed = Server()->TickSpeed();
if (g_Config.m_SvDnsblVote && !m_pServer->DnsblWhite(ClientID))
{
// blacklisted by dnsbl
SendChatTarget(ClientID, "You are not allowed to vote due to DNSBL");
return;
}
if(g_Config.m_SvSpamprotection && pPlayer->m_LastVoteTry && pPlayer->m_LastVoteTry + TickSpeed * 3 > Now)
return;