diff mod_s2s_v6mesh/mod_s2s_v6mesh.lua @ 6490:771944f2a7c7

mod_s2s_v6mesh: Update configuration syntax and associated documentation
author Matthew Wild <mwild1@gmail.com>
date Tue, 24 Mar 2026 13:20:51 +0000
parents bd785f524fd2
children
line wrap: on
line diff
--- a/mod_s2s_v6mesh/mod_s2s_v6mesh.lua	Mon Mar 23 19:47:03 2026 +0100
+++ b/mod_s2s_v6mesh/mod_s2s_v6mesh.lua	Tue Mar 24 13:20:51 2026 +0000
@@ -9,15 +9,16 @@
 local ip = require "prosody.util.ip";
 local parse_cidr = require "prosody.util.ip".parse_cidr;
 
-local secure_ranges = module:get_option_set("s2s_v6mesh_secure_ranges", {});
+local mesh_ranges = module:get_option("s2s_v6mesh_ranges", {});
+local trust_all_certs = module:get_option_boolean("s2s_v6mesh_trust_all_certs", true);
 
 local function is_secure_range(remote_ip)
-	for range in secure_ranges do
+	for range, range_config in pairs(mesh_ranges) do
 		if ip.match(remote_ip, parse_cidr(range)) then
-			return true, range;
+			return range, range_config;
 		end
 	end
-	return false;
+	return nil;
 end
 
 function lookup(dom)
@@ -38,6 +39,30 @@
 	return net.ntop(raw), raw;
 end
 
+local function apply_range_config(host_module, host, session, target_ip)
+	local range, range_config = is_secure_range(target_ip);
+
+	if range then
+		if range_config.use_tls == false then
+			host_module:log("debug", "Treating non-TLS connection to %s as secure because of range configuration", host);
+			session.secure = true;
+		end
+		if range_config.trust_all_certs ~= false then
+			module:log("debug", "Auto-trusting certificate for %s because of range configuration", host);
+			session.authenticated_remote = true;
+			session.cert_chain_status = "valid";
+			session.cert_identity_status = "valid";
+		else
+			module:log("debug", "Not auto-trusting certificate for $s (IP in unconfigured range): %s", host);
+		end
+	elseif trust_all_certs then
+		module:log("debug", "Auto-trusting certificate for %s because of default policy", host);
+		session.authenticated_remote = true;
+		session.cert_chain_status = "valid";
+		session.cert_identity_status = "valid";
+	end
+end
+
 function module.add_host(host_module)
 	host_module:hook("s2sout-pre-connect", function(event)
 		local session = event.session;
@@ -54,13 +79,8 @@
 
 		event.resolver = basic_resolver.new(target_ip, 5269, "tcp", {});
 
-		if is_secure_range(ip.new_ip(target_ip, "IPv6")) then
-			host_module:log("debug", "Treating non-TLS connection to %s as secure because it's in a secure IP range", host);
-			session.secure = true;
-			session.authenticated_remote = true;
-			session.cert_chain_status = "valid";
-			session.cert_identity_status = "valid";
-		end
+		local range_ip = ip.new_ip(target_ip, "IPv6");
+		apply_range_config(host_module, host, session, range_ip);
 	end);
 
 	host_module:hook("s2s-stream-features", function (event)
@@ -80,13 +100,7 @@
 			return;
 		end
 
-		if is_secure_range(remote_ip) then
-			host_module:log("debug", "Treating non-TLS connection from %s as secure because it's in a secure IP range", host);
-			session.secure = true;
-			session.authenticated_remote = true;
-			session.cert_chain_status = "valid";
-			session.cert_identity_status = "valid";
-		end
+		apply_range_config(host_module, host, session, remote_ip);
 	end, 200);
 end
 
@@ -105,10 +119,29 @@
 		return;
 	end
 
-	module:log("debug", "Trusting certificate for %s because of IP match", host);
-	session.cert_chain_status = "valid";
-	session.cert_identity_status = "valid";
-	return true;
+	local range, range_config = is_secure_range(remote_ip);
+	if range then
+		if range_config.trust_all_certs ~= false then
+			module:log("debug", "Auto-trusting certificate for %s because of IP match", host);
+			session.cert_chain_status = "valid";
+			session.cert_identity_status = "valid";
+		else
+			module:log("debug", "Not auto-trusting certificate for $s (IP in unconfigured range): %s", host);
+		end
+	elseif trust_all_certs then
+		module:log("debug", "Auto-trusting certificate for %s because of default policy", host);
+		session.authenticated_remote = true;
+		session.cert_chain_status = "valid";
+		session.cert_identity_status = "valid";
+		return true;
+	end
+
+	if not session.conn.extra then
+		session.conn.extra = {};
+	end
+	-- This can be used by mod_s2s_auth_certs to validate IP certificates,
+	-- if supported.
+	session.conn.extra.secure_hostname = tostring(remote_ip);
 end, 600);
 
 module:add_item("shell-command", {
@@ -160,23 +193,30 @@
 module:add_item("shell-command", {
 	section = "v6alt";
 	section_desc = module.name.." utility commands";
-	name = "is_secure_range";
-	desc = "Check whether an IP address is considered secure";
+	name = "range";
+	desc = "Check whether a host/IP address is within a configured range";
 	args = {
 		{ name = "ip", type = "string" };
 	};
-	handler = function(self, ip_str) --luacheck: ignore 212/self 212/host
+	handler = function(self, str) --luacheck: ignore 212/self 212/host
+		local encoded = str:match("([%w-]+)%.v6%.alt$");
+
+		local ip_str = encoded and lookup(encoded) or str;
 		local user_ip = ip.new_ip(ip_str, "IPv6");
 		if not user_ip then
-			return nil, "Invalid IP address: "..tostring(ip_str);
+			return nil, "Invalid domain or IP: "..tostring(str);
 		end
 
-		local secure, range = is_secure_range(user_ip);
+		local range, range_config = is_secure_range(user_ip);
 
-		if not secure then
-			return true, "Not secure";
+		if not range then
+			return true, "Not configured";
 		end
 
-		return true, ("In secure range: %s"):format(range);
+		self.session.print(("In range: %s"):format(range));
+		self.session.print(("Use TLS: %s"):format(range_config.use_tls == false and "no" or "yes"));
+		self.session.print(("Trust certs: %s"):format(range_config.trust_all_certs == false and "no" or "yes"));
+
+		return true, "IP is in configured range";
 	end;
 });