mirror of
https://github.com/ddnet/ddnet.git
synced 2024-11-13 03:28:19 +00:00
protected econ authentication against brute force
This commit is contained in:
parent
1705c90e14
commit
9418802150
|
@ -92,6 +92,7 @@ MACRO_CONFIG_INT(SvAutoDemoMax, sv_auto_demo_max, 10, 0, 1000, CFGFLAG_SERVER, "
|
||||||
MACRO_CONFIG_STR(EcBindaddr, ec_bindaddr, 128, "localhost", CFGFLAG_SERVER, "Address to bind the external console to. Anything but 'localhost' is dangerous")
|
MACRO_CONFIG_STR(EcBindaddr, ec_bindaddr, 128, "localhost", CFGFLAG_SERVER, "Address to bind the external console to. Anything but 'localhost' is dangerous")
|
||||||
MACRO_CONFIG_INT(EcPort, ec_port, 0, 0, 0, CFGFLAG_SERVER, "Port to use for the external console")
|
MACRO_CONFIG_INT(EcPort, ec_port, 0, 0, 0, CFGFLAG_SERVER, "Port to use for the external console")
|
||||||
MACRO_CONFIG_STR(EcPassword, ec_password, 32, "", CFGFLAG_SERVER, "External console password")
|
MACRO_CONFIG_STR(EcPassword, ec_password, 32, "", CFGFLAG_SERVER, "External console password")
|
||||||
|
MACRO_CONFIG_INT(EcBantime, ec_bantime, 0, 0, 1440, CFGFLAG_SERVER, "The time a client gets banned if econ authentication fails. 0 just closes the connection")
|
||||||
MACRO_CONFIG_INT(EcAuthTimeout, ec_auth_timeout, 30, 1, 120, CFGFLAG_SERVER, "Time in seconds before the the econ authentification times out")
|
MACRO_CONFIG_INT(EcAuthTimeout, ec_auth_timeout, 30, 1, 120, CFGFLAG_SERVER, "Time in seconds before the the econ authentification times out")
|
||||||
MACRO_CONFIG_INT(EcOutputLevel, ec_output_level, 1, 0, 2, CFGFLAG_SERVER, "Adjusts the amount of information in the external console")
|
MACRO_CONFIG_INT(EcOutputLevel, ec_output_level, 1, 0, 2, CFGFLAG_SERVER, "Adjusts the amount of information in the external console")
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,7 @@ int CEcon::NewClientCallback(int ClientID, void *pUser)
|
||||||
|
|
||||||
pThis->m_aClients[ClientID].m_State = CClient::STATE_CONNECTED;
|
pThis->m_aClients[ClientID].m_State = CClient::STATE_CONNECTED;
|
||||||
pThis->m_aClients[ClientID].m_TimeConnected = time_get();
|
pThis->m_aClients[ClientID].m_TimeConnected = time_get();
|
||||||
|
pThis->m_aClients[ClientID].m_AuthTries = 0;
|
||||||
|
|
||||||
pThis->m_NetConsole.Send(ClientID, "Enter password:");
|
pThis->m_NetConsole.Send(ClientID, "Enter password:");
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -112,7 +113,22 @@ void CEcon::Update()
|
||||||
Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "econ", aBuf);
|
Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "econ", aBuf);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
m_NetConsole.Send(ClientID, "Wrong password");
|
{
|
||||||
|
m_aClients[ClientID].m_AuthTries++;
|
||||||
|
char aBuf[128];
|
||||||
|
str_format(aBuf, sizeof(aBuf), "Wrong password %d/%d.", m_aClients[ClientID].m_AuthTries, MAX_AUTH_TRIES);
|
||||||
|
m_NetConsole.Send(ClientID, aBuf);
|
||||||
|
if(m_aClients[ClientID].m_AuthTries >= MAX_AUTH_TRIES)
|
||||||
|
{
|
||||||
|
if(!g_Config.m_EcBantime)
|
||||||
|
m_NetConsole.Drop(ClientID, "Too many authentication tries");
|
||||||
|
else
|
||||||
|
{
|
||||||
|
NETADDR Addr = m_NetConsole.ClientAddr(ClientID);
|
||||||
|
m_NetConsole.AddBan(Addr, g_Config.m_EcBantime*60);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if(m_aClients[ClientID].m_State == CClient::STATE_AUTHED)
|
else if(m_aClients[ClientID].m_State == CClient::STATE_AUTHED)
|
||||||
{
|
{
|
||||||
|
|
|
@ -5,6 +5,11 @@
|
||||||
|
|
||||||
class CEcon
|
class CEcon
|
||||||
{
|
{
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
MAX_AUTH_TRIES=3,
|
||||||
|
};
|
||||||
|
|
||||||
class CClient
|
class CClient
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -17,6 +22,7 @@ class CEcon
|
||||||
|
|
||||||
int m_State;
|
int m_State;
|
||||||
int64 m_TimeConnected;
|
int64 m_TimeConnected;
|
||||||
|
int m_AuthTries;
|
||||||
};
|
};
|
||||||
CClient m_aClients[NET_MAX_CONSOLE_CLIENTS];
|
CClient m_aClients[NET_MAX_CONSOLE_CLIENTS];
|
||||||
|
|
||||||
|
|
|
@ -325,7 +325,21 @@ public:
|
||||||
|
|
||||||
class CNetConsole
|
class CNetConsole
|
||||||
{
|
{
|
||||||
private:
|
enum
|
||||||
|
{
|
||||||
|
MAX_BANS=128,
|
||||||
|
};
|
||||||
|
|
||||||
|
int FindBan(NETADDR Addr);
|
||||||
|
void UpdateBans();
|
||||||
|
|
||||||
|
struct CBanEntry
|
||||||
|
{
|
||||||
|
NETADDR m_Addr;
|
||||||
|
int m_Expires;
|
||||||
|
} m_aBans[MAX_BANS];
|
||||||
|
int m_NumBans;
|
||||||
|
|
||||||
struct CSlot
|
struct CSlot
|
||||||
{
|
{
|
||||||
CConsoleNetConnection m_Connection;
|
CConsoleNetConnection m_Connection;
|
||||||
|
@ -356,6 +370,8 @@ public:
|
||||||
int AcceptClient(NETSOCKET Socket, const NETADDR *pAddr);
|
int AcceptClient(NETSOCKET Socket, const NETADDR *pAddr);
|
||||||
int Drop(int ClientID, const char *pReason);
|
int Drop(int ClientID, const char *pReason);
|
||||||
|
|
||||||
|
bool AddBan(NETADDR Addr, int Seconds);
|
||||||
|
|
||||||
// status requests
|
// status requests
|
||||||
NETADDR ClientAddr(int ClientID) const { return m_aSlots[ClientID].m_Connection.PeerAddress(); }
|
NETADDR ClientAddr(int ClientID) const { return m_aSlots[ClientID].m_Connection.PeerAddress(); }
|
||||||
};
|
};
|
||||||
|
|
|
@ -97,9 +97,28 @@ int CNetConsole::Update()
|
||||||
NETSOCKET Socket;
|
NETSOCKET Socket;
|
||||||
NETADDR Addr;
|
NETADDR Addr;
|
||||||
|
|
||||||
while(net_tcp_accept(m_Socket, &Socket, &Addr) > 0)
|
if(net_tcp_accept(m_Socket, &Socket, &Addr) > 0)
|
||||||
{
|
{
|
||||||
AcceptClient(Socket, &Addr);
|
int Index = FindBan(Addr);
|
||||||
|
if(Index == -1)
|
||||||
|
AcceptClient(Socket, &Addr);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
char aBuf[128];
|
||||||
|
if(m_aBans[Index].m_Expires > -1)
|
||||||
|
{
|
||||||
|
int Mins = (m_aBans[Index].m_Expires-time_timestamp()+ 59) / 60;
|
||||||
|
if(Mins <= 1)
|
||||||
|
str_format(aBuf, sizeof(aBuf), "You have been banned for 1 minute");
|
||||||
|
else
|
||||||
|
str_format(aBuf, sizeof(aBuf), "You have been banned for %d minutes", Mins);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
str_format(aBuf, sizeof(aBuf), "You have been banned for life");
|
||||||
|
|
||||||
|
net_tcp_send(Socket, aBuf, str_length(aBuf));
|
||||||
|
net_tcp_close(Socket);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for(int i = 0; i < NET_MAX_CONSOLE_CLIENTS; i++)
|
for(int i = 0; i < NET_MAX_CONSOLE_CLIENTS; i++)
|
||||||
|
@ -110,6 +129,8 @@ int CNetConsole::Update()
|
||||||
Drop(i, m_aSlots[i].m_Connection.ErrorString());
|
Drop(i, m_aSlots[i].m_Connection.ErrorString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UpdateBans();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -134,3 +155,65 @@ int CNetConsole::Send(int ClientID, const char *pLine)
|
||||||
else
|
else
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int CNetConsole::FindBan(NETADDR Addr)
|
||||||
|
{
|
||||||
|
Addr.port = 0;
|
||||||
|
for(int i = 0; i < m_NumBans; i++)
|
||||||
|
if(net_addr_comp(&m_aBans[i].m_Addr, &Addr) == 0)
|
||||||
|
return i;
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CNetConsole::AddBan(NETADDR Addr, int Seconds)
|
||||||
|
{
|
||||||
|
if(m_NumBans == MAX_BANS)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Addr.port = 0;
|
||||||
|
int Index = FindBan(Addr);
|
||||||
|
if(Index == -1)
|
||||||
|
{
|
||||||
|
Index = m_NumBans++;
|
||||||
|
m_aBans[Index].m_Addr = Addr;
|
||||||
|
}
|
||||||
|
m_aBans[Index].m_Expires = Seconds>0 ? time_timestamp()+Seconds : -1;
|
||||||
|
|
||||||
|
for(int i = 0; i < NET_MAX_CONSOLE_CLIENTS; i++)
|
||||||
|
{
|
||||||
|
if(m_aSlots[i].m_Connection.State() != NET_CONNSTATE_OFFLINE)
|
||||||
|
{
|
||||||
|
NETADDR PeerAddr = m_aSlots[i].m_Connection.PeerAddress();
|
||||||
|
PeerAddr.port = 0;
|
||||||
|
if(net_addr_comp(&Addr, &PeerAddr) == 0)
|
||||||
|
{
|
||||||
|
char aBuf[128];
|
||||||
|
if(Seconds>0)
|
||||||
|
{
|
||||||
|
int Mins = (Seconds + 59) / 60;
|
||||||
|
if(Mins <= 1)
|
||||||
|
str_format(aBuf, sizeof(aBuf), "You have been banned for 1 minute");
|
||||||
|
else
|
||||||
|
str_format(aBuf, sizeof(aBuf), "You have been banned for %d minutes", Mins);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
str_format(aBuf, sizeof(aBuf), "You have been banned for life");
|
||||||
|
Drop(i, aBuf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CNetConsole::UpdateBans()
|
||||||
|
{
|
||||||
|
int Now = time_timestamp();
|
||||||
|
for(int i = 0; i < m_NumBans; ++i)
|
||||||
|
if(m_aBans[i].m_Expires > 0 && m_aBans[i].m_Expires < Now)
|
||||||
|
{
|
||||||
|
m_aBans[i] = m_aBans[m_NumBans-1];
|
||||||
|
--m_NumBans;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue