Merge 0.9->trunk
[prosody.git] / prosodyctl
index 262be676727d5c15107d6ebeafa55d008c16c8f8..4d7f678fa2e767b05381657f719f09156e8e0904 100755 (executable)
@@ -274,11 +274,12 @@ local commands = {};
 local command = arg[1];
 
 function commands.adduser(arg)
+       local jid_split = require "util.jid".split;
        if not arg[1] or arg[1] == "--help" then
                show_usage([[adduser JID]], [[Create the specified user account in Prosody]]);
                return 1;
        end
-       local user, host = arg[1]:match("([^@]+)@(.+)");
+       local user, host = jid_split(arg[1]);
        if not user and host then
                show_message [[Failed to understand JID, please supply the JID you want to create]]
                show_usage [[adduser user@host]]
@@ -313,11 +314,12 @@ function commands.adduser(arg)
 end
 
 function commands.passwd(arg)
+       local jid_split = require "util.jid".split;
        if not arg[1] or arg[1] == "--help" then
                show_usage([[passwd JID]], [[Set the password for the specified user account in Prosody]]);
                return 1;
        end
-       local user, host = arg[1]:match("([^@]+)@(.+)");
+       local user, host = jid_split(arg[1]);
        if not user and host then
                show_message [[Failed to understand JID, please supply the JID you want to set the password for]]
                show_usage [[passwd user@host]]
@@ -352,11 +354,12 @@ function commands.passwd(arg)
 end
 
 function commands.deluser(arg)
+       local jid_split = require "util.jid".split;
        if not arg[1] or arg[1] == "--help" then
                show_usage([[deluser JID]], [[Permanently remove the specified user account from Prosody]]);
                return 1;
        end
-       local user, host = arg[1]:match("([^@]+)@(.+)");
+       local user, host = jid_split(arg[1]);
        if not user and host then
                show_message [[Failed to understand JID, please supply the JID you want to set the password for]]
                show_usage [[passwd user@host]]
@@ -817,8 +820,203 @@ function commands.check(arg)
                                print("");
                                print("    You need to move the following option"..(n>1 and "s" or "")..": "..table.concat(it.to_array(misplaced_options), ", "));
                        end
