Comparison

plugins/mod_c2s.lua @ 11120:b2331f3dfeea

Merge 0.11->trunk
author Matthew Wild <mwild1@gmail.com>
date Wed, 30 Sep 2020 09:50:33 +0100
parent 11118:ece430d49809
parent 10850:bd2814f900dd
child 11359:db146bf7b120
comparison
equal deleted inserted replaced
11119:68df52bf08d5 11120:b2331f3dfeea
54 54
55 --- Stream events handlers 55 --- Stream events handlers
56 local stream_xmlns_attr = {xmlns='urn:ietf:params:xml:ns:xmpp-streams'}; 56 local stream_xmlns_attr = {xmlns='urn:ietf:params:xml:ns:xmpp-streams'};
57 57
58 function stream_callbacks.streamopened(session, attr) 58 function stream_callbacks.streamopened(session, attr)
59 -- run _streamopened in async context
60 session.thread:run({ stream = "opened", attr = attr });
61 end
62
63 function stream_callbacks._streamopened(session, attr)
59 local send = session.send; 64 local send = session.send;
65 if not attr.to then
66 session:close{ condition = "improper-addressing",
67 text = "A 'to' attribute is required on stream headers" };
68 return;
69 end
60 local host = nameprep(attr.to); 70 local host = nameprep(attr.to);
61 if not host then 71 if not host then
62 session:close{ condition = "improper-addressing", 72 session:close{ condition = "improper-addressing",
63 text = "A valid 'to' attribute is required on stream headers" }; 73 text = "A valid 'to' attribute is required on stream headers" };
64 return; 74 return;
96 local info = sock:info(); 106 local info = sock:info();
97 (session.log or log)("info", "Stream encrypted (%s with %s)", info.protocol, info.cipher); 107 (session.log or log)("info", "Stream encrypted (%s with %s)", info.protocol, info.cipher);
98 session.compressed = info.compression; 108 session.compressed = info.compression;
99 else 109 else
100 (session.log or log)("info", "Stream encrypted"); 110 (session.log or log)("info", "Stream encrypted");
101 session.compressed = sock.compression and sock:compression(); --COMPAT mw/luasec-hg
102 end 111 end
103 end 112 end
104 113
105 local features = st.stanza("stream:features"); 114 local features = st.stanza("stream:features");
106 hosts[session.host].events.fire_event("stream-features", { origin = session, features = features }); 115 hosts[session.host].events.fire_event("stream-features", { origin = session, features = features });
107 if features.tags[1] or session.full_jid then 116 if features.tags[1] or session.full_jid then
108 send(features); 117 send(features);
109 else 118 else
110 (session.log or log)("warn", "No stream features to offer"); 119 if session.secure then
120 -- Here SASL should be offered
121 (session.log or log)("warn", "No stream features to offer on secure session. Check authentication settings.");
122 else
123 -- Normally STARTTLS would be offered
124 (session.log or log)("warn", "No stream features to offer on insecure session. Check encryption and security settings.");
125 end
111 session:close{ condition = "undefined-condition", text = "No stream features to proceed with" }; 126 session:close{ condition = "undefined-condition", text = "No stream features to proceed with" };
112 end 127 end
113 end 128 end
114 129
115 function stream_callbacks.streamclosed(session) 130 function stream_callbacks.streamclosed(session, attr)
131 -- run _streamclosed in async context
132 session.thread:run({ stream = "closed", attr = attr });
133 end
134
135 function stream_callbacks._streamclosed(session)
116 session.log("debug", "Received </stream:stream>"); 136 session.log("debug", "Received </stream:stream>");
117 session:close(false); 137 session:close(false);
118 end 138 end
119 139
120 function stream_callbacks.error(session, error, data) 140 function stream_callbacks.error(session, error, data)
121 if error == "no-stream" then 141 if error == "no-stream" then
122 session.log("debug", "Invalid opening stream header (%s)", (data:gsub("^([^\1]+)\1", "{%1}"))); 142 session.log("debug", "Invalid opening stream header (%s)", (data:gsub("^([^\1]+)\1", "{%1}")));
123 session:close("invalid-namespace"); 143 session:close("invalid-namespace");
124 elseif error == "parse-error" then 144 elseif error == "parse-error" then
125 (session.log or log)("debug", "Client XML parse error: %s", tostring(data)); 145 (session.log or log)("debug", "Client XML parse error: %s", data);
126 session:close("not-well-formed"); 146 session:close("not-well-formed");
127 elseif error == "stream-error" then 147 elseif error == "stream-error" then
128 local condition, text = "undefined-condition"; 148 local condition, text = "undefined-condition";
129 for child in data:childtags(nil, xmlns_xmpp_streams) do 149 for child in data:childtags(nil, xmlns_xmpp_streams) do
130 if child.name ~= "text" then 150 if child.name ~= "text" then
250 270
251 -- Check if TLS compression is used 271 -- Check if TLS compression is used
252 local sock = conn:socket(); 272 local sock = conn:socket();
253 if sock.info then 273 if sock.info then
254 session.compressed = sock:info"compression"; 274 session.compressed = sock:info"compression";
255 elseif sock.compression then
256 session.compressed = sock:compression(); --COMPAT mw/luasec-hg
257 end 275 end
258 end 276 end
259 277
260 if opt_keepalives then 278 if opt_keepalives then
261 conn:setoption("keepalive", opt_keepalives); 279 conn:setoption("keepalive", opt_keepalives);
271 session.notopen = true; 289 session.notopen = true;
272 session.stream:reset(); 290 session.stream:reset();
273 end 291 end
274 292
275 session.thread = runner(function (stanza) 293 session.thread = runner(function (stanza)
276 core_process_stanza(session, stanza); 294 if st.is_stanza(stanza) then
295 core_process_stanza(session, stanza);
296 elseif stanza.stream == "opened" then
297 stream_callbacks._streamopened(session, stanza.attr);
298 elseif stanza.stream == "closed" then
299 stream_callbacks._streamclosed(session, stanza.attr);
300 end
277 end, runner_callbacks, session); 301 end, runner_callbacks, session);
278 302
279 local filter = session.filter; 303 local filter = session.filter;
280 function session.data(data) 304 function session.data(data)
281 -- Parse the data, which will store stanzas in session.pending_stanzas 305 -- Parse the data, which will store stanzas in session.pending_stanzas
282 if data then 306 if data then
283 data = filter("bytes/in", data); 307 data = filter("bytes/in", data);
284 if data then 308 if data then
285 local ok, err = stream:feed(data); 309 local ok, err = stream:feed(data);
286 if not ok then 310 if not ok then
287 log("debug", "Received invalid XML (%s) %d bytes: %s", tostring(err), #data, data:sub(1, 300):gsub("[\r\n]+", " "):gsub("[%z\1-\31]", "_")); 311 log("debug", "Received invalid XML (%s) %d bytes: %q", err, #data, data:sub(1, 300));
288 session:close("not-well-formed"); 312 if err == "stanza-too-large" then
313 session:close({ condition = "policy-violation", text = "XML stanza is too big" });
314 else
315 session:close("not-well-formed");
316 end
289 end 317 end
290 end 318 end
291 end 319 end
292 end 320 end
293 321
326 if session then 354 if session then
327 return (hosts[session.host] or prosody).events.fire_event("c2s-read-timeout", { session = session }); 355 return (hosts[session.host] or prosody).events.fire_event("c2s-read-timeout", { session = session });
328 end 356 end
329 end 357 end
330 358
359 function listener.ondrain(conn)
360 local session = sessions[conn];
361 if session then
362 return (hosts[session.host] or prosody).events.fire_event("c2s-ondrain", { session = session });
363 end
364 end
365
331 local function keepalive(event) 366 local function keepalive(event)
332 local session = event.session; 367 local session = event.session;
333 if not session.notopen then 368 if not session.notopen then
334 return event.session.send(' '); 369 return event.session.send(' ');
335 end 370 end
358 name = "c2s"; 393 name = "c2s";
359 listener = listener; 394 listener = listener;
360 default_port = 5222; 395 default_port = 5222;
361 encryption = "starttls"; 396 encryption = "starttls";
362 multiplex = { 397 multiplex = {
398 protocol = "xmpp-client";
363 pattern = "^<.*:stream.*%sxmlns%s*=%s*(['\"])jabber:client%1.*>"; 399 pattern = "^<.*:stream.*%sxmlns%s*=%s*(['\"])jabber:client%1.*>";
364 }; 400 };
365 }); 401 });
366 402
367 module:provides("net", { 403 module:provides("net", {