Merge 0.9 -> 0.10
authorKim Alvefur <zash@zash.se>
Wed, 12 Feb 2014 18:26:22 +0000 (19:26 +0100)
committerKim Alvefur <zash@zash.se>
Wed, 12 Feb 2014 18:26:22 +0000 (19:26 +0100)
1  2 
plugins/mod_admin_telnet.lua
plugins/mod_s2s/s2sout.lib.lua

index 2572e982c2a70427879fcbc05b2896235981edaf,e13d27c24a9ac2c8019e26ad6956aa8854c63a47..2aa9bd9bc26e8b06f66ed66dc87d84ca13e6fd02
@@@ -1,7 -1,7 +1,7 @@@
  -- Prosody IM
  -- Copyright (C) 2008-2010 Matthew Wild
  -- Copyright (C) 2008-2010 Waqas Hussain
- -- 
+ --
  -- This project is MIT/X11 licensed. Please see the
  -- COPYING file in the source package for more information.
  --
@@@ -17,13 -17,13 +17,12 @@@ local _G = _G
  
  local prosody = _G.prosody;
  local hosts = prosody.hosts;
- local incoming_s2s = prosody.incoming_s2s;
  
  local console_listener = { default_port = 5582; default_mode = "*a"; interface = "127.0.0.1" };
  
  local iterators = require "util.iterators";
  local keys, values = iterators.keys, iterators.values;
 -local jid = require "util.jid";
 -local jid_bare, jid_split = jid.bare, jid.split;
 +local jid_bare, jid_split = import("util.jid", "bare", "prepped_split");
  local set, array = require "util.set", require "util.array";
  local cert_verify_identity = require "util.x509".verify_identity;
  local envload = require "util.envload".envload;
@@@ -60,20 -60,20 +59,20 @@@ function console:new_session(conn
                        disconnect = function () conn:close(); end;
                        };
        session.env = setmetatable({}, default_env_mt);
-       
        -- Load up environment with helper objects
        for name, t in pairs(def_env) do
                if type(t) == "table" then
                        session.env[name] = setmetatable({ session = session }, { __index = t });
                end
        end
-       
        return session;
  end
  
  function console:process_line(session, line)
        local useglobalenv;
-       
        if line:match("^>") then
                line = line:gsub("^>", "");
                useglobalenv = true;
@@@ -87,9 -87,9 +86,9 @@@
                        return;
                end
        end
-       
        session.env._ = line;
-       
        local chunkname = "=console";
        local env = (useglobalenv and redirect_output(_G, session)) or session.env or nil
        local chunk, err = envload("return "..line, chunkname, env);
                        return;
                end
        end
-       
        local ranok, taskok, message = pcall(chunk);
-       
        if not (ranok or message or useglobalenv) and commands[line:lower()] then
                commands[line:lower()](session, line);
                return;
        end
-       
        if not ranok then
                session.print("Fatal error while running command, it did not complete");
                session.print("Error: "..taskok);
                return;
        end
-       
        if not message then
                session.print("Result: "..tostring(taskok));
                return;
                session.print("Message: "..tostring(message));
                return;
        end
-       
        session.print("OK: "..tostring(message));
  end
  
@@@ -344,9 -344,9 +343,9 @@@ en
  
  function def_env.module:load(name, hosts, config)
        local mm = require "modulemanager";
-       
        hosts = get_hosts_set(hosts);
-       
        -- Load the module for each host
        local ok, err, count, mod = true, nil, 0, nil;
        for host in hosts do
                        end
                end
        end
-       
-       return ok, (ok and "Module loaded onto "..count.." host"..(count ~= 1 and "s" or "")) or ("Last error: "..tostring(err));       
+       return ok, (ok and "Module loaded onto "..count.." host"..(count ~= 1 and "s" or "")) or ("Last error: "..tostring(err));
  end
  
  function def_env.module:unload(name, hosts)
        local mm = require "modulemanager";
  
        hosts = get_hosts_set(hosts, name);
