]> source.dussan.org Git - rspamd.git/commitdiff
Rework ip_score module completely.
authorVsevolod Stakhov <vsevolod@highsecure.ru>
Thu, 26 Feb 2015 16:05:51 +0000 (16:05 +0000)
committerVsevolod Stakhov <vsevolod@highsecure.ru>
Thu, 26 Feb 2015 16:05:51 +0000 (16:05 +0000)
conf/modules.conf
src/plugins/lua/ip_score.lua

index 582ca5204a8fc79d7ec9baee0714feef3583b7ca..69d47b4a8f989343c511ffe087dd987045c8f7ac 100644 (file)
@@ -260,6 +260,15 @@ regexp {
     max_size = 1M;
 }
 
+ip_score {
+#      servers = "localhost";
+#   treshold = 100;
+#   reject_score = 3;
+#   no_action_score = -2;
+#   add_header_score = 1;
+#   whitelist = "file:///ip_map";
+}
+
 hfilter {
     helo_enabled = true;
     hostname_enabled = true;
index 6da59c3ed64cde56cd95b1794f56ffb192ae31ca..53f88acecbdc59229cd50464cda2127fded62bd2 100644 (file)
@@ -24,178 +24,192 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ]]--
 
--- IP score is a module that set ip score of specific ip and 
+-- IP score is a module that set ip score of specific ip and
 
 -- Default settings
-local keystorage_host = nil
-local keystorage_port = 0
+local default_port = 6379
+local upstreams = nil
 local metric = 'default'
 local reject_score = 3
 local add_header_score = 1
 local no_action_score = -2
 local symbol = 'IP_SCORE'
+local prefix = 'ip_score:'
 -- This score is used for normalization of scores from keystorage
-local normalize_score = 100 
+local normalize_score = 100
 local whitelist = nil
 local expire = 240
-local rspamd_redis = require "rspamd_redis"
 local rspamd_logger = require "rspamd_logger"
+local rspamd_redis = require "rspamd_redis"
+local upstream_list = require "rspamd_upstream_list"
+local _ = require "fun"
 
 -- Set score based on metric's action
 local ip_score_set = function(task)
-       -- Callback generator
-       local make_key_cb = function(ip)
-               local cb = function(task, err, data)
-                       if err then
-                               if string.find(err, 'not found') then 
-                                       -- Try to set this key
-                                       local cb_set = function(task, err, data)
-                                               if err then
-                                                       if err ~= 'OK' then
-                                                               rspamd_logger.info('got error: ' .. err)
-                                                       end
-                                               end
-                                       end
-                                       rspamd_redis.make_request(task, keystorage_host, keystorage_port, cb_set, 'SET %b %b %b', ip, expire, '0')
-                               else
-                                       rspamd_logger.info('got error while incrementing: ' .. err)
-                               end
-                       end
-               end
-               return cb
-       end
-       local action = task:get_metric_action(metric)
-       if action then
-               -- Check whitelist 
-               if whitelist then
-                       if task:get_from_ip():is_valid() and whitelist:get_key(task:get_from_ip()) then
-                               -- Address is whitelisted
-                               return
-                       end
-               end
-               -- Now check action
-               if action == 'reject' then
-                       local ip = task:get_from_ip()
-                       if ip:is_valid() then
-                               local cb = make_key_cb(ip)
-                               if reject_score > 0 then
-                                       rspamd_redis.make_request(task, keystorage_host, keystorage_port, cb, 'INCRBY %b %b', ip, reject_score)
-                               else
-                                       rspamd_redis.make_request(task, keystorage_host, keystorage_port, cb, 'DECRBY %b %b', ip, -reject_score)
-                               end
-                       end
-               elseif action == 'add header' then
-                       local ip = task:get_from_ip()
-                       if ip:is_valid() then
-                               local cb = make_key_cb(ip)
-                               if add_header_score > 0 then
-                                       rspamd_redis.make_request(task, keystorage_host, keystorage_port, cb, 'INCRBY %b %b', ip, add_header_score)
-                               else
-                                       rspamd_redis.make_request(task, keystorage_host, keystorage_port, cb, 'DECRBY %b %b', ip, -add_header_score)
-                               end
-                       end
-               elseif action == 'no action' then
-                       local ip = task:get_from_ip()
-                       if ip:is_valid() then
-                               local cb = make_key_cb(ip)
-                               if no_action_score > 0 then
-                                       rspamd_redis.make_request(task, keystorage_host, keystorage_port, cb, 'INCRBY %b %b', ip, no_action_score)
-                               else
-                                       rspamd_redis.make_request(task, keystorage_host, keystorage_port, cb, 'DECRBY %b %b', ip, -no_action_score)
-                               end
-                       end
-               end
-       end
+  -- Callback generator
+  local make_key_cb = function(ip)
+    local cb = function(task, err, data)
+      if err then
+        rspamd_logger.info('got error while IP score changing: ' .. err)
+      end
+    end
+    return cb
+  end
+  
+  local function process_action(ip, score)
+    local cmd = 'INCRBY'
+    local args = {}
+    table.insert(args, prefix .. ip:to_string())
+    if score > 0 then
+      table.insert(args, score)
+    else
+      cmd = 'DECRBY'
+      table.insert(args, -score)
+    end
+    
+    return cmd, args
+  end
+
+  local action = task:get_metric_action(metric)
+  local ip = task:get_from_ip()
+  if not ip or not ip:is_valid() then
+    return
+  end
+
+  -- Check whitelist
+  if whitelist then
+    if whitelist:get_key(ip) then
+      -- Address is whitelisted
+      return
+    end
+  end
+
+  local cmd, args
+  if action then
+    local cb = make_key_cb(ip)
+    -- Now check action
+    if action == 'reject' then
+      cmd, args = process_action(ip, reject_score)
+    elseif action == 'add header' then
+      cmd, args = process_action(ip, add_header_score)
+    elseif action == 'no action' then
+      cmd, args = process_action(ip, no_action_score)
+    end
+  end
+  
+  if cmd then
+    local upstream = upstreams:get_upstream_by_hash(ip:to_string())
+    local addr = upstream:get_addr()
+    rspamd_redis.make_request(task, addr, make_key_cb(ip), cmd, args)
+  end
 end
 
 -- Check score for ip in keystorage
 local ip_score_check = function(task)
