File

mod_muc_ban_ip/mod_muc_ban_ip.lua @ 3579:b5511c48c958

mod_http_muc_log: Add table header and body tags for improved semantics
author Kim Alvefur <zash@zash.se>
date Sun, 05 May 2019 12:59:06 +0200
parent 3403:823027110e29
child 3995:4c9805f29f2d
line wrap: on
line source

module:set_global();

local jid_bare = require "util.jid".bare;
local st = require "util.stanza";
local xmlns_muc_user = "http://jabber.org/protocol/muc#user";

local ip_bans = module:shared("bans");
local full_sessions = prosody.full_sessions;

local function ban_ip(session, from)
	local ip = session.ip;
	if not ip then
		module:log("warn", "Failed to ban IP (IP unknown) for %s", session.full_jid);
		return;
	end
	local banned_from = ip_bans[ip];
	if not banned_from then
		banned_from = {};
		ip_bans[ip] = banned_from;
	end
	banned_from[from] = true;
	module:log("debug", "Added ban for IP address %s from %s", ip, from);
end

local function check_for_incoming_ban(event)
	local stanza = event.stanza;
	local to_session = full_sessions[stanza.attr.to];
	if to_session then
		local directed = to_session.directed;
		local from = stanza.attr.from;
		if directed and directed[from] and stanza.attr.type == "unavailable" then
			-- This is a stanza from somewhere we sent directed presence to (may be a MUC)
			local x = stanza:get_child("x", xmlns_muc_user);
			if x then
				for status in x:childtags("status") do
					if status.attr.code == '301' then
						ban_ip(to_session, jid_bare(from));
					end
				end
			end
		end
	end
end

local function check_for_ban(event)
	local origin, stanza = event.origin, event.stanza;
	local ip = origin.ip;
	local to = jid_bare(stanza.attr.to);
	if ip_bans[ip] and ip_bans[ip][to] then
		origin.log("debug", "IP banned: %s is banned from %s", ip, to)
		origin.send(st.error_reply(stanza, "auth", "forbidden")
			:tag("x", { xmlns = xmlns_muc_user })
				:tag("status", { code = '301' }));
		return true;
	end
	origin.log("debug", "IP not banned: %s from %s", ip, to)
end

function module.add_host(module)
	module:hook("presence/full", check_for_incoming_ban, 100);
	module:hook("pre-presence/full", check_for_ban, 100);
end