diff options
author | Vsevolod Stakhov <vsevolod@highsecure.ru> | 2018-12-26 14:59:14 +0000 |
---|---|---|
committer | Vsevolod Stakhov <vsevolod@highsecure.ru> | 2018-12-26 15:00:02 +0000 |
commit | 434255a2a71e508d1e1de2bda368572d62be7e3e (patch) | |
tree | c3d5730ab0a53d3f30fe16711fb7dbbb612411c3 /lualib/lua_scanners/common.lua | |
parent | e96cab20b996c1555ba0e5748057649c5ab82d8d (diff) | |
download | rspamd-434255a2a71e508d1e1de2bda368572d62be7e3e.tar.gz rspamd-434255a2a71e508d1e1de2bda368572d62be7e3e.zip |
[Rework] Lua_scanners: Further library split
Diffstat (limited to 'lualib/lua_scanners/common.lua')
-rw-r--r-- | lualib/lua_scanners/common.lua | 199 |
1 files changed, 199 insertions, 0 deletions
diff --git a/lualib/lua_scanners/common.lua b/lualib/lua_scanners/common.lua new file mode 100644 index 000000000..ad99137a2 --- /dev/null +++ b/lualib/lua_scanners/common.lua @@ -0,0 +1,199 @@ +--[[ +Copyright (c) 2018, Vsevolod Stakhov <vsevolod@highsecure.ru> + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +]]-- + +--[[[ +-- @module lua_scanners_common +-- This module contains common external scanners functions +--]] + +local rspamd_logger = require "rspamd_logger" +local lua_util = require "lua_util" +local lua_redis = require "lua_redis" + +local exports = {} + +local function match_patterns(default_sym, found, patterns) + if type(patterns) ~= 'table' then return default_sym end + if not patterns[1] then + for sym, pat in pairs(patterns) do + if pat:match(found) then + return sym + end + end + return default_sym + else + for _, p in ipairs(patterns) do + for sym, pat in pairs(p) do + if pat:match(found) then + return sym + end + end + end + return default_sym + end +end + +local function yield_result(task, rule, vname, N) + local all_whitelisted = true + if type(vname) == 'string' then + local symname = match_patterns(rule['symbol'], vname, rule['patterns']) + if rule['whitelist'] and rule['whitelist']:get_key(vname) then + rspamd_logger.infox(task, '%s: "%s" is in whitelist', rule['type'], vname) + return + end + task:insert_result(symname, 1.0, vname) + rspamd_logger.infox(task, '%s: virus found: "%s"', rule['type'], vname) + elseif type(vname) == 'table' then + for _, vn in ipairs(vname) do + local symname = match_patterns(rule['symbol'], vn, rule['patterns']) + if rule['whitelist'] and rule['whitelist']:get_key(vn) then + rspamd_logger.infox(task, '%s: "%s" is in whitelist', rule['type'], vn) + else + all_whitelisted = false + task:insert_result(symname, 1.0, vn) + rspamd_logger.infox(task, '%s: virus found: "%s"', rule['type'], vn) + end + end + end + if rule['action'] then + if type(vname) == 'table' then + if all_whitelisted then return end + vname = table.concat(vname, '; ') + end + task:set_pre_result(rule['action'], + lua_util.template(rule.message or 'Rejected', { + SCANNER = rule['type'], + VIRUS = vname, + }), N) + end +end + +local function message_not_too_large(task, content, rule) + local max_size = tonumber(rule.max_size) + if not max_size then return true end + if #content > max_size then + rspamd_logger.infox(task, "skip %s AV check as it is too large: %s (%s is allowed)", + rule.type, #content, max_size) + return false + end + return true +end + +local function need_av_check(task, content, rule) + return message_not_too_large(task, content, rule) +end + +local function check_av_cache(task, digest, rule, fn, N) + local key = digest + + local function redis_av_cb(err, data) + if data and type(data) == 'string' then + -- Cached + if data ~= 'OK' then + lua_util.debugm(N, task, 'got cached result for %s: %s', + key, data) + data = lua_util.str_split(data, '\v') + yield_result(task, rule, data, N) + else + lua_util.debugm(N, task, 'got cached result for %s: %s', + key, data) + end + else + if err then + rspamd_logger.errx(task, 'got error checking cache: %s', err) + end + fn() + end + end + + if rule.redis_params then + + key = rule['prefix'] .. key + + if lua_redis.redis_make_request(task, + rule.redis_params, -- connect params + key, -- hash key + false, -- is write + redis_av_cb, --callback + 'GET', -- command + {key} -- arguments) + ) then + return true + end + end + + return false +end + +local function save_av_cache(task, digest, rule, to_save, N) + local key = digest + + local function redis_set_cb(err) + -- Do nothing + if err then + rspamd_logger.errx(task, 'failed to save virus cache for %s -> "%s": %s', + to_save, key, err) + else + lua_util.debugm(N, task, 'saved cached result for %s: %s', + key, to_save) + end + end + + if type(to_save) == 'table' then + to_save = table.concat(to_save, '\v') + end + + if rule.redis_params then + key = rule['prefix'] .. key + + lua_redis.redis_make_request(task, + rule.redis_params, -- connect params + key, -- hash key + true, -- is write + redis_set_cb, --callback + 'SETEX', -- command + { key, rule['cache_expire'], to_save } + ) + end + + return false +end + +exports.yield_result = yield_result +exports.match_patterns = match_patterns +exports.need_av_check = need_av_check +exports.check_av_cache = check_av_cache +exports.save_av_cache = save_av_cache + +setmetatable(exports, { + __call = function(t, override) + for k, v in pairs(t) do + if _G[k] ~= nil then + local msg = 'function ' .. k .. ' already exists in global scope.' + if override then + _G[k] = v + print('WARNING: ' .. msg .. ' Overwritten.') + else + print('NOTICE: ' .. msg .. ' Skipped.') + end + else + _G[k] = v + end + end + end, +}) + +return exports
\ No newline at end of file |