util/prosodyctl/check.lua
changeset 10875 e5dee71d0ebb
child 10936 ea4a7619058f
equal deleted inserted replaced
10874:3f1889608f3e 10875:e5dee71d0ebb
       
     1 local configmanager = require "core.configmanager";
       
     2 local show_usage = require "util.prosodyctl".show_usage;
       
     3 local show_warning = require "util.prosodyctl".show_warning;
       
     4 local dependencies = require "util.dependencies";
       
     5 local socket = require "socket";
       
     6 local jid_split = require "util.jid".prepped_split;
       
     7 local modulemanager = require "core.modulemanager";
       
     8 
       
     9 local function check(arg)
       
    10 	if arg[1] == "--help" then
       
    11 		show_usage([[check]], [[Perform basic checks on your Prosody installation]]);
       
    12 		return 1;
       
    13 	end
       
    14 	local what = table.remove(arg, 1);
       
    15 	local set = require "util.set";
       
    16 	local it = require "util.iterators";
       
    17 	local ok = true;
       
    18 	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
       
    20 	if not (what == nil or what == "disabled" or what == "config" or what == "dns" or what == "certs") then
       
    21 		show_warning("Don't know how to check '%s'. Try one of 'config', 'dns', 'certs' or 'disabled'.", what);
       
    22 		return 1;
       
    23 	end
       
    24 	if not what or what == "disabled" then
       
    25 		local disabled_hosts_set = set.new();
       
    26 		for host, host_options in it.filter("*", pairs(configmanager.getconfig())) do
       
    27 			if host_options.enabled == false then
       
    28 				disabled_hosts_set:add(host);
       
    29 			end
       
    30 		end
       
    31 		if not disabled_hosts_set:empty() then
       
    32 			local msg = "Checks will be skipped for these disabled hosts: %s";
       
    33 			if what then msg = "These hosts are disabled: %s"; end
       
    34 			show_warning(msg, tostring(disabled_hosts_set));
       
    35 			if what then return 0; end
       
    36 			print""
       
    37 		end
       
    38 	end
       
    39 	if not what or what == "config" then
       
    40 		print("Checking config...");
       
    41 		local deprecated = set.new({
       
    42 			"bosh_ports", "disallow_s2s", "no_daemonize", "anonymous_login", "require_encryption",
       
    43 			"vcard_compatibility", "cross_domain_bosh", "cross_domain_websocket", "daemonize",
       
    44 		});
       
    45 		local known_global_options = set.new({
       
    46 			"pidfile", "log", "plugin_paths", "prosody_user", "prosody_group", "daemonize",
       
    47 			"umask", "prosodyctl_timeout", "use_ipv6", "use_libevent", "network_settings",
       
    48 			"network_backend", "http_default_host",
       
    49 			"statistics_interval", "statistics", "statistics_config",
       
    50 		});
       
    51 		local config = configmanager.getconfig();
       
    52 		-- Check that we have any global options (caused by putting a host at the top)
       
    53 		if it.count(it.filter("log", pairs(config["*"]))) == 0 then
       
    54 			ok = false;
       
    55 			print("");
       
    56 			print("    No global options defined. Perhaps you have put a host definition at the top")
       
    57 			print("    of the config file? They should be at the bottom, see https://prosody.im/doc/configure#overview");
       
    58 		end
       
    59 		if it.count(enabled_hosts()) == 0 then
       
    60 			ok = false;
       
    61 			print("");
       
    62 			if it.count(it.filter("*", pairs(config))) == 0 then
       
    63 				print("    No hosts are defined, please add at least one VirtualHost section")
       
    64 			elseif config["*"]["enabled"] == false then
       
    65 				print("    No hosts are enabled. Remove enabled = false from the global section or put enabled = true under at least one VirtualHost section")
       
    66 			else
       
    67 				print("    All hosts are disabled. Remove enabled = false from at least one VirtualHost section")
       
    68 			end
       
    69 		end
       
    70 		if not config["*"].modules_enabled then
       
    71 			print("    No global modules_enabled is set?");
       
    72 			local suggested_global_modules;
       
    73 			for host, options in enabled_hosts() do --luacheck: ignore 213/host
       
    74 				if not options.component_module and options.modules_enabled then
       
    75 					suggested_global_modules = set.intersection(suggested_global_modules or set.new(options.modules_enabled), set.new(options.modules_enabled));
       
    76 				end
       
    77 			end
       
    78 			if suggested_global_modules and not suggested_global_modules:empty() then
       
    79 				print("    Consider moving these modules into modules_enabled in the global section:")
       
    80 				print("    "..tostring(suggested_global_modules / function (x) return ("%q"):format(x) end));
       
    81 			end
       
    82 			print();
       
    83 		end
       
    84 
       
    85 		do -- Check for modules enabled both normally and as components
       
    86 			local modules = set.new(config["*"]["modules_enabled"]);
       
    87 			for host, options in enabled_hosts() do
       
    88 				local component_module = options.component_module;
       
    89 				if component_module and modules:contains(component_module) then
       
    90 					print(("    mod_%s is enabled both in modules_enabled and as Component %q %q"):format(component_module, host, component_module));
       
    91 					print("    This means the service is enabled on all VirtualHosts as well as the Component.");
       
    92 					print("    Are you sure this what you want? It may cause unexpected behaviour.");
       
    93 				end
       
    94 			end
       
    95 		end
       
    96 
       
    97 		-- Check for global options under hosts
       
    98 		local global_options = set.new(it.to_array(it.keys(config["*"])));
       
    99 		local deprecated_global_options = set.intersection(global_options, deprecated);
       
   100 		if not deprecated_global_options:empty() then
       
   101 			print("");
       
   102 			print("    You have some deprecated options in the global section:");
       
   103 			print("    "..tostring(deprecated_global_options))
       
   104 			ok = false;
       
   105 		end
       
   106 		for host, options in it.filter(function (h) return h ~= "*" end, pairs(configmanager.getconfig())) do
       
   107 			local host_options = set.new(it.to_array(it.keys(options)));
       
   108 			local misplaced_options = set.intersection(host_options, known_global_options);
       
   109 			for name in pairs(options) do
       
   110 				if name:match("^interfaces?")
       
   111 				or name:match("_ports?$") or name:match("_interfaces?$")
       
   112 				or (name:match("_ssl$") and not name:match("^[cs]2s_ssl$")) then
       
   113 					misplaced_options:add(name);
       
   114 				end
       
   115 			end
       
   116 			if not misplaced_options:empty() then
       
   117 				ok = false;
       
   118 				print("");
       
   119 				local n = it.count(misplaced_options);
       
   120 				print("    You have "..n.." option"..(n>1 and "s " or " ").."set under "..host.." that should be");
       
   121 				print("    in the global section of the config file, above any VirtualHost or Component definitions,")
       
   122 				print("    see https://prosody.im/doc/configure#overview for more information.")
       
   123 				print("");
       
   124 				print("    You need to move the following option"..(n>1 and "s" or "")..": "..table.concat(it.to_array(misplaced_options), ", "));
       
   125 			end
       
   126 		end
       
   127 		for host, options in enabled_hosts() do
       
   128 			local host_options = set.new(it.to_array(it.keys(options)));
       
   129 			local subdomain = host:match("^[^.]+");
       
   130 			if not(host_options:contains("component_module")) and (subdomain == "jabber" or subdomain == "xmpp"
       
   131 			   or subdomain == "chat" or subdomain == "im") then
       
   132 				print("");
       
   133 				print("    Suggestion: If "..host.. " is a new host with no real users yet, consider renaming it now to");
       
   134 				print("     "..host:gsub("^[^.]+%.", "")..". You can use SRV records to redirect XMPP clients and servers to "..host..".");
       
   135 				print("     For more information see: https://prosody.im/doc/dns");
       
   136 			end
       
   137 		end
       
   138 		local all_modules = set.new(config["*"].modules_enabled);
       
   139 		local all_options = set.new(it.to_array(it.keys(config["*"])));
       
   140 		for host in enabled_hosts() do
       
   141 			all_options:include(set.new(it.to_array(it.keys(config[host]))));
       
   142 			all_modules:include(set.new(config[host].modules_enabled));
       
   143 		end
       
   144 		for mod in all_modules do
       
   145 			if mod:match("^mod_") then
       
   146 				print("");
       
   147 				print("    Modules in modules_enabled should not have the 'mod_' prefix included.");
       
   148 				print("    Change '"..mod.."' to '"..mod:match("^mod_(.*)").."'.");
       
   149 			elseif mod:match("^auth_") then
       
   150 				print("");
       
   151 				print("    Authentication modules should not be added to modules_enabled,");
       
   152 				print("    but be specified in the 'authentication' option.");
       
   153 				print("    Remove '"..mod.."' from modules_enabled and instead add");
       
   154 				print("        authentication = '"..mod:match("^auth_(.*)").."'");
       
   155 				print("    For more information see https://prosody.im/doc/authentication");
       
   156 			elseif mod:match("^storage_") then
       
   157 				print("");
       
   158 				print("    storage modules should not be added to modules_enabled,");
       
   159 				print("    but be specified in the 'storage' option.");
       
   160 				print("    Remove '"..mod.."' from modules_enabled and instead add");
       
   161 				print("        storage = '"..mod:match("^storage_(.*)").."'");
       
   162 				print("    For more information see https://prosody.im/doc/storage");
       
   163 			end
       
   164 		end
       
   165 		if all_modules:contains("vcard") and all_modules:contains("vcard_legacy") then
       
   166 			print("");
       
   167 			print("    Both mod_vcard_legacy and mod_vcard are enabled but they conflict");
       
   168 			print("    with each other. Remove one.");
       
   169 		end
       
   170 		if all_modules:contains("pep") and all_modules:contains("pep_simple") then
       
   171 			print("");
       
   172 			print("    Both mod_pep_simple and mod_pep are enabled but they conflict");
       
   173 			print("    with each other. Remove one.");
       
   174 		end
       
   175 		for host, host_config in pairs(config) do --luacheck: ignore 213/host
       
   176 			if type(rawget(host_config, "storage")) == "string" and rawget(host_config, "default_storage") then
       
   177 				print("");
       
   178 				print("    The 'default_storage' option is not needed if 'storage' is set to a string.");
       
   179 				break;
       
   180 			end
       
   181 		end
       
   182 		local require_encryption = set.intersection(all_options, set.new({
       
   183 			"require_encryption", "c2s_require_encryption", "s2s_require_encryption"
       
   184 		})):empty();
       
   185 		local ssl = dependencies.softreq"ssl";
       
   186 		if not ssl then
       
   187 			if not require_encryption then
       
   188 				print("");
       
   189 				print("    You require encryption but LuaSec is not available.");
       
   190 				print("    Connections will fail.");
       
   191 				ok = false;
       
   192 			end
       
   193 		elseif not ssl.loadcertificate then
       
   194 			if all_options:contains("s2s_secure_auth") then
       
   195 				print("");
       
   196 				print("    You have set s2s_secure_auth but your version of LuaSec does ");
       
   197 				print("    not support certificate validation, so all s2s connections will");
       
   198 				print("    fail.");
       
   199 				ok = false;
       
   200 			elseif all_options:contains("s2s_secure_domains") then
       
   201 				local secure_domains = set.new();
       
   202 				for host in enabled_hosts() do
       
   203 					if config[host].s2s_secure_auth == true then
       
   204 						secure_domains:add("*");
       
   205 					else
       
   206 						secure_domains:include(set.new(config[host].s2s_secure_domains));
       
   207 					end
       
   208 				end
       
   209 				if not secure_domains:empty() then
       
   210 					print("");
       
   211 					print("    You have set s2s_secure_domains but your version of LuaSec does ");
       
   212 					print("    not support certificate validation, so s2s connections to/from ");
       
   213 					print("    these domains will fail.");
       
   214 					ok = false;
       
   215 				end
       
   216 			end
       
   217 		elseif require_encryption and not all_modules:contains("tls") then
       
   218 			print("");
       
   219 			print("    You require encryption but mod_tls is not enabled.");
       
   220 			print("    Connections will fail.");
       
   221 			ok = false;
       
   222 		end
       
   223 
       
   224 		print("Done.\n");
       
   225 	end
       
   226 	if not what or what == "dns" then
       
   227 		local dns = require "net.dns";
       
   228 		local idna = require "util.encodings".idna;
       
   229 		local ip = require "util.ip";
       
   230 		local c2s_ports = set.new(configmanager.get("*", "c2s_ports") or {5222});
       
   231 		local s2s_ports = set.new(configmanager.get("*", "s2s_ports") or {5269});
       
   232 
       
   233 		local c2s_srv_required, s2s_srv_required;
       
   234 		if not c2s_ports:contains(5222) then
       
   235 			c2s_srv_required = true;
       
   236 		end
       
   237 		if not s2s_ports:contains(5269) then
       
   238 			s2s_srv_required = true;
       
   239 		end
       
   240 
       
   241 		local problem_hosts = set.new();
       
   242 
       
   243 		local external_addresses, internal_addresses = set.new(), set.new();
       
   244 
       
   245 		local fqdn = socket.dns.tohostname(socket.dns.gethostname());
       
   246 		if fqdn then
       
   247 			do
       
   248 				local res = dns.lookup(idna.to_ascii(fqdn), "A");
       
   249 				if res then
       
   250 					for _, record in ipairs(res) do
       
   251 						external_addresses:add(record.a);
       
   252 					end
       
   253 				end
       
   254 			end
       
   255 			do
       
   256 				local res = dns.lookup(idna.to_ascii(fqdn), "AAAA");
       
   257 				if res then
       
   258 					for _, record in ipairs(res) do
       
   259 						external_addresses:add(record.aaaa);
       
   260 					end
       
   261 				end
       
   262 			end
       
   263 		end
       
   264 
       
   265 		local local_addresses = require"util.net".local_addresses() or {};
       
   266 
       
   267 		for addr in it.values(local_addresses) do
       
   268 			if not ip.new_ip(addr).private then
       
   269 				external_addresses:add(addr);
       
   270 			else
       
   271 				internal_addresses:add(addr);
       
   272 			end
       
   273 		end
       
   274 
       
   275 		if external_addresses:empty() then
       
   276 			print("");
       
   277 			print("   Failed to determine the external addresses of this server. Checks may be inaccurate.");
       
   278 			c2s_srv_required, s2s_srv_required = true, true;
       
   279 		end
       
   280 
       
   281 		local v6_supported = not not socket.tcp6;
       
   282 
       
   283 		for jid, host_options in enabled_hosts() do
       
   284 			local all_targets_ok, some_targets_ok = true, false;
       
   285 			local node, host = jid_split(jid);
       
   286 
       
   287 			local modules, component_module = modulemanager.get_modules_for_host(host);
       
   288 			if component_module then
       
   289 				modules:add(component_module);
       
   290 			end
       
   291 
       
   292 			local is_component = not not host_options.component_module;
       
   293 			print("Checking DNS for "..(is_component and "component" or "host").." "..jid.."...");
       
   294 			if node then
       
   295 				print("Only the domain part ("..host..") is used in DNS.")
       
   296 			end
       
   297 			local target_hosts = set.new();
       
   298 			if modules:contains("c2s") then
       
   299 				local res = dns.lookup("_xmpp-client._tcp."..idna.to_ascii(host)..".", "SRV");
       
   300 				if res then
       
   301 					for _, record in ipairs(res) do
       
   302 						target_hosts:add(record.srv.target);
       
   303 						if not c2s_ports:contains(record.srv.port) then
       
   304 							print("    SRV target "..record.srv.target.." contains unknown client port: "..record.srv.port);
       
   305 						end
       
   306 					end
       
   307 				else
       
   308 					if c2s_srv_required then
       
   309 						print("    No _xmpp-client SRV record found for "..host..", but it looks like you need one.");
       
   310 						all_targets_ok = false;
       
   311 					else
       
   312 						target_hosts:add(host);
       
   313 					end
       
   314 				end
       
   315 			end
       
   316 			if modules:contains("s2s") then
       
   317 				local res = dns.lookup("_xmpp-server._tcp."..idna.to_ascii(host)..".", "SRV");
       
   318 				if res then
       
   319 					for _, record in ipairs(res) do
       
   320 						target_hosts:add(record.srv.target);
       
   321 						if not s2s_ports:contains(record.srv.port) then
       
   322 							print("    SRV target "..record.srv.target.." contains unknown server port: "..record.srv.port);
       
   323 						end
       
   324 					end
       
   325 				else
       
   326 					if s2s_srv_required then
       
   327 						print("    No _xmpp-server SRV record found for "..host..", but it looks like you need one.");
       
   328 						all_targets_ok = false;
       
   329 					else
       
   330 						target_hosts:add(host);
       
   331 					end
       
   332 				end
       
   333 			end
       
   334 			if target_hosts:empty() then
       
   335 				target_hosts:add(host);
       
   336 			end
       
   337 
       
   338 			if target_hosts:contains("localhost") then
       
   339 				print("    Target 'localhost' cannot be accessed from other servers");
       
   340 				target_hosts:remove("localhost");
       
   341 			end
       
   342 
       
   343 			if modules:contains("proxy65") then
       
   344 				local proxy65_target = configmanager.get(host, "proxy65_address") or host;
       
   345 				if type(proxy65_target) == "string" then
       
   346 					local A, AAAA = dns.lookup(idna.to_ascii(proxy65_target), "A"), dns.lookup(idna.to_ascii(proxy65_target), "AAAA");
       
   347 					local prob = {};
       
   348 					if not A then
       
   349 						table.insert(prob, "A");
       
   350 					end
       
   351 					if v6_supported and not AAAA then
       
   352 						table.insert(prob, "AAAA");
       
   353 					end
       
   354 					if #prob > 0 then
       
   355 						print("    File transfer proxy "..proxy65_target.." has no "..table.concat(prob, "/")
       
   356 						.." record. Create one or set 'proxy65_address' to the correct host/IP.");
       
   357 					end
       
   358 				else
       
   359 					print("    proxy65_address for "..host.." should be set to a string, unable to perform DNS check");
       
   360 				end
       
   361 			end
       
   362 
       
   363 			for target_host in target_hosts do
       
   364 				local host_ok_v4, host_ok_v6;
       
   365 				do
       
   366 					local res = dns.lookup(idna.to_ascii(target_host), "A");
       
   367 					if res then
       
   368 						for _, record in ipairs(res) do
       
   369 							if external_addresses:contains(record.a) then
       
   370 								some_targets_ok = true;
       
   371 								host_ok_v4 = true;
       
   372 							elseif internal_addresses:contains(record.a) then
       
   373 								host_ok_v4 = true;
       
   374 								some_targets_ok = true;
       
   375 								print("    "..target_host.." A record points to internal address, external connections might fail");
       
   376 							else
       
   377 								print("    "..target_host.." A record points to unknown address "..record.a);
       
   378 								all_targets_ok = false;
       
   379 							end
       
   380 						end
       
   381 					end
       
   382 				end
       
   383 				do
       
   384 					local res = dns.lookup(idna.to_ascii(target_host), "AAAA");
       
   385 					if res then
       
   386 						for _, record in ipairs(res) do
       
   387 							if external_addresses:contains(record.aaaa) then
       
   388 								some_targets_ok = true;
       
   389 								host_ok_v6 = true;
       
   390 							elseif internal_addresses:contains(record.aaaa) then
       
   391 								host_ok_v6 = true;
       
   392 								some_targets_ok = true;
       
   393 								print("    "..target_host.." AAAA record points to internal address, external connections might fail");
       
   394 							else
       
   395 								print("    "..target_host.." AAAA record points to unknown address "..record.aaaa);
       
   396 								all_targets_ok = false;
       
   397 							end
       
   398 						end
       
   399 					end
       
   400 				end
       
   401 
       
   402 				local bad_protos = {}
       
   403 				if not host_ok_v4 then
       
   404 					table.insert(bad_protos, "IPv4");
       
   405 				end
       
   406 				if not host_ok_v6 then
       
   407 					table.insert(bad_protos, "IPv6");
       
   408 				end
       
   409 				if #bad_protos > 0 then
       
   410 					print("    Host "..target_host.." does not seem to resolve to this server ("..table.concat(bad_protos, "/")..")");
       
   411 				end
       
   412 				if host_ok_v6 and not v6_supported then
       
   413 					print("    Host "..target_host.." has AAAA records, but your version of LuaSocket does not support IPv6.");
       
   414 					print("      Please see https://prosody.im/doc/ipv6 for more information.");
       
   415 				end
       
   416 			end
       
   417 			if not all_targets_ok then
       
   418 				print("    "..(some_targets_ok and "Only some" or "No").." targets for "..host.." appear to resolve to this server.");
       
   419 				if is_component then
       
   420 					print("    DNS records are necessary if you want users on other servers to access this component.");
       
   421 				end
       
   422 				problem_hosts:add(host);
       
   423 			end
       
   424 			print("");
       
   425 		end
       
   426 		if not problem_hosts:empty() then
       
   427 			print("");
       
   428 			print("For more information about DNS configuration please see https://prosody.im/doc/dns");
       
   429 			print("");
       
   430 			ok = false;
       
   431 		end
       
   432 	end
       
   433 	if not what or what == "certs" then
       
   434 		local cert_ok;
       
   435 		print"Checking certificates..."
       
   436 		local x509_verify_identity = require"util.x509".verify_identity;
       
   437 		local create_context = require "core.certmanager".create_context;
       
   438 		local ssl = dependencies.softreq"ssl";
       
   439 		-- local datetime_parse = require"util.datetime".parse_x509;
       
   440 		local load_cert = ssl and ssl.loadcertificate;
       
   441 		-- or ssl.cert_from_pem
       
   442 		if not ssl then
       
   443 			print("LuaSec not available, can't perform certificate checks")
       
   444 			if what == "certs" then cert_ok = false end
       
   445 		elseif not load_cert then
       
   446 			print("This version of LuaSec (" .. ssl._VERSION .. ") does not support certificate checking");
       
   447 			cert_ok = false
       
   448 		else
       
   449 			local function skip_bare_jid_hosts(host)
       
   450 				if jid_split(host) then
       
   451 					-- See issue #779
       
   452 					return false;
       
   453 				end
       
   454 				return true;
       
   455 			end
       
   456 			for host in it.filter(skip_bare_jid_hosts, enabled_hosts()) do
       
   457 				print("Checking certificate for "..host);
       
   458 				-- First, let's find out what certificate this host uses.
       
   459 				local host_ssl_config = configmanager.rawget(host, "ssl")
       
   460 					or configmanager.rawget(host:match("%.(.*)"), "ssl");
       
   461 				local global_ssl_config = configmanager.rawget("*", "ssl");
       
   462 				local ok, err, ssl_config = create_context(host, "server", host_ssl_config, global_ssl_config);
       
   463 				if not ok then
       
   464 					print("  Error: "..err);
       
   465 					cert_ok = false
       
   466 				elseif not ssl_config.certificate then
       
   467 					print("  No 'certificate' found for "..host)
       
   468 					cert_ok = false
       
   469 				elseif not ssl_config.key then
       
   470 					print("  No 'key' found for "..host)
       
   471 					cert_ok = false
       
   472 				else
       
   473 					local key, err = io.open(ssl_config.key); -- Permissions check only
       
   474 					if not key then
       
   475 						print("    Could not open "..ssl_config.key..": "..err);
       
   476 						cert_ok = false
       
   477 					else
       
   478 						key:close();
       
   479 					end
       
   480 					local cert_fh, err = io.open(ssl_config.certificate); -- Load the file.
       
   481 					if not cert_fh then
       
   482 						print("    Could not open "..ssl_config.certificate..": "..err);
       
   483 						cert_ok = false
       
   484 					else
       
   485 						print("  Certificate: "..ssl_config.certificate)
       
   486 						local cert = load_cert(cert_fh:read"*a"); cert_fh:close();
       
   487 						if not cert:validat(os.time()) then
       
   488 							print("    Certificate has expired.")
       
   489 							cert_ok = false
       
   490 						elseif not cert:validat(os.time() + 86400) then
       
   491 							print("    Certificate expires within one day.")
       
   492 							cert_ok = false
       
   493 						elseif not cert:validat(os.time() + 86400*7) then
       
   494 							print("    Certificate expires within one week.")
       
   495 						elseif not cert:validat(os.time() + 86400*31) then
       
   496 							print("    Certificate expires within one month.")
       
   497 						end
       
   498 						if configmanager.get(host, "component_module") == nil
       
   499 							and not x509_verify_identity(host, "_xmpp-client", cert) then
       
   500 							print("    Not valid for client connections to "..host..".")
       
   501 							cert_ok = false
       
   502 						end
       
   503 						if (not (configmanager.get(host, "anonymous_login")
       
   504 							or configmanager.get(host, "authentication") == "anonymous"))
       
   505 							and not x509_verify_identity(host, "_xmpp-server", cert) then
       
   506 							print("    Not valid for server-to-server connections to "..host..".")
       
   507 							cert_ok = false
       
   508 						end
       
   509 					end
       
   510 				end
       
   511 			end
       
   512 		end
       
   513 		if cert_ok == false then
       
   514 			print("")
       
   515 			print("For more information about certificates please see https://prosody.im/doc/certificates");
       
   516 			ok = false
       
   517 		end
       
   518 		print("")
       
   519 	end
       
   520 	if not ok then
       
   521 		print("Problems found, see above.");
       
   522 	else
       
   523 		print("All checks passed, congratulations!");
       
   524 	end
       
   525 	return ok and 0 or 2;
       
   526 end
       
   527 
       
   528 return {
       
   529 	check = check;
       
   530 };