-       local cb = function(task, err, data)
-               if err then
-                       -- Key is not found or error occured
-                       return
-               elseif data then
-                       local score = tonumber(data)
-                       -- Normalize
-                       if score > 0 and score > normalize_score then
-                               score = 1
-                       elseif score < 0 and score < -normalize_score then
-                               score = -1
-                       else
-                               score = score / normalize_score
-                       end
-                       task:insert_result(symbol, score)
-               end
-       end
-       local ip = task:get_from_ip()
-       if ip:is_valid() then
-               if whitelist then
-                       if whitelist:get_key(task:get_from_ip()) then
-                               -- Address is whitelisted
-                               return
-                       end
-               end
-               rspamd_redis.make_request(task, keystorage_host, keystorage_port, cb, 'GET %b', ip)
-       end
+  local cb = function(task, err, data)
+    if err then
+      -- Key is not found or error occurred
+      return
+    elseif data then
+      local score = tonumber(data)
+      if not score then
+        return
+      end
+      
+      -- Normalize
+      if score > 0 and score > normalize_score then
+        score = 1
+      elseif score < 0 and score < -normalize_score then
+        score = -1
+      else
+        score = score / normalize_score
+      end
+      task:insert_result(symbol, score)
+    end
+  end
+  local ip = task:get_from_ip()
+  if ip:is_valid() then
+    if whitelist then
+      if whitelist:get_key(task:get_from_ip()) then
+        -- Address is whitelisted
+        return
+      end
+    end
+    local upstream = upstreams:get_upstream_by_hash(ip:to_string())
+    local addr = upstream:get_addr()
+    rspamd_redis.make_request(task, addr, cb, 'GET', {prefix .. ip:to_string()})
+  end
 end
 
 
 -- Configuration options
 local configure_ip_score_module = function()
