aboutsummaryrefslogtreecommitdiffstats
path: root/src/plugins/lua/ratelimit.lua
diff options
context:
space:
mode:
authorVsevolod Stakhov <vsevolod@highsecure.ru>2018-08-15 11:25:49 +0100
committerVsevolod Stakhov <vsevolod@highsecure.ru>2018-08-15 11:26:08 +0100
commitc5da4b573a5348dbc5aaa68c0629021d38794d35 (patch)
treef4f302b80526b2d7b3787102264a4125fabb47eb /src/plugins/lua/ratelimit.lua
parentd68c3d066be218cff691ebe4f8ed4fe1960b3f72 (diff)
downloadrspamd-c5da4b573a5348dbc5aaa68c0629021d38794d35.tar.gz
rspamd-c5da4b573a5348dbc5aaa68c0629021d38794d35.zip
[Fix] Fix dynamic buckets in ratelimits
Diffstat (limited to 'src/plugins/lua/ratelimit.lua')
-rw-r--r--src/plugins/lua/ratelimit.lua54
1 files changed, 31 insertions, 23 deletions
diff --git a/src/plugins/lua/ratelimit.lua b/src/plugins/lua/ratelimit.lua
index acf5b9a8e..c6caf6d41 100644
--- a/src/plugins/lua/ratelimit.lua
+++ b/src/plugins/lua/ratelimit.lua
@@ -65,7 +65,7 @@ local settings = {
local bucket_check_script = [[
local last = redis.call('HGET', KEYS[1], 'l')
local now = tonumber(KEYS[2])
- local dynr, dynb = 0, 0
+ local dynr, dynb, leaked = 0, 0, 0
if not last then
-- New bucket
redis.call('HSET', KEYS[1], 'l', KEYS[2])
@@ -73,7 +73,7 @@ local bucket_check_script = [[
redis.call('HSET', KEYS[1], 'dr', '10000')
redis.call('HSET', KEYS[1], 'db', '10000')
redis.call('EXPIRE', KEYS[1], KEYS[5])
- return {0, 0, 1, 1}
+ return {0, '0', '1', '1', '0'}
end
last = tonumber(last)
@@ -84,9 +84,10 @@ local bucket_check_script = [[
local rate = tonumber(KEYS[3])
dynr = tonumber(redis.call('HGET', KEYS[1], 'dr')) / 10000.0
rate = rate * dynr
- local leaked = ((now - last) * rate)
+ leaked = ((now - last) * rate)
burst = burst - leaked
redis.call('HINCRBYFLOAT', KEYS[1], 'b', -(leaked))
+ redis.call('HSET', KEYS[1], 'l', KEYS[2])
end
else
burst = 0
@@ -95,11 +96,11 @@ local bucket_check_script = [[
dynb = tonumber(redis.call('HGET', KEYS[1], 'db')) / 10000.0
- if (burst + 1) * dynb > tonumber(KEYS[4]) then
- return {1, tostring(burst), tostring(dynr), tostring(dynb)}
+ if (burst + 1) > tonumber(KEYS[4]) * dynb then
+ return {1, tostring(burst), tostring(dynr), tostring(dynb), tostring(leaked)}
end
- return {0, tostring(burst), tostring(dynr), tostring(dynb)}
+ return {0, tostring(burst), tostring(dynr), tostring(dynb), tostring(leaked)}
]]
local bucket_check_id
@@ -461,28 +462,35 @@ local function ratelimit_cb(task)
return function(err, data)
if err then
rspamd_logger.errx('cannot check limit %s: %s %s', prefix, err, data)
- elseif type(data) == 'table' and data[1] and data[1] == 1 then
- -- set symbol only and do NOT soft reject
- if settings.symbol then
- task:insert_result(settings.symbol, 0.0, lim_name .. "(" .. prefix .. ")")
+ elseif type(data) == 'table' and data[1] then
+ lua_util.debugm(N, task,
+ "got reply for limit %s (%s / %s); %s burst, %s:%s dyn, %s leaked",
+ prefix, bucket.burst, bucket.rate,
+ data[2], data[3], data[4], data[5])
+
+ if data[1] == 1 then
+ -- set symbol only and do NOT soft reject
+ if settings.symbol then
+ task:insert_result(settings.symbol, 0.0, lim_name .. "(" .. prefix .. ")")
+ rspamd_logger.infox(task,
+ 'set_symbol_only: ratelimit "%s(%s)" exceeded, (%s / %s): %s (%s:%s dyn)',
+ lim_name, prefix,
+ bucket.burst, bucket.rate,
+ data[2], data[3], data[4])
+ return
+ -- set INFO symbol and soft reject
+ elseif settings.info_symbol then
+ task:insert_result(settings.info_symbol, 1.0,
+ lim_name .. "(" .. prefix .. ")")
+ end
rspamd_logger.infox(task,
- 'set_symbol_only: ratelimit "%s(%s)" exceeded, (%s / %s): %s (%s:%s dyn)',
+ 'ratelimit "%s(%s)" exceeded, (%s / %s): %s (%s:%s dyn)',
lim_name, prefix,
bucket.burst, bucket.rate,
data[2], data[3], data[4])
- return
- -- set INFO symbol and soft reject
- elseif settings.info_symbol then
- task:insert_result(settings.info_symbol, 1.0,
- lim_name .. "(" .. prefix .. ")")
+ task:set_pre_result('soft reject',
+ message_func(task, lim_name, prefix, bucket))
end
- rspamd_logger.infox(task,
- 'ratelimit "%s(%s)" exceeded, (%s / %s): %s (%s:%s dyn)',
- lim_name, prefix,
- bucket.burst, bucket.rate,
- data[2], data[3], data[4])
- task:set_pre_result('soft reject',
- message_func(task, lim_name, prefix, bucket))
end
end
end