소스 검색

Rework ratelimit plugin

- 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 configuration
tags/1.1.0
Vsevolod Stakhov 8 년 전
부모
커밋
c73e9fc202
3개의 변경된 파일67개의 추가작업 그리고 33개의 파일을 삭제
  1. 17
    7
      conf/modules.d/ratelimit.conf
  2. 12
    11
      doc/markdown/modules/ratelimit.md
  3. 38
    15
      src/plugins/lua/ratelimit.lua

+ 17
- 7
conf/modules.d/ratelimit.conf 파일 보기

@@ -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;
}
}

+ 12
- 11
doc/markdown/modules/ratelimit.md 파일 보기

@@ -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

+ 38
- 15
src/plugins/lua/ratelimit.lua 파일 보기

@@ -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

Loading…
취소
저장