aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--core/certmanager.lua14
-rw-r--r--core/moduleapi.lua1
-rw-r--r--net/http.lua3
-rw-r--r--net/server_event.lua17
-rw-r--r--net/tls_luasec.lua5
-rw-r--r--plugins/mod_auth_internal_hashed.lua3
-rw-r--r--plugins/mod_auth_internal_plain.lua3
-rw-r--r--plugins/mod_c2s.lua18
-rw-r--r--plugins/mod_csi.lua21
-rw-r--r--plugins/mod_s2s.lua27
-rw-r--r--plugins/mod_s2s_bidi.lua7
-rw-r--r--spec/util_xtemplate_spec.lua4
-rw-r--r--teal-src/prosody/util/xtemplate.tl5
-rw-r--r--util/sslconfig.lua14
-rw-r--r--util/xtemplate.lua3
15 files changed, 130 insertions, 15 deletions
diff --git a/core/certmanager.lua b/core/certmanager.lua
index 263797e5..9e0ace6a 100644
--- a/core/certmanager.lua
+++ b/core/certmanager.lua
@@ -213,6 +213,18 @@ local core_defaults = {
dane = tls.features.capabilities.dane and configmanager.get("*", "use_dane") and { "no_ee_namechecks" };
}
+-- https://datatracker.ietf.org/doc/html/rfc7919#appendix-A.1
+local ffdhe2048 = [[
+-----BEGIN DH PARAMETERS-----
+MIIBCAKCAQEA//////////+t+FRYortKmq/cViAnPTzx2LnFg84tNpWp4TZBFGQz
++8yTnc4kmz75fS/jY2MMddj2gbICrsRhetPfHtXV/WVhJDP1H18GbtCFY2VVPe0a
+87VXE15/V8k1mE8McODmi3fipona8+/och3xWKE2rec1MKzKT0g6eXq8CrGCsyT7
+YdEIqUuyyOP7uWrat2DX9GgdT0Kj3jlN9K5W7edjcrsZCwenyO4KbXCeAvzhzffi
+7MA0BM0oNC9hkXL+nOmFg/+OTxIy7vKBg8P+OxtMb61zO7X8vC7CIAXFjvGDfRaD
+ssbzSibBsu/6iGtCOGEoXJf//////////wIBAg==
+-----END DH PARAMETERS-----
+]]
+
local mozilla_ssl_configs = {
-- https://wiki.mozilla.org/Security/Server_Side_TLS
-- Version 5.7 as of 2023-07-09
@@ -225,7 +237,7 @@ local mozilla_ssl_configs = {
};
intermediate = {
protocol = "tlsv1_2+";
- dhparam = nil; -- ffdhe2048.txt
+ dhparam = ffdhe2048;
options = { cipher_server_preference = false };
ciphers = {
"ECDHE-ECDSA-AES128-GCM-SHA256";
diff --git a/core/moduleapi.lua b/core/moduleapi.lua
index 31d1b1bd..fa5086cf 100644
--- a/core/moduleapi.lua
+++ b/core/moduleapi.lua
@@ -653,6 +653,7 @@ end
function api:metric(type_, name, unit, description, label_keys, conf)
local metric = require "prosody.core.statsmanager".metric;
local is_scoped = self.host ~= "*"
+ label_keys = label_keys or {};
if is_scoped then
-- prepend `host` label to label keys if this is not a global module
local orig_labels = label_keys
diff --git a/net/http.lua b/net/http.lua
index bea1e905..35a92d57 100644
--- a/net/http.lua
+++ b/net/http.lua
@@ -317,6 +317,9 @@ local function request(self, u, ex, callback)
if ex and ex.use_dane ~= nil then
use_dane = ex.use_dane;
end
+ if not sslctx then
+ error("Attempt to make HTTPS request but no 'sslctx' provided in options");
+ end
end
if self.pool then
diff --git a/net/server_event.lua b/net/server_event.lua
index 3bad3474..44222aa3 100644
--- a/net/server_event.lua
+++ b/net/server_event.lua
@@ -735,7 +735,10 @@ local function handleserver( server, addr, port, pattern, listener, sslctx, star
debug( "maximal connections reached, refuse client connection; accept delay:", delay )
return EV_TIMEOUT, delay -- delay for next accept attempt
end
- local client_ip, client_port = client:getpeername( )
+ local client_ip, client_port = addr, port;
+ if client.getpeername then -- Only IP sockets have this method, UNIX sockets don't
+ client_ip, client_port = client:getpeername( )
+ end
interface._connections = interface._connections + 1 -- increase connection count
local clientinterface = handleclient( client, client_ip, client_port, interface, pattern, listener, sslctx )
--vdebug( "client id:", clientinterface, "startssl:", startssl )
@@ -758,6 +761,17 @@ local function handleserver( server, addr, port, pattern, listener, sslctx, star
return interface
end
+local function wrapserver(conn, addr, port, listeners, config)
+ config = config or {}
+ if config.sslctx and not has_luasec then
+ debug "fatal error: luasec not found"
+ return nil, "luasec not found"
+ end
+ local interface = handleserver( conn, addr, port, config.read_size, listeners, config.tls_ctx, config.tls_direct) -- new server handler
+ debug( "new server created with id:", tostring(interface))
+ return interface
+end
+
local function listen(addr, port, listener, config)
config = config or {}
if config.sslctx and not has_luasec then
@@ -947,6 +961,7 @@ return {
listen = listen,
addclient = addclient,
wrapclient = wrapclient,
+ wrapserver = wrapserver,
setquitting = setquitting,
closeall = closeallservers,
get_backend = get_backend,
diff --git a/net/tls_luasec.lua b/net/tls_luasec.lua
index 3af2fc6b..4e4e92ed 100644
--- a/net/tls_luasec.lua
+++ b/net/tls_luasec.lua
@@ -54,7 +54,10 @@ local function new_context(cfg, builder)
-- LuaSec expects dhparam to be a callback that takes two arguments.
-- We ignore those because it is mostly used for having a separate
-- set of params for EXPORT ciphers, which we don't have by default.
- if type(cfg.dhparam) == "string" then
+ if type(cfg.dhparam) == "string" and cfg.dhparam:sub(1, 10) == "-----BEGIN" then
+ local dhparam = cfg.dhparam;
+ cfg.dhparam = function() return dhparam; end
+ elseif type(cfg.dhparam) == "string" then
local f, err = io_open(cfg.dhparam);
if not f then return nil, "Could not open DH parameters: "..err end
local dhparam = f:read("*a");
diff --git a/plugins/mod_auth_internal_hashed.lua b/plugins/mod_auth_internal_hashed.lua
index 4840f431..806eb9bd 100644
--- a/plugins/mod_auth_internal_hashed.lua
+++ b/plugins/mod_auth_internal_hashed.lua
@@ -37,6 +37,9 @@ local provider = {};
function provider.test_password(username, password)
log("debug", "test password for user '%s'", username);
local credentials = accounts:get(username) or {};
+ if credentials.disabled then
+ return nil, "Account disabled.";
+ end
password = saslprep(password);
if not password then
return nil, "Password fails SASLprep.";
diff --git a/plugins/mod_auth_internal_plain.lua b/plugins/mod_auth_internal_plain.lua
index 98df1983..6cced803 100644
--- a/plugins/mod_auth_internal_plain.lua
+++ b/plugins/mod_auth_internal_plain.lua
@@ -22,6 +22,9 @@ local provider = {};
function provider.test_password(username, password)
log("debug", "test password for user '%s'", username);
local credentials = accounts:get(username) or {};
+ if credentials.disabled then
+ return nil, "Account disabled.";
+ end
password = saslprep(password);
if not password then
return nil, "Password fails SASLprep.";
diff --git a/plugins/mod_c2s.lua b/plugins/mod_c2s.lua
index 1a24c27c..09d4be08 100644
--- a/plugins/mod_c2s.lua
+++ b/plugins/mod_c2s.lua
@@ -30,6 +30,12 @@ local stream_close_timeout = module:get_option_period("c2s_close_timeout", 5);
local opt_keepalives = module:get_option_boolean("c2s_tcp_keepalives", module:get_option_boolean("tcp_keepalives", true));
local stanza_size_limit = module:get_option_integer("c2s_stanza_size_limit", 1024*256,10000);
+local advertised_idle_timeout = 14*60; -- default in all net.server implementations
+local network_settings = module:get_option("network_settings");
+if type(network_settings) == "table" and type(network_settings.read_timeout) == "number" then
+ advertised_idle_timeout = network_settings.read_timeout;
+end
+
local measure_connections = module:metric("gauge", "connections", "", "Established c2s connections", {"host", "type", "ip_family"});
local sessions = module:shared("sessions");
@@ -130,10 +136,16 @@ function stream_callbacks._streamopened(session, attr)
local features = st.stanza("stream:features");
hosts[session.host].events.fire_event("stream-features", { origin = session, features = features, stream = attr });
if features.tags[1] or session.full_jid then
- if stanza_size_limit then
+ if stanza_size_limit or advertised_idle_timeout then
features:reset();
- features:tag("limits", { xmlns = "urn:xmpp:stream-limits:0" })
- :text_tag("max-bytes", string.format("%d", stanza_size_limit)):up();
+ local limits = features:tag("limits", { xmlns = "urn:xmpp:stream-limits:0" });
+ if stanza_size_limit then
+ limits:text_tag("max-bytes", string.format("%d", stanza_size_limit));
+ end
+ if advertised_idle_timeout then
+ limits:text_tag("idle-seconds", string.format("%d", advertised_idle_timeout));
+ end
+ limits:reset();
end
send(features);
else
diff --git a/plugins/mod_csi.lua b/plugins/mod_csi.lua
index 82efd831..7a1857c0 100644
--- a/plugins/mod_csi.lua
+++ b/plugins/mod_csi.lua
@@ -3,6 +3,7 @@ local xmlns_csi = "urn:xmpp:csi:0";
local csi_feature = st.stanza("csi", { xmlns = xmlns_csi });
local change = module:metric("counter", "changes", "events", "CSI state changes", {"csi_state"});
+local count = module:metric("gauge", "state", "sessions", "", { "state" });
module:hook("stream-features", function (event)
if event.origin.username then
@@ -23,3 +24,23 @@ end
module:hook("stanza/"..xmlns_csi..":active", refire_event("csi-client-active"));
module:hook("stanza/"..xmlns_csi..":inactive", refire_event("csi-client-inactive"));
+
+module:hook_global("stats-update", function()
+ local sessions = prosody.hosts[module.host].sessions;
+ if not sessions then return end
+ local active, inactive, flushing = 0, 0, 0;
+ for _, user_session in pairs(sessions) do
+ for _, session in pairs(user_session.sessions) do
+ if session.state == "inactive" then
+ inactive = inactive + 1;
+ elseif session.state == "active" then
+ inactive = inactive + 1;
+ elseif session.state == "flushing" then
+ inactive = inactive + 1;
+ end
+ end
+ end
+ count:with_labels("active"):set(active);
+ count:with_labels("inactive"):set(inactive);
+ count:with_labels("flushing"):set(flushing);
+end);
diff --git a/plugins/mod_s2s.lua b/plugins/mod_s2s.lua
index 88b73eba..660b5828 100644
--- a/plugins/mod_s2s.lua
+++ b/plugins/mod_s2s.lua
@@ -43,6 +43,12 @@ local secure_domains, insecure_domains =
local require_encryption = module:get_option_boolean("s2s_require_encryption", true);
local stanza_size_limit = module:get_option_integer("s2s_stanza_size_limit", 1024*512, 10000);
+local advertised_idle_timeout = 14*60; -- default in all net.server implementations
+local network_settings = module:get_option("network_settings");
+if type(network_settings) == "table" and type(network_settings.read_timeout) == "number" then
+ advertised_idle_timeout = network_settings.read_timeout;
+end
+
local measure_connections_inbound = module:metric(
"gauge", "connections_inbound", "",
"Established incoming s2s connections",
@@ -258,10 +264,15 @@ function module.add_host(module)
module:hook("route/remote", route_to_existing_session, -1);
module:hook("route/remote", route_to_new_session, -10);
module:hook("s2sout-stream-features", function (event)
+ if not (stanza_size_limit or advertised_idle_timeout) then return end
+ local limits = event.features:tag("limits", { xmlns = "urn:xmpp:stream-limits:0" })
if stanza_size_limit then
- event.features:tag("limits", { xmlns = "urn:xmpp:stream-limits:0" })
- :text_tag("max-bytes", string.format("%d", stanza_size_limit)):up();
+ limits:text_tag("max-bytes", string.format("%d", stanza_size_limit));
end
+ if advertised_idle_timeout then
+ limits:text_tag("idle-seconds", string.format("%d", advertised_idle_timeout));
+ end
+ limits:up();
end);
module:hook_tag("urn:xmpp:bidi", "bidi", function(session, stanza)
-- Advertising features on bidi connections where no <stream:features> is sent in the other direction
@@ -551,10 +562,16 @@ function stream_callbacks._streamopened(session, attr)
end
if ( session.type == "s2sin" or session.type == "s2sout" ) or features.tags[1] then
- if stanza_size_limit then
+ if stanza_size_limit or advertised_idle_timeout then
+ features:reset();
+ local limits = features:tag("limits", { xmlns = "urn:xmpp:stream-limits:0" });
+ if stanza_size_limit then
+ limits:text_tag("max-bytes", string.format("%d", stanza_size_limit));
+ end
+ if advertised_idle_timeout then
+ limits:text_tag("idle-seconds", string.format("%d", advertised_idle_timeout));
+ end
features:reset();
- features:tag("limits", { xmlns = "urn:xmpp:stream-limits:0" })
- :text_tag("max-bytes", string.format("%d", stanza_size_limit)):up();
end
log("debug", "Sending stream features: %s", features);
diff --git a/plugins/mod_s2s_bidi.lua b/plugins/mod_s2s_bidi.lua
index 22415293..8588ce59 100644
--- a/plugins/mod_s2s_bidi.lua
+++ b/plugins/mod_s2s_bidi.lua
@@ -12,10 +12,15 @@ local xmlns_bidi = "urn:xmpp:bidi";
local require_encryption = module:get_option_boolean("s2s_require_encryption", true);
+local offers_sent = module:metric("counter", "offers_sent", "", "Bidirectional connection offers sent", {});
+local offers_recv = module:metric("counter", "offers_recv", "", "Bidirectional connection offers received", {});
+local offers_taken = module:metric("counter", "offers_taken", "", "Bidirectional connection offers taken", {});
+
module:hook("s2s-stream-features", function(event)
local origin, features = event.origin, event.features;
if origin.type == "s2sin_unauthed" and (not require_encryption or origin.secure) then
features:tag("bidi", { xmlns = xmlns_bidi_feature }):up();
+ offers_sent:with_labels():add(1);
end
end);
@@ -28,6 +33,7 @@ module:hook_tag("http://etherx.jabber.org/streams", "features", function (sessio
local request_bidi = st.stanza("bidi", { xmlns = xmlns_bidi });
module:fire_event("s2sout-stream-features", { origin = session, features = request_bidi });
session.sends2s(request_bidi);
+ offers_taken:with_labels():add(1);
end
end
end, 200);
@@ -36,6 +42,7 @@ module:hook_tag("urn:xmpp:bidi", "bidi", function(session)
if session.type == "s2sin_unauthed" and (not require_encryption or session.secure) then
session.log("debug", "Requested bidirectional stream");
session.outgoing = true;
+ offers_recv:with_labels():add(1);
return true;
end
end);
diff --git a/spec/util_xtemplate_spec.lua b/spec/util_xtemplate_spec.lua
index 4561378e..421be43f 100644
--- a/spec/util_xtemplate_spec.lua
+++ b/spec/util_xtemplate_spec.lua
@@ -38,6 +38,10 @@ describe("util.xtemplate", function ()
x:reset();
assert.same("12345", xtemplate.render("{foo/bar|each(i){{#}}}", x));
end)
+ it("handles missing inputs", function ()
+ local x = st.stanza("root");
+ assert.same("", xtemplate.render("{foo/bar|each(i){{#}}}", x));
+ end)
end)
end)
end)
diff --git a/teal-src/prosody/util/xtemplate.tl b/teal-src/prosody/util/xtemplate.tl
index 9b6b678b..84003051 100644
--- a/teal-src/prosody/util/xtemplate.tl
+++ b/teal-src/prosody/util/xtemplate.tl
@@ -54,7 +54,10 @@ local function render(template : string, root : st.stanza_t, escape : escape_t,
if tmpl then tmpl = s_sub(tmpl, 2, -2); end
if args then args = s_sub(args, 2, -2); end
- if func == "each" and tmpl and st.is_stanza(value) then
+ if func == "each" and tmpl then
+ if not st.is_stanza(value) then
+ return pre_blank..post_blank;
+ end
if not args then value, args = root, path; end
local ns, name = s_match(args, "^(%b{})(.*)$");
if ns then ns = s_sub(ns, 2, -2); else name, ns = args, nil; end
diff --git a/util/sslconfig.lua b/util/sslconfig.lua
index 7b0ed34a..01a8adb5 100644
--- a/util/sslconfig.lua
+++ b/util/sslconfig.lua
@@ -84,8 +84,18 @@ end
finalisers.certificate = finalisers.key;
finalisers.cafile = finalisers.key;
finalisers.capath = finalisers.key;
--- XXX: copied from core/certmanager.lua, but this seems odd, because it would remove a dhparam function from the config
-finalisers.dhparam = finalisers.key;
+
+function finalisers.dhparam(value, config)
+ if type(value) == "string" then
+ if value:sub(1, 10) == "-----BEGIN" then
+ -- literal value
+ return value;
+ else
+ -- assume a filename
+ return resolve_path(config._basedir, value);
+ end
+ end
+end
-- protocol = "x" should enable only that protocol
-- protocol = "x+" should enable x and later versions
diff --git a/util/xtemplate.lua b/util/xtemplate.lua
index 56413012..e23b1a01 100644
--- a/util/xtemplate.lua
+++ b/util/xtemplate.lua
@@ -39,7 +39,8 @@ local function render(template, root, escape, filters)
if tmpl then tmpl = s_sub(tmpl, 2, -2); end
if args then args = s_sub(args, 2, -2); end
- if func == "each" and tmpl and st.is_stanza(value) then
+ if func == "each" and tmpl then
+ if not st.is_stanza(value) then return pre_blank .. post_blank end
if not args then value, args = root, path; end
local ns, name = s_match(args, "^(%b{})(.*)$");
if ns then