General fixes for s2s, to make it more robust (I hope), sending data to remote hosts sane (s2ssession.send() works as expected), recycle outgoing dialback connections, etc.

This commit is contained in:
Matthew Wild 2008-11-01 18:28:46 +00:00
parent 40726a8a0a
commit 7a2fc45f65
2 changed files with 41 additions and 23 deletions

View file

@ -3,6 +3,7 @@ local hosts = hosts;
local sessions = sessions; local sessions = sessions;
local socket = require "socket"; local socket = require "socket";
local format = string.format; local format = string.format;
local t_insert = table.insert;
local tostring, pairs, ipairs, getmetatable, print, newproxy, error, tonumber local tostring, pairs, ipairs, getmetatable, print, newproxy, error, tonumber
= tostring, pairs, ipairs, getmetatable, print, newproxy, error, tonumber; = tostring, pairs, ipairs, getmetatable, print, newproxy, error, tonumber;
@ -20,7 +21,7 @@ local md5_hash = require "util.hashes".md5;
local dialback_secret = "This is very secret!!! Ha!"; local dialback_secret = "This is very secret!!! Ha!";
local srvmap = { ["gmail.com"] = "talk.google.com", ["identi.ca"] = "longlance.controlezvous.ca" }; local srvmap = { ["gmail.com"] = "talk.google.com", ["identi.ca"] = "longlance.controlezvous.ca", ["cdr.se"] = "jabber.cdr.se" };
module "s2smanager" module "s2smanager"
@ -28,10 +29,19 @@ function connect_host(from_host, to_host)
end end
function send_to_host(from_host, to_host, data) function send_to_host(from_host, to_host, data)
if hosts[to_host] then local host = hosts[to_host];
if host then
-- Write to connection -- Write to connection
hosts[to_host].sends2s(data); if host.type == "s2sout_unauthed" and not host.notopen and not host.dialback_key then
log("debug", "stanza sent over s2s"); log("debug", "trying to send over unauthed s2sout to "..to_host..", authing it now...");
initiate_dialback(host);
if not host.sendq then host.sendq = { data };
else t_insert(host.sendq, data); end
else
log("debug", "going to send stanza to "..to_host.." from "..from_host);
hosts[to_host].sends2s(data);
log("debug", "stanza sent over "..hosts[to_host].type);
end
else else
log("debug", "opening a new outgoing connection for this stanza"); log("debug", "opening a new outgoing connection for this stanza");
local host_session = new_outgoing(from_host, to_host); local host_session = new_outgoing(from_host, to_host);
@ -61,7 +71,6 @@ end
function new_outgoing(from_host, to_host) function new_outgoing(from_host, to_host)
local host_session = { to_host = to_host, from_host = from_host, notopen = true, type = "s2sout_unauthed", direction = "outgoing" }; local host_session = { to_host = to_host, from_host = from_host, notopen = true, type = "s2sout_unauthed", direction = "outgoing" };
hosts[to_host] = host_session; hosts[to_host] = host_session;
local cl = connlisteners_get("xmppserver"); local cl = connlisteners_get("xmppserver");
local conn, handler = socket.tcp() local conn, handler = socket.tcp()
@ -113,13 +122,11 @@ function streamopened(session, attr)
send(format("<stream:stream xmlns='jabber:server' xmlns:db='jabber:server:dialback' xmlns:stream='http://etherx.jabber.org/streams' id='%s' from='%s'>", session.streamid, session.to_host)); send(format("<stream:stream xmlns='jabber:server' xmlns:db='jabber:server:dialback' xmlns:stream='http://etherx.jabber.org/streams' id='%s' from='%s'>", session.streamid, session.to_host));
elseif session.direction == "outgoing" then elseif session.direction == "outgoing" then
-- If we are just using the connection for verifying dialback keys, we won't try and auth it -- If we are just using the connection for verifying dialback keys, we won't try and auth it
if not attr.id then error("stream response did not give us a streamid!!!"); end
session.streamid = attr.id;
if not session.dialback_verifying then if not session.dialback_verifying then
-- generate dialback key initiate_dialback(session);
if not attr.id then error("stream response did not give us a streamid!!!"); end
session.streamid = attr.id;
session.dialback_key = generate_dialback(session.streamid, session.to_host, session.from_host);
session.sends2s(format("<db:result from='%s' to='%s'>%s</db:result>", session.from_host, session.to_host, session.dialback_key));
session.log("info", "sent dialback key on outgoing s2s stream");
else else
mark_connected(session); mark_connected(session);
end end
@ -139,6 +146,13 @@ function streamopened(session, attr)
session.notopen = nil; session.notopen = nil;
end end
function initiate_dialback(session)
-- generate dialback key
session.dialback_key = generate_dialback(session.streamid, session.to_host, session.from_host);
session.sends2s(format("<db:result from='%s' to='%s'>%s</db:result>", session.from_host, session.to_host, session.dialback_key));
session.log("info", "sent dialback key on outgoing s2s stream");
end
function generate_dialback(id, to, from) function generate_dialback(id, to, from)
return md5_hash(id..to..from..dialback_secret); -- FIXME: See XEP-185 and XEP-220 return md5_hash(id..to..from..dialback_secret); -- FIXME: See XEP-185 and XEP-220
end end
@ -167,18 +181,22 @@ function mark_connected(session)
local from, to = session.from_host, session.to_host; local from, to = session.from_host, session.to_host;
session.log("debug", session.direction.." s2s connection "..session.from_host.."->"..session.to_host.." is now complete"); session.log("debug", session.direction.." s2s connection "..from.."->"..to.." is now complete");
local send_to_host = send_to_host; local send_to_host = send_to_host;
function session.send(data) send_to_host(from, to, data); end function session.send(data) send_to_host(to, from, data); end
if sendq then
session.log("debug", "sending queued stanzas across new outgoing connection to "..session.to_host); if session.direction == "outgoing" then
for i, data in ipairs(sendq) do hosts[to] = session;
send(data); if sendq then
sendq[i] = nil; session.log("debug", "sending queued stanzas across new outgoing connection to "..session.to_host);
for i, data in ipairs(sendq) do
send(data);
sendq[i] = nil;
end
session.sendq = nil;
end end
session.sendq = nil;
end end
end end

