]> source.dussan.org Git - rspamd.git/commitdiff
Start lua-settings implementation.
authorVsevolod Stakhov <vsevolod@highsecure.ru>
Mon, 18 Aug 2014 15:45:55 +0000 (16:45 +0100)
committerVsevolod Stakhov <vsevolod@highsecure.ru>
Mon, 18 Aug 2014 15:45:55 +0000 (16:45 +0100)
src/plugins/lua/settings.lua [new file with mode: 0644]

diff --git a/src/plugins/lua/settings.lua b/src/plugins/lua/settings.lua
new file mode 100644 (file)
index 0000000..bed01c4
--- /dev/null
@@ -0,0 +1,209 @@
+-- This plugin implements user dynamic settings
+-- Settings documentation can be found here:
+-- https://rspamd.com/doc/configuration/settings.html
+
+local set_section = rspamd_config:get_key("settings")
+local settings = {}
+
+-- Functional utilities
+local function filter(func, tbl)
+  local newtbl= {}
+  for i,v in pairs(tbl) do
+    if func(v) then
+      newtbl[i]=v
+    end
+  end
+  return newtbl
+end
+
+-- Check limit for a task
+local function check_settings(task)
+
+end
+
+-- Process settings based on their priority
+local function process_settings_table(tbl)
+  local get_priority = function(elt)
+    local pri_tonum = function(p)
+      if p then
+        if type(p) == "number" then
+          return tonumber(p)
+        elseif type(p) == "string" then
+          if p == "high" then
+            return 3
+          elseif p == "medium" then
+            return 2
+          end
+          
+        end
+        
+      end
+      
+      return 1
+     end
+     
+     return pri_tonum(elt['priority'])
+  end
+   
+  -- Check the setting element internal data
+  local process_setting_elt = function(elt)
+    -- Process IP address
+    local function process_ip(ip)
+      local out = {}
+      
+      if type(ip) == "table" then
+        for i,v in ipairs(ip) do 
+          table.insert(out, process_ip(v))
+        end
+      elseif type(ip) == "string" then
+        local slash = string.find(ip, '/')
+        
+        if not slash then
+          -- Just a plain IP address
+          local res = rspamd_ip.from_string(ip)
+          
+          if res:is_valid() then
+            table.insert(out, {res, 0})
+          else
+            rspamd_logger.err("bad IP address: " .. ip)
+            return nil
+          end
+        else
+          local res = rspamd_ip.from_string(string.sub(ip, 1, slash))
+          local mask = tonumber(string.sub(ip, slash + 1))
+          
+          if res:is_valid() then
+            table.insert(out, {res, mask})
+          else
+            rspamd_logger.err("bad IP address: " .. ip)
+            return nil
+          end
+        end
+      else
+        return nil
+      end
+      
+      return out
+    end
+    
+    local process_addr = function(addr)
+      local out = {
+        name = {},
+        user = {},
+        domain = {},
+        regexp = {}
+      }
+      if type(addr) == "table" then
+        for i,v in ipairs(addr) do 
+          table.insert(out, process_addr(v))
+        end
+      elseif type(addr) == "string" then
+        if addr[1] == '/' then
+          -- It is a regexp
+          local re = rspamd_regexp.create(string.sub(addr, 2))
+          if re then
+            out['regexp'] = re
+            setmetatable(out, {
+              __gc = function(t) t['regexp']:destroy() end 
+            })
+          else
+            rspamd_logger.err("bad regexp: " .. addr)
+          end
+          
+        elseif addr[1] == '@' then
+          -- It is a domain if form @domain
+          out['domain'] = string.sub(addr, 2)
+        else
+          -- Check user@domain parts
+          local at = string.find(addr, '@')
+          if at then
+            -- It is full address
+            out['name'] = addr
+          else
+            -- It is a user
+            out['user'] = addr
+          end
+        end
+      else
+        return nil
+      end
+      
+      return out
+    end
+    
+    
+    local out = {
+      ip = {},
+      rcpt = {},
+      from = {}
+    }
+    if elt['ip'] then
+      local ip = process_ip(elt['ip'])
+      
+      if ip then
+        table.insert(out['ip'], ip)
+      end
+    end
+    if elt['from'] then
+      local from = process_addr(elt['from'])
+      
+      if from then
+        table.insert(out['from'], from)
+      end
+    end
+    if elt['rcpt'] then
+      local rcpt = process_addr(elt['rcpt'])
+      
+      if rcpt then
+        table.insert(out['rcpt'], rcpt)
+      end
+    end
+    
+    return out
+  end
+  
+  -- filter trash in the input
+  local ft = filter(
+    function(elt)
+      if type(elt) == "table" then
+        return true
+      end
+      return false
+    end, tbl)
+  -- clear all settings
+  
+  for k,v in pairs(settings) do settings[k]=nil end
+  -- fill new settings by priority
+  for k,v in pairs(ft) do
+    local pri = get_priority(v)
+    if not settings[pri] then
+      settings[pri] = {}
+    end
+    local s = process_setting_elt(v)
+    if s then
+      settings[pri][k] = s
+    end
+  end
+end
+
+-- Parse settings map from the ucl line
+local function process_settings_map(string)
+  local ucl_parser = require "ucl.parser"
+  local res,err = ucl_parser:parse_string(string)
+  if not res then
+    rspamd_log.warn('cannot parse settings map: ' .. err)
+  else
+    process_settings_table(res)
+  end
+end
+
+if type(set_section) == "string" then
+  -- Just a map of ucl
+  if rspamd_config:add_map(set_section, process_settings_map) then
+    rspamd_config:register_pre_filter(check_settings)
+  end
+elseif type(set_section) == "table" then
+  if process_settings_table(set_section) then
+    rspamd_config:register_pre_filter(check_settings)
+  end
+end
\ No newline at end of file