mirror of
https://github.com/znc/znc.git
synced 2026-03-28 17:42:41 +01:00
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 <psychon@znc.in>
This commit is contained in:
@@ -19,6 +19,7 @@
|
||||
#include <znc/User.h>
|
||||
#include <znc/IRCNetwork.h>
|
||||
#include <znc/znc.h>
|
||||
#include <algorithm>
|
||||
#include <sstream>
|
||||
|
||||
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<const CString, CWebSession *> &first, const std::pair<const CString, CWebSession *> &second) {
|
||||
return first.second->GetLastActive() < second.second->GetLastActive();
|
||||
}
|
||||
|
||||
CSmartPtr<CWebSession> CWebSock::GetSession() {
|
||||
if (!m_spSession.IsNull()) {
|
||||
return m_spSession;
|
||||
@@ -818,13 +828,16 @@ CSmartPtr<CWebSession> 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<mIPSessionsIterator, mIPSessionsIterator> 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());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user