diff options
-rw-r--r-- | CHANGES | 1 | ||||
-rw-r--r-- | GNUmakefile | 43 | ||||
-rw-r--r-- | core/certmanager.lua | 2 | ||||
-rw-r--r-- | core/portmanager.lua | 4 | ||||
-rw-r--r-- | makefile | 47 | ||||
-rw-r--r-- | plugins/mod_c2s.lua | 4 | ||||
-rw-r--r-- | plugins/mod_carbons.lua | 10 | ||||
-rw-r--r-- | plugins/mod_mam/mod_mam.lua | 19 | ||||
-rw-r--r-- | plugins/mod_s2s.lua | 4 | ||||
-rw-r--r-- | teal-src/util/poll.d.tl | 9 | ||||
-rw-r--r-- | util-src/poll.c | 172 | ||||
-rw-r--r-- | util/async.lua | 4 | ||||
-rw-r--r-- | util/prosodyctl/check.lua | 84 |
13 files changed, 351 insertions, 52 deletions
@@ -58,6 +58,7 @@ TRUNK - MUC: support for XEP-0421 occupant identifiers - `prosodyctl check connectivity` via observe.jabber.network - libunbound for DNS queries +- The POSIX poll() API used by server_epoll on \*nix other than Linux ## Changes diff --git a/GNUmakefile b/GNUmakefile index 829a1c3e..e9ec78c4 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -31,23 +31,36 @@ ifeq ($(EXCERTS),yes) -$(MAKE) -C certs localhost.crt example.com.crt endif -CMODULES=util/encodings.so util/encodings.so util/pposix.so util/signal.so util/struct.so - -install: prosody.install prosodyctl.install prosody.cfg.lua.install $(CMODULES) - $(MKDIR) $(BIN) $(CONFIG) $(MODULES) $(SOURCE) - $(MKDIR_PRIVATE) $(DATA) - $(MKDIR) $(MAN)/man1 +install-etc: prosody.cfg.lua.install + $(MKDIR) $(CONFIG) $(MKDIR) $(CONFIG)/certs - $(MKDIR) $(SOURCE)/core $(SOURCE)/net $(SOURCE)/util + $(INSTALL_DATA) certs/* $(CONFIG)/certs + test -f $(CONFIG)/prosody.cfg.lua || $(INSTALL_DATA) prosody.cfg.lua.install $(CONFIG)/prosody.cfg.lua + +install-bin: prosody.install prosodyctl.install + $(MKDIR) $(BIN) $(INSTALL_EXEC) ./prosody.install $(BIN)/prosody $(INSTALL_EXEC) ./prosodyctl.install $(BIN)/prosodyctl + +install-core: + $(MKDIR) $(SOURCE) + $(MKDIR) $(SOURCE)/core $(INSTALL_DATA) core/*.lua $(SOURCE)/core + +install-net: + $(MKDIR) $(SOURCE) + $(MKDIR) $(SOURCE)/net $(INSTALL_DATA) net/*.lua $(SOURCE)/net $(MKDIR) $(SOURCE)/net/http $(SOURCE)/net/resolvers $(SOURCE)/net/websocket $(INSTALL_DATA) net/http/*.lua $(SOURCE)/net/http $(INSTALL_DATA) net/resolvers/*.lua $(SOURCE)/net/resolvers $(INSTALL_DATA) net/websocket/*.lua $(SOURCE)/net/websocket + +install-util: util/encodings.so util/encodings.so util/pposix.so util/signal.so util/struct.so + $(MKDIR) $(SOURCE) + $(MKDIR) $(SOURCE)/util $(INSTALL_DATA) util/*.lua $(SOURCE)/util + $(MAKE) install -C util-src $(INSTALL_DATA) util/*.so $(SOURCE)/util $(MKDIR) $(SOURCE)/util/sasl $(INSTALL_DATA) util/sasl/*.lua $(SOURCE)/util/sasl @@ -55,17 +68,27 @@ install: prosody.install prosodyctl.install prosody.cfg.lua.install $(CMODULES) $(INSTALL_DATA) util/human/*.lua $(SOURCE)/util/human $(MKDIR) $(SOURCE)/util/prosodyctl $(INSTALL_DATA) util/prosodyctl/*.lua $(SOURCE)/util/prosodyctl + +install-plugins: + $(MKDIR) $(MODULES) $(MKDIR) $(MODULES)/mod_pubsub $(MODULES)/adhoc $(MODULES)/muc $(MODULES)/mod_mam $(INSTALL_DATA) plugins/*.lua $(MODULES) $(INSTALL_DATA) plugins/mod_pubsub/*.lua $(MODULES)/mod_pubsub $(INSTALL_DATA) plugins/adhoc/*.lua $(MODULES)/adhoc $(INSTALL_DATA) plugins/muc/*.lua $(MODULES)/muc $(INSTALL_DATA) plugins/mod_mam/*.lua $(MODULES)/mod_mam - $(INSTALL_DATA) certs/* $(CONFIG)/certs + +install-man: + $(MKDIR) $(MAN)/man1 $(INSTALL_DATA) man/prosodyctl.man $(MAN)/man1/prosodyctl.1 - test -f $(CONFIG)/prosody.cfg.lua || $(INSTALL_DATA) prosody.cfg.lua.install $(CONFIG)/prosody.cfg.lua + +install-meta: -test -f prosody.version && $(INSTALL_DATA) prosody.version $(SOURCE)/prosody.version - $(MAKE) install -C util-src + +install-data: + $(MKDIR_PRIVATE) $(DATA) + +install: install-util install-net install-core install-plugins install-bin install-etc install-man install-meta install-data clean: rm -f prosody.install diff --git a/core/certmanager.lua b/core/certmanager.lua index 2585716f..c193e824 100644 --- a/core/certmanager.lua +++ b/core/certmanager.lua @@ -120,7 +120,7 @@ local function index_certs(dir, files_by_name, depth_limit) if f then -- TODO look for chained certificates local firstline = f:read(); - if firstline == "-----BEGIN CERTIFICATE-----" then + if firstline == "-----BEGIN CERTIFICATE-----" and lfs.attributes(find_matching_key(full), "mode") == "file" then f:seek("set") local cert = ssl.loadcertificate(f:read("*a")) -- TODO if more than one cert is found for a name, the most recently diff --git a/core/portmanager.lua b/core/portmanager.lua index 95d42b77..38c74b66 100644 --- a/core/portmanager.lua +++ b/core/portmanager.lua @@ -216,7 +216,9 @@ function close(interface, port) end function get_service_at(interface, port) - local data = active_services:search(nil, interface, port)[1][1]; + local data = active_services:search(nil, interface, port); + if not data or not data[1] or not data[1][1] then return nil, "not-found"; end + data = data[1][1]; return data.service, data.server; end @@ -30,21 +30,39 @@ all: prosody.install prosodyctl.install prosody.cfg.lua.install prosody.version $(MAKE) -C certs localhost.crt example.com.crt .endif -install: prosody.install prosodyctl.install prosody.cfg.lua.install util/encodings.so util/encodings.so util/pposix.so util/signal.so - $(MKDIR) $(BIN) $(CONFIG) $(MODULES) $(SOURCE) - $(MKDIR_PRIVATE) $(DATA) - $(MKDIR) $(MAN)/man1 +install-etc: prosody.cfg.lua.install + $(MKDIR) $(CONFIG) $(MKDIR) $(CONFIG)/certs - $(MKDIR) $(SOURCE)/core $(SOURCE)/net $(SOURCE)/util + test -f $(CONFIG)/prosody.cfg.lua || $(INSTALL_DATA) prosody.cfg.lua.install $(CONFIG)/prosody.cfg.lua +.if $(EXCERTS) == "yes" + $(INSTALL_DATA) certs/localhost.crt certs/localhost.key $(CONFIG)/certs + $(INSTALL_DATA) certs/example.com.crt certs/example.com.key $(CONFIG)/certs +.endif + +install-bin: prosody.install prosodyctl.install + $(MKDIR) $(BIN) $(INSTALL_EXEC) ./prosody.install $(BIN)/prosody $(INSTALL_EXEC) ./prosodyctl.install $(BIN)/prosodyctl + +install-core: + $(MKDIR) $(SOURCE) + $(MKDIR) $(SOURCE)/core $(INSTALL_DATA) core/*.lua $(SOURCE)/core + +install-net: + $(MKDIR) $(SOURCE) + $(MKDIR) $(SOURCE)/net $(INSTALL_DATA) net/*.lua $(SOURCE)/net $(MKDIR) $(SOURCE)/net/http $(SOURCE)/net/resolvers $(SOURCE)/net/websocket $(INSTALL_DATA) net/http/*.lua $(SOURCE)/net/http $(INSTALL_DATA) net/resolvers/*.lua $(SOURCE)/net/resolvers $(INSTALL_DATA) net/websocket/*.lua $(SOURCE)/net/websocket + +install-util: util/encodings.so util/encodings.so util/pposix.so util/signal.so + $(MKDIR) $(SOURCE) + $(MKDIR) $(SOURCE)/util $(INSTALL_DATA) util/*.lua $(SOURCE)/util + $(MAKE) install -C util-src $(INSTALL_DATA) util/*.so $(SOURCE)/util $(MKDIR) $(SOURCE)/util/sasl $(INSTALL_DATA) util/sasl/*.lua $(SOURCE)/util/sasl @@ -52,20 +70,27 @@ install: prosody.install prosodyctl.install prosody.cfg.lua.install util/encodin $(INSTALL_DATA) util/human/*.lua $(SOURCE)/util/human $(MKDIR) $(SOURCE)/util/prosodyctl $(INSTALL_DATA) util/prosodyctl/*.lua $(SOURCE)/util/prosodyctl + +install-plugins: + $(MKDIR) $(MODULES) $(MKDIR) $(MODULES)/mod_pubsub $(MODULES)/adhoc $(MODULES)/muc $(MODULES)/mod_mam $(INSTALL_DATA) plugins/*.lua $(MODULES) $(INSTALL_DATA) plugins/mod_pubsub/*.lua $(MODULES)/mod_pubsub $(INSTALL_DATA) plugins/adhoc/*.lua $(MODULES)/adhoc $(INSTALL_DATA) plugins/muc/*.lua $(MODULES)/muc $(INSTALL_DATA) plugins/mod_mam/*.lua $(MODULES)/mod_mam -.if $(EXCERTS) == "yes" - $(INSTALL_DATA) certs/localhost.crt certs/localhost.key $(CONFIG)/certs - $(INSTALL_DATA) certs/example.com.crt certs/example.com.key $(CONFIG)/certs -.endif + +install-man: + $(MKDIR) $(MAN)/man1 $(INSTALL_DATA) man/prosodyctl.man $(MAN)/man1/prosodyctl.1 - test -f $(CONFIG)/prosody.cfg.lua || $(INSTALL_DATA) prosody.cfg.lua.install $(CONFIG)/prosody.cfg.lua + +install-meta: -test -f prosody.version && $(INSTALL_DATA) prosody.version $(SOURCE)/prosody.version - $(MAKE) install -C util-src + +install-data: + $(MKDIR_PRIVATE) $(DATA) + +install: install-util install-net install-core install-plugins install-bin install-etc install-man install-meta install-data clean: rm -f prosody.install diff --git a/plugins/mod_c2s.lua b/plugins/mod_c2s.lua index 33fd7a0a..c8f54fa7 100644 --- a/plugins/mod_c2s.lua +++ b/plugins/mod_c2s.lua @@ -433,7 +433,7 @@ module:hook("server-stopping", function(event) -- luacheck: ignore 212/event end, -80); module:hook("server-stopping", function(event) - local wait, done = async.waiter(); + local wait, done = async.waiter(1, true); module:hook("c2s-closed", function () if next(sessions) == nil then done(); end end) @@ -446,7 +446,7 @@ module:hook("server-stopping", function(event) -- Wait for them to close properly if they haven't already if next(sessions) ~= nil then - add_task(stream_close_timeout+1, done); + add_task(stream_close_timeout+1, function () done() end); module:log("info", "Waiting for sessions to close"); wait(); end diff --git a/plugins/mod_carbons.lua b/plugins/mod_carbons.lua index 5b0bdeb7..7a5b757c 100644 --- a/plugins/mod_carbons.lua +++ b/plugins/mod_carbons.lua @@ -69,6 +69,12 @@ local function should_copy(stanza, c2s, user_bare) --> boolean, reason: string return false, "default"; end +module:hook("carbons-should-copy", function (event) + local should, why = should_copy(event.stanza); + event.reason = why; + return should; +end, -1) + local function message_handler(event, c2s) local origin, stanza = event.origin, event.stanza; local orig_type = stanza.attr.type or "normal"; @@ -101,7 +107,9 @@ local function message_handler(event, c2s) return -- No use in sending carbons to an offline user end - local should, why = should_copy(stanza, c2s, bare_jid); + local event_payload = { stanza = stanza; session = origin }; + local should = module:fire_event("carbons-should-copy", event_payload); + local why = event_payload.reason; if not should then module:log("debug", "Not copying stanza: %s (%s)", stanza:top_tag(), why); diff --git a/plugins/mod_mam/mod_mam.lua b/plugins/mod_mam/mod_mam.lua index d4b2b060..50095e2f 100644 --- a/plugins/mod_mam/mod_mam.lua +++ b/plugins/mod_mam/mod_mam.lua @@ -54,7 +54,7 @@ end local use_total = module:get_option_boolean("mam_include_total", true); function schedule_cleanup() - -- replaced by non-noop later if cleanup is enabled + -- replaced later if cleanup is enabled end -- Handle prefs. @@ -311,7 +311,7 @@ local function strip_stanza_id(stanza, user) return stanza; end -local function should_store(stanza, c2s) --> boolean, reason: string +local function should_store(stanza) --> boolean, reason: string local st_type = stanza.attr.type or "normal"; -- FIXME pass direction of stanza and use that along with bare/full JID addressing -- for more accurate MUC / type=groupchat check @@ -320,7 +320,7 @@ local function should_store(stanza, c2s) --> boolean, reason: string -- Headline messages are ephemeral by definition return false, "headline"; end - if st_type == "error" and not c2s then + if st_type == "error" then -- Errors not sent sent from a local client -- Why would a client send an error anyway? if jid_resource(stanza.attr.to) then @@ -380,6 +380,12 @@ local function should_store(stanza, c2s) --> boolean, reason: string return false, "default"; end +module:hook("archive-should-store", function (event) + local should, why = should_store(event.stanza); + event.reason = why; + return should; +end, -1) + -- Handle messages local function message_handler(event, c2s) local origin, stanza = event.origin, event.stanza; @@ -396,9 +402,12 @@ local function message_handler(event, c2s) -- Filter out <stanza-id> that claim to be from us event.stanza = strip_stanza_id(stanza, store_user); - local should, why = should_store(stanza, c2s); + local event_payload = { stanza = stanza; session = origin }; + local should = module:fire_event("archive-should-store", event_payload); + local why = event_payload.reason; + if not should then - log("debug", "Not archiving stanza: %s (%s)", stanza:top_tag(), why); + log("debug", "Not archiving stanza: %s (%s)", stanza:top_tag(), event_payload.reason); return; end diff --git a/plugins/mod_s2s.lua b/plugins/mod_s2s.lua index 655cb599..3ad0f521 100644 --- a/plugins/mod_s2s.lua +++ b/plugins/mod_s2s.lua @@ -973,7 +973,7 @@ module:hook("server-stopping", function(event) end end - local wait, done = async.waiter(); + local wait, done = async.waiter(1, true); module:hook("s2s-closed", function () if next(sessions) == nil then done(); end end, 1) @@ -987,7 +987,7 @@ module:hook("server-stopping", function(event) -- Wait for them to close properly if they haven't already if next(sessions) ~= nil then module:log("info", "Waiting for sessions to close"); - add_task(stream_close_timeout + 1, done); + add_task(stream_close_timeout + 1, function () done() end); wait(); end diff --git a/teal-src/util/poll.d.tl b/teal-src/util/poll.d.tl index 7e346161..8df56d57 100644 --- a/teal-src/util/poll.d.tl +++ b/teal-src/util/poll.d.tl @@ -17,8 +17,15 @@ end local record lib new : function () : state - ENOENT : integer EEXIST : integer + EMFILE : integer + ENOENT : integer + enum api_backend + "epoll" + "poll" + "select" + end + api : api_backend end return lib diff --git a/util-src/poll.c b/util-src/poll.c index 6c6a4e63..81caa953 100644 --- a/util-src/poll.c +++ b/util-src/poll.c @@ -1,7 +1,7 @@ /* * Lua polling library - * Copyright (C) 2017-2018 Kim Alvefur + * Copyright (C) 2017-2022 Kim Alvefur * * This project is MIT licensed. Please see the * COPYING file in the source package for more information. @@ -12,8 +12,15 @@ #include <string.h> #include <errno.h> -#ifdef __linux__ +#if defined(__linux__) #define USE_EPOLL +#define POLL_BACKEND "epoll" +#elif defined(__unix__) +#define USE_POLL +#define POLL_BACKEND "poll" +#else +#define USE_SELECT +#define POLL_BACKEND "select" #endif #ifdef USE_EPOLL @@ -21,18 +28,21 @@ #ifndef MAX_EVENTS #define MAX_EVENTS 64 #endif -#else +#endif +#ifdef USE_POLL +#include <poll.h> +#ifndef MAX_EVENTS +#define MAX_EVENTS 10000 +#endif +#endif +#ifdef USE_SELECT #include <sys/select.h> #endif #include <lualib.h> #include <lauxlib.h> -#ifdef USE_EPOLL -#define STATE_MT "util.poll<epoll>" -#else -#define STATE_MT "util.poll<select>" -#endif +#define STATE_MT "util.poll<" POLL_BACKEND ">" #if (LUA_VERSION_NUM == 501) #define luaL_setmetatable(L, tname) luaL_getmetatable(L, tname); lua_setmetatable(L, -2) @@ -49,7 +59,12 @@ typedef struct Lpoll_state { #ifdef USE_EPOLL int epoll_fd; struct epoll_event events[MAX_EVENTS]; -#else +#endif +#ifdef USE_POLL + nfds_t count; + struct pollfd events[MAX_EVENTS]; +#endif +#ifdef USE_SELECT fd_set wantread; fd_set wantwrite; fd_set readable; @@ -96,7 +111,34 @@ static int Ladd(lua_State *L) { lua_pushboolean(L, 1); return 1; -#else +#endif +#ifdef USE_POLL + + for(nfds_t i = 0; i < state->count; i++) { + if(state->events[i].fd == fd) { + luaL_pushfail(L); + lua_pushstring(L, strerror(EEXIST)); + lua_pushinteger(L, EEXIST); + return 3; + } + } + + if(state->count >= MAX_EVENTS) { + luaL_pushfail(L); + lua_pushstring(L, strerror(EMFILE)); + lua_pushinteger(L, EMFILE); + return 3; + } + + state->events[state->count].fd = fd; + state->events[state->count].events = (wantread ? POLLIN : 0) | (wantwrite ? POLLOUT : 0); + state->events[state->count].revents = 0; + state->count++; + + lua_pushboolean(L, 1); + return 1; +#endif +#ifdef USE_SELECT if(fd > FD_SETSIZE) { luaL_pushfail(L); @@ -169,7 +211,29 @@ static int Lset(lua_State *L) { return 3; } -#else +#endif +#ifdef USE_POLL + int wantread = lua_toboolean(L, 3); + int wantwrite = lua_toboolean(L, 4); + + for(nfds_t i = 0; i < state->count; i++) { + struct pollfd *event = &state->events[i]; + + if(event->fd == fd) { + event->events = (wantread ? POLLIN : 0) | (wantwrite ? POLLOUT : 0); + lua_pushboolean(L, 1); + return 1; + } else if(event->fd == -1) { + break; + } + } + + luaL_pushfail(L); + lua_pushstring(L, strerror(ENOENT)); + lua_pushinteger(L, ENOENT); + return 3; +#endif +#ifdef USE_SELECT if(!FD_ISSET(fd, &state->all)) { luaL_pushfail(L); @@ -227,7 +291,42 @@ static int Ldel(lua_State *L) { return 3; } -#else +#endif +#ifdef USE_POLL + + if(state->count == 0) { + luaL_pushfail(L); + lua_pushstring(L, strerror(ENOENT)); + lua_pushinteger(L, ENOENT); + return 3; + } + + /* + * Move the last item on top of the removed one + */ + struct pollfd *last = &state->events[state->count - 1]; + + for(nfds_t i = 0; i < state->count; i++) { + struct pollfd *event = &state->events[i]; + + if(event->fd == fd) { + event->fd = last->fd; + event->events = last->events; + event->revents = last->revents; + last->fd = -1; + state->count--; + + lua_pushboolean(L, 1); + return 1; + } + } + + luaL_pushfail(L); + lua_pushstring(L, strerror(ENOENT)); + lua_pushinteger(L, ENOENT); + return 3; +#endif +#ifdef USE_SELECT if(!FD_ISSET(fd, &state->all)) { luaL_pushfail(L); @@ -264,7 +363,24 @@ static int Lpushevent(lua_State *L, struct Lpoll_state *state) { return 3; } -#else +#endif +#ifdef USE_POLL + + for(int i = state->processed - 1; i >= 0; i--) { + struct pollfd *event = &state->events[i]; + + if(event->fd != -1 && event->revents != 0) { + lua_pushinteger(L, event->fd); + lua_pushboolean(L, event->revents & (POLLIN | POLLHUP | POLLERR)); + lua_pushboolean(L, event->revents & POLLOUT); + event->revents = 0; + state->processed = i; + return 3; + } + } + +#endif +#ifdef USE_SELECT for(int fd = state->processed + 1; fd < FD_SETSIZE; fd++) { if(FD_ISSET(fd, &state->readable) || FD_ISSET(fd, &state->writable) || FD_ISSET(fd, &state->err)) { @@ -300,7 +416,11 @@ static int Lwait(lua_State *L) { #ifdef USE_EPOLL ret = epoll_wait(state->epoll_fd, state->events, MAX_EVENTS, timeout * 1000); -#else +#endif +#ifdef USE_POLL + ret = poll(state->events, state->count, timeout * 1000); +#endif +#ifdef USE_SELECT /* * select(2) mutates the fd_sets passed to it so in order to not * have to recreate it manually every time a copy is made. @@ -341,7 +461,11 @@ static int Lwait(lua_State *L) { */ #ifdef USE_EPOLL state->processed = ret; -#else +#endif +#ifdef USE_POLL + state->processed = state->count; +#endif +#ifdef USE_SELECT state->processed = -1; #endif return Lpushevent(L, state); @@ -411,7 +535,19 @@ static int Lnew(lua_State *L) { } state->epoll_fd = epoll_fd; -#else +#endif +#ifdef USE_POLL + state->processed = -1; + state->count = 0; + + for(nfds_t i = 0; i < MAX_EVENTS; i++) { + state->events[i].fd = -1; + state->events[i].events = 0; + state->events[i].revents = 0; + } + +#endif +#ifdef USE_SELECT FD_ZERO(&state->wantread); FD_ZERO(&state->wantwrite); FD_ZERO(&state->readable); @@ -473,8 +609,12 @@ int luaopen_util_poll(lua_State *L) { lua_setfield(L, -2, #named_error); push_errno(EEXIST); + push_errno(EMFILE); push_errno(ENOENT); + lua_pushliteral(L, POLL_BACKEND); + lua_setfield(L, -2, "api"); + } return 1; } diff --git a/util/async.lua b/util/async.lua index ece589cb..2830238f 100644 --- a/util/async.lua +++ b/util/async.lua @@ -73,7 +73,7 @@ local function runner_continue(thread) return true; end -local function waiter(num) +local function waiter(num, allow_many) local thread = checkthread(); num = num or 1; local waiting; @@ -85,7 +85,7 @@ local function waiter(num) num = num - 1; if num == 0 and waiting then runner_continue(thread); - elseif num < 0 then + elseif not allow_many and num < 0 then error("done() called too many times"); end end; diff --git a/util/prosodyctl/check.lua b/util/prosodyctl/check.lua index f2b84c7a..2ef3bbcb 100644 --- a/util/prosodyctl/check.lua +++ b/util/prosodyctl/check.lua @@ -505,6 +505,69 @@ local function check(arg) ok = false; end + do + local global_modules = set.new(config["*"].modules_enabled); + local registration_enabled_hosts = {}; + for host in enabled_hosts() do + local host_modules = set.new(config[host].modules_enabled) + global_modules; + local allow_registration = config[host].allow_registration; + local mod_register = host_modules:contains("register"); + local mod_register_ibr = host_modules:contains("register_ibr"); + local mod_invites_register = host_modules:contains("invites_register"); + local registration_invite_only = config[host].registration_invite_only; + local is_vhost = not config[host].component_module; + if is_vhost and (mod_register_ibr or (mod_register and allow_registration)) + and not (mod_invites_register and registration_invite_only) then + table.insert(registration_enabled_hosts, host); + end + end + if #registration_enabled_hosts > 0 then + table.sort(registration_enabled_hosts); + print(""); + print(" Public registration is enabled on:"); + print(" "..table.concat(registration_enabled_hosts, ", ")); + print(""); + print(" If this is intentional, review our guidelines on running a public server"); + print(" at https://prosody.im/doc/public_servers - otherwise, consider switching to"); + print(" invite-based registration, which is more secure."); + end + end + + do + local orphan_components = {}; + local referenced_components = set.new(); + local enabled_hosts_set = set.new(); + for host, host_options in it.filter("*", pairs(configmanager.getconfig())) do + if host_options.enabled ~= false then + enabled_hosts_set:add(host); + for _, disco_item in ipairs(host_options.disco_items or {}) do + referenced_components:add(disco_item[1]); + end + end + end + for host, host_config in enabled_hosts() do + local is_component = not not host_config.component_module; + if is_component then + local parent_domain = host:match("^[^.]+%.(.+)$"); + local is_orphan = not (enabled_hosts_set:contains(parent_domain) or referenced_components:contains(host)); + if is_orphan then + table.insert(orphan_components, host); + end + end + end + if #orphan_components > 0 then + table.sort(orphan_components); + print(""); + print(" Your configuration contains the following unreferenced components:\n"); + print(" "..table.concat(orphan_components, "\n ")); + print(""); + print(" Clients may not be able to discover these services because they are not linked to"); + print(" any VirtualHost. They are automatically linked if they are direct subdomains of a"); + print(" VirtualHost. Alternatively, you can explicitly link them using the disco_items option."); + print(" For more information see https://prosody.im/doc/modules/mod_disco#items"); + end + end + print("Done.\n"); end if not what or what == "dns" then @@ -585,6 +648,11 @@ local function check(arg) end end + -- Allow admin to specify additional (e.g. undiscoverable) IP addresses in the config + for _, address in ipairs(configmanager.get("*", "external_addresses") or {}) do + external_addresses:add(address); + end + if external_addresses:empty() then print(""); print(" Failed to determine the external addresses of this server. Checks may be inaccurate."); @@ -599,6 +667,8 @@ local function check(arg) return (n:gsub("%.$", "")); end + local unknown_addresses = set.new(); + for jid, host_options in enabled_hosts() do local all_targets_ok, some_targets_ok = true, false; local node, host = jid_split(jid); @@ -781,6 +851,7 @@ local function check(arg) print(" "..target_host.." A record points to internal address, external connections might fail"); else print(" "..target_host.." A record points to unknown address "..record.a); + unknown_addresses:add(record.a); all_targets_ok = false; end end @@ -799,6 +870,7 @@ local function check(arg) print(" "..target_host.." AAAA record points to internal address, external connections might fail"); else print(" "..target_host.." AAAA record points to unknown address "..record.aaaa); + unknown_addresses:add(record.aaaa); all_targets_ok = false; end end @@ -844,6 +916,18 @@ local function check(arg) print(""); end if not problem_hosts:empty() then + if not unknown_addresses:empty() then + print(""); + print("Some of your DNS records point to unknown IP addresses. This may be expected if your server"); + print("is behind a NAT or proxy. The unrecognized addresses were:"); + print(""); + print(" Unrecognized: "..tostring(unknown_addresses)); + print(""); + print("The addresses we found on this system are:"); + print(""); + print(" Internal: "..tostring(internal_addresses)); + print(" External: "..tostring(external_addresses)); + end print(""); print("For more information about DNS configuration please see https://prosody.im/doc/dns"); print(""); |