comparison mod_s2s_v6mesh/mod_s2s_v6mesh.lua @ 6478:bd785f524fd2

mod_s2s_v6mesh: Fix various bugs, s2s auth policies now work as expected
author Matthew Wild <mwild1@gmail.com>
date Wed, 18 Mar 2026 18:54:30 +0000
parents 88852e4f81bf
children 771944f2a7c7
comparison
equal deleted inserted replaced
6477:88852e4f81bf 6478:bd785f524fd2
1 --% requires: s2sout-pre-connect-event 1 --% requires: s2sout-pre-connect-event
2
3 module:set_global();
2 4
3 local basic_resolver = require "net.resolvers.basic"; 5 local basic_resolver = require "net.resolvers.basic";
4 local base32 = module:require("base32"); 6 local base32 = module:require("base32");
5 local net = require "prosody.util.net"; 7 local net = require "prosody.util.net";
6 8
34 if not raw then return nil; end 36 if not raw then return nil; end
35 37
36 return net.ntop(raw), raw; 38 return net.ntop(raw), raw;
37 end 39 end
38 40
39 module:hook("s2sout-pre-connect", function(event) 41 function module.add_host(host_module)
40 local host = event.session.to_host; 42 host_module:hook("s2sout-pre-connect", function(event)
41 local dom = host:match("([%w-]+)%.v6%.alt$"); 43 local session = event.session;
42 if not dom then return; end 44 local host = session.to_host;
45 local dom = host:match("([%w-]+)%.v6%.alt$");
46 if not dom then return; end
43 47
44 local target_ip = lookup(dom); 48 local target_ip = lookup(dom);
45 if not target_ip then 49 if not target_ip then
46 return; 50 return;
47 end 51 end
48 52
49 module:log("debug", "Resolved %s to [%s]:%d", target_ip, 5269); 53 host_module:log("debug", "Resolved %s to [%s]:%d", host, target_ip, 5269);
50 54
51 event.resolver = basic_resolver.new(target_ip, 5269, "tcp", {}); 55 event.resolver = basic_resolver.new(target_ip, 5269, "tcp", {});
52 56
53 if is_secure_range(ip.new_ip(target_ip, "IPv6")) then 57 if is_secure_range(ip.new_ip(target_ip, "IPv6")) then
54 module:log("debug", "Treating non-TLS connection to %s as secure because it's in a secure IP range", host); 58 host_module:log("debug", "Treating non-TLS connection to %s as secure because it's in a secure IP range", host);
55 event.session.secure = true; 59 session.secure = true;
56 end 60 session.authenticated_remote = true;
57 end); 61 session.cert_chain_status = "valid";
62 session.cert_identity_status = "valid";
63 end
64 end);
58 65
59 module:hook("s2s-stream-features", function (event) 66 host_module:hook("s2s-stream-features", function (event)
60 local host = event.origin.from_host; 67 local session = event.origin;
68 local host = session.from_host;
61 69
62 local dom = host:match("([%w-]+)%.v6%.alt$"); 70 local dom = host:match("([%w-]+)%.v6%.alt$");
63 if not dom then 71 if not dom then
64 return; 72 return;
65 end 73 end
66 74
67 local remote_ip = ip.new_ip(event.origin.ip); 75 local remote_ip = ip.new_ip(session.ip);
68 76
69 if select(2, lookup(dom)) ~= remote_ip.packed then 77 if select(2, lookup(dom)) ~= remote_ip.packed then
70 module:log("warn", "Rejecting incoming connection from %s: unexpected IP %s", host, remote_ip); 78 host_module:log("warn", "Rejecting incoming connection from %s: unexpected IP %s", host, remote_ip);
71 event.origin:close({ condition = "not-authorized", text = "Hostname does not match IP address" }); 79 session:close({ condition = "not-authorized", text = "Hostname does not match IP address" });
72 return; 80 return;
73 end 81 end
74 82
75 if is_secure_range(remote_ip) then 83 if is_secure_range(remote_ip) then
76 module:log("debug", "Treating non-TLS connection from %s as secure because it's in a secure IP range", host); 84 host_module:log("debug", "Treating non-TLS connection from %s as secure because it's in a secure IP range", host);
77 event.origin.secure = true; 85 session.secure = true;
78 end 86 session.authenticated_remote = true;
79 end, 100); 87 session.cert_chain_status = "valid";
88 session.cert_identity_status = "valid";
89 end
90 end, 200);
91 end
80 92
81 module:hook("s2s-check-certificate", function(event) 93 module:hook("s2s-check-certificate", function(event)
82 local session, host = event.session, event.host; 94 local session, host = event.session, event.host;
83 95
84 local dom = host:match("([%w-]+)%.v6%.alt$"); 96 local dom = host:match("([%w-]+)%.v6%.alt$");
95 107
96 module:log("debug", "Trusting certificate for %s because of IP match", host); 108 module:log("debug", "Trusting certificate for %s because of IP match", host);
97 session.cert_chain_status = "valid"; 109 session.cert_chain_status = "valid";
98 session.cert_identity_status = "valid"; 110 session.cert_identity_status = "valid";
99 return true; 111 return true;
100 end, 100); 112 end, 600);
101 113
102 module:add_item("shell-command", { 114 module:add_item("shell-command", {
103 section = "v6alt"; 115 section = "v6alt";
104 section_desc = module.name.." utility commands"; 116 section_desc = module.name.." utility commands";
105 name = "get_domain"; 117 name = "get_domain";
106 desc = "Convert an IPv6 address to a .v6.alt domain"; 118 desc = "Convert an IPv6 address to a .v6.alt domain";
107 args = { 119 args = {
108 { name = "host", type = "string" };
109 { name = "ip", type = "string" }; 120 { name = "ip", type = "string" };
110 }; 121 };
111 host_selector = "host"; 122 handler = function(self, ip_str) --luacheck: ignore 212/self 212/host
112 handler = function(self, host, ip_str) --luacheck: ignore 212/self 212/host
113 local user_ip = ip.new_ip(ip_str, "IPv6"); 123 local user_ip = ip.new_ip(ip_str, "IPv6");
114 if not user_ip then 124 if not user_ip then
115 return nil, "Invalid IP address: "..tostring(ip_str); 125 return nil, "Invalid IP address: "..tostring(ip_str);
116 end 126 end
117 127
133 section = "v6alt"; 143 section = "v6alt";
134 section_desc = module.name.." utility commands"; 144 section_desc = module.name.." utility commands";
135 name = "get_ip"; 145 name = "get_ip";
136 desc = "Convert a .v6.alt domain to an IP address"; 146 desc = "Convert a .v6.alt domain to an IP address";
137 args = { 147 args = {
138 { name = "host", type = "string" };
139 { name = "domain", type = "string" }; 148 { name = "domain", type = "string" };
140 }; 149 };
141 host_selector = "host"; 150 handler = function(self, domain) --luacheck: ignore 212/self 212/host
142 handler = function(self, host, domain) --luacheck: ignore 212/self 212/host
143 local encoded = domain:match("([%w-]+)%.v6%.alt$"); 151 local encoded = domain:match("([%w-]+)%.v6%.alt$");
144 if not encoded then 152 if not encoded then
145 return nil, "Invalid domain: "..domain; 153 return nil, "Invalid domain: "..domain;
146 end 154 end
147 local user_ip = lookup(encoded); 155 local user_ip = lookup(encoded);
153 section = "v6alt"; 161 section = "v6alt";
154 section_desc = module.name.." utility commands"; 162 section_desc = module.name.." utility commands";
155 name = "is_secure_range"; 163 name = "is_secure_range";
156 desc = "Check whether an IP address is considered secure"; 164 desc = "Check whether an IP address is considered secure";
157 args = { 165 args = {
158 { name = "host", type = "string" };
159 { name = "ip", type = "string" }; 166 { name = "ip", type = "string" };
160 }; 167 };
161 host_selector = "host"; 168 handler = function(self, ip_str) --luacheck: ignore 212/self 212/host
162 handler = function(self, host, ip_str) --luacheck: ignore 212/self 212/host
163 local user_ip = ip.new_ip(ip_str, "IPv6"); 169 local user_ip = ip.new_ip(ip_str, "IPv6");
164 if not user_ip then 170 if not user_ip then
165 return nil, "Invalid IP address: "..tostring(ip_str); 171 return nil, "Invalid IP address: "..tostring(ip_str);
166 end 172 end
167 173