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