-       local opts =  rspamd_config:get_all_opt('ip_score')
-       if opts then
-               if opts['keystorage_host'] then
-                       keystorage_host = opts['keystorage_host']
-               end
-               if opts['keystorage_port'] then
-                       keystorage_port = opts['keystorage_port']
-               end
-               if opts['metric'] then
-                       metric = opts['metric']
-               end
-               if opts['reject_score'] then
-                       reject_score = opts['reject_score']
-               end
-               if opts['add_header_score'] then
-                       add_header_score = opts['add_header_score']
-               end
-               if opts['no_action_score'] then
-                       no_action_score = opts['no_action_score']
-               end
-               if opts['symbol'] then
-                       symbol = opts['symbol']
-               end
-               if opts['normalize_score'] then
-                       normalize_score = opts['normalize_score']
-               end
-               if opts['whitelist'] then
-                       whitelist = rspamd_config:add_radix_map(opts['whitelist'])
-               end
-               if opts['expire'] then
-                       expire = opts['expire']
-               end
-       end
+  local opts =  rspamd_config:get_all_opt('ip_score')
+  if opts then
+    if opts['keystorage_host'] then
+      keystorage_host = opts['keystorage_host']
+    end
+    if opts['keystorage_port'] then
+      keystorage_port = opts['keystorage_port']
+    end
+    if opts['metric'] then
+      metric = opts['metric']
+    end
+    if opts['reject_score'] then
+      reject_score = opts['reject_score']
+    end
+    if opts['add_header_score'] then
+      add_header_score = opts['add_header_score']
+    end
+    if opts['no_action_score'] then
+      no_action_score = opts['no_action_score']
+    end
+    if opts['symbol'] then
+      symbol = opts['symbol']
+    end
+    if opts['normalize_score'] then
+      normalize_score = opts['normalize_score']
+    end
+    if opts['threshold'] then
+      normalize_score = opts['normalize_score']
+    end
+    if opts['whitelist'] then
+      whitelist = rspamd_config:add_radix_map(opts['whitelist'])
+    end
+    if opts['expire'] then
+      expire = opts['expire']
+    end
+    if opts['prefix'] then
+      prefix = opts['prefix']
+    end
+  end
+  if opts['servers'] then
+    upstreams = upstream_list.create(opts['servers'], default_port)
+    if not upstreams then
+      rspamd_logger.err('no servers are specified')
+    end
+  end
 end
 
 -- Registration
 if rspamd_config:get_api_version() >= 9 then
-       rspamd_config:register_module_option('ip_score', 'keystorage_host', 'string')
-       rspamd_config:register_module_option('ip_score', 'keystorage_port', 'uint')
-       rspamd_config:register_module_option('ip_score', 'metric', 'string')
-       rspamd_config:register_module_option('ip_score', 'reject_score', 'int')
-       rspamd_config:register_module_option('ip_score', 'add_header_score', 'int')
-       rspamd_config:register_module_option('ip_score', 'no_action_score', 'int')
-       rspamd_config:register_module_option('ip_score', 'symbol', 'string')
-       rspamd_config:register_module_option('ip_score', 'normalize_score', 'uint')
-       rspamd_config:register_module_option('ip_score', 'whitelist', 'map')
-       rspamd_config:register_module_option('ip_score', 'expire', 'uint')
+  rspamd_config:register_module_option('ip_score', 'keystorage_host', 'string')
+  rspamd_config:register_module_option('ip_score', 'keystorage_port', 'uint')
+  rspamd_config:register_module_option('ip_score', 'metric', 'string')
+  rspamd_config:register_module_option('ip_score', 'reject_score', 'int')
+  rspamd_config:register_module_option('ip_score', 'add_header_score', 'int')
+  rspamd_config:register_module_option('ip_score', 'no_action_score', 'int')
+  rspamd_config:register_module_option('ip_score', 'symbol', 'string')
+  rspamd_config:register_module_option('ip_score', 'normalize_score', 'uint')
+  rspamd_config:register_module_option('ip_score', 'whitelist', 'map')
+  rspamd_config:register_module_option('ip_score', 'expire', 'uint')
 
-       configure_ip_score_module()
-       if keystorage_host and keystorage_port and normalize_score > 0 then
-               -- Register ip_score module
-               rspamd_config:register_symbol(symbol, 1.0, ip_score_check)
-               rspamd_config:register_post_filter(ip_score_set)
-       end
+  configure_ip_score_module()
+  if upstreams and normalize_score > 0 then
+    -- Register ip_score module
+    rspamd_config:register_symbol(symbol, 1.0, ip_score_check)
+    rspamd_config:register_post_filter(ip_score_set)
+  end
 else
-       rspamd_logger.err('cannot register module ip_score as it requires at least 9 version of lua API and rspamd >= 0.4.6')
+  rspamd_logger.err('cannot register module ip_score as it requires at least 9 version of lua API and rspamd >= 0.4.6')
 end