Mercurial > prosody-modules
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 |
