aboutsummaryrefslogtreecommitdiffstats
path: root/src/plugins/lua/url_reputation.lua
diff options
context:
space:
mode:
authorAndrew Lewis <nerf@judo.za.org>2017-02-07 10:58:21 +0200
committerAndrew Lewis <nerf@judo.za.org>2017-02-07 10:58:21 +0200
commitd2432839763d867c3a666a61e43d2b6678e15279 (patch)
tree23822919b7526d50f753f6dad7de511c2826f146 /src/plugins/lua/url_reputation.lua
parent5840268601eec9e16a42395d60063afa5eb09628 (diff)
downloadrspamd-d2432839763d867c3a666a61e43d2b6678e15279.tar.gz
rspamd-d2432839763d867c3a666a61e43d2b6678e15279.zip
[Minor] Add URL tags plugin; drop functionality from URL reputation
- Also fix saving of tags - Reload scripts in URL reputation plugin
Diffstat (limited to 'src/plugins/lua/url_reputation.lua')
-rw-r--r--src/plugins/lua/url_reputation.lua233
1 files changed, 20 insertions, 213 deletions
diff --git a/src/plugins/lua/url_reputation.lua b/src/plugins/lua/url_reputation.lua
index 2c842a45f..056e6b30f 100644
--- a/src/plugins/lua/url_reputation.lua
+++ b/src/plugins/lua/url_reputation.lua
@@ -20,11 +20,10 @@ limitations under the License.
local E = {}
local N = 'url_reputation'
-local whitelist, redis_params, redis_set_script_sha, redis_incr_script_sha
+local whitelist, redis_params, redis_incr_script_sha
local settings = {
expire = 86400, -- 1 day
- key_prefix_tags = 'Ut.',
- key_prefix_rep = 'Ur.',
+ key_prefix = 'Ur.',
symbols = {
white = 'URL_REPUTATION_WHITE',
black = 'URL_REPUTATION_BLACK',
@@ -60,7 +59,6 @@ local scale = {
local rspamd_logger = require "rspamd_logger"
local rspamd_util = require "rspamd_util"
-local ucl = require "ucl"
-- This function is used for taskless redis requests (to load scripts)
local function redis_make_request(ev_base, cfg, key, is_write, callback, command, args)
@@ -114,49 +112,6 @@ local function redis_make_request(ev_base, cfg, key, is_write, callback, command
return ret,conn,addr
end
--- Tags are stored in format: [timestamp]|[tag1],[timestamp]|[tag2]
-local redis_set_script_head = 'local expiry = '
-local redis_set_script_tail = [[
-local now = math.floor(table.remove(ARGV))
-local res = redis.call('MGET', unpack(KEYS))
-for i = 1, #res do
- local tmp1, tmp2, metatags = {}, {}, {}
- if res[i] then
- for goo in string.gmatch(res[i], '[^/]+') do
- local time, tag, meta = string.match(goo, '(%d+)|([^|]+)|(.+)')
- if (time + expiry) > now then
- for m in string.gmatch(meta, '[^,]+') do
- metatags[m] = true
- end
- tmp1[tag] = {time, metatags}
- end
- end
- end
- local idx = string.find(ARGV[i], '|')
- if not idx then
- return redis.error_reply('bad arguments')
- end
- local t = string.sub(ARGV[i], 1, idx - 1)
- local m_str = string.sub(ARGV[i], idx + 1)
- if not tmp1[t] then
- tmp1[t] = {now, {}}
- else
- tmp1[t][1] = now
- end
- for mt in string.gmatch(m_str, '[^,]+') do
- tmp1[t][2][mt] = true
- end
- for k, v in pairs(tmp1) do
- local meta_list = {}
- for kk in pairs(v[2]) do
- table.insert(meta_list, kk)
- end
- table.insert(tmp2, v[1] .. '|' .. k .. '|' .. table.concat(meta_list, ','))
- end
- redis.call('SETEX', KEYS[i], expiry, table.concat(tmp2, '/'))
-end
-]]
-
local redis_incr_script = [[
for _, k in ipairs(KEYS) do
redis.call('INCR', k)
@@ -165,13 +120,6 @@ end
-- Function to load the script
local function load_scripts(cfg, ev_base)
- local function redis_set_script_cb(err, data)
- if err then
- rspamd_logger.errx(cfg, 'Set script loading failed: ' .. err)
- else
- redis_set_script_sha = tostring(data)
- end
- end
local function redis_incr_script_cb(err, data)
if err then
rspamd_logger.errx(cfg, 'Increment script loading failed: ' .. err)
@@ -179,19 +127,6 @@ local function load_scripts(cfg, ev_base)
redis_incr_script_sha = tostring(data)
end
end
- local set_script =
- redis_set_script_head ..
- settings.expire ..
- '\n' ..
- redis_set_script_tail
- redis_make_request(ev_base,
- rspamd_config,
- nil,
- true, -- is write
- redis_set_script_cb, --callback
- 'SCRIPT', -- command
- {'LOAD', set_script}
- )
redis_make_request(ev_base,
rspamd_config,
nil,
@@ -202,18 +137,8 @@ local function load_scripts(cfg, ev_base)
)
end
--- Saves tags and calculates URL reputation
-local function tags_save(task)
-
- -- Handle errors (reloads script if necessary)
- local function redis_set_cb(err)
- if err then
- rspamd_logger.errx(task, 'Redis error: %s', err)
- if string.match(err, 'NOSCRIPT') then
- load_scripts(rspamd_config, task:get_ev_base())
- end
- end
- end
+-- Calculates URL reputation
+local function url_reputation_check(task)
local tags = {}
local tlds = {}
@@ -222,63 +147,14 @@ local function tags_save(task)
local which
local confidence
- -- Save tags to redis and insert symbol
+ -- Insert symbol
local function insert_results()
if which and confidence then
task:insert_result(settings.symbols[scale[reputation]], confidence, which)
end
- -- Don't populate old tags
- local old_tags = task:get_mempool():get_variable('urltags')
- if old_tags then
- local parser = ucl.parser()
- local res, err = parser:parse_string(old_tags)
- if not res then
- rspamd_logger.errx(task, 'Parser error: %s', err)
- return
- end
- local obj = parser:get_object()
- for k, v in pairs(obj) do
- if tags[k] then
- for sk in pairs(v) do
- tags[k][sk] = nil
- end
- if not next(tags[k]) then
- tags[k] = nil
- end
- end
- end
- end
- -- Abort if no tags were found
- if not next(tags) then return end
- -- Prepare arguments to send to Redis
- local redis_keys = {}
- local redis_args = {}
- for dom, v in pairs(tags) do
- table.insert(redis_keys, settings.key_prefix_tags .. dom)
- for k, vv in pairs(v) do
- table.insert(redis_args, k .. '|' .. table.concat(vv, ','))
- end
- end
- local redis_final = {redis_set_script_sha}
- table.insert(redis_final, #redis_keys)
- for _, k in ipairs(redis_keys) do
- table.insert(redis_final, k)
- end
- for _, a in ipairs(redis_args) do
- table.insert(redis_final, a)
- end
- table.insert(redis_final, rspamd_util.get_time())
- rspamd_redis_make_request(task,
- redis_params,
- nil,
- true, -- is write
- redis_set_cb, --callback
- 'EVALSHA', -- command
- redis_final
- )
end
- -- Dynamic reputation is used in absence of tags
+ -- Calculate reputation
local function dynamic_reputation()
local subset = {}
@@ -288,6 +164,9 @@ local function tags_save(task)
local function redis_incr_cb(err)
if err then
rspamd_logger.errx(task, 'couldnt increment reputation: %s', err)
+ if string.match(err, 'NOSCRIPT') then
+ load_scripts(rspamd_config, task:get_ev_base())
+ end
end
end
@@ -344,8 +223,8 @@ local function tags_save(task)
rk = {
redis_incr_script_sha,
2,
- settings.key_prefix_rep .. which .. '_total',
- settings.key_prefix_rep .. which .. '_' .. scale[reputation],
+ settings.key_prefix .. which .. '_total',
+ settings.key_prefix .. which .. '_' .. scale[reputation],
}
else
-- No reputation found, pick some URLs
@@ -426,8 +305,8 @@ local function tags_save(task)
rspamd_logger.warnx(task, 'Not updating reputation on all TLDs')
break
end
- table.insert(rk, settings.key_prefix_rep .. t .. '_total')
- table.insert(rk, settings.key_prefix_rep .. t .. '_' .. scale[reputation])
+ table.insert(rk, settings.key_prefix .. t .. '_total')
+ table.insert(rk, settings.key_prefix .. t .. '_' .. scale[reputation])
added = added + 1
end
end
@@ -469,11 +348,11 @@ local function tags_save(task)
if (not whitelist) or (not whitelist:get_key(k)) then
added = added + 1
table.insert(subset, k)
- table.insert(keys, settings.key_prefix_rep .. k .. '_total')
- table.insert(keys, settings.key_prefix_rep .. k .. '_white')
- table.insert(keys, settings.key_prefix_rep .. k .. '_black')
- table.insert(keys, settings.key_prefix_rep .. k .. '_grey')
- table.insert(keys, settings.key_prefix_rep .. k .. '_neutral')
+ table.insert(keys, settings.key_prefix .. k .. '_total')
+ table.insert(keys, settings.key_prefix .. k .. '_white')
+ table.insert(keys, settings.key_prefix .. k .. '_black')
+ table.insert(keys, settings.key_prefix .. k .. '_grey')
+ table.insert(keys, settings.key_prefix .. k .. '_neutral')
end
end
@@ -519,72 +398,6 @@ local function tags_save(task)
end
end
-local function tags_restore(task)
- local urls
- local tlds = {}
- local tld_reverse = {}
- local mpool = task:get_mempool()
-
- local function redis_get_cb(err, data)
- if err then
- rspamd_logger.errx(task, 'Redis error: %s', err)
- return
- end
- local d_len = #data
- if d_len == 0 then return end
- local now = rspamd_util.get_time()
- local tracking = {}
- for i = 1, d_len do
- if type(data[i]) == 'string' then
- local tld = tld_reverse[i]
- for time, tag, meta in string.gmatch(data[i], '(%d+)|([^|]+)|(.+)') do
- if (time + settings.expire) > now then
- local metatags = {}
- for m in string.gmatch(meta, '[^,]+') do
- table.insert(metatags, m)
- end
- for _, idx in ipairs(tlds[tld]) do
- for _, ttag in ipairs(metatags) do
- urls[idx]:add_tag(tag, ttag, mpool)
- end
- end
- if not tracking[tld] then
- tracking[tld] = {}
- end
- tracking[tld][tag] = true
- end
- end
- end
- end
- mpool:set_variable('urltags', ucl.to_format(tracking, 'ucl'))
- end
-
- urls = task:get_urls(false)
- for idx = 1, #urls do
- local tld = urls[idx]:get_tld()
- tld_reverse[idx] = tld
- if not tlds[tld] then
- tlds[tld] = {}
- end
- table.insert(tlds[tld], idx)
- end
- local first = next(tlds)
- if first then
- local keys = {}
- for x in pairs(tlds) do
- table.insert(keys, settings.key_prefix_tags .. x)
- end
- rspamd_redis_make_request(task,
- redis_params,
- first,
- false, -- is write
- redis_get_cb, --callback
- 'MGET', -- command
- keys
- )
- end
-end
-
local opts = rspamd_config:get_all_opt(N)
if not opts then return end
redis_params = rspamd_parse_redis_server(N)
@@ -619,17 +432,11 @@ rspamd_config:add_on_load(function(cfg, ev_base, worker)
load_scripts(cfg, ev_base)
end)
local id = rspamd_config:register_symbol({
- name = 'URL_TAGS_SAVE',
+ name = 'URL_REPUTATION_CHECK',
type = 'postfilter',
- callback = tags_save,
+ callback = url_reputation_check,
priority = 10
})
-rspamd_config:register_symbol({
- name = 'URL_TAGS_RESTORE',
- type = 'prefilter',
- callback = tags_restore,
- priority = 5
-})
for _, v in pairs(settings.symbols) do
rspamd_config:register_symbol({
name = v,