view mod_watchuntrusted/mod_watchuntrusted.lua @ 2491:5fbca7de2088

mod_smacks: Send out more ack requests where needed Under some circumstances it was possible that more than "max_unacked_stanzas" where left in the outgoing stanza queue without forcing an ack. This could happen, when more stanzas entered the queue while the last ack request was still unanswered. Now the test "#queue > max_unacked_stanzas" is done upon receiving an ack as well as when sending out stanzas, which fixes this bug.
author tmolitor <thilo@eightysoft.de>
date Sun, 12 Feb 2017 19:27:50 +0100
parents dd1f0173f538
children 9a3e51f348fe
line wrap: on
line source

local jid_prep = require "util.jid".prep;

local secure_auth = module:get_option_boolean("s2s_secure_auth", false);
local secure_domains, insecure_domains =
	module:get_option_set("s2s_secure_domains", {})._items, module:get_option_set("s2s_insecure_domains", {})._items;

local untrusted_fail_watchers = module:get_option_set("untrusted_fail_watchers", module:get_option("admins", {})) / jid_prep;
local untrusted_fail_notification = module:get_option("untrusted_fail_notification", "Establishing a secure connection from $from_host to $to_host failed. Certificate hash: $sha1. $errors");

local st = require "util.stanza";

local notified_about_already = { };

module:hook_global("s2s-check-certificate", function (event)
    local session, host = event.session, event.host;
    if not host then return end
    local conn = session.conn:socket();
    local local_host = session.direction == "outgoing" and session.from_host or session.to_host;

    if not (local_host == module:get_host()) then return end

    module:log("debug", "Checking certificate...");
    local must_secure = secure_auth;

    if not must_secure and secure_domains[host] then
            must_secure = true;
    elseif must_secure and insecure_domains[host] then
            must_secure = false;
    end

    if must_secure and (session.cert_chain_status ~= "valid" or session.cert_identity_status ~= "valid") and not notified_about_already[host] then
		notified_about_already[host] = os.time();
		local _, errors = conn:getpeerverification();
		local error_message = "";

		for depth, t in pairs(errors or {}) do
			if #t > 0 then
				error_message = error_message .. "Error with certificate " .. (depth - 1) .. ": " .. table.concat(t, ", ") .. ". ";
			end
		end

		if session.cert_identity_status then
			error_message = error_message .. "This certificate is " .. session.cert_identity_status .. " for " .. host .. ".";
		end

		local replacements = {
			sha1 = event.cert and event.cert:digest("sha1") or "(No certificate)",
			sha256 = event.cert and event.cert:digest("sha256") or "(No certificate)",
			errors = error_message
		};

		local message = st.message{ type = "chat", from = local_host }
			:tag("body")
				:text(untrusted_fail_notification:gsub("%$([%w_]+)", function (v)
					return event[v] or session and session[v] or replacements and replacements[v] or nil;
				end));
		for jid in untrusted_fail_watchers do
			module:log("debug", "Notifying %s", jid);
			message.attr.to = jid;
			module:send(message);
		end
	end
end, -0.5);

module:add_timer(14400, function (now)
	for host, time in pairs(notified_about_already) do
		if time + 86400 < now then
			notified_about_already[host] = nil;
		end
	end
	return 14400;
end)