From: Vsevolod Stakhov Date: Sat, 7 Oct 2017 14:55:58 +0000 (+0100) Subject: [Minor] Add basic DNS backend to the reputation plugin X-Git-Tag: 1.7.0~579 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=e528ad8f4d8057f0373cfe9c402873a3c4783206;p=rspamd.git [Minor] Add basic DNS backend to the reputation plugin --- diff --git a/src/plugins/lua/reputation.lua b/src/plugins/lua/reputation.lua index e97a7600f..e0ee5f268 100644 --- a/src/plugins/lua/reputation.lua +++ b/src/plugins/lua/reputation.lua @@ -25,7 +25,9 @@ local N = 'reputation' local rspamd_logger = require "rspamd_logger" local rspamd_util = require "rspamd_util" +local lua_util = require "lua_util" local rspamd_lua_utils = require "lua_util" +local hash = require 'rspamd_cryptobox_hash' local fun = require "fun" local redis_params = nil local default_expiry = 864000 -- 10 day by default @@ -75,16 +77,114 @@ local function reputation_dns_init(rule) return true end -local function reputation_dns_get_token(task, token) + +local function gen_token_key(token, rule) + local res = token + if rule.backend.config.hashed then + local hash_alg = rule.backend.config.hash_alg or "blake2" + local encoding = "base32" + + if rule.backend.config.hash_encoding then + encoding = rule.backend.config.hash_encoding + end + + local h = hash.create_specific(hash_alg, res) + if encoding == 'hex' then + res = h:hex() + elseif encoding == 'base64' then + res = h:base64() + else + res = h:base32() + end + end + + if rule.backend.config.hashlen then + res = string.sub(res, 1, rule.backend.config.hashlen) + end + + return res +end + +--[[ +-- Generic interface for get and set tokens functions: +-- get_token(task, rule, token, continuation), where `continuation` is the following function: +-- +-- function(err, token, values) ... end +-- `err`: string value for error (similar to redis or DNS callbacks) +-- `token`: string value of a token +-- `values`: table of key=number, parsed from backend. It is selector's duty +-- to deal with missing, invalid or other values +-- +-- set_token(task, rule, token, values, continuation_cb) +-- This function takes values, encodes them using whatever suitable format +-- and calls for continuation: +-- +-- function(err, token) ... end +-- `err`: string value for error (similar to redis or DNS callbacks) +-- `token`: string value of a token +-- +-- example of tokens: {'s': 0, 'h': 0, 'p': 1} +--]] + +local function reputation_dns_get_token(task, rule, token, continuation_cb) + local r = task:get_resolver() + local to_resolve = gen_token_key(token) + local dns_name = to_resolve .. '.' .. rule.backend.config.list + + local function dns_callback(_, to_resolve, results, err) + if err and (err ~= 'requested record is not found' and err ~= 'no records with this name') then + rspamd_logger.errx(task, 'error looking up %s: %s', to_resolve, err) + end + if not results then + rspamd_logger.debugm(N, task, 'DNS RESPONSE: label=%1 results=%2 error=%3 list=%4', + to_resolve, false, err, rule.backend.config.list) + else + rspamd_logger.debugm(N, task, 'DNS RESPONSE: label=%1 results=%2 error=%3 list=%4', + to_resolve, true, err, rule.backend.config.list) + end + + -- Now split tokens to list of values + if not err and results then + local values = {} + -- Format: key1=num1;key2=num2...keyn=numn + fun.each(function(e) + local vals = lua_util.rspamd_str_split(e, "=") + if vals and #vals == 2 then + local nv = tonumber[vals[2]] + if nv then + values[vals[1]] = nv + end + end + end, + lua_util.rspamd_str_split(results[1], ";")) + continuation_cb(nil, to_resolve, values) + else + continuation_cb(err, to_resolve, nil) + end + + task:inc_dns_req() + end + r:resolve_a({ + task = task, + name = dns_name, + callback = dns_callback, + forced = true, + }) end -local function reputation_redis_get_token(task, token) +local function reputation_redis_get_token(task, token, continuation_cb) end -local function reputation_redis_set_token(task, token, value) +local function reputation_redis_set_token(task, token, values, continuation_cb) end --- Backends are responsible for getting reputation tokens +--[[ Backends are responsible for getting reputation tokens + -- Common config options: + -- `hashed`: if `true` then apply hash function to the key + -- `hash_alg`: use specific hash type (`blake2` by default) + -- `hash_len`: strip hash to this amount of bytes (no strip by default) + -- `hash_encoding`: use specific hash encoding (base32 by default) +--]] local backends = { redis = { config = {