|
|
@@ -38,11 +38,15 @@ local default_expiry = 864000 -- 10 day by default |
|
|
|
-- Selectors are used to extract reputation tokens |
|
|
|
local ip_selector = { |
|
|
|
config = { |
|
|
|
actions = { -- how each action is treated in scoring |
|
|
|
['reject'] = 1.0, |
|
|
|
['add header'] = 0.25, |
|
|
|
['rewrite subject'] = 0.25, |
|
|
|
['no action'] = 1.0 |
|
|
|
-- keys map between actions and hash elements in bucket, |
|
|
|
-- h is for ham, |
|
|
|
-- s is for spam, |
|
|
|
-- p is for probable spam |
|
|
|
keys_map = { |
|
|
|
['reject'] = 's', |
|
|
|
['add header'] = 'p', |
|
|
|
['rewrite subject'] = 'p', |
|
|
|
['no action'] = 'h' |
|
|
|
}, |
|
|
|
scores = { -- how each component is evaluated |
|
|
|
['asn'] = 0.4, |
|
|
@@ -51,7 +55,6 @@ local ip_selector = { |
|
|
|
['ip'] = 1.0 |
|
|
|
}, |
|
|
|
symbol = 'IP_SCORE', -- symbol to be inserted |
|
|
|
hash = 'ip_score', -- hash table in redis used for storing scores |
|
|
|
asn_suffix = 'a:', -- prefix for ASN hashes |
|
|
|
country_suffix = 'c:', -- prefix for country hashes |
|
|
|
ipnet_suffix = 'n:', -- prefix for ipnet hashes |
|
|
@@ -172,10 +175,84 @@ local function reputation_dns_get_token(task, rule, token, continuation_cb) |
|
|
|
}) |
|
|
|
end |
|
|
|
|
|
|
|
local function reputation_redis_get_token(task, token, continuation_cb) |
|
|
|
local function reputation_redis_get_token(task, rule, token, continuation_cb) |
|
|
|
local key = gen_token_key(token) |
|
|
|
|
|
|
|
local function redis_get_cb(err, data) |
|
|
|
if data then |
|
|
|
if type(data) == 'table' then |
|
|
|
local values = {} |
|
|
|
for i=1,#data,2 do |
|
|
|
local ndata = tonumber(data[i + 1]) |
|
|
|
if ndata then |
|
|
|
values[data[i]] = ndata |
|
|
|
end |
|
|
|
end |
|
|
|
continuation_cb(nil, key, values) |
|
|
|
else |
|
|
|
rspamd_logger.errx(task, 'invalid type while getting reputation keys %s: %s', |
|
|
|
key, type(data)) |
|
|
|
continuation_cb("invalid type", key, nil) |
|
|
|
end |
|
|
|
|
|
|
|
elseif err then |
|
|
|
rspamd_logger.errx(task, 'got error while getting reputation keys %s: %s', |
|
|
|
key, err) |
|
|
|
continuation_cb(err, key, nil) |
|
|
|
else |
|
|
|
continuation_cb("unknown error", key, nil) |
|
|
|
end |
|
|
|
end |
|
|
|
|
|
|
|
local ret = rspamd_redis_make_request(task, |
|
|
|
redis_params, -- connect params |
|
|
|
key, -- hash key |
|
|
|
false, -- is write |
|
|
|
redis_get_cb, --callback |
|
|
|
'HGETALL', -- command |
|
|
|
{key} -- arguments |
|
|
|
) |
|
|
|
if not ret then |
|
|
|
rspamd_logger.errx(task, 'cannot make redis request to check results') |
|
|
|
end |
|
|
|
end |
|
|
|
|
|
|
|
local function reputation_redis_set_token(task, token, values, continuation_cb) |
|
|
|
local function reputation_redis_set_token(task, rule, token, values, continuation_cb) |
|
|
|
local key = gen_token_key(token) |
|
|
|
|
|
|
|
local ret,conn,upstream |
|
|
|
|
|
|
|
local function redis_set_cb(err, data) |
|
|
|
if err then |
|
|
|
rspamd_logger.errx(task, 'got error while setting reputation keys %s: %s', |
|
|
|
key, err) |
|
|
|
continuation_cb(err, key) |
|
|
|
else |
|
|
|
continuation_cb(nil, key) |
|
|
|
end |
|
|
|
end |
|
|
|
|
|
|
|
-- We start from expiry update |
|
|
|
ret,conn,upstream = rspamd_redis_make_request(task, |
|
|
|
redis_params, -- connect params |
|
|
|
nil, -- hash key |
|
|
|
true, -- is write |
|
|
|
redis_set_cb, --callback |
|
|
|
'EXPIRE', -- command |
|
|
|
{key, tostring(rule.backend.config.expiry)} -- arguments |
|
|
|
) |
|
|
|
-- Update greylisting record expire |
|
|
|
if ret then |
|
|
|
-- Here, we increment all hash keys that are listed in values |
|
|
|
-- E.g. {'s': 1.0} or {'h': -1.0}, floating point allows better flexibility |
|
|
|
fun.each(function(k, v) |
|
|
|
conn:add_cmd('HINCRBYFLOAT', {key, tostring(k), tostring(v)}) |
|
|
|
end, values) |
|
|
|
-- Add last modification time (might be not very consistent between updates) |
|
|
|
conn:add_cmd('HSET', {key, 'last', tostring(rspamd_util:get_calendar_ticks())}) |
|
|
|
else |
|
|
|
rspamd_logger.errx(task, 'got error while connecting to redis') |
|
|
|
end |
|
|
|
end |
|
|
|
|
|
|
|
--[[ Backends are responsible for getting reputation tokens |
|
|
@@ -195,6 +272,7 @@ local backends = { |
|
|
|
}, |
|
|
|
dns = { |
|
|
|
config = { |
|
|
|
-- list = rep.example.com |
|
|
|
}, |
|
|
|
get_token = reputation_dns_get_token, |
|
|
|
-- No set token for DNS |
|
|
@@ -335,7 +413,7 @@ local function parse_rule(name, tbl) |
|
|
|
end |
|
|
|
|
|
|
|
redis_params = rspamd_parse_redis_server('reputation') |
|
|
|
local opts = rspamd_config:get_all_opt("fann_redis") |
|
|
|
local opts = rspamd_config:get_all_opt("reputation") |
|
|
|
|
|
|
|
-- Initialization part |
|
|
|
if not (opts and type(opts) == 'table') then |