Software /
code /
prosody
Comparison
util/prosodyctl/check.lua @ 11779:f4f0bdaeabd2
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.
author | Jonas Schäfer <jonas@wielicki.name> |
---|---|
date | Wed, 06 May 2020 18:20:33 +0200 |
parent | 11778:f254fd16218a |
child | 11780:98ae95235775 |
comparison
equal
deleted
inserted
replaced
11778:f254fd16218a | 11779:f4f0bdaeabd2 |
---|---|
4 local dependencies = require "util.dependencies"; | 4 local dependencies = require "util.dependencies"; |
5 local socket = require "socket"; | 5 local socket = require "socket"; |
6 local jid_split = require "util.jid".prepped_split; | 6 local jid_split = require "util.jid".prepped_split; |
7 local modulemanager = require "core.modulemanager"; | 7 local modulemanager = require "core.modulemanager"; |
8 | 8 |
9 local function check_api(check_type, target_host) | |
10 local async = require "util.async"; | |
11 local wait, done = async.waiter(); | |
12 local http = require "net.http"; -- .new({}); | |
13 local urlencode = require "util.http".urlencode; | |
14 local json = require "util.json"; | |
15 | |
16 local ok = false; | |
17 local err = nil; | |
18 local decoded_body = nil; | |
19 | |
20 http.request( | |
21 ("https://observe.jabber.network/api/v1/check/%s"):format(urlencode(check_type)), | |
22 { | |
23 method="POST", | |
24 headers={["Accept"] = "application/json"; ["Content-Type"] = "application/json"}, | |
25 body=json.encode({target=target_host}), | |
26 }, | |
27 function (body, code) | |
28 if code ~= 200 then | |
29 err = ("API replied with non-200 code: %d"):format(code) | |
30 else | |
31 decoded_body, err = json.decode(body); | |
32 if decoded_body == nil then | |
33 err = ("Failed to parse API JSON: %s"):format(err) | |
34 else | |
35 ok = true | |
36 end | |
37 end | |
38 done(); | |
39 end | |
40 ); | |
41 wait(); | |
42 | |
43 if not ok then | |
44 return false, err | |
45 end | |
46 | |
47 local success = decoded_body["success"]; | |
48 return success == true, nil; | |
49 end | |
50 | |
51 local function skip_bare_jid_hosts(host) | |
52 if jid_split(host) then | |
53 -- See issue #779 | |
54 return false; | |
55 end | |
56 return true; | |
57 end | |
58 | |
9 local function check(arg) | 59 local function check(arg) |
10 if arg[1] == "--help" then | 60 if arg[1] == "--help" then |
11 show_usage([[check]], [[Perform basic checks on your Prosody installation]]); | 61 show_usage([[check]], [[Perform basic checks on your Prosody installation]]); |
12 return 1; | 62 return 1; |
13 end | 63 end |
15 local set = require "util.set"; | 65 local set = require "util.set"; |
16 local it = require "util.iterators"; | 66 local it = require "util.iterators"; |
17 local ok = true; | 67 local ok = true; |
18 local function disabled_hosts(host, conf) return host ~= "*" and conf.enabled ~= false; end | 68 local function disabled_hosts(host, conf) return host ~= "*" and conf.enabled ~= false; end |
19 local function enabled_hosts() return it.filter(disabled_hosts, pairs(configmanager.getconfig())); end | 69 local function enabled_hosts() return it.filter(disabled_hosts, pairs(configmanager.getconfig())); end |
20 if not (what == nil or what == "disabled" or what == "config" or what == "dns" or what == "certs") then | 70 if not (what == nil or what == "disabled" or what == "config" or what == "dns" or what == "certs" or what == "connectivity") then |
21 show_warning("Don't know how to check '%s'. Try one of 'config', 'dns', 'certs' or 'disabled'.", what); | 71 show_warning("Don't know how to check '%s'. Try one of 'config', 'dns', 'certs', 'disabled' or 'connectivity'.", what); |
72 show_warning("Note: The connectivity check will connect to a remote server."); | |
22 return 1; | 73 return 1; |
23 end | 74 end |
24 if not what or what == "disabled" then | 75 if not what or what == "disabled" then |
25 local disabled_hosts_set = set.new(); | 76 local disabled_hosts_set = set.new(); |
26 for host, host_options in it.filter("*", pairs(configmanager.getconfig())) do | 77 for host, host_options in it.filter("*", pairs(configmanager.getconfig())) do |
604 if what == "certs" then cert_ok = false end | 655 if what == "certs" then cert_ok = false end |
605 elseif not load_cert then | 656 elseif not load_cert then |
606 print("This version of LuaSec (" .. ssl._VERSION .. ") does not support certificate checking"); | 657 print("This version of LuaSec (" .. ssl._VERSION .. ") does not support certificate checking"); |
607 cert_ok = false | 658 cert_ok = false |
608 else | 659 else |
609 local function skip_bare_jid_hosts(host) | |
610 if jid_split(host) then | |
611 -- See issue #779 | |
612 return false; | |
613 end | |
614 return true; | |
615 end | |
616 for host in it.filter(skip_bare_jid_hosts, enabled_hosts()) do | 660 for host in it.filter(skip_bare_jid_hosts, enabled_hosts()) do |
617 print("Checking certificate for "..host); | 661 print("Checking certificate for "..host); |
618 -- First, let's find out what certificate this host uses. | 662 -- First, let's find out what certificate this host uses. |
619 local host_ssl_config = configmanager.rawget(host, "ssl") | 663 local host_ssl_config = configmanager.rawget(host, "ssl") |
620 or configmanager.rawget(host:match("%.(.*)"), "ssl"); | 664 or configmanager.rawget(host:match("%.(.*)"), "ssl"); |
675 print("For more information about certificates please see https://prosody.im/doc/certificates"); | 719 print("For more information about certificates please see https://prosody.im/doc/certificates"); |
676 ok = false | 720 ok = false |
677 end | 721 end |
678 print("") | 722 print("") |
679 end | 723 end |
724 -- intentionally not doing this by default | |
725 if what == "connectivity" then | |
726 for host in it.filter(skip_bare_jid_hosts, enabled_hosts()) do | |
727 local modules, component_module = modulemanager.get_modules_for_host(host); | |
728 if component_module then | |
729 modules:add(component_module) | |
730 end | |
731 | |
732 print("Checking external connectivity for "..host.." via observe.jabber.network") | |
733 local function check_connectivity(protocol) | |
734 local success, err = check_api(protocol, host); | |
735 if not success and err ~= nil then | |
736 print((" %s: Failed to request check at API: %s"):format(protocol, err)) | |
737 elseif success then | |
738 print((" %s: Works"):format(protocol)) | |
739 else | |
740 print((" %s: Check service failed to establish (secure) connection"):format(protocol)) | |
741 ok = false | |
742 end | |
743 end | |
744 | |
745 if modules:contains("c2s") then | |
746 check_connectivity("xmpp-client") | |
747 end | |
748 | |
749 if modules:contains("s2s") then | |
750 check_connectivity("xmpp-server") | |
751 end | |
752 | |
753 print() | |
754 end | |
755 print("Note: The connectivity check only checks the reachability of the domain.") | |
756 print("Note: It does not ensure that the check actually reaches this specific prosody instance.") | |
757 end | |
680 if not ok then | 758 if not ok then |
681 print("Problems found, see above."); | 759 print("Problems found, see above."); |
682 else | 760 else |
683 print("All checks passed, congratulations!"); | 761 print("All checks passed, congratulations!"); |
684 end | 762 end |