From 4cc90797462549df16c802f42db8d9ee96e9412e Mon Sep 17 00:00:00 2001 From: Waqas Hussain Date: Sun, 17 Sep 2017 13:29:14 -0400 Subject: util.throttle: Fix initial time setting (double accounting the first time) and fractional balance updates (0.1*10 was not the same as 1*1) --- util/throttle.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/util/throttle.lua b/util/throttle.lua index 18692a8a..a8191886 100644 --- a/util/throttle.lua +++ b/util/throttle.lua @@ -12,7 +12,7 @@ function throttle:update() local newt = gettime(); local elapsed = newt - self.t; self.t = newt; - local balance = floor(self.rate * elapsed) + self.balance; + local balance = (self.rate * elapsed) + self.balance; if balance > self.max then self.balance = self.max; else @@ -40,7 +40,7 @@ function throttle:poll(cost, split) end local function create(max, period) - return setmetatable({ rate = max / period, max = max, t = 0, balance = max }, throttle_mt); + return setmetatable({ rate = max / period, max = max, t = gettime(), balance = max }, throttle_mt); end return { -- cgit v1.2.3 From 03b4a9a938d1ec27f5a0119e2c799cfbba360ff3 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Sat, 23 Sep 2017 13:20:46 +0100 Subject: util.dataforms: Don't include list options in result forms (fixes #983) --- util/dataforms.lua | 40 ++++++++++++++++++++++------------------ 1 file changed, 22 insertions(+), 18 deletions(-) diff --git a/util/dataforms.lua b/util/dataforms.lua index 756f35a7..469ce976 100644 --- a/util/dataforms.lua +++ b/util/dataforms.lua @@ -68,33 +68,37 @@ function form_t.form(layout, data, formtype) form:tag("value"):text(line):up(); end elseif field_type == "list-single" then - local has_default = false; - for _, val in ipairs(field.options or value) do - if type(val) == "table" then - form:tag("option", { label = val.label }):tag("value"):text(val.value):up():up(); - if value == val.value or val.default and (not has_default) then - form:tag("value"):text(val.value):up(); - has_default = true; + if formtype ~= "result" then + local has_default = false; + for _, val in ipairs(field.options or value) do + if type(val) == "table" then + form:tag("option", { label = val.label }):tag("value"):text(val.value):up():up(); + if value == val.value or val.default and (not has_default) then + form:tag("value"):text(val.value):up(); + has_default = true; + end + else + form:tag("option", { label= val }):tag("value"):text(tostring(val)):up():up(); end - else - form:tag("option", { label= val }):tag("value"):text(tostring(val)):up():up(); end end - if field.options and value then + if (field.options or formtype == "result") and value then form:tag("value"):text(value):up(); end elseif field_type == "list-multi" then - for _, val in ipairs(field.options or value) do - if type(val) == "table" then - form:tag("option", { label = val.label }):tag("value"):text(val.value):up():up(); - if not field.options and val.default then - form:tag("value"):text(val.value):up(); + if formtype ~= "result" then + for _, val in ipairs(field.options or value) do + if type(val) == "table" then + form:tag("option", { label = val.label }):tag("value"):text(val.value):up():up(); + if not field.options and val.default then + form:tag("value"):text(val.value):up(); + end + else + form:tag("option", { label= val }):tag("value"):text(tostring(val)):up():up(); end - else - form:tag("option", { label= val }):tag("value"):text(tostring(val)):up():up(); end end - if field.options and value then + if (field.options or formtype == "result") and value then for _, val in ipairs(value) do form:tag("value"):text(val):up(); end -- cgit v1.2.3 From 9f73fcbf8a933ad82ee5ad89e047f42713903ea2 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Sat, 23 Sep 2017 13:29:54 +0100 Subject: mod_limits: Import from prosody-modules 2c59f2f0c37d (fixes #129) --- plugins/mod_limits.lua | 96 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 96 insertions(+) create mode 100644 plugins/mod_limits.lua diff --git a/plugins/mod_limits.lua b/plugins/mod_limits.lua new file mode 100644 index 00000000..2a6ee8a2 --- /dev/null +++ b/plugins/mod_limits.lua @@ -0,0 +1,96 @@ +-- Because we deal we pre-authed sessions and streams we can't be host-specific +module:set_global(); + +local filters = require "util.filters"; +local throttle = require "util.throttle"; +local timer = require "util.timer"; + +local limits_cfg = module:get_option("limits", {}); +local limits_resolution = module:get_option_number("limits_resolution", 1); + +local default_bytes_per_second = 3000; +local default_burst = 2; + +local rate_units = { b = 1, k = 3, m = 6, g = 9, t = 12 } -- Plan for the future. +local function parse_rate(rate, sess_type) + local quantity, unit, exp; + if rate then + quantity, unit = rate:match("^(%d+) ?([^/]+)/s$"); + exp = quantity and rate_units[unit:sub(1,1):lower()]; + end + if not exp then + module:log("error", "Error parsing rate for %s: %q, using default rate (%d bytes/s)", sess_type, rate, default_bytes_per_second); + return default_bytes_per_second; + end + return quantity*(10^exp); +end + +local function parse_burst(burst, sess_type) + if type(burst) == "string" then + burst = burst:match("^(%d+) ?s$"); + end + local n_burst = tonumber(burst); + if not n_burst then + module:log("error", "Unable to parse burst for %s: %q, using default burst interval (%ds)", sess_type, tostring(burst), default_burst); + end + return n_burst or default_burst; +end + +-- Process config option into limits table: +-- limits = { c2s = { bytes_per_second = X, burst_seconds = Y } } +local limits = {}; + +for sess_type, sess_limits in pairs(limits_cfg) do + limits[sess_type] = { + bytes_per_second = parse_rate(sess_limits.rate, sess_type); + burst_seconds = parse_burst(sess_limits.burst, sess_type); + }; +end + +local default_filter_set = {}; + +function default_filter_set.bytes_in(bytes, session) + local throttle = session.throttle; + if throttle then + local ok, balance, outstanding = throttle:poll(#bytes, true); + if not ok then + session.log("debug", "Session over rate limit (%d) with %d (by %d), pausing", throttle.max, #bytes, outstanding); + session.conn:pause(); -- Read no more data from the connection until there is no outstanding data + local outstanding_data = bytes:sub(-outstanding); + bytes = bytes:sub(1, #bytes-outstanding); + timer.add_task(limits_resolution, function () + if not session.conn then return; end + if throttle:peek(#outstanding_data) then + session.log("debug", "Resuming paused session"); + session.conn:resume(); + end + -- Handle what we can of the outstanding data + session.data(outstanding_data); + end); + end + end + return bytes; +end + +local type_filters = { + c2s = default_filter_set; + s2sin = default_filter_set; + s2sout = default_filter_set; +}; + +local function filter_hook(session) + local session_type = session.type:match("^[^_]+"); + local filter_set, opts = type_filters[session_type], limits[session_type]; + if opts then + session.throttle = throttle.create(opts.bytes_per_second * opts.burst_seconds, opts.burst_seconds); + filters.add_filter(session, "bytes/in", filter_set.bytes_in, 1000); + end +end + +function module.load() + filters.add_filter_hook(filter_hook); +end + +function module.unload() + filters.remove_filter_hook(filter_hook); +end -- cgit v1.2.3 From 4e943d2770349776744a473c1c32c7bd297fabb9 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Sat, 23 Sep 2017 13:35:33 +0100 Subject: mod_server_contact_info: Import from prosody-modules 2c59f2f0c37d (fixes #778) --- plugins/mod_server_contact_info.lua | 49 +++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 plugins/mod_server_contact_info.lua diff --git a/plugins/mod_server_contact_info.lua b/plugins/mod_server_contact_info.lua new file mode 100644 index 00000000..7ee8a08f --- /dev/null +++ b/plugins/mod_server_contact_info.lua @@ -0,0 +1,49 @@ +-- XEP-0157: Contact Addresses for XMPP Services for Prosody +-- +-- Copyright (C) 2011-2016 Kim Alvefur +-- +-- This file is MIT/X11 licensed. +-- + +local t_insert = table.insert; +local array = require "util.array"; +local df_new = require "util.dataforms".new; + +-- Source: http://xmpp.org/registrar/formtypes.html#http:--jabber.org-network-serverinfo +local valid_types = { + abuse = true; + admin = true; + feedback = true; + sales = true; + security = true; + support = true; +} + +local contact_config = module:get_option("contact_info"); +if not contact_config or not next(contact_config) then -- we'll use admins from the config as default + local admins = module:get_option_inherited_set("admins", {}); + if admins:empty() then + module:log("error", "No contact_info or admins set in config"); + return -- Nothing to attach, so we'll just skip it. + end + module:log("info", "No contact_info in config, using admins as fallback"); + contact_config = { + admin = array.collect( admins / function(admin) return "xmpp:" .. admin; end); + }; +end + +local form_layout = { + { value = "http://jabber.org/network/serverinfo"; type = "hidden"; name = "FORM_TYPE"; }; +}; + +local form_values = {}; + +for t in pairs(valid_types) do + local addresses = contact_config[t]; + if addresses then + t_insert(form_layout, { name = t .. "-addresses", type = "list-multi" }); + form_values[t .. "-addresses"] = addresses; + end +end + +module:add_extension(df_new(form_layout):form(form_values, "result")); -- cgit v1.2.3 From 6c2df72e9711ce352b2822f85c8181f37087e2c6 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Sat, 23 Sep 2017 13:39:16 +0100 Subject: prosody.cfg.lua.dist: Update in preparation for 0.10.0 release --- prosody.cfg.lua.dist | 113 +++++++++++++++++++++++++++++++++------------------ 1 file changed, 73 insertions(+), 40 deletions(-) diff --git a/prosody.cfg.lua.dist b/prosody.cfg.lua.dist index d2af75a0..7f1c3e62 100644 --- a/prosody.cfg.lua.dist +++ b/prosody.cfg.lua.dist @@ -1,10 +1,11 @@ -- Prosody Example Configuration File -- -- Information on configuring Prosody can be found on our --- website at http://prosody.im/doc/configure +-- website at https://prosody.im/doc/configure -- -- Tip: You can check that the syntax of this file is correct --- when you have finished by running: prosodyctl check config +-- when you have finished by running this command: +-- prosodyctl check config -- If there are any errors, it will let you know what and where -- they are, otherwise it will keep quiet. -- @@ -18,17 +19,22 @@ -- This is a (by default, empty) list of accounts that are admins -- for the server. Note that you must create the accounts separately --- (see http://prosody.im/doc/creating_accounts for info) +-- (see https://prosody.im/doc/creating_accounts for info) -- Example: admins = { "user1@example.com", "user2@example.net" } admins = { } -- Enable use of libevent for better performance under high load --- For more information see: http://prosody.im/doc/libevent +-- For more information see: https://prosody.im/doc/libevent --use_libevent = true +-- Prosody will always look in its source directory for modules, but +-- this option allows you to specify additional locations where Prosody +-- will look for modules first. For community modules, see https://modules.prosody.im/ +--plugin_paths = {} + -- This is the list of modules Prosody will load on startup. -- It looks for mod_modulename.lua in the plugins folder, so make sure that exists too. --- Documentation on modules can be found at: http://prosody.im/doc/modules +-- Documentation for bundled modules can be found at: https://prosody.im/doc/modules modules_enabled = { -- Generally required @@ -39,36 +45,41 @@ modules_enabled = { "disco"; -- Service discovery -- Not essential, but recommended + "carbons"; -- Keep multiple clients in sync + "pep"; -- Enables users to publish their mood, activity, playing music and more "private"; -- Private XML storage (for room bookmarks, etc.) + "blocklist"; -- Allow users to block communications with other users "vcard"; -- Allow users to set vCards - - -- These are commented by default as they have a performance impact - --"blocklist"; -- Allow users to block communications with other users - --"compression"; -- Stream compression -- Nice to have "version"; -- Replies to server version requests "uptime"; -- Report how long server has been running "time"; -- Let others know the time here on this server "ping"; -- Replies to XMPP pings with pongs - "pep"; -- Enables users to publish their mood, activity, playing music and more "register"; -- Allow users to register on this server using a client and change passwords + --"mam"; -- Store messages in an archive and allow users to access it + + -- Not merged yet, nice to have or recommended? -- Admin interfaces "admin_adhoc"; -- Allows administration via an XMPP client that supports ad-hoc commands --"admin_telnet"; -- Opens telnet console interface on localhost port 5582 - + -- HTTP modules --"bosh"; -- Enable BOSH clients, aka "Jabber over HTTP" + --"websockets"; -- XMPP over WebSockets --"http_files"; -- Serve static files from a directory over HTTP -- Other specific functionality + --"limits"; -- Enable bandwidth limiting for XMPP connections --"groups"; -- Shared roster support + --"server_contact_info"; -- Publish contact information for this service --"announce"; -- Send announcement to all online users --"welcome"; -- Welcome users who register accounts --"watchregistrations"; -- Alert admins of registrations --"motd"; -- Send a message to users when they log in --"legacyauth"; -- Legacy authentication. Only used by some old clients and bots. + --"proxy65"; -- Enables a file transfer proxy service which clients behind NAT can use } -- These modules are auto-loaded, but should you want @@ -81,34 +92,47 @@ modules_disabled = { } -- Disable account creation by default, for security --- For more information see http://prosody.im/doc/creating_accounts +-- For more information see https://prosody.im/doc/creating_accounts allow_registration = false --- These are the SSL/TLS-related settings. If you don't want --- to use SSL/TLS, you may comment or remove this -ssl = { - key = "certs/localhost.key"; - certificate = "certs/localhost.crt"; -} +-- If no certificate has been explicitly configured, Prosody will attempt to +-- locate one based on the service name. +-- This option determines which directory to search. +-- certificates = "certs"; + +-- OR -- + +-- Specify the location of certificates +-- Prosody will attempt to locate a certificate and key for hosts and +-- services offered. +-- For more information see https://prosody.im/doc/certificates#magic -- Force clients to use encrypted connections? This option will -- prevent clients from authenticating unless they are using encryption. c2s_require_encryption = true +-- Force servers to use encrypted connections? This option will +-- prevent servers from authenticating unless they are using encryption. +-- Note that this is different from authentication + +s2s_require_encryption = true + + -- Force certificate authentication for server-to-server connections? -- This provides ideal security, but requires servers you communicate -- with to support encryption AND present valid, trusted certificates. -- NOTE: Your version of LuaSec must support certificate verification! --- For more information see http://prosody.im/doc/s2s#security +-- For more information see https://prosody.im/doc/s2s#security s2s_secure_auth = false --- Many servers don't support encryption or have invalid or self-signed --- certificates. You can list domains here that will not be required to --- authenticate using certificates. They will be authenticated using DNS. +-- Some servers have invalid or self-signed certificates. You can list +-- remote domains here that will not be required to authenticate using +-- certificates. They will be authenticated using DNS instead, even +-- when s2s_secure_auth is enabled. ---s2s_insecure_domains = { "gmail.com" } +--s2s_insecure_domains = { "insecure.example" } -- Even if you leave s2s_secure_auth disabled, you can still require valid -- certificates for some domains by specifying a list here. @@ -119,15 +143,15 @@ s2s_secure_auth = false -- use Prosody's configured data storage to store the authentication data. -- To allow Prosody to offer secure authentication mechanisms to clients, the -- default provider stores passwords in plaintext. If you do not trust your --- server please see http://prosody.im/doc/modules/mod_auth_internal_hashed +-- server please see https://prosody.im/doc/modules/mod_auth_internal_hashed -- for information about using the hashed backend. -authentication = "internal_plain" +authentication = "internal_hashed" -- Select the storage backend to use. By default Prosody uses flat files -- in its configured data directory, but it also supports more backends -- through modules. An "sql" backend is included by default, but requires --- additional dependencies. See http://prosody.im/doc/storage for more info. +-- additional dependencies. See https://prosody.im/doc/storage for more info. --storage = "sql" -- Default is "internal" @@ -136,8 +160,20 @@ authentication = "internal_plain" --sql = { driver = "MySQL", database = "prosody", username = "prosody", password = "secret", host = "localhost" } --sql = { driver = "PostgreSQL", database = "prosody", username = "prosody", password = "secret", host = "localhost" } + +-- Archiving configuration +-- If mod_mam is enabled, Prosody will store a copy of every message. This +-- is used to synchronize conversations between multiple clients, even if +-- they are offline. This setting controls how long Prosody will keep +-- messages in the archive before removing them. + +archive_expires_after = "1w" -- Remove archived messages after 1 week + +-- You can also configure messages to be stored in-memory only. For more +-- archiving options, see https://prosody.im/doc/modules/mod_mam + -- Logging configuration --- For advanced logging see http://prosody.im/doc/logging +-- For advanced logging see https://prosody.im/doc/logging log = { info = "prosody.log"; -- Change 'info' to 'debug' for verbose logging error = "prosody.err"; @@ -145,6 +181,10 @@ log = { -- "*console"; -- Log to the console, useful for debugging with daemonize=false } +-- Uncomment to enable statistics +-- For more info see https://prosody.im/doc/statistics +-- statistics = "internal" + ----------- Virtual hosts ----------- -- You need to add a VirtualHost entry for each domain you wish Prosody to serve. -- Settings under each VirtualHost entry apply *only* to that host. @@ -154,31 +194,24 @@ VirtualHost "localhost" VirtualHost "example.com" enabled = false -- Remove this line to enable this host - -- Assign this host a certificate for TLS, otherwise it would use the one - -- set in the global section (if any). - -- Note that old-style SSL on port 5223 only supports one certificate, and will always - -- use the global one. - ssl = { - key = "certs/example.com.key"; - certificate = "certs/example.com.crt"; - } + -- Assign this host a certificate for TLS, otherwise it would attempt locate one, + -- based on the hostname. + -- certificate = "certs/example.com.crt"; + -- `prosodyctl check certs` ------ Components ------ -- You can specify components to add hosts that provide special services, -- like multi-user conferences, and transports. --- For more information on components, see http://prosody.im/doc/components +-- For more information on components, see https://prosody.im/doc/components ---Set up a MUC (multi-user chat) room server on conference.example.com: --Component "conference.example.com" "muc" --- Set up a SOCKS5 bytestream proxy for server-proxied file transfers: ---Component "proxy.example.com" "proxy65" - ---Set up an external component (default component port is 5347) -- -- External components allow adding various services, such as gateways/ -- transports to other networks like ICQ, MSN and Yahoo. For more info --- see: http://prosody.im/doc/components#adding_an_external_component +-- see: https://prosody.im/doc/components#adding_an_external_component -- --Component "gateway.example.com" -- component_secret = "password" -- cgit v1.2.3 From 2ae9801ba6347e385445de70ea350e535abb2630 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Sat, 23 Sep 2017 17:13:29 +0100 Subject: certmanager: Add debug logging (thanks av6) --- core/certmanager.lua | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/core/certmanager.lua b/core/certmanager.lua index 2e237595..288836ce 100644 --- a/core/certmanager.lua +++ b/core/certmanager.lua @@ -58,6 +58,7 @@ local key_try = { "", "/%s.key", "/%s/privkey.pem", "/%s.pem", }; local function find_cert(user_certs, name) local certs = resolve_path(config_path, user_certs or global_certificates); + log("debug", "Searching %s for a key and certificate for %s...", certs, name); for i = 1, #crt_try do local crt_path = certs .. crt_try[i]:format(name); local key_path = certs .. key_try[i]:format(name); @@ -66,13 +67,16 @@ local function find_cert(user_certs, name) if key_path:sub(-4) == ".crt" then key_path = key_path:sub(1, -4) .. "key"; if stat(key_path, "mode") == "file" then + log("debug", "Selecting certificate %s with key %s for %s", crt_path, key_path, name); return { certificate = crt_path, key = key_path }; end elseif stat(key_path, "mode") == "file" then + log("debug", "Selecting certificate %s with key %s for %s", crt_path, key_path, name); return { certificate = crt_path, key = key_path }; end end end + log("debug", "No certificate/key found for %s", name); end local function find_host_cert(host) -- cgit v1.2.3 From 1c3b4b2da906dab63c06242c8a9848ed747f7cd8 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Sat, 23 Sep 2017 17:39:36 +0100 Subject: prosody.cfg.lua.dist: Further tweaks in preparation for 0.10.0 --- prosody.cfg.lua.dist | 33 ++++++++++++--------------------- 1 file changed, 12 insertions(+), 21 deletions(-) diff --git a/prosody.cfg.lua.dist b/prosody.cfg.lua.dist index 7f1c3e62..716b7b2a 100644 --- a/prosody.cfg.lua.dist +++ b/prosody.cfg.lua.dist @@ -59,8 +59,6 @@ modules_enabled = { "register"; -- Allow users to register on this server using a client and change passwords --"mam"; -- Store messages in an archive and allow users to access it - -- Not merged yet, nice to have or recommended? - -- Admin interfaces "admin_adhoc"; -- Allows administration via an XMPP client that supports ad-hoc commands --"admin_telnet"; -- Opens telnet console interface on localhost port 5582 @@ -95,18 +93,6 @@ modules_disabled = { -- For more information see https://prosody.im/doc/creating_accounts allow_registration = false --- If no certificate has been explicitly configured, Prosody will attempt to --- locate one based on the service name. --- This option determines which directory to search. --- certificates = "certs"; - --- OR -- - --- Specify the location of certificates --- Prosody will attempt to locate a certificate and key for hosts and --- services offered. --- For more information see https://prosody.im/doc/certificates#magic - -- Force clients to use encrypted connections? This option will -- prevent clients from authenticating unless they are using encryption. @@ -185,19 +171,24 @@ log = { -- For more info see https://prosody.im/doc/statistics -- statistics = "internal" +-- Certificates +-- Every virtual host and component needs a certificate so that clients and +-- servers can securely verify its identity. Prosody will automatically load +-- certificates/keys from the directory specified here (paths are relative to +-- the main configuration file). +-- For more information, including how to use 'prosodyctl' to auto-import certificates +-- (from e.g. Let's Encrypt) see https://prosody.im/doc/certificates + +certificates = "certs" + ----------- Virtual hosts ----------- -- You need to add a VirtualHost entry for each domain you wish Prosody to serve. -- Settings under each VirtualHost entry apply *only* to that host. VirtualHost "localhost" -VirtualHost "example.com" - enabled = false -- Remove this line to enable this host - - -- Assign this host a certificate for TLS, otherwise it would attempt locate one, - -- based on the hostname. - -- certificate = "certs/example.com.crt"; - -- `prosodyctl check certs` +--VirtualHost "example.com" +-- certificate = "/path/to/example.crt" ------ Components ------ -- You can specify components to add hosts that provide special services, -- cgit v1.2.3 From 18fff9b8458fda22f5c24f1ec7a6da4f8463a9a7 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Sat, 23 Sep 2017 17:49:48 +0100 Subject: prosody.cfg.lua.dist: Improve certificates comment --- prosody.cfg.lua.dist | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/prosody.cfg.lua.dist b/prosody.cfg.lua.dist index 716b7b2a..bd897f74 100644 --- a/prosody.cfg.lua.dist +++ b/prosody.cfg.lua.dist @@ -174,11 +174,11 @@ log = { -- Certificates -- Every virtual host and component needs a certificate so that clients and -- servers can securely verify its identity. Prosody will automatically load --- certificates/keys from the directory specified here (paths are relative to --- the main configuration file). +-- certificates/keys from the directory specified here. -- For more information, including how to use 'prosodyctl' to auto-import certificates -- (from e.g. Let's Encrypt) see https://prosody.im/doc/certificates +-- Location of directory to find certificates in (relative to main config file): certificates = "certs" ----------- Virtual hosts ----------- -- cgit v1.2.3 From 9bb6847d26e2a0d312feb16a9f632836deccff2e Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Sat, 23 Sep 2017 23:32:08 +0100 Subject: tests: util.throttle: Fix time override to simply override util.time. Recent change bypasses current override method. --- tests/test_util_throttle.lua | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/tests/test_util_throttle.lua b/tests/test_util_throttle.lua index 582f499d..6d47238a 100644 --- a/tests/test_util_throttle.lua +++ b/tests/test_util_throttle.lua @@ -7,20 +7,12 @@ local function later(n) now = now + n; -- time passes at a different rate end -local function override_gettime(throttle) - local i = 0; - repeat - i = i + 1; - local name = debug.getupvalue(throttle.update, i); - if name then - debug.setupvalue(throttle.update, i, predictable_gettime); - return throttle; - end - until not name; -end +package.loaded["util.time"] = { + now = predictable_gettime; +} function create(create) - local a = override_gettime( create(3, 10) ); + local a = create(3, 10); assert_equal(a:poll(1), true); -- 3 -> 2 assert_equal(a:poll(1), true); -- 2 -> 1 -- cgit v1.2.3 From 11402a46bb145ad626c775f02d15d6a68b48ec1d Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Sun, 24 Sep 2017 01:04:56 +0200 Subject: net.dns: Correctly apply lower bound of RTT (thanks Ge0rG) --- net/dns.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/dns.lua b/net/dns.lua index 188bdf43..5ba3db0e 100644 --- a/net/dns.lua +++ b/net/dns.lua @@ -504,7 +504,7 @@ function resolver:rr() -- - - - - - - - - - - - - - - - - - - - - - - - rr rr.ttl = 0x10000*self:word() + self:word(); rr.rdlength = self:word(); - rr.tod = self.time + math.min(rr.ttl, 1); + rr.tod = self.time + math.max(rr.ttl, 1); local remember = self.offset; local rr_parser = self[dns.type[rr.type]]; -- cgit v1.2.3 From abc508f21cdc0de4814d6c88b846582e764f37fa Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Sun, 24 Sep 2017 05:46:24 +0200 Subject: prosody: Tiny whitespace fix --- prosody | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/prosody b/prosody index a9ef6117..da204214 100755 --- a/prosody +++ b/prosody @@ -20,8 +20,8 @@ CFG_DATADIR=CFG_DATADIR or os.getenv("PROSODY_DATADIR"); local function is_relative(path) local path_sep = package.config:sub(1,1); - return ((path_sep == "/" and path:sub(1,1) ~= "/") - or (path_sep == "\\" and (path:sub(1,1) ~= "/" and path:sub(2,3) ~= ":\\"))) + return ((path_sep == "/" and path:sub(1,1) ~= "/") + or (path_sep == "\\" and (path:sub(1,1) ~= "/" and path:sub(2,3) ~= ":\\"))) end -- Tell Lua where to find our libraries -- cgit v1.2.3 From 30dcc732985f627643da951e0b518d61ec442559 Mon Sep 17 00:00:00 2001 From: Waqas Hussain Date: Sun, 24 Sep 2017 18:23:45 -0400 Subject: prosodyctl check: Fix traceback when no modules_enabled are defined (e.g., a completely empty config) --- prosodyctl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/prosodyctl b/prosodyctl index cdcd25d9..311f251e 100755 --- a/prosodyctl +++ b/prosodyctl @@ -1032,7 +1032,7 @@ function commands.check(arg) suggested_global_modules = set.intersection(suggested_global_modules or set.new(options.modules_enabled), set.new(options.modules_enabled)); end end - if not suggested_global_modules:empty() then + if suggested_global_modules and not suggested_global_modules:empty() then print(" Consider moving these modules into modules_enabled in the global section:") print(" "..tostring(suggested_global_modules / function (x) return ("%q"):format(x) end)); end -- cgit v1.2.3 From a2e27dd4fb9e2f8a6c1d46958b878f78d872eba8 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Mon, 25 Sep 2017 23:06:00 +0100 Subject: net.adns: Restructure to allow creating separate resolver objects, like net.dns --- net/adns.lua | 79 +++++++++++++++++++++++++++++++++++------------------------- 1 file changed, 46 insertions(+), 33 deletions(-) diff --git a/net/adns.lua b/net/adns.lua index 0b7247ed..f1196a6c 100644 --- a/net/adns.lua +++ b/net/adns.lua @@ -7,7 +7,7 @@ -- local server = require "net.server"; -local dns = require "net.dns"; +local new_resolver = require "net.dns".resolver; local log = require "util.logger".init("adns"); @@ -17,35 +17,11 @@ local function dummy_send(sock, data, i, j) return (j-i)+1; end local _ENV = nil; -local function lookup(handler, qname, qtype, qclass) - return coroutine.wrap(function (peek) - if peek then - log("debug", "Records for %s already cached, using those...", qname); - handler(peek); - return; - end - log("debug", "Records for %s not in cache, sending query (%s)...", qname, tostring(coroutine.running())); - local ok, err = dns.query(qname, qtype, qclass); - if ok then - coroutine.yield({ qclass or "IN", qtype or "A", qname, coroutine.running()}); -- Wait for reply - log("debug", "Reply for %s (%s)", qname, tostring(coroutine.running())); - end - if ok then - ok, err = pcall(handler, dns.peek(qname, qtype, qclass)); - else - log("error", "Error sending DNS query: %s", err); - ok, err = pcall(handler, nil, err); - end - if not ok then - log("error", "Error in DNS response handler: %s", tostring(err)); - end - end)(dns.peek(qname, qtype, qclass)); -end +local async_resolver_methods = {}; +local async_resolver_mt = { __index = async_resolver_methods }; -local function cancel(handle, call_handler, reason) - log("warn", "Cancelling DNS lookup for %s", tostring(handle[3])); - dns.cancel(handle[1], handle[2], handle[3], handle[4], call_handler); -end +local query_methods = {}; +local query_mt = { __index = query_methods }; local function new_async_socket(sock, resolver) local peername = ""; @@ -54,7 +30,7 @@ local function new_async_socket(sock, resolver) local err; function listener.onincoming(conn, data) if data then - dns.feed(handler, data); + resolver:feed(handler, data); end end function listener.ondisconnect(conn, err) @@ -85,10 +61,47 @@ local function new_async_socket(sock, resolver) return handler; end -dns.socket_wrapper_set(new_async_socket); +function async_resolver_methods:lookup(handler, qname, qtype, qclass) + local resolver = self._resolver; + return coroutine.wrap(function (peek) + if peek then + log("debug", "Records for %s already cached, using those...", qname); + handler(peek); + return; + end + log("debug", "Records for %s not in cache, sending query (%s)...", qname, tostring(coroutine.running())); + local ok, err = resolver:query(qname, qtype, qclass); + if ok then + coroutine.yield(setmetatable({ resolver, qclass or "IN", qtype or "A", qname, coroutine.running()}, query_mt)); -- Wait for reply + log("debug", "Reply for %s (%s)", qname, tostring(coroutine.running())); + end + if ok then + ok, err = pcall(handler, resolver:peek(qname, qtype, qclass)); + else + log("error", "Error sending DNS query: %s", err); + ok, err = pcall(handler, nil, err); + end + if not ok then + log("error", "Error in DNS response handler: %s", tostring(err)); + end + end)(resolver:peek(qname, qtype, qclass)); +end + +function query_methods:cancel(call_handler, reason) + log("warn", "Cancelling DNS lookup for %s", tostring(self[4])); + self[1].cancel(self[2], self[3], self[4], self[5], call_handler); +end + +local function new_async_resolver() + local resolver = new_resolver(); + resolver:socket_wrapper_set(new_async_socket); + return setmetatable({ _resolver = resolver}, async_resolver_mt); +end return { - lookup = lookup; - cancel = cancel; + lookup = function (...) + return new_async_resolver():lookup(...); + end; + resolver = new_async_resolver; new_async_socket = new_async_socket; }; -- cgit v1.2.3 From 86ee041be81ad313a24c87b6e38f92fe4400cf17 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Mon, 25 Sep 2017 23:12:47 +0100 Subject: mod_s2s: Use a separate resolver object for each outgoing session Cleaner approach hopefully fixes problems with some peoples' DNS hanging after a while, failed DNS when a large number of queries are made at once, and source port re-use. Related issues: #487, 761, #991, #992, #1001 --- plugins/mod_s2s/mod_s2s.lua | 2 ++ plugins/mod_s2s/s2sout.lib.lua | 10 +++++----- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/plugins/mod_s2s/mod_s2s.lua b/plugins/mod_s2s/mod_s2s.lua index c060b974..aa7fe8b6 100644 --- a/plugins/mod_s2s/mod_s2s.lua +++ b/plugins/mod_s2s/mod_s2s.lua @@ -174,6 +174,7 @@ end -- Stream is authorised, and ready for normal stanzas function mark_connected(session) + local sendq = session.sendq; local from, to = session.from_host, session.to_host; @@ -205,6 +206,7 @@ function mark_connected(session) session.sendq = nil; end + session.resolver = nil; session.ip_hosts = nil; session.srv_hosts = nil; end diff --git a/plugins/mod_s2s/s2sout.lib.lua b/plugins/mod_s2s/s2sout.lib.lua index 61d6086e..cd8553e1 100644 --- a/plugins/mod_s2s/s2sout.lib.lua +++ b/plugins/mod_s2s/s2sout.lib.lua @@ -49,6 +49,8 @@ function s2sout.initiate_connection(host_session) initialize_filters(host_session); host_session.version = 1; + host_session.resolver = adns.resolver(); + -- Kick the connection attempting machine into life if not s2sout.attempt_connection(host_session) then -- Intentionally not returning here, the @@ -84,9 +86,7 @@ function s2sout.attempt_connection(host_session, err) if not err then -- This is our first attempt log("debug", "First attempt to connect to %s, starting with SRV lookup...", to_host); host_session.connecting = true; - local handle; - handle = adns.lookup(function (answer) - handle = nil; + host_session.resolver:lookup(function (answer) local srv_hosts = { answer = answer }; host_session.srv_hosts = srv_hosts; host_session.srv_choice = 0; @@ -168,7 +168,7 @@ function s2sout.try_connect(host_session, connect_host, connect_port, err) local have_other_result = not(has_ipv4) or not(has_ipv6) or false; if has_ipv4 then - handle4 = adns.lookup(function (reply, err) + handle4 = host_session.resolver:lookup(function (reply, err) handle4 = nil; if reply and reply[#reply] and reply[#reply].a then @@ -206,7 +206,7 @@ function s2sout.try_connect(host_session, connect_host, connect_port, err) end if has_ipv6 then - handle6 = adns.lookup(function (reply, err) + handle6 = host_session.resolver:lookup(function (reply, err) handle6 = nil; if reply and reply[#reply] and reply[#reply].aaaa then -- cgit v1.2.3