# HG changeset patch
# User Kim Alvefur <zash@zash.se>
# Date 1642784359 -3600
# Node ID 77ac0d96ac24c6c6a0ce851c893de670dffa3ffd
# Parent  a2e6605303faf5401970ee7a6c953c7bef57c7d0
mod_s2s: Enable outgoing Direct TLS connections

Makes it faster by cutting out the roundtrips involved in <starttls/>,
at the cost of making an additional SRV lookup.

Since we already ignore a missing <starttls/> offer and try anyway there
is not much difference in security. The fact that XMPP is used and the
hostnames involved might still be visible until the future Encrypted
ClientHello extension allows hiding those too.

diff -r a2e6605303fa -r 77ac0d96ac24 CHANGES
--- a/CHANGES	Fri Jan 21 17:57:47 2022 +0100
+++ b/CHANGES	Fri Jan 21 17:59:19 2022 +0100
@@ -27,7 +27,7 @@
 -   SNI support (including automatic certificate selection)
 -   ALPN support in mod_net_multiplex
 -   DANE support in low-level network layer
--   Direct TLS support (c2s and incoming s2s)
+-   Direct TLS support (c2s and s2s)
 -   SCRAM-SHA-256
 -   Direct TLS (including https) certificates updated on reload
 -   Pluggable authorization providers (mod_authz_)
diff -r a2e6605303fa -r 77ac0d96ac24 plugins/mod_s2s.lua
--- a/plugins/mod_s2s.lua	Fri Jan 21 17:57:47 2022 +0100
+++ b/plugins/mod_s2s.lua	Fri Jan 21 17:59:19 2022 +0100
@@ -29,6 +29,7 @@
 local runner = require "util.async".runner;
 local connect = require "net.connect".connect;
 local service = require "net.resolvers.service";
+local resolver_chain = require "net.resolvers.chain";
 local errors = require "util.error";
 local set = require "util.set";
 
@@ -217,8 +218,14 @@
 	log("debug", "stanza [%s] queued until connection complete", stanza.name);
 	-- FIXME Cleaner solution to passing extra data from resolvers to net.server
 	-- This mt-clone allows resolvers to add extra data, currently used for DANE TLSA records
-	local extra = setmetatable({}, s2s_service_options_mt);
-	connect(service.new(to_host, "xmpp-server", "tcp", extra), listener, nil, { session = host_session });
+	local xmpp_extra = setmetatable({}, s2s_service_options_mt);
+	local sslctx = require"core.certmanager".create_context(from_host, "client"); -- TODO this should live in mod_tls ?
+	local xmpps_extra = setmetatable({ default_port = false; servername = to_host; sslctx = sslctx }, s2s_service_options_mt);
+	local direct_and_normal = resolver_chain.new({
+		service.new(to_host, "xmpps-server", "tcp", xmpps_extra);
+		service.new(to_host, "xmpp-server", "tcp", xmpp_extra);
+	});
+	connect(direct_and_normal, listener, nil, { session = host_session });
 	m_initiated_connections:with_labels(from_host):add(1)
 	return true;
 end