Mercurial > prosody-hg
comparison plugins/mod_s2s.lua @ 14122:8a4417d32b0f 13.0
mod_c2s,mod_s2s: Introduce separate pre-authentication stanza size limit
This should prevent unauthenticated resource use via the XML parser.
| author | Kim Alvefur <zash@zash.se> |
|---|---|
| date | Tue, 07 Apr 2026 20:35:41 +0200 |
| parents | a1fb05cbd44e |
| children | 791426dda30d |
comparison
equal
deleted
inserted
replaced
| 14120:0e9e3efa381f | 14122:8a4417d32b0f |
|---|---|
| 39 local opt_keepalives = module:get_option_boolean("s2s_tcp_keepalives", module:get_option_boolean("tcp_keepalives", true)); | 39 local opt_keepalives = module:get_option_boolean("s2s_tcp_keepalives", module:get_option_boolean("tcp_keepalives", true)); |
| 40 local secure_auth = module:get_option_boolean("s2s_secure_auth", false); -- One day... | 40 local secure_auth = module:get_option_boolean("s2s_secure_auth", false); -- One day... |
| 41 local secure_domains, insecure_domains = | 41 local secure_domains, insecure_domains = |
| 42 module:get_option_set("s2s_secure_domains", {})._items, module:get_option_set("s2s_insecure_domains", {})._items; | 42 module:get_option_set("s2s_secure_domains", {})._items, module:get_option_set("s2s_insecure_domains", {})._items; |
| 43 local require_encryption = module:get_option_boolean("s2s_require_encryption", true); | 43 local require_encryption = module:get_option_boolean("s2s_require_encryption", true); |
| 44 local stanza_size_limit = module:get_option_integer("s2s_stanza_size_limit", 1024*512, 10000); | 44 local unauthed_stanza_size_limit = module:get_option_integer("s2s_unauthed_stanza_size_limit", 10000, 1000); |
| 45 local authed_stanza_size_limit = module:get_option_integer("s2s_stanza_size_limit", 1024*512, 10000); | |
| 45 local sendq_size = module:get_option_integer("s2s_send_queue_size", 1024*32, 1); | 46 local sendq_size = module:get_option_integer("s2s_send_queue_size", 1024*32, 1); |
| 46 | 47 |
| 47 local advertised_idle_timeout = 14*60; -- default in all net.server implementations | 48 local advertised_idle_timeout = 14*60; -- default in all net.server implementations |
| 48 local network_settings = module:get_option("network_settings"); | 49 local network_settings = module:get_option("network_settings"); |
| 49 if type(network_settings) == "table" and type(network_settings.read_timeout) == "number" then | 50 if type(network_settings) == "table" and type(network_settings.read_timeout) == "number" then |
| 224 local from_host, to_host, stanza = event.from_host, event.to_host, event.stanza; | 225 local from_host, to_host, stanza = event.from_host, event.to_host, event.stanza; |
| 225 log("debug", "opening a new outgoing connection for this stanza"); | 226 log("debug", "opening a new outgoing connection for this stanza"); |
| 226 local host_session = s2s_new_outgoing(from_host, to_host); | 227 local host_session = s2s_new_outgoing(from_host, to_host); |
| 227 host_session.version = 1; | 228 host_session.version = 1; |
| 228 | 229 |
| 230 host_session.stanza_size_limit = unauthed_stanza_size_limit; | |
| 231 | |
| 229 -- Store in buffer | 232 -- Store in buffer |
| 230 host_session.bounce_sendq = bounce_sendq; | 233 host_session.bounce_sendq = bounce_sendq; |
| 231 host_session.sendq = queue.new(sendq_size); | 234 host_session.sendq = queue.new(sendq_size); |
| 232 host_session.sendq:push(st.clone(stanza)); | 235 host_session.sendq:push(st.clone(stanza)); |
| 233 log("debug", "stanza [%s] queued until connection complete", stanza.name); | 236 log("debug", "stanza [%s] queued until connection complete", stanza.name); |
| 268 return nil, "This host has disallow_s2s set"; | 271 return nil, "This host has disallow_s2s set"; |
| 269 end | 272 end |
| 270 module:hook("route/remote", route_to_existing_session, -1); | 273 module:hook("route/remote", route_to_existing_session, -1); |
| 271 module:hook("route/remote", route_to_new_session, -10); | 274 module:hook("route/remote", route_to_new_session, -10); |
| 272 module:hook("s2sout-stream-features", function (event) | 275 module:hook("s2sout-stream-features", function (event) |
| 273 if not (stanza_size_limit or advertised_idle_timeout) then return end | 276 local session = event.origin; |
| 277 if not (session.stanza_size_limit or advertised_idle_timeout) then return end | |
| 274 local limits = event.features:tag("limits", { xmlns = "urn:xmpp:stream-limits:0" }) | 278 local limits = event.features:tag("limits", { xmlns = "urn:xmpp:stream-limits:0" }) |
| 275 if stanza_size_limit then | 279 if session.stanza_size_limit then |
| 276 limits:text_tag("max-bytes", string.format("%d", stanza_size_limit)); | 280 limits:text_tag("max-bytes", string.format("%d", session.stanza_size_limit)); |
| 277 end | 281 end |
| 278 if advertised_idle_timeout then | 282 if advertised_idle_timeout then |
| 279 limits:text_tag("idle-seconds", string.format("%d", advertised_idle_timeout)); | 283 limits:text_tag("idle-seconds", string.format("%d", advertised_idle_timeout)); |
| 280 end | 284 end |
| 281 limits:up(); | 285 limits:up(); |
| 413 session.type = "s2sin"; | 417 session.type = "s2sin"; |
| 414 elseif session.type ~= "s2sin" and session.type ~= "s2sout" then | 418 elseif session.type ~= "s2sin" and session.type ~= "s2sout" then |
| 415 return false; | 419 return false; |
| 416 end | 420 end |
| 417 | 421 |
| 422 session.stanza_size_limit = authed_stanza_size_limit; | |
| 423 session.stream:set_stanza_size_limit(session.stanza_size_limit); | |
| 424 | |
| 418 if session.incoming and host then | 425 if session.incoming and host then |
| 419 if not session.hosts[host] then session.hosts[host] = {}; end | 426 if not session.hosts[host] then session.hosts[host] = {}; end |
| 420 session.hosts[host].authed = true; | 427 session.hosts[host].authed = true; |
| 421 end | 428 end |
| 422 session.log("debug", "connection %s->%s is now authenticated for %s", session.from_host, session.to_host, host); | 429 session.log("debug", "connection %s->%s is now authenticated for %s", session.from_host, session.to_host, host); |
| 571 (session.log or log)("warn", "No 'to' on stream header from %s means we can't offer any features", from or session.ip or "unknown host"); | 578 (session.log or log)("warn", "No 'to' on stream header from %s means we can't offer any features", from or session.ip or "unknown host"); |
| 572 module:fire_event("s2s-stream-features-legacy", { origin = session, features = features }); | 579 module:fire_event("s2s-stream-features-legacy", { origin = session, features = features }); |
| 573 end | 580 end |
| 574 | 581 |
| 575 if ( session.type == "s2sin" or session.type == "s2sout" ) or features.tags[1] then | 582 if ( session.type == "s2sin" or session.type == "s2sout" ) or features.tags[1] then |
| 576 if stanza_size_limit or advertised_idle_timeout then | 583 if session.stanza_size_limit or advertised_idle_timeout then |
| 577 features:reset(); | 584 features:reset(); |
| 578 local limits = features:tag("limits", { xmlns = "urn:xmpp:stream-limits:0" }); | 585 local limits = features:tag("limits", { xmlns = "urn:xmpp:stream-limits:0" }); |
| 579 if stanza_size_limit then | 586 if session.stanza_size_limit then |
| 580 limits:text_tag("max-bytes", string.format("%d", stanza_size_limit)); | 587 limits:text_tag("max-bytes", string.format("%d", session.stanza_size_limit)); |
| 581 end | 588 end |
| 582 if advertised_idle_timeout then | 589 if advertised_idle_timeout then |
| 583 limits:text_tag("idle-seconds", string.format("%d", advertised_idle_timeout)); | 590 limits:text_tag("idle-seconds", string.format("%d", advertised_idle_timeout)); |
| 584 end | 591 end |
| 585 features:reset(); | 592 features:reset(); |
| 792 end | 799 end |
| 793 end | 800 end |
| 794 | 801 |
| 795 -- Session initialization logic shared by incoming and outgoing | 802 -- Session initialization logic shared by incoming and outgoing |
| 796 local function initialize_session(session) | 803 local function initialize_session(session) |
| 797 local stream = new_xmpp_stream(session, stream_callbacks, stanza_size_limit); | 804 local stream = new_xmpp_stream(session, stream_callbacks, session.stanza_size_limit or unauthed_stanza_size_limit); |
| 798 | 805 |
| 799 session.thread = runner(function (item) | 806 session.thread = runner(function (item) |
| 800 if st.is_stanza(item) then | 807 if st.is_stanza(item) then |
| 801 core_process_stanza(session, item); | 808 core_process_stanza(session, item); |
| 802 else | 809 else |
