Diff

mod_limit_auth/mod_limit_auth.lua @ 1583:c1bb2a64aabb

mod_limit_auth: Throttle authentication (failed) attempts with optional (0.10+) tarpit
author Kim Alvefur <zash@zash.se>
date Sat, 06 Dec 2014 17:42:51 +0100
child 1854:450ada5bb1b5
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mod_limit_auth/mod_limit_auth.lua	Sat Dec 06 17:42:51 2014 +0100
@@ -0,0 +1,49 @@
+-- mod_limit_auth
+
+local st = require"util.stanza";
+local new_throttle = require "util.throttle".create;
+
+local period = math.max(module:get_option_number(module.name.."_period", 30), 0);
+local max = math.max(module:get_option_number(module.name.."_max", 5), 1);
+
+local tarpit_delay = module:get_option_number(module.name.."_tarpit_delay", nil);
+if tarpit_delay then
+	local waiter = require "util.async".waiter;
+	local delay = tarpit_delay;
+	function tarpit_delay()
+		local wait, done = waiter();
+		module:add_timer(delay, done);
+		wait();
+	end
+else
+	function tarpit_delay() end
+end
+
+local throttles = module:shared"throttles";
+
+local reply = st.stanza("failure", { xmlns = "urn:ietf:params:xml:ns:xmpp-sasl" }):tag("temporary-auth-failure");
+
+local function get_throttle(ip)
+	local throttle = throttles[ip];
+	if not throttle then
+		throttle = new_throttle(max, period);
+		throttles[ip] = throttle;
+	end
+	return throttle;
+end
+
+module:hook("stanza/urn:ietf:params:xml:ns:xmpp-sasl:auth", function (event)
+	local origin = event.origin;
+	if not get_throttle(origin.ip):peek(1) then
+		origin.log("warn", "Too many authentication attepmts for ip %s", origin.ip);
+		tarpit_delay();
+		origin.send(reply);
+		return true;
+	end
+end, 10);
+
+module:hook("authentication-failure", function (event)
+	get_throttle(event.session.ip):poll(1);
+end);
+
+-- TODO remove old throttles after some time