- Switch to `rates` instead of old and stupid strings to setup - Check if a bucket is zero and disable the corresponding limits - Turn off all buckets by default - Check either `rcpt` or `user` buckets, not all together - Document new `rates` and `symbol` options - Inform user about what buckets are used in the configurationtags/1.1.0
@@ -1,11 +1,21 @@ | |||
ratelimit { | |||
.include(try=true,priority=1) "${DBDIR}/dynamic/ratelimit.conf" | |||
limit = "to:100:0.033333333"; | |||
limit = "to_ip:30:0.025"; | |||
limit = "to_ip_from:20:0.01666666667"; | |||
limit = "bounce_to:10:0.000555556"; | |||
limit = "bounce_to_ip:5:0.000277778"; | |||
limit = "user:20:0.01666666667"; | |||
rates { | |||
# Limit for all mail per recipient (burst 100, rate 2 per minute) | |||
to = [100, 0.033333333]; | |||
# Limit for all mail per one source ip (burst 30, rate 1.5 per minute) | |||
to_ip = [30, 0.025]; | |||
# Limit for all mail per one source ip and from address (burst 20, rate 1 per minute) | |||
to_ip_from = [20, 0.01666666667]; | |||
# Limit for all bounce mail (burst 10, rate 2 per hour) | |||
bounce_to = [10, 0.000555556]; | |||
# Limit for bounce mail per one source ip (burst 5, rate 1 per hour) | |||
bounce_to_ip = [5, 0.000277778]; | |||
# Limit for all mail per authenticated user (burst 20, rate 1 per minute) | |||
user = [20, 0.01666666667]; | |||
} | |||
# If symbol is specified, then it is inserted instead of setting result | |||
#symbol = "R_RATELIMIT"; | |||
whitelisted_rcpts = "postmaster,mailer-daemon"; | |||
max_rcpt = 5; | |||
} | |||
} |
@@ -39,26 +39,25 @@ Each bucket has two parameters: | |||
For example, a bucket with capacity `100` and leak `1` can accept up to 100 messages but then | |||
will accept not more than a message per second. | |||
By default, ratelimit module has the following settings: | |||
By default, ratelimit module has the following settings which disable all limits: | |||
~~~lua | |||
-- Default settings for limits, 1-st member is burst, second is rate and the third is numeric type | |||
local settings = { | |||
-- Limit for all mail per recipient (burst 100, rate 2 per minute) | |||
to = {[1] = 100, [2] = 0.033333333, [3] = 1}, | |||
to = {0, 0.033333333}, | |||
-- Limit for all mail per one source ip (burst 30, rate 1.5 per minute) | |||
to_ip = {[1] = 30, [2] = 0.025, [3] = 2}, | |||
to_ip = {0, 0.025}, | |||
-- Limit for all mail per one source ip and from address (burst 20, rate 1 per minute) | |||
to_ip_from = {[1] = 20, [2] = 0.01666666667, [3] = 3}, | |||
to_ip_from = {0, 0.01666666667}, | |||
-- Limit for all bounce mail (burst 10, rate 2 per hour) | |||
bounce_to = {[1] = 10, [2] = 0.000555556, [3] = 4}, | |||
bounce_to = {0, 0.000555556}, | |||
-- Limit for bounce mail per one source ip (burst 5, rate 1 per hour) | |||
bounce_to_ip = {[1] = 5 , [2] = 0.000277778, [3] = 5}, | |||
bounce_to_ip = {0, 0.000277778}, | |||
-- Limit for all mail per user (authuser) (burst 20, rate 1 per minute) | |||
user = {[1] = 20, [2] = 0.01666666667, [3] = 6} | |||
user = {0, 0.01666666667} | |||
} | |||
~~~ | |||
@@ -73,9 +72,9 @@ the value of this option is 'postmaster, mailer-daemon' | |||
- `whitelisted_ip` - a map of ip addresses or networks whitelisted | |||
- `max_rcpts` - do not apply ratelimit if it contains more than this value of recipients (5 by default). This | |||
option allows to avoid too many work for setting buckets if there are a lot of recipients in a message). | |||
- `limit` - allows to set limit for a specific category. This option should be in the following form: | |||
- `rates` - a table of allowed rates in form: | |||
type:burst:leak | |||
type = [burst,leak]; | |||
Where `type` is one of: | |||
@@ -86,4 +85,6 @@ Where `type` is one of: | |||
- `bounce_to_ip` | |||
`burst` is a capacity of a bucket and `leak` is a rate in messages per second. | |||
Both these attributes are floating point values. | |||
Both these attributes are floating point values. | |||
- `symbol` - if this option is specified, then `ratelimit` plugin just adds the corresponding symbol instead of setting pre-result, the value is scaled as $$ 2 * tanh(\frac{bucket}{threshold * 2}) $$, where `tanh` is the hyperbolic tanhent function |
@@ -31,20 +31,19 @@ local default_port = 6379 | |||
-- Default settings for limits, 1-st member is burst, second is rate and the third is numeric type | |||
local settings = { | |||
-- Limit for all mail per recipient (burst 100, rate 2 per minute) | |||
to = {[1] = 100, [2] = 0.033333333, [3] = 1}, | |||
to = {0, 0.033333333}, | |||
-- Limit for all mail per one source ip (burst 30, rate 1.5 per minute) | |||
to_ip = {[1] = 30, [2] = 0.025, [3] = 2}, | |||
to_ip = {0, 0.025}, | |||
-- Limit for all mail per one source ip and from address (burst 20, rate 1 per minute) | |||
to_ip_from = {[1] = 20, [2] = 0.01666666667, [3] = 3}, | |||
to_ip_from = {0, 0.01666666667}, | |||
-- Limit for all bounce mail (burst 10, rate 2 per hour) | |||
bounce_to = {[1] = 10, [2] = 0.000555556, [3] = 4}, | |||
bounce_to = {0, 0.000555556}, | |||
-- Limit for bounce mail per one source ip (burst 5, rate 1 per hour) | |||
bounce_to_ip = {[1] = 5 , [2] = 0.000277778, [3] = 5}, | |||
bounce_to_ip = {0, 0.000277778}, | |||
-- Limit for all mail per user (authuser) (burst 20, rate 1 per minute) | |||
user = {[1] = 20, [2] = 0.01666666667, [3] = 6} | |||
user = {0, 0.01666666667} | |||
} | |||
-- Senders that are considered as bounce | |||
local bounce_senders = {'postmaster', 'mailer-daemon', '', 'null', 'fetchmail-daemon', 'mdaemon'} | |||
@@ -259,24 +258,32 @@ local function rate_test_set(task, func) | |||
end | |||
-- Get user (authuser) | |||
local auser = task:get_user() | |||
if auser then | |||
if auser and settings['user'] > 0 then | |||
table.insert(args, {settings['user'], make_rate_key (auser, '<auth>', nil)}) | |||
end | |||
local is_bounce = check_bounce(from_user) | |||
if rcpts then | |||
if rcpts and not auser then | |||
_.each(function(r) | |||
if is_bounce then | |||
table.insert(args, {settings['bounce_to'], make_rate_key ('<>', r['addr'], nil)}) | |||
if ip then | |||
table.insert(args, {settings['bounce_to_ip'], make_rate_key ('<>', r['addr'], ip)}) | |||
if settings['bounce_to'][1] > 0 then | |||
table.insert(args, { settings['bounce_to'], make_rate_key('<>', r['addr'], nil) }) | |||
end | |||
if ip and settings['bounce_to_ip'][1] > 0 then | |||
table.insert(args, { settings['bounce_to_ip'], make_rate_key('<>', r['addr'], ip) }) | |||
end | |||
end | |||
table.insert(args, {settings['to'], make_rate_key (nil, r['addr'], nil)}) | |||
if settings['to'][1] > 0 then | |||
table.insert(args, { settings['to'], make_rate_key(nil, r['addr'], nil) }) | |||
end | |||
if ip then | |||
table.insert(args, {settings['to_ip'], make_rate_key (nil, r['addr'], ip)}) | |||
table.insert(args, {settings['to_ip_from'], make_rate_key (from_addr, r['addr'], ip)}) | |||
if settings['to_ip'][1] > 0 then | |||
table.insert(args, { settings['to_ip'], make_rate_key(nil, r['addr'], ip) }) | |||
end | |||
if settings['to_ip_from'][1] > 0 then | |||
table.insert(args, { settings['to_ip_from'], make_rate_key(from_addr, r['addr'], ip) }) | |||
end | |||
end | |||
end, rcpts) | |||
end | |||
@@ -362,6 +369,22 @@ if opts then | |||
parse_limit(rates) | |||
end | |||
if opts['rates'] and type(opts['rates']) == 'table' then | |||
-- new way of setting limits | |||
_.each(function(t, lim) | |||
if type(lim) == 'table' and settings[t] then | |||
settings[t] = lim | |||
else | |||
rspamd_logger.errx(rspamd_config, 'bad rate: %s: %s', t, lim) | |||
end | |||
end, opts['rates']) | |||
end | |||
local enabled_limits = _.totable(_.map(function(t, lim) | |||
return t | |||
end, _.filter(function(t, lim) return lim[1] > 0 end, settings))) | |||
rspamd_logger.infox(rspamd_config, 'enabled rate buckets: %s', enabled_limits) | |||
if opts['whitelisted_rcpts'] and type(opts['whitelisted_rcpts']) == 'string' then | |||
whitelisted_rcpts = split(opts['whitelisted_rcpts'], ',') | |||
elseif type(opts['whitelisted_rcpts']) == 'table' then |