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:
Uli Schlachter
2013-12-07 20:42:18 +01:00
parent 9e0597fd07
commit 414fa40eb5
2 changed files with 17 additions and 1 deletions

View File

@@ -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());
}