diff --git a/Client.h b/Client.h index 18fed080..7dac0721 100644 --- a/Client.h +++ b/Client.h @@ -85,6 +85,8 @@ public: SetMaxBufferThreshold(1024); StartLoginTimeout(); + + SetNick("unknown-nick"); } virtual ~CClient(); diff --git a/Modules.cpp b/Modules.cpp index f81445ce..1e3b6080 100644 --- a/Modules.cpp +++ b/Modules.cpp @@ -145,6 +145,10 @@ void CSocket::SockError(int iErrno) { } } +bool CSocket::ConnectionFrom(const CString& sHost, unsigned short uPort) { + return CZNC::Get().AllowConnectionFrom(sHost); +} + bool CSocket::Connect(const CString& sHostname, unsigned short uPort, bool bSSL, unsigned int uTimeout) { CUser* pUser = m_pModule->GetUser(); CString sSockName = "MOD::C::" + m_pModule->GetModName(); diff --git a/Modules.h b/Modules.h index dfd2ed2b..f16bdd66 100644 --- a/Modules.h +++ b/Modules.h @@ -151,6 +151,9 @@ public: // This defaults to closing the socket, feel free to override virtual void ReachedMaxBuffer(); virtual void SockError(int iErrno); + // This limits the global connections from this IP to defeat DoS + // attacks, feel free to override + virtual bool ConnectionFrom(const CString& sHost, unsigned short uPort); bool Connect(const CString& sHostname, unsigned short uPort, bool bSSL = false, unsigned int uTimeout = 60); bool Listen(unsigned short uPort, bool bSSL = false, unsigned int uTimeout = 0); diff --git a/Socket.cpp b/Socket.cpp index ed8903bc..7152afc5 100644 --- a/Socket.cpp +++ b/Socket.cpp @@ -191,3 +191,20 @@ int CZNCSock::GetAddrInfo(const CS_STRING &sHostname, CSSockAddr &csSockAddr) { return 0; } #endif + +unsigned int CSockManager::GetAnonConnectionCount(const CString &sIP) const { + const_iterator it; + unsigned int ret = 0; + + for (it = begin(); it != end(); it++) { + CZNCSock *pSock = *it; + // Logged in CClients have "USR::" as their sockname + if (pSock->GetRemoteIP() == sIP && pSock->GetSockName().Left(5) != "USR::") { + ret++; + } + } + + DEBUG("There are [" << ret << "] clients from [" << sIP << "]"); + + return ret; +} diff --git a/Socket.h b/Socket.h index 65ebc883..89015a79 100644 --- a/Socket.h +++ b/Socket.h @@ -98,6 +98,8 @@ public: return TSocketManager::Connect(C, pcSock); } + + unsigned int GetAnonConnectionCount(const CString &sIP) const; private: protected: #ifdef HAVE_ARES diff --git a/znc.cpp b/znc.cpp index e8cbcd08..81b804a0 100644 --- a/znc.cpp +++ b/znc.cpp @@ -399,6 +399,12 @@ bool CZNC::IsHostAllowed(const CString& sHostMask) const { return false; } +bool CZNC::AllowConnectionFrom(const CString& sIP) const { + if (GetManager().GetAnonConnectionCount(sIP) >= 10) + return false; + return true; +} + void CZNC::InitDirs(const CString& sArgvPath, const CString& sDataDir) { char *home; diff --git a/znc.h b/znc.h index 41855af2..7844b30f 100644 --- a/znc.h +++ b/znc.h @@ -37,6 +37,8 @@ public: CUser* GetUser(const CString& sUser); Csock* FindSockByName(const CString& sSockName); bool IsHostAllowed(const CString& sHostMask) const; + // This returns false if there are too many anonymous connections from this ip + bool AllowConnectionFrom(const CString& sIP) const; void InitDirs(const CString& sArgvPath, const CString& sDataDir); bool OnBoot(); CString ExpandConfigPath(const CString& sConfigFile); @@ -86,6 +88,7 @@ public: // Getters bool GetNeedRehash() const { return m_bNeedRehash; } CSockManager& GetManager() { return m_Manager; } + const CSockManager& GetManager() const { return m_Manager; } #ifdef _MODULES CGlobalModules& GetModules() { return *m_pModules; } #endif @@ -175,9 +178,16 @@ public: virtual Csock* GetSockObj(const CString& sHost, unsigned short uPort) { CClient *pClient = new CClient(sHost, uPort); + if (CZNC::Get().AllowConnectionFrom(sHost)) #ifdef _MODULES - CZNC::Get().GetModules().OnClientConnect(pClient, sHost, uPort); + CZNC::Get().GetModules().OnClientConnect(pClient, sHost, uPort); #endif + else { + pClient->RefuseLogin("Too many anonymous connections from your IP"); +#ifdef _MODULES + CZNC::Get().GetModules().OnFailedLogin("", sHost); +#endif + } return pClient; }