From a0a62bcd70d1d8c0874d5ff52e443b5fb417854c Mon Sep 17 00:00:00 2001 From: oy Date: Sat, 30 Jul 2011 13:40:01 +0200 Subject: fixed econ feature and tcp --- src/engine/shared/econ.h | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 src/engine/shared/econ.h (limited to 'src/engine/shared/econ.h') diff --git a/src/engine/shared/econ.h b/src/engine/shared/econ.h new file mode 100644 index 00000000..33b23ea6 --- /dev/null +++ b/src/engine/shared/econ.h @@ -0,0 +1,43 @@ +#ifndef ENGINE_SHARED_ECON_H +#define ENGINE_SHARED_ECON_H + +#include "network.h" + +class CEcon +{ + class CClient + { + public: + enum + { + STATE_EMPTY=0, + STATE_CONNECTED, + STATE_AUTHED, + }; + + int m_State; + int64 m_TimeConnected; + }; + CClient m_aClients[NET_MAX_CONSOLE_CLIENTS]; + + IConsole *m_pConsole; + CNetConsole m_NetConsole; + + bool m_Ready; + int m_PrintCBIndex; + + static void SendLineCB(const char *pLine, void *pUserData); + static void ConchainEconOutputLevelUpdate(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData); + + static int NewClientCallback(int ClientID, void *pUser); + static int DelClientCallback(int ClientID, const char *pReason, void *pUser); + +public: + IConsole *Console() { return m_pConsole; } + + void Init(IConsole *pConsole); + void Update(); + void Send(int ClientID, const char *pLine); +}; + +#endif -- cgit 1.4.1 From 9349af008572efe573ec435cf70d02c2f5db9821 Mon Sep 17 00:00:00 2001 From: oy Date: Sun, 31 Jul 2011 02:20:46 +0200 Subject: clean up econ sockets on shutdown. Closes #804 --- src/engine/server/server.cpp | 2 ++ src/engine/shared/econ.cpp | 8 ++++++++ src/engine/shared/econ.h | 1 + src/engine/shared/network_console.cpp | 9 ++++++++- 4 files changed, 19 insertions(+), 1 deletion(-) (limited to 'src/engine/shared/econ.h') diff --git a/src/engine/server/server.cpp b/src/engine/server/server.cpp index 55208caa..2d288740 100644 --- a/src/engine/server/server.cpp +++ b/src/engine/server/server.cpp @@ -1331,6 +1331,8 @@ int CServer::Run() { if(m_aClients[i].m_State != CClient::STATE_EMPTY) m_NetServer.Drop(i, "Server shutdown"); + + m_Econ.Shutdown(); } GameServer()->OnShutdown(); diff --git a/src/engine/shared/econ.cpp b/src/engine/shared/econ.cpp index ba86e5c0..0bc3a988 100644 --- a/src/engine/shared/econ.cpp +++ b/src/engine/shared/econ.cpp @@ -145,3 +145,11 @@ void CEcon::Send(int ClientID, const char *pLine) else if(ClientID >= 0 && ClientID < NET_MAX_CONSOLE_CLIENTS && m_aClients[ClientID].m_State == CClient::STATE_AUTHED) m_NetConsole.Send(ClientID, pLine); } + +void CEcon::Shutdown() +{ + if(!m_Ready) + return; + + m_NetConsole.Close(); +} diff --git a/src/engine/shared/econ.h b/src/engine/shared/econ.h index 33b23ea6..3ec19e28 100644 --- a/src/engine/shared/econ.h +++ b/src/engine/shared/econ.h @@ -38,6 +38,7 @@ public: void Init(IConsole *pConsole); void Update(); void Send(int ClientID, const char *pLine); + void Shutdown(); }; #endif diff --git a/src/engine/shared/network_console.cpp b/src/engine/shared/network_console.cpp index 0cf2a718..f77e40f2 100644 --- a/src/engine/shared/network_console.cpp +++ b/src/engine/shared/network_console.cpp @@ -7,6 +7,9 @@ bool CNetConsole::Open(NETADDR BindAddr, int Flags) { // zero out the whole structure mem_zero(this, sizeof(*this)); + m_Socket.type = NETTYPE_INVALID; + m_Socket.ipv4sock = -1; + m_Socket.ipv6sock = -1; // open socket m_Socket = net_tcp_create(BindAddr); @@ -31,7 +34,11 @@ void CNetConsole::SetCallbacks(NETFUNC_NEWCLIENT pfnNewClient, NETFUNC_DELCLIENT int CNetConsole::Close() { - // TODO: implement me + for(int i = 0; i < NET_MAX_CONSOLE_CLIENTS; i++) + m_aSlots[i].m_Connection.Disconnect("closing console"); + + net_tcp_close(m_Socket); + return 0; } -- cgit 1.4.1 From 94188021509a376fc352b7707d9a324335a97eba Mon Sep 17 00:00:00 2001 From: oy Date: Sun, 31 Jul 2011 13:05:12 +0200 Subject: protected econ authentication against brute force --- src/engine/shared/config_variables.h | 1 + src/engine/shared/econ.cpp | 18 +++++++- src/engine/shared/econ.h | 6 +++ src/engine/shared/network.h | 18 +++++++- src/engine/shared/network_console.cpp | 87 ++++++++++++++++++++++++++++++++++- 5 files changed, 126 insertions(+), 4 deletions(-) (limited to 'src/engine/shared/econ.h') diff --git a/src/engine/shared/config_variables.h b/src/engine/shared/config_variables.h index 0789476e..c812063a 100644 --- a/src/engine/shared/config_variables.h +++ b/src/engine/shared/config_variables.h @@ -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_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_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(EcOutputLevel, ec_output_level, 1, 0, 2, CFGFLAG_SERVER, "Adjusts the amount of information in the external console") diff --git a/src/engine/shared/econ.cpp b/src/engine/shared/econ.cpp index 18a551e7..617cdbd6 100644 --- a/src/engine/shared/econ.cpp +++ b/src/engine/shared/econ.cpp @@ -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_TimeConnected = time_get(); + pThis->m_aClients[ClientID].m_AuthTries = 0; pThis->m_NetConsole.Send(ClientID, "Enter password:"); return 0; @@ -112,7 +113,22 @@ void CEcon::Update() Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "econ", aBuf); } 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) { diff --git a/src/engine/shared/econ.h b/src/engine/shared/econ.h index 3ec19e28..daec34c4 100644 --- a/src/engine/shared/econ.h +++ b/src/engine/shared/econ.h @@ -5,6 +5,11 @@ class CEcon { + enum + { + MAX_AUTH_TRIES=3, + }; + class CClient { public: @@ -17,6 +22,7 @@ class CEcon int m_State; int64 m_TimeConnected; + int m_AuthTries; }; CClient m_aClients[NET_MAX_CONSOLE_CLIENTS]; diff --git a/src/engine/shared/network.h b/src/engine/shared/network.h index 94e2824c..d10c03b6 100644 --- a/src/engine/shared/network.h +++ b/src/engine/shared/network.h @@ -325,7 +325,21 @@ public: 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 { CConsoleNetConnection m_Connection; @@ -356,6 +370,8 @@ public: int AcceptClient(NETSOCKET Socket, const NETADDR *pAddr); int Drop(int ClientID, const char *pReason); + bool AddBan(NETADDR Addr, int Seconds); + // status requests NETADDR ClientAddr(int ClientID) const { return m_aSlots[ClientID].m_Connection.PeerAddress(); } }; diff --git a/src/engine/shared/network_console.cpp b/src/engine/shared/network_console.cpp index f77e40f2..13ed3751 100644 --- a/src/engine/shared/network_console.cpp +++ b/src/engine/shared/network_console.cpp @@ -97,9 +97,28 @@ int CNetConsole::Update() NETSOCKET Socket; 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++) @@ -110,6 +129,8 @@ int CNetConsole::Update() Drop(i, m_aSlots[i].m_Connection.ErrorString()); } + UpdateBans(); + return 0; } @@ -134,3 +155,65 @@ int CNetConsole::Send(int ClientID, const char *pLine) else 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; + } +} -- cgit 1.4.1