-       
        -- Unload the module for each host
        local ok, err, count = true, nil, 0;
        for host in hosts do
@@@ -433,7 -433,7 +432,7 @@@ function def_env.module:list(hosts
        if type(hosts) ~= "table" then
                return false, "Please supply a host or a list of hosts you would like to see";
        end
-       
        local print = self.session.print;
        for _, host in ipairs(hosts) do
                print((host == "*" and "Global" or host)..":");
@@@ -483,6 -483,25 +482,25 @@@ en
  function def_env.hosts:add(name)
  end
  
+ local function session_flags(session, line)
+       line = line or {};
+       if session.cert_identity_status == "valid" then
+               line[#line+1] = "(secure)";
+       elseif session.secure then
+               line[#line+1] = "(encrypted)";
+       end
+       if session.compressed then
+               line[#line+1] = "(compressed)";
+       end
+       if session.smacks then
+               line[#line+1] = "(sm)";
+       end
+       if session.ip and session.ip:match(":") then
+               line[#line+1] = "(IPv6)";
+       end
+       return table.concat(line, " ");
+ end
  def_env.c2s = {};
  
  local function show_c2s(callback)
@@@ -501,7 -520,7 +519,7 @@@ function def_env.c2s:count(match_jid
        show_c2s(function (jid, session)
                if (not match_jid) or jid:match(match_jid) then
                        count = count + 1;
-               end             
+               end
        end);
        return true, "Total: "..count.." clients";
  end
@@@ -518,15 -537,10 +536,10 @@@ function def_env.c2s:show(match_jid
                        count = count + 1;
                        local status, priority = "unavailable", tostring(session.priority or "-");
                        if session.presence then
-                               status = session.presence:child_with_name("show");
-                               if status then
-                                       status = status:get_text() or "[invalid!]";
-                               else
-                                       status = "available";
-                               end
+                               status = session.presence:get_child_text("show") or "available";
                        end
-                       print("   "..jid.." - "..status.."("..priority..")");
-               end             
+                       print(session_flags(session, { "   "..jid.." - "..status.."("..priority..")" }));
+               end
        end);
        return true, "Total: "..count.." clients";
  end
@@@ -537,7 -551,7 +550,7 @@@ function def_env.c2s:show_insecure(matc
                if ((not match_jid) or jid:match(match_jid)) and not session.secure then
                        count = count + 1;
                        print(jid);
-               end             
+               end
        end);
        return true, "Total: "..count.." insecure client connections";
  end
@@@ -548,7 -562,7 +561,7 @@@ function def_env.c2s:show_secure(match_
                if ((not match_jid) or jid:match(match_jid)) and session.secure then
                        count = count + 1;
                        print(jid);
-               end             
+               end
        end);
        return true, "Total: "..count.." secure client connections";
  end
@@@ -564,96 -578,80 +577,80 @@@ function def_env.c2s:close(match_jid
        return true, "Total: "..count.." sessions closed";
  end
  
- local function session_flags(session, line)
-       if session.cert_identity_status == "valid" then
-               line[#line+1] = "(secure)";
-       elseif session.secure then
-               line[#line+1] = "(encrypted)";
-       end
-       if session.compressed then
-               line[#line+1] = "(compressed)";
-       end
-       if session.smacks then
-               line[#line+1] = "(sm)";
-       end
-       if session.conn and session.conn:ip():match(":") then
-               line[#line+1] = "(IPv6)";
-       end
-       return table.concat(line, " ");
- end
  
  def_env.s2s = {};
  function def_env.s2s:show(match_jid)
-       local _print = self.session.print;
        local print = self.session.print;
-       
        local count_in, count_out = 0,0;
-       
-       for host, host_session in pairs(hosts) do
-               print = function (...) _print(host); _print(...); print = _print; end
-               for remotehost, session in pairs(host_session.s2sout) do
-                       if (not match_jid) or remotehost:match(match_jid) or host:match(match_jid) then
-                               count_out = count_out + 1;
-                               print(session_flags(session, {"   ", host, "->", remotehost}));
-                               if session.sendq then
-                                       print("        There are "..#session.sendq.." queued outgoing stanzas for this connection");
-                               end
-                               if session.type == "s2sout_unauthed" then
-                                       if session.connecting then
-                                               print("        Connection not yet established");
-                                               if not session.srv_hosts then
-                                                       if not session.conn then
-                                                               print("        We do not yet have a DNS answer for this host's SRV records");
-                                                       else
-                                                               print("        This host has no SRV records, using A record instead");
-                                                       end
-                                               elseif session.srv_choice then
-                                                       print("        We are on SRV record "..session.srv_choice.." of "..#session.srv_hosts);
-                                                       local srv_choice = session.srv_hosts[session.srv_choice];
-                                                       print("        Using "..(srv_choice.target or ".")..":"..(srv_choice.port or 5269));
+       local s2s_list = { };
+       local s2s_sessions = module:shared"/*/s2s/sessions";
+       for _, session in pairs(s2s_sessions) do
+               local remotehost, localhost, direction;
+               if session.direction == "outgoing" then
+                       direction = "->";
+                       count_out = count_out + 1;
+                       remotehost, localhost = session.to_host or "?", session.from_host or "?";
+               else
+                       direction = "<-";
+                       count_in = count_in + 1;
+                       remotehost, localhost = session.from_host or "?", session.to_host or "?";
+               end
+               local sess_lines = { l = localhost, r = remotehost,
+                       session_flags(session, { "", direction, remotehost or "?",
+                               "["..session.type..tostring(session):match("[a-f0-9]*$").."]" })};
+               if (not match_jid) or remotehost:match(match_jid) or localhost:match(match_jid) then
+                       table.insert(s2s_list, sess_lines);
+                       local print = function (s) table.insert(sess_lines, "        "..s); end
+                       if session.sendq then
+                               print("There are "..#session.sendq.." queued outgoing stanzas for this connection");
+                       end
+                       if session.type == "s2sout_unauthed" then
+                               if session.connecting then
+                                       print("Connection not yet established");
+                                       if not session.srv_hosts then
+                                               if not session.conn then
+                                                       print("We do not yet have a DNS answer for this host's SRV records");
+                                               else
+                                                       print("This host has no SRV records, using A record instead");
                                                end
-                                       elseif session.notopen then
-                                               print("        The <stream> has not yet been opened");
-                                       elseif not session.dialback_key then
-                                               print("        Dialback has not been initiated yet");
-                                       elseif session.dialback_key then
-                                               print("        Dialback has been requested, but no result received");
+                                       elseif session.srv_choice then
+                                               print("We are on SRV record "..session.srv_choice.." of "..#session.srv_hosts);
+                                               local srv_choice = session.srv_hosts[session.srv_choice];
+                                               print("Using "..(srv_choice.target or ".")..":"..(srv_choice.port or 5269));
                                        end
+                               elseif session.notopen then
+                                       print("The <stream> has not yet been opened");
+                               elseif not session.dialback_key then
+                                       print("Dialback has not been initiated yet");
+                               elseif session.dialback_key then
+                                       print("Dialback has been requested, but no result received");
                                end
                        end
-               end     
-               local subhost_filter = function (h)
-                               return (match_jid and h:match(match_jid));
-                       end
-               for session in pairs(incoming_s2s) do
-                       if session.to_host == host and ((not match_jid) or host:match(match_jid)
-                               or (session.from_host and session.from_host:match(match_jid))
-                               -- Pft! is what I say to list comprehensions
-                               or (session.hosts and #array.collect(keys(session.hosts)):filter(subhost_filter)>0)) then
-                               count_in = count_in + 1;
-                               print(session_flags(session, {"   ", host, "<-", session.from_host or "(unknown)"}));
-                               if session.type == "s2sin_unauthed" then
-                                               print("        Connection not yet authenticated");
-                               end
+                       if session.type == "s2sin_unauthed" then
+                               print("Connection not yet authenticated");
+                       elseif session.type == "s2sin" then
                                for name in pairs(session.hosts) do
                                        if name ~= session.from_host then
-                                               print("        also hosts "..tostring(name));
+                                               print("also hosts "..tostring(name));
                                        end
                                end
                        end
                end
-               
-               print = _print;
        end
-       
-       for session in pairs(incoming_s2s) do
-               if not session.to_host and ((not match_jid) or session.from_host and session.from_host:match(match_jid)) then
-                       count_in = count_in + 1;
-                       print("Other incoming s2s connections");
-                       print("    (unknown) <- "..(session.from_host or "(unknown)"));                 
-               end
+       -- Sort by local host, then remote host
+       table.sort(s2s_list, function(a,b)
+               if a.l == b.l then return a.r < b.r; end
+               return a.l < b.l;
+       end);
+       local lasthost;
+       for _, sess_lines in ipairs(s2s_list) do
+               if sess_lines.l ~= lasthost then print(sess_lines.l); lasthost=sess_lines.l end
+               for _, line in ipairs(sess_lines) do print(line); end
        end
-       
        return true, "Total: "..count_out.." outgoing, "..count_in.." incoming connections";
  end
  
@@@ -685,14 -683,9 +682,9 @@@ en
  function def_env.s2s:showcert(domain)
        local ser = require "util.serialization".serialize;
        local print = self.session.print;
-       local domain_sessions = set.new(array.collect(keys(incoming_s2s)))
-               /function(session) return session.from_host == domain and session or nil; end;
-       for local_host in values(prosody.hosts) do
-               local s2sout = local_host.s2sout;
-               if s2sout and s2sout[domain] then
-                       domain_sessions:add(s2sout[domain]);
-               end
-       end
+       local s2s_sessions = module:shared"/*/s2s/sessions";
+       local domain_sessions = set.new(array.collect(values(s2s_sessions)))
+               /function(session) return (session.to_host == domain or session.from_host == domain) and session or nil; end;
        local cert_set = {};
        for session in domain_sessions do
                local conn = session.conn;
        local domain_certs = array.collect(values(cert_set));
        -- Phew. We now have a array of unique certificates presented by domain.
        local n_certs = #domain_certs;
-       
        if n_certs == 0 then
                return "No certificates found for "..domain;
        end
-       
        local function _capitalize_and_colon(byte)
                return string.upper(byte)..":";
        end
        local function pretty_fingerprint(hash)
                return hash:gsub("..", _capitalize_and_colon):sub(1, -2);
        end
-       
        for cert_info in values(domain_certs) do
                local certs = cert_info.certs;
                local cert = certs[1];
@@@ -783,76 -776,38 +775,38 @@@ en
  
  function def_env.s2s:close(from, to)
        local print, count = self.session.print, 0;
-       
-       if not (from and to) then
+       local s2s_sessions = module:shared"/*/s2s/sessions";
+       local match_id;
+       if from and not to then
+               match_id, from = from;
+       elseif not to then
                return false, "Syntax: s2s:close('from', 'to') - Closes all s2s sessions from 'from' to 'to'";
        elseif from == to then
                return false, "Both from and to are the same... you can't do that :)";
        end
-       
-       if hosts[from] and not hosts[to] then
-               -- Is an outgoing connection
-               local session = hosts[from].s2sout[to];
-               if not session then
-                       print("No outgoing connection from "..from.." to "..to)
-               else
+       for _, session in pairs(s2s_sessions) do
+               local id = session.type..tostring(session):match("[a-f0-9]+$");
+               if (match_id and match_id == id)
+               or (session.from_host == from and session.to_host == to) then
+                       print(("Closing connection from %s to %s [%s]"):format(session.from_host, session.to_host, id));
                        (session.close or s2smanager.destroy_session)(session);
-                       count = count + 1;
-                       print("Closed outgoing session from "..from.." to "..to);
+                       count = count + 1 ;
                end
-       elseif hosts[to] and not hosts[from] then
-               -- Is an incoming connection
-               for session in pairs(incoming_s2s) do
-                       if session.to_host == to and session.from_host == from then
-                               (session.close or s2smanager.destroy_session)(session);
-                               count = count + 1;
                        end
-               end
-               
-               if count == 0 then
-                       print("No incoming connections from "..from.." to "..to);
-               else
-                       print("Closed "..count.." incoming session"..((count == 1 and "") or "s").." from "..from.." to "..to);
-               end
-       elseif hosts[to] and hosts[from] then
-               return false, "Both of the hostnames you specified are local, there are no s2s sessions to close";
-       else
-               return false, "Neither of the hostnames you specified are being used on this server";
-       end
-       
        return true, "Closed "..count.." s2s session"..((count == 1 and "") or "s");
  end
  
  function def_env.s2s:closeall(host)
          local count = 0;
-         if not host or type(host) ~= "string" then return false, "wrong syntax: please use s2s:closeall('hostname.tld')"; end
-         if hosts[host] then
-                 for session in pairs(incoming_s2s) do
-                         if session.to_host == host then
-                                 (session.close or s2smanager.destroy_session)(session);
+       local s2s_sessions = module:shared"/*/s2s/sessions";
+       for _,session in pairs(s2s_sessions) do
+               if not host or session.from_host == host or session.to_host == host then
+                       session:close();
                                  count = count + 1;
                          end
                  end
-                 for _, session in pairs(hosts[host].s2sout) do
-                         (session.close or s2smanager.destroy_session)(session);
-                         count = count + 1;
-                 end
-         else
-                 for session in pairs(incoming_s2s) do
-                       if session.from_host == host then
-                               (session.close or s2smanager.destroy_session)(session);
-                               count = count + 1;
-                       end
-               end
-               for _, h in pairs(hosts) do
-                       if h.s2sout[host] then
-                               (h.s2sout[host].close or s2smanager.destroy_session)(h.s2sout[host]);
-                               count = count + 1;
-                       end
-               end
-         end
        if count == 0 then return false, "No sessions to close.";
        else return true, "Closed "..count.." s2s session"..((count == 1 and "") or "s"); end
  end
@@@ -1076,12 -1031,12 +1030,12 @@@ function printbanner(session
        local option = module:get_option("console_banner");
        if option == nil or option == "full" or option == "graphic" then
                session.print [[
-                    ____                \   /     _       
-                     |  _ \ _ __ ___  ___  _-_   __| |_   _ 
+                    ____                \   /     _
+                     |  _ \ _ __ ___  ___  _-_   __| |_   _
                      | |_) | '__/ _ \/ __|/ _ \ / _` | | | |
                      |  __/| | | (_) \__ \ |_| | (_| | |_| |
                      |_|   |_|  \___/|___/\___/ \__,_|\__, |
-                     A study in simplicity            |___/ 
+                     A study in simplicity            |___/
  
  ]]
        end
index b24faf8553cf84d5dd173cd674429766cc880052,dbbef3603355e00c73b8bf91ae743dd62c8c8648..42b4281c7deb859de9b3fab40e121ac947250bd1
@@@ -1,7 -1,7 +1,7 @@@
  -- Prosody IM
  -- Copyright (C) 2008-2010 Matthew Wild
  -- Copyright (C) 2008-2010 Waqas Hussain
- -- 
+ --
  -- This project is MIT/X11 licensed. Please see the
  -- COPYING file in the source package for more information.
  --
@@@ -47,14 -47,14 +47,14 @@@ en
  function s2sout.initiate_connection(host_session)
        initialize_filters(host_session);
        host_session.version = 1;
-       
        -- Kick the connection attempting machine into life
        if not s2sout.attempt_connection(host_session) then
                -- Intentionally not returning here, the
                -- session is needed, connected or not
                s2s_destroy_session(host_session);
        end
-       
        if not host_session.sends2s then
                -- A sends2s which buffers data (until the stream is opened)
                -- note that data in this buffer will be sent before the stream is authed
@@@ -75,11 -75,11 +75,11 @@@ en
  function s2sout.attempt_connection(host_session, err)
        local to_host = host_session.to_host;
        local connect_host, connect_port = to_host and idna_to_ascii(to_host), 5269;
-       
        if not connect_host then
                return false;
        end
-       
        if not err then -- This is our first attempt
                log("debug", "First attempt to connect to %s, starting with SRV lookup...", to_host);
                host_session.connecting = true;
                                        return;
                                end
                                t_sort(srv_hosts, compare_srv_priorities);
-                               
                                local srv_choice = srv_hosts[1];
                                host_session.srv_choice = 1;
                                if srv_choice then
                                end
                        end
                end, "_xmpp-server._tcp."..connect_host..".", "SRV");
-               
                return true; -- Attempt in progress
        elseif host_session.ip_hosts then
                return s2sout.try_connect(host_session, connect_host, connect_port, err);
                connect_host, connect_port = srv_choice.target or to_host, srv_choice.port or connect_port;
                host_session.log("info", "Connection failed (%s). Attempt #%d: This time to %s:%d", tostring(err), host_session.srv_choice, connect_host, connect_port);
        else
-               host_session.log("info", "Out of connection options, can't connect to %s", tostring(host_session.to_host));
+               host_session.log("info", "Failed in all attempts to connect to %s", tostring(host_session.to_host));
                -- We're out of options
                return false;
        end
-       
        if not (connect_host and connect_port) then
                -- Likely we couldn't resolve DNS
                log("warn", "Hmm, we're without a host (%s) and port (%s) to connect to for %s, giving up :(", tostring(connect_host), tostring(connect_port), tostring(to_host));
@@@ -265,11 -265,12 +265,12 @@@ function s2sout.try_connect(host_sessio
  end
  
  function s2sout.make_connect(host_session, connect_host, connect_port)
-       (host_session.log or log)("info", "Beginning new connection attempt to %s ([%s]:%d)", host_session.to_host, connect_host.addr, connect_port);
+       (host_session.log or log)("debug", "Beginning new connection attempt to %s ([%s]:%d)", host_session.to_host, connect_host.addr, connect_port);
  
        -- Reset secure flag in case this is another
        -- connection attempt after a failed STARTTLS
        host_session.secure = nil;
+       host_session.encrypted = nil;
  
        local conn, handler;
        local proto = connect_host.proto;
        else
                handler = "Unsupported protocol: "..tostring(proto);
        end
-       
        if not conn then
                log("warn", "Failed to create outgoing connection, system error: %s", handler);
                return false, handler;
                log("warn", "s2s connect() to %s (%s:%d) failed: %s", host_session.to_host, connect_host.addr, connect_port, err);
                return false, err;
        end
-       
        conn = wrapclient(conn, connect_host.addr, connect_port, s2s_listener, "*a");
        host_session.conn = conn;
-       
        local filter = initialize_filters(host_session);
        local w, log = conn.write, host_session.log;
        host_session.sends2s = function (t)
                        end
                end
        end
-       
        -- Register this outgoing connection so that xmppserver_listener knows about it
        -- otherwise it will assume it is a new incoming connection
        s2s_listener.register_outgoing(conn, host_session);
-       
        log("debug", "Connection attempt in progress...");
        return true;
  end
@@@ -347,9 -348,6 +348,9 @@@ module:hook_global("service-added", fun
                        has_ipv4 = true;
                end
        end
 +      if not (has_ipv4 or has_ipv6)  then
 +              module:log("warn", "No local IPv4 or IPv6 addresses detected, outgoing connections may fail");
 +      end
  end);
  
  return s2sout;