commit 2b9ee10: [Feature] DCC: Add bulkness and reputation checks to dcc
Vsevolod Stakhov
vsevolod at highsecure.ru
Sat Dec 29 12:21:05 UTC 2018
Author: Vsevolod Stakhov
Date: 2018-12-29 12:13:53 +0000
URL: https://github.com/rspamd/rspamd/commit/2b9ee10f8dd690bfc8c6c244f783d0555de9b0ab (HEAD -> master)
[Feature] DCC: Add bulkness and reputation checks to dcc
---
lualib/lua_scanners/dcc.lua | 81 +++++++++++++++++++++++++++++++++++++++------
src/plugins/lua/dcc.lua | 43 +++++++++++++++++++++---
2 files changed, 110 insertions(+), 14 deletions(-)
diff --git a/lualib/lua_scanners/dcc.lua b/lualib/lua_scanners/dcc.lua
index 27230fd6f..3d59f0f1b 100644
--- a/lualib/lua_scanners/dcc.lua
+++ b/lualib/lua_scanners/dcc.lua
@@ -104,7 +104,10 @@ local function dcc_check(task, content, _, rule)
timeout = rule.timeout or 2.0,
shutdown = true,
data = request_data,
- callback = dcc_callback
+ callback = dcc_callback,
+ body_max = 999999,
+ fuz1_max = 999999,
+ fuz2_max = 999999,
})
else
rspamd_logger.errx(task, '%s: failed to scan, maximum retransmits exceed', rule['symbol'], rule['type'])
@@ -117,25 +120,75 @@ local function dcc_check(task, content, _, rule)
lua_util.debugm(N, task, 'DCC result=%1 disposition=%2 header="%3"',
result, disposition, header)
- --[[
- @todo: Implement math function to calc the score dynamically based on return values. Maybe check spamassassin implementation.
- ]] --
-
if header then
local _,_,info = header:find("; (.-)$")
+
if (result == 'R') then
-- Reject
common.yield_result(task, rule, info, rule.default_score)
elseif (result == 'T') then
-- Temporary failure
rspamd_logger.warnx(task, 'DCC returned a temporary failure result: %s', result)
- task:insert_result(rule['symbol_fail'], 0.0, 'DCC returned a temporary failure result:' .. result)
+ task:insert_result(rule.symbol_fail,
+ 0.0,
+ 'tempfail:' .. result)
elseif result == 'A' then
- -- do nothing
if rule.log_clean then
- rspamd_logger.infox(task, '%s: clean, returned result A - info: %s', rule.log_prefix, info)
+ rspamd_logger.infox(task, '%s: clean, returned result A - info: %s',
+ rule.log_prefix, info)
else
- lua_util.debugm(N, task, '%s: returned result A - info: %s', rule.log_prefix, info)
+ lua_util.debugm(N, task, '%s: returned result A - info: %s',
+ rule.log_prefix, info)
+
+ local opts = {}
+ local score = 0.0
+ info = info:lower()
+ local rep = info:match('rep=([^=%s]+)')
+
+ -- Adjust reputation if available
+ if rep then rep = tonumber(rep) end
+ if not rep then
+ rep = 1.0
+ end
+
+ local function check_threshold(what, num, lim)
+ local rnum
+ if num == 'many' then
+ rnum = lim
+ else
+ rnum = tonumber(num)
+ end
+
+ if rnum and rnum >= lim then
+ opts[#opts + 1] = string.format('%s=%s', what, num)
+ score = score + rep / 3.0
+ end
+ end
+
+ info = info:lower()
+ local body = info:match('body=([^=%s]+)')
+
+ if body then
+ check_threshold('body', body, rule.body_max)
+ end
+
+ local fuz1 = info:match('fuz1=([^=%s]+)')
+
+ if fuz1 then
+ check_threshold('fuz1', fuz1, rule.fuz1_max)
+ end
+
+ local fuz2 = info:match('fuz2=([^=%s]+)')
+
+ if fuz2 then
+ check_threshold('fuz2', fuz2, rule.fuz2_max)
+ end
+
+ if #opts > 0 and score > 0 then
+ task:insert_result(rule.symbol_bulk,
+ score,
+ opts)
+ end
end
elseif result == 'G' then
-- do nothing
@@ -154,7 +207,9 @@ local function dcc_check(task, content, _, rule)
else
-- Unknown result
rspamd_logger.warnx(task, 'DCC result error: %1', result);
- task:insert_result(rule['symbol_fail'], 0.0, 'DCC result error: ' .. result)
+ task:insert_result(rule.symbol_fail,
+ 0.0,
+ 'error: ' .. result)
end
end
end
@@ -187,6 +242,12 @@ local function dcc_config(opts)
default_score = 1,
action = false,
client = '0.0.0.0',
+ symbol_fail = 'DCC_FAIL',
+ symbol = 'DCC_REJECT',
+ symbol_bulk = 'DCC_BULK',
+ body_max = 999999,
+ fuz1_max = 999999,
+ fuz2_max = 999999,
}
dcc_conf = lua_util.override_defaults(dcc_conf, opts)
diff --git a/src/plugins/lua/dcc.lua b/src/plugins/lua/dcc.lua
index d82ceda94..32cb6624b 100644
--- a/src/plugins/lua/dcc.lua
+++ b/src/plugins/lua/dcc.lua
@@ -19,6 +19,7 @@ limitations under the License.
local N = 'dcc'
local symbol_bulk = "DCC_BULK"
+local symbol = "DCC_REJECT"
local opts = rspamd_config:get_all_opt(N)
local rspamd_logger = require "rspamd_logger"
local dcc = require("lua_scanners").filter('dcc').dcc
@@ -32,6 +33,9 @@ dcc {
socket = "/var/dcc/dccifd"; # Unix socket
servers = "127.0.0.1:10045" # OR TCP upstreams
timeout = 2s; # Timeout to wait for checks
+ body_max = 999999; # Bulkness threshold for body
+ fuz1_max = 999999; # Bulkness threshold for fuz1
+ fuz2_max = 999999; # Bulkness threshold for fuz2
}
]])
return
@@ -58,21 +62,52 @@ if opts['host'] ~= nil and not opts['port'] then
end
-- WORKAROUND for deprecated host and port settings
-if not opts.symbol then opts.symbol = symbol_bulk end
+if not opts.symbol_bulk then opts.symbol_bulk = symbol_bulk end
+if not opts.symbol then opts.symbol = symbol end
+
rule = dcc.configure(opts)
if rule then
- rspamd_config:register_symbol({
- name = opts.symbol,
+ local id = rspamd_config:register_symbol({
+ name = 'DCC_CHECK',
callback = check_dcc
})
+ rspamd_config:register_symbol{
+ type = 'virtual',
+ parent = id,
+ name = opts.symbol
+ }
+ rspamd_config:register_symbol{
+ type = 'virtual',
+ parent = id,
+ name = opts.symbol_bulk
+ }
+ rspamd_config:register_symbol{
+ type = 'virtual',
+ parent = id,
+ name = 'DCC_FAIL'
+ }
rspamd_config:set_metric_symbol({
group = N,
- score = 2.0,
+ score = 1.0,
description = 'Detected as bulk mail by DCC',
one_shot = true,
+ name = opts.symbol_bulk,
+ })
+ rspamd_config:set_metric_symbol({
+ group = N,
+ score = 2.0,
+ description = 'Rejected by DCC',
+ one_shot = true,
name = opts.symbol,
})
+ rspamd_config:set_metric_symbol({
+ group = N,
+ score = 0.0,
+ description = 'DCC failure',
+ one_shot = true,
+ name = 'DCC_FAIL',
+ })
else
lua_util.disable_module(N, "config")
rspamd_logger.infox('DCC module not configured');
More information about the Commits
mailing list