# HG changeset patch # User Jonas Schäfer # Date 1588782033 -7200 # Node ID f4f0bdaeabd257f487995d97468fae812f3d13fa # Parent f254fd16218a3c17c1630e23cc4ce2c8cee580ef prosodyctl: Add external connectivity check based on observe.jabber.network This uses the (experimental) observe.jabber.network API to perform external connectivity checks. The idea is to complement the checks prosodyctl can already do with a (nearly) complete s2s/c2s handshake from a remote party to test the entire stack. diff -r f254fd16218a -r f4f0bdaeabd2 CHANGES --- a/CHANGES Thu Sep 09 22:14:43 2021 +0200 +++ b/CHANGES Wed May 06 18:20:33 2020 +0200 @@ -29,6 +29,7 @@ - Direct TLS support (c2s and incoming s2s) - Offline messages aren't sent to MAM clients - Network backend server_select deprecated +- Check connectivity via observe.jabber.network 0.11.0 ====== diff -r f254fd16218a -r f4f0bdaeabd2 util/prosodyctl/check.lua --- a/util/prosodyctl/check.lua Thu Sep 09 22:14:43 2021 +0200 +++ b/util/prosodyctl/check.lua Wed May 06 18:20:33 2020 +0200 @@ -6,6 +6,56 @@ local jid_split = require "util.jid".prepped_split; local modulemanager = require "core.modulemanager"; +local function check_api(check_type, target_host) + local async = require "util.async"; + local wait, done = async.waiter(); + local http = require "net.http"; -- .new({}); + local urlencode = require "util.http".urlencode; + local json = require "util.json"; + + local ok = false; + local err = nil; + local decoded_body = nil; + + http.request( + ("https://observe.jabber.network/api/v1/check/%s"):format(urlencode(check_type)), + { + method="POST", + headers={["Accept"] = "application/json"; ["Content-Type"] = "application/json"}, + body=json.encode({target=target_host}), + }, + function (body, code) + if code ~= 200 then + err = ("API replied with non-200 code: %d"):format(code) + else + decoded_body, err = json.decode(body); + if decoded_body == nil then + err = ("Failed to parse API JSON: %s"):format(err) + else + ok = true + end + end + done(); + end + ); + wait(); + + if not ok then + return false, err + end + + local success = decoded_body["success"]; + return success == true, nil; +end + +local function skip_bare_jid_hosts(host) + if jid_split(host) then + -- See issue #779 + return false; + end + return true; +end + local function check(arg) if arg[1] == "--help" then show_usage([[check]], [[Perform basic checks on your Prosody installation]]); @@ -17,8 +67,9 @@ local ok = true; local function disabled_hosts(host, conf) return host ~= "*" and conf.enabled ~= false; end local function enabled_hosts() return it.filter(disabled_hosts, pairs(configmanager.getconfig())); end - if not (what == nil or what == "disabled" or what == "config" or what == "dns" or what == "certs") then - show_warning("Don't know how to check '%s'. Try one of 'config', 'dns', 'certs' or 'disabled'.", what); + if not (what == nil or what == "disabled" or what == "config" or what == "dns" or what == "certs" or what == "connectivity") then + show_warning("Don't know how to check '%s'. Try one of 'config', 'dns', 'certs', 'disabled' or 'connectivity'.", what); + show_warning("Note: The connectivity check will connect to a remote server."); return 1; end if not what or what == "disabled" then @@ -606,13 +657,6 @@ print("This version of LuaSec (" .. ssl._VERSION .. ") does not support certificate checking"); cert_ok = false else - local function skip_bare_jid_hosts(host) - if jid_split(host) then - -- See issue #779 - return false; - end - return true; - end for host in it.filter(skip_bare_jid_hosts, enabled_hosts()) do print("Checking certificate for "..host); -- First, let's find out what certificate this host uses. @@ -677,6 +721,40 @@ end print("") end + -- intentionally not doing this by default + if what == "connectivity" then + for host in it.filter(skip_bare_jid_hosts, enabled_hosts()) do + local modules, component_module = modulemanager.get_modules_for_host(host); + if component_module then + modules:add(component_module) + end + + print("Checking external connectivity for "..host.." via observe.jabber.network") + local function check_connectivity(protocol) + local success, err = check_api(protocol, host); + if not success and err ~= nil then + print((" %s: Failed to request check at API: %s"):format(protocol, err)) + elseif success then + print((" %s: Works"):format(protocol)) + else + print((" %s: Check service failed to establish (secure) connection"):format(protocol)) + ok = false + end + end + + if modules:contains("c2s") then + check_connectivity("xmpp-client") + end + + if modules:contains("s2s") then + check_connectivity("xmpp-server") + end + + print() + end + print("Note: The connectivity check only checks the reachability of the domain.") + print("Note: It does not ensure that the check actually reaches this specific prosody instance.") + end if not ok then print("Problems found, see above."); else