From 414fa40eb56a4f9f25113bc8bcecffb2a7470334 Mon Sep 17 00:00:00 2001 From: Uli Schlachter Date: Sat, 7 Dec 2013 20:42:18 +0100 Subject: [PATCH] WebModules: Discard sessions in LRU order Currently, znc has a limit of 5 web sessions per IP address. This limit exists to defend against some obvious DoS attacks. When this limit is hit, some session is discarded. Previously, we would discard the session that std::multimap::find() would give us. The multimap used mapped from IP addresses to sessions. Thus, we would discard the oldest session. This commit changes this into some least-recently-used logic. Whenever a session is used, we record the timestamp of this. Then when a session has to be picked for discarding, the one with the oldest timestamp is used. Signed-off-by: Uli Schlachter --- include/znc/WebModules.h | 3 +++ src/WebModules.cpp | 15 ++++++++++++++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/include/znc/WebModules.h b/include/znc/WebModules.h index a60c88f9..c445b4e4 100644 --- a/include/znc/WebModules.h +++ b/include/znc/WebModules.h @@ -49,8 +49,10 @@ public: const CString& GetId() const { return m_sId; } const CString& GetIP() const { return m_sIP; } CUser* GetUser() const { return m_pUser; } + time_t GetLastActive() const { return m_tmLastActive; } bool IsLoggedIn() const { return m_pUser != NULL; } bool IsAdmin() const; + void UpdateLastActive(); CUser* SetUser(CUser* p) { m_pUser = p; return m_pUser; } @@ -64,6 +66,7 @@ private: CUser* m_pUser; VCString m_vsErrorMsgs; VCString m_vsSuccessMsgs; + time_t m_tmLastActive; }; diff --git a/src/WebModules.cpp b/src/WebModules.cpp index 3f000f71..cf0aa484 100644 --- a/src/WebModules.cpp +++ b/src/WebModules.cpp @@ -19,6 +19,7 @@ #include #include #include +#include #include using std::pair; @@ -97,6 +98,11 @@ bool CZNCTagHandler::HandleTag(CTemplate& Tmpl, const CString& sName, const CStr CWebSession::CWebSession(const CString& sId, const CString& sIP) : m_sId(sId), m_sIP(sIP) { m_pUser = NULL; Sessions.m_mIPSessions.insert(make_pair(sIP, this)); + UpdateLastActive(); +} + +void CWebSession::UpdateLastActive() { + time(&m_tmLastActive); } bool CWebSession::IsAdmin() const { return IsLoggedIn() && m_pUser->IsAdmin(); } @@ -807,6 +813,10 @@ void CWebSock::PrintErrorPage(const CString& sMessage) { m_Template["Error"] = sMessage; } +static inline bool compareLastActive(const std::pair &first, const std::pair &second) { + return first.second->GetLastActive() < second.second->GetLastActive(); +} + CSmartPtr CWebSock::GetSession() { if (!m_spSession.IsNull()) { return m_spSession; @@ -818,13 +828,16 @@ CSmartPtr CWebSock::GetSession() { if (pSession != NULL) { // Refresh the timeout Sessions.m_mspSessions.AddItem((*pSession)->GetId(), *pSession); + (*pSession)->UpdateLastActive(); m_spSession = *pSession; DEBUG("Found existing session from cookie: [" + sCookieSessionId + "] IsLoggedIn(" + CString((*pSession)->IsLoggedIn() ? "true" : "false") + ")"); return *pSession; } if (Sessions.m_mIPSessions.count(GetRemoteIP()) > m_uiMaxSessions) { - mIPSessionsIterator it = Sessions.m_mIPSessions.find(GetRemoteIP()); + pair p = + Sessions.m_mIPSessions.equal_range(GetRemoteIP()); + mIPSessionsIterator it = std::min_element(p.first, p.second, compareLastActive); DEBUG("Remote IP: " << GetRemoteIP() << "; discarding session [" << it->second->GetId() << "]"); Sessions.m_mspSessions.RemItem(it->second->GetId()); }