View file

@ -23,7 +23,7 @@ local jid_split = require "util.jid".split;
local print = print; local print = print;
function core_process_stanza(origin, stanza) function core_process_stanza(origin, stanza)
log("debug", "Received: "..tostring(stanza)) log("debug", "Received["..origin.type.."]: "..tostring(stanza))
-- TODO verify validity of stanza (as well as JID validity) -- TODO verify validity of stanza (as well as JID validity)
if stanza.name == "iq" and not(#stanza.tags == 1 and stanza.tags[1].attr.xmlns) then if stanza.name == "iq" and not(#stanza.tags == 1 and stanza.tags[1].attr.xmlns) then
if stanza.attr.type == "set" or stanza.attr.type == "get" then if stanza.attr.type == "set" or stanza.attr.type == "get" then
@ -137,9 +137,9 @@ function core_handle_stanza(origin, stanza)
origin.from_host = attr.from; origin.from_host = attr.from;
origin.to_host = attr.to; origin.to_host = attr.to;
origin.dialback_key = stanza[1]; origin.dialback_key = stanza[1];
log("debug", "asking %s if key %s belongs to them", attr.from, stanza[1]); log("debug", "asking %s if key %s belongs to them", origin.from_host, origin.dialback_key);
send_s2s(attr.to, attr.from, format("<db:verify from='%s' to='%s' id='%s'>%s</db:verify>", attr.to, attr.from, origin.streamid, stanza[1])); send_s2s(origin.to_host, origin.from_host, format("<db:verify from='%s' to='%s' id='%s'>%s</db:verify>", origin.to_host, origin.from_host, origin.streamid, origin.dialback_key));
hosts[attr.from].dialback_verifying = origin; hosts[origin.from_host].dialback_verifying = origin;
end end
end end
elseif origin.type == "s2sout_unauthed" or origin.type == "s2sout" then elseif origin.type == "s2sout_unauthed" or origin.type == "s2sout" then