# HG changeset patch # User tmolitor # Date 1564445233 -7200 # Node ID 915e32d5a14795f0bd434bc789fa1d6dd5e82548 # Parent 6b0db0f2d57a6fa86a299e99e6c9ccf36044c815 mod_smacks: fix bug for missbehaving clients sending multiple acks in a row Missbehaving clients, sending multiple acks in a row (I'm looking at you Monal!) triggered the ack-loop-prevention code added in 2017, leaving unacked stanzas in the queue. This fixes the bug while still preventing ack-loops. diff -r 6b0db0f2d57a -r 915e32d5a147 mod_smacks/mod_smacks.lua --- a/mod_smacks/mod_smacks.lua Tue Jul 30 01:46:57 2019 +0200 +++ b/mod_smacks/mod_smacks.lua Tue Jul 30 02:07:13 2019 +0200 @@ -160,6 +160,10 @@ local function request_ack_if_needed(session, force, reason) local queue = session.outgoing_stanza_queue; if session.awaiting_ack == nil and not session.hibernating then + -- this check of last_queue_count prevents ack-loops if missbehaving clients report wrong + -- stanza counts. it is set when an is really sent (e.g. inside timer), preventing any + -- further requests until the queue count changes (either by incoming acks or by adding + -- more stanzas) if (#queue > max_unacked_stanzas and session.last_queue_count ~= #queue) or force then session.log("debug", "Queuing (in a moment) from %s - #queue=%d", reason, #queue); session.awaiting_ack = false; @@ -167,8 +171,9 @@ if not session.awaiting_ack and not session.hibernating then session.log("debug", "Sending (inside timer, before send)"); (session.sends2s or session.send)(st.stanza("r", { xmlns = session.smacks })) + session.awaiting_ack = true; + session.last_queue_count = #queue; session.log("debug", "Sending (inside timer, after send)"); - session.awaiting_ack = true; if not session.delayed_ack_timer then session.delayed_ack_timer = stoppable_timer(delayed_ack_timeout, function() delayed_ack_function(session); @@ -187,8 +192,6 @@ session.log("debug", "Calling delayed_ack_function directly (still waiting for ack)"); delayed_ack_function(session); end - - session.last_queue_count = #queue; end local function outgoing_stanza_filter(stanza, session) @@ -587,7 +590,6 @@ return false; -- Kick the session end session.log("debug", "Sending (read timeout)"); - session.awaiting_ack = false; (session.sends2s or session.send)(st.stanza("r", { xmlns = session.smacks })); session.awaiting_ack = true; if not session.delayed_ack_timer then