From 56846d8e505b82128ae091fc63ea62e400a07827 Mon Sep 17 00:00:00 2001 From: moparisthebest Date: Mon, 25 Apr 2022 00:57:26 -0400 Subject: [PATCH] Make mod_s2s_outgoing_proxy compatible with prosody 0.12 Based off mod_onions rev 44be2c6087f3, thanks for the pointer Zash! --- .../mod_s2s_outgoing_proxy.lua | 92 +++++++++++++++---- integration/test.sh | 9 +- 2 files changed, 81 insertions(+), 20 deletions(-) diff --git a/contrib/prosody-modules/mod_s2s_outgoing_proxy.lua b/contrib/prosody-modules/mod_s2s_outgoing_proxy.lua index c8e5ab0..9c3280a 100644 --- a/contrib/prosody-modules/mod_s2s_outgoing_proxy.lua +++ b/contrib/prosody-modules/mod_s2s_outgoing_proxy.lua @@ -2,41 +2,97 @@ local st = require"util.stanza"; local new_ip = require"util.ip".new_ip; local new_outgoing = require"core.s2smanager".new_outgoing; local bounce_sendq = module:depends"s2s".route_to_new_session.bounce_sendq; -local s2sout = module:depends"s2s".route_to_new_session.s2sout; +local initialize_filters = require "util.filters".initialize; +local st = require "util.stanza"; + +local portmanager = require "core.portmanager"; + +local addclient = require "net.server".addclient; + +module:depends("s2s"); + +local sessions = module:shared("sessions"); local s2s_outgoing_proxy = module:get_option("s2s_outgoing_proxy"); +local host, port = s2s_outgoing_proxy[1] or s2s_outgoing_proxy, tonumber(s2s_outgoing_proxy[2]) or 15270; + +-- The proxy_listener handles connection while still connecting to the proxy, +-- then it hands them over to the normal listener (in mod_s2s) +local proxy_listener = { default_port = port, default_mode = "*a", default_interface = "*" }; + +function proxy_listener.onconnect(conn) + local session = sessions[conn]; + + -- Now the real s2s listener can take over the connection. + local listener = portmanager.get_service("s2s").listener; + + session.proxy_handler = nil; + + local w, log = conn.send, session.log; + + local filter = initialize_filters(session); + + session.version = 1; + + session.sends2s = function (t) + log("debug", "sending (s2s over proxy): %s", (t.top_tag and t:top_tag()) or t:match("^[^>]*>?")); + if t.name then + t = filter("stanzas/out", t); + end + if t then + t = filter("bytes/out", tostring(t)); + if t then + return conn:write(tostring(t)); + end + end + end + + session.open_stream = function () + session.sends2s(st.stanza("stream:stream", { + xmlns='jabber:server', ["xmlns:db"]='jabber:server:dialback', + ["xmlns:stream"]='http://etherx.jabber.org/streams', + from=session.from_host, to=session.to_host, version='1.0', ["xml:lang"]='en'}):top_tag()); + end + + conn.setlistener(conn, listener); + + listener.register_outgoing(conn, session); + + listener.onconnect(conn); + + -- this marks outgoing s2s as secure so we accept SASL EXTERNAL on it + session.secure = true; +end + +function proxy_listener.register_outgoing(conn, session) + session.direction = "outgoing"; + sessions[conn] = session; +end + +function proxy_listener.ondisconnect(conn, err) + sessions[conn] = nil; +end + module:hook("route/remote", function(event) local from_host, to_host, stanza = event.from_host, event.to_host, event.stanza; log("debug", "opening a new outgoing connection for this stanza"); local host_session = new_outgoing(from_host, to_host); - host_session.version = 1; -- Store in buffer host_session.bounce_sendq = bounce_sendq; host_session.sendq = { {tostring(stanza), stanza.attr.type ~= "error" and stanza.attr.type ~= "result" and st.reply(stanza)} }; log("debug", "stanza [%s] queued until connection complete", tostring(stanza.name)); + + local conn = addclient(host, port, proxy_listener, "*a"); - local ip_hosts = {}; + proxy_listener.register_outgoing(conn, host_session); - local host, port = s2s_outgoing_proxy[1] or s2s_outgoing_proxy, tonumber(s2s_outgoing_proxy[2]) or 15270; - ip_hosts[#ip_hosts+1] = { ip = new_ip(host), port = port } - - host_session.ip_hosts = ip_hosts; - host_session.ip_choice = 0; -- Incremented by try_next_ip - s2sout.try_next_ip(host_session); + host_session.conn = conn; return true; end, -2); --- todo: is this the best place to do these hooks? --- this hook marks outgoing s2s as secure so we accept SASL EXTERNAL on it -module:hook_tag("http://etherx.jabber.org/streams", "features", function (session, stanza) - if session.type == "s2sout_unauthed" then - module:log("debug", "marking hook session.type '%s' secure!", session.type); - session.secure = true; - end -end, 3000); - +-- todo: is this the best place to do this hook? -- this hook marks incoming s2s as secure so we offer SASL EXTERNAL on it module:hook("s2s-stream-features", function(event) local session, features = event.origin, event.features; diff --git a/integration/test.sh b/integration/test.sh index 7bc4bb7..34f8d9f 100755 --- a/integration/test.sh +++ b/integration/test.sh @@ -13,8 +13,9 @@ build_args='' img='xmpp-proxy-test' xmpp_proxy_bind='' run_blocked=0 +rebuild_image=0 ecdsa=0 -while getopts ":i:drben" o; do +while getopts ":i:drbeno" o; do case "${o}" in i) ipv4=${OPTARG} @@ -40,6 +41,9 @@ while getopts ":i:drben" o; do podman image rm -f "$img" "$img-dev" "$img-dev-ecdsa" exit $? ;; + o) + rebuild_image=1 + ;; *) usage ;; @@ -137,7 +141,8 @@ set -euxo pipefail podman network exists xmpp-proxy-net4 && cleanup -podman image exists "$img" || podman build -f Dockerfile --build-arg="ECDSA=$ecdsa" --build-arg="BUILD=$build" -t "$img" .. +podman image exists "$img" || rebuild_image=1 +[ $rebuild_image -eq 0 ] || podman build -f Dockerfile --build-arg="ECDSA=$ecdsa" --build-arg="BUILD=$build" -t "$img" .. #podman run --rm "$img" openssl pkey -in /etc/prosody/certs/one.example.org.key -text if [ $build -eq 1 ]