summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--modules/webcpanel/pages/index.cpp33
-rw-r--r--modules/webcpanel/pages/index.h7
-rw-r--r--modules/webcpanel/webcpanel.cpp4
3 files changed, 42 insertions, 2 deletions
diff --git a/modules/webcpanel/pages/index.cpp b/modules/webcpanel/pages/index.cpp
index 8fdd11352..227a348fd 100644
--- a/modules/webcpanel/pages/index.cpp
+++ b/modules/webcpanel/pages/index.cpp
@@ -36,6 +36,14 @@ class WebpanelRequest : public IdentifyRequest
return;
}
+ // Rate limit logins to 1/sec
+ time_t *last_login = na->nc->GetExt<time_t>("webcpanel_last_login");
+ if (last_login != NULL && Anope::CurTime == *last_login)
+ {
+ this->OnFail();
+ return;
+ }
+
Anope::string id;
for (int i = 0; i < 64; ++i)
{
@@ -48,6 +56,7 @@ class WebpanelRequest : public IdentifyRequest
na->Extend<Anope::string>("webcpanel_id", id);
na->Extend<Anope::string>("webcpanel_ip", client->GetIP());
+ na->nc->Extend<time_t>("webcpanel_last_login", Anope::CurTime);
{
HTTPReply::cookie c;
@@ -91,6 +100,30 @@ bool WebCPanel::Index::OnRequest(HTTPProvider *server, const Anope::string &page
if (!user.empty() && !pass.empty())
{
// Rate limit check.
+ Anope::string ip = client->clientaddr.addr();
+
+ Anope::hash_map<time_t>::iterator it = last_login_attempt.find(ip);
+ if (it != last_login_attempt.end())
+ {
+ time_t last_time = it->second;
+
+ if (last_time == Anope::CurTime)
+ {
+ replacements["INVALID_LOGIN"] = "Rate limited";
+ TemplateFileServer page("login.html");
+ page.Serve(server, page_name, client, message, reply, replacements);
+ return true;
+ }
+ }
+
+ // don't let ip hash grow too long
+ if (Anope::CurTime > last_clear + FLUSH_TIME)
+ {
+ last_login_attempt.clear();
+ last_clear = Anope::CurTime;
+ }
+
+ last_login_attempt[ip] = Anope::CurTime;
WebpanelRequest *req = new WebpanelRequest(me, reply, message, server, page_name, client, replacements, user, pass);
FOREACH_MOD(OnCheckAuthentication, (NULL, req));
diff --git a/modules/webcpanel/pages/index.h b/modules/webcpanel/pages/index.h
index 76e3d12a1..771cbf8fc 100644
--- a/modules/webcpanel/pages/index.h
+++ b/modules/webcpanel/pages/index.h
@@ -12,8 +12,13 @@ namespace WebCPanel
class Index : public WebPanelPage
{
+ static const int FLUSH_TIME = 60;
+
+ Anope::hash_map<time_t> last_login_attempt;
+ time_t last_clear;
+
public:
- Index(const Anope::string &u) : WebPanelPage(u) { }
+ Index(const Anope::string &u) : WebPanelPage(u), last_clear(0) { }
bool OnRequest(HTTPProvider *, const Anope::string &, HTTPClient *, HTTPMessage &, HTTPReply &) anope_override;
};
diff --git a/modules/webcpanel/webcpanel.cpp b/modules/webcpanel/webcpanel.cpp
index 14080191e..aa65b4f6c 100644
--- a/modules/webcpanel/webcpanel.cpp
+++ b/modules/webcpanel/webcpanel.cpp
@@ -15,6 +15,7 @@ class ModuleWebCPanel : public Module
ServiceReference<HTTPProvider> provider;
Panel panel;
PrimitiveExtensibleItem<Anope::string> id, ip;
+ PrimitiveExtensibleItem<time_t> last_login;
StaticFileServer style_css, logo_png, cubes_png, favicon_ico;
@@ -44,7 +45,8 @@ class ModuleWebCPanel : public Module
public:
ModuleWebCPanel(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, EXTRA | VENDOR),
- panel(this, "webcpanel"), id(this, "webcpanel_id"), ip(this, "webcpanel_ip"),
+ panel(this, "webcpanel"),
+ id(this, "webcpanel_id"), ip(this, "webcpanel_ip"), last_login(this, "webcpanel_last_login"),
style_css("style.css", "/static/style.css", "text/css"), logo_png("logo.png", "/static/logo.png", "image/png"), cubes_png("cubes.png", "/static/cubes.png", "image/png"), favicon_ico("favicon.ico", "/favicon.ico", "image/x-icon"),
index("/"), logout("/logout"), _register("/register"), confirm("/confirm"),
nickserv_info("NickServ", "/nickserv/info"), nickserv_cert("NickServ", "/nickserv/cert"), nickserv_access("NickServ", "/nickserv/access"), nickserv_alist("NickServ", "/nickserv/alist"),