+                       local subdomain = host:match("^[^.]+");
+                       if not(host_options:contains("component_module")) and (subdomain == "jabber" or subdomain == "xmpp"
+                          or subdomain == "chat" or subdomain == "im") then
+                               print("");
+                               print("    Suggestion: If "..host.. " is a new host with no real users yet, consider renaming it now to");
+                               print("     "..host:gsub("^[^.]+%.", "")..". You can use SRV records to redirect XMPP clients and servers to "..host..".");
+                               print("     For more information see: http://prosody.im/doc/dns");
+                       end
+               end
+               
+               print("Done.\n");
+       end
+       if not what or what == "dns" then
+               local dns = require "net.dns";
+               local ip = require "util.ip";
+               local c2s_ports = set.new(config.get("*", "c2s_ports") or {5222});
+               local s2s_ports = set.new(config.get("*", "s2s_ports") or {5269});
+               
+               local c2s_srv_required, s2s_srv_required;
+               if not c2s_ports:contains(5222) then
+                       c2s_srv_required = true;
+               end
+               if not s2s_ports:contains(5269) then
+                       s2s_srv_required = true;
+               end
+               
+               local problem_hosts = set.new();
+               
+               local external_addresses, internal_addresses = set.new(), set.new();
+               
+               local fqdn = socket.dns.tohostname(socket.dns.gethostname());
+               if fqdn then
+                       local res = dns.lookup(fqdn, "A");
+                       if res then
+                               for _, record in ipairs(res) do
+                                       external_addresses:add(record.a);
+                               end
+                       end
+                       local res = dns.lookup(fqdn, "AAAA");
+                       if res then
+                               for _, record in ipairs(res) do
+                                       external_addresses:add(record.aaaa);
+                               end
+                       end
+               end
+               
+               local local_addresses = socket.local_addresses and socket.local_addresses() or {};
+               
+               for addr in it.values(local_addresses) do
+                       if not ip.new_ip(addr).private then
+                               external_addresses:add(addr);
+                       else
+                               internal_addresses:add(addr);
+                       end
+               end
+               
+               if external_addresses:empty() then
+                       print("");
+                       print("   Failed to determine the external addresses of this server. Checks may be inaccurate.");
+                       c2s_srv_required, s2s_srv_required = true, true;
+               end
+               
+               local v6_supported = not not socket.tcp6;
+               
+               for host, host_options in it.filter("*", pairs(config.getconfig())) do
+                       local all_targets_ok, some_targets_ok = true, false;
+                       
+                       local is_component = not not host_options.component_module;
+                       print("Checking DNS for "..(is_component and "component" or "host").." "..host.."...");
+                       local target_hosts = set.new();
+                       if not is_component then
+                               local res = dns.lookup("_xmpp-client._tcp."..host..".", "SRV");
+                               if res then
+                                       for _, record in ipairs(res) do
+                                               target_hosts:add(record.srv.target);
+                                               if not c2s_ports:contains(record.srv.port) then
+                                                       print("    SRV target "..record.srv.target.." contains unknown client port: "..record.srv.port);
+                                               end
+                                       end
+                               else
+                                       if c2s_srv_required then
+                                               print("    No _xmpp-client SRV record found for "..host..", but it looks like you need one.");
+                                               all_targst_ok = false;
+                                       else
+                                               target_hosts:add(host);
+                                       end
+                               end
+                       end
+                       local res = dns.lookup("_xmpp-server._tcp."..host..".", "SRV");
+                       if res then
+                               for _, record in ipairs(res) do
+                                       target_hosts:add(record.srv.target);
+                                       if not s2s_ports:contains(record.srv.port) then
+                                               print("    SRV target "..record.srv.target.." contains unknown server port: "..record.srv.port);
+                                       end
+                               end
+                       else
+                               if s2s_srv_required then
+                                       print("    No _xmpp-server SRV record found for "..host..", but it looks like you need one.");
+                                       all_targets_ok = false;
+                               else
+                                       target_hosts:add(host);
+                               end
+                       end
+                       if target_hosts:empty() then
+                               target_hosts:add(host);
+                       end
+                       
+                       if target_hosts:contains("localhost") then
+                               print("    Target 'localhost' cannot be accessed from other servers");
+                               target_hosts:remove("localhost");
+                       end
+                       
+                       local modules = set.new(it.to_array(it.values(host_options.modules_enabled)))
+                                       + set.new(it.to_array(it.values(config.get("*", "modules_enabled"))))
+                                       + set.new({ config.get(host, "component_module") });
+
+                       if modules:contains("proxy65") then
+                               local proxy65_target = config.get(host, "proxy65_address") or host;
+                               local A, AAAA = dns.lookup(proxy65_target, "A"), dns.lookup(proxy65_target, "AAAA");
+                               local prob = {};
+                               if not A then
+                                       table.insert(prob, "A");
+                               end
+                               if v6_supported and not AAAA then
+                                       table.insert(prob, "AAAA");
+                               end
+                               if #prob > 0 then
+                                       print("    File transfer proxy "..proxy65_target.." has no "..table.concat(prob, "/").." record. Create one or set 'proxy65_address' to the correct host/IP.");
+                               end
+                       end
+                       
+                       for host in target_hosts do
+                               local host_ok_v4, host_ok_v6;
+                               local res = dns.lookup(host, "A");
+                               if res then
+                                       for _, record in ipairs(res) do
+                                               if external_addresses:contains(record.a) then
+                                                       some_targets_ok = true;
+                                                       host_ok_v4 = true;
+                                               elseif internal_addresses:contains(record.a) then
+                                                       host_ok_v4 = true;
+                                                       some_targets_ok = true;
+                                                       print("    "..host.." A record points to internal address, external connections might fail");
+                                               else
+                                                       print("    "..host.." A record points to unknown address "..record.a);
+                                                       all_targets_ok = false;
+                                               end
+                                       end
+                               end
+                               local res = dns.lookup(host, "AAAA");
+                               if res then
+                                       for _, record in ipairs(res) do
+                                               if external_addresses:contains(record.aaaa) then
+                                                       some_targets_ok = true;
+                                                       host_ok_v6 = true;
+                                               elseif internal_addresses:contains(record.aaaa) then
+                                                       host_ok_v6 = true;
+                                                       some_targets_ok = true;
+                                                       print("    "..host.." AAAA record points to internal address, external connections might fail");
+                                               else
+                                                       print("    "..host.." AAAA record points to unknown address "..record.aaaa);
+                                                       all_targets_ok = false;
+                                               end
+                                       end
+                               end
+                               
+                               local bad_protos = {}
+                               if not host_ok_v4 then
+                                       table.insert(bad_protos, "IPv4");
+                               end
+                               if not host_ok_v6 then
+                                       table.insert(bad_protos, "IPv6");
+                               end
+                               if #bad_protos > 0 then
+                                       print("    Host "..host.." does not seem to resolve to this server ("..table.concat(bad_protos, "/")..")");
+                               end
+                               if host_ok_v6 and not v6_supported then
+                                       print("    Host "..host.." has AAAA records, but your version of LuaSocket does not support IPv6.");
+                                       print("      Please see http://prosody.im/doc/ipv6 for more information.");
+                               end
+                       end
+                       if not all_targets_ok then
+                               print("    "..(some_targets_ok and "Only some" or "No").." targets for "..host.." appear to resolve to this server.");
+                               if is_component then
+                                       print("    DNS records are necessary if you want users on other servers to access this component.");
+                               end
+                               problem_hosts:add(host);
+                       end
+                       print("");
+               end
+               if not problem_hosts:empty() then
+                       print("");
+                       print("For more information about DNS configuration please see http://prosody.im/doc/dns");
+                       print("");
+                       ok = false;
                end
-               print("Done.");
        end
        if not ok then
                print("Problems found, see above.");