commit c82b20c: [Rework] Settings: Rework settings check

Vsevolod Stakhov vsevolod at highsecure.ru
Mon Feb 11 13:21:05 UTC 2019


Author: Vsevolod Stakhov
Date: 2019-02-11 13:18:33 +0000
URL: https://github.com/rspamd/rspamd/commit/c82b20c9ee82a0d204f7367e93d2f87a74154c52 (HEAD -> master)

[Rework] Settings: Rework settings check

---
 src/plugins/lua/settings.lua | 206 ++++++++++++++++++++-----------------------
 1 file changed, 98 insertions(+), 108 deletions(-)

diff --git a/src/plugins/lua/settings.lua b/src/plugins/lua/settings.lua
index 26c4ac02b..6cea01192 100644
--- a/src/plugins/lua/settings.lua
+++ b/src/plugins/lua/settings.lua
@@ -199,126 +199,112 @@ local function check_settings(task)
     return false
   end
 
-  local function check_specific_setting(rule_name, rule, ip, client_ip, from, rcpt,
-      user, auth_user, hostname, matched)
+  local function check_specific_setting(rule_name, rule, data, matched)
     local res = false
 
-    if rule.authenticated then
-      if auth_user then
-        res = true
-        matched[#matched + 1] = 'authenticated'
-      end
-      if not res then
-        return nil
-      end
+    local function ip_valid(ip)
+      return ip:is_valid()
     end
 
-    if rule['local'] then
-      if not ip or not ip:is_valid() then
-        return nil
+    local function not_empty(s)
+      return #s > 0
+    end
+
+    local function generic_check(value, to_check, check_func, what, valid_func)
+      if not to_check then return true end
+
+      if type(value) == 'function' then
+        value = value()
       end
 
-      if ip:is_local() then
-        matched[#matched + 1] = 'local'
-        res = true
+      if value then
+        if valid_func then
+          if not valid_func(value) then
+            return false
+          end
+        end
+
+        if not check_func then
+          check_func = function(a, b) return a == b end
+        end
+
+        local ret = fun.any(function(d)
+          return check_func(value, d)
+        end, to_check)
+        if ret then
+          res = true
+          matched[#matched + 1] = what
+        else
+          return false
+        end
       else
-        return nil
+        return false
       end
+
+      return true
     end
 
-    if rule.ip then
-      if not ip or not ip:is_valid() then
-        return nil
-      end
-      for _, ip_check in ipairs(rule.ip) do
-        res = check_ip_setting(ip_check, ip)
-        if res then
-          matched[#matched + 1] = 'ip'
-          break
-        end
-      end
-      if not res then
-        return nil
-      end
+    if not generic_check(data.ip, rule.ip,
+        check_ip_setting, 'ip', ip_valid) then
+      return nil
     end
 
-    if rule.client_ip then
-      if not client_ip or not client_ip:is_valid() then
-        return nil
-      end
-      for _, ip_check in ipairs(rule.client_ip) do
-        res = check_ip_setting(ip_check, client_ip)
-        if res then
-          matched[#matched + 1] = 'client_ip'
-          break
-        end
-      end
-      if not res then
-        return nil
-      end
+    if not generic_check(data.client_ip, rule.client_ip,
+        check_ip_setting, 'client_ip', ip_valid) then
+      return nil
     end
 
-    if rule.from then
-      if not from then
-        return nil
-      end
-      for _, from_check in ipairs(rule.from) do
-        res = check_addr_setting(from_check, from)
-        if res then
-          matched[#matched + 1] = 'from'
-          break
-        end
-      end
-      if not res then
-        return nil
-      end
+    if not generic_check(data.from, rule.from,
+        check_addr_setting, 'from') then
+      return nil
     end
 
-    if rule.rcpt then
-      if not rcpt then
-        return nil
-      end
-      for _, rcpt_check in ipairs(rule.rcpt) do
-        res = check_addr_setting(rcpt_check, rcpt)
+    if not generic_check(data.from_mime, rule.from_mime,
+        check_addr_setting, 'from_mime') then
+      return nil
+    end
 
-        if res then
-          matched[#matched + 1] = 'rcpt'
-          break
-        end
-      end
-      if not res then
-        return nil
-      end
+    if not generic_check(data.rcpt, rule.rcpt,
+        check_addr_setting, 'rcpt') then
+      return nil
     end
 
-    if rule.user then
-      if not user then
-        return nil
-      end
-      for _, user_check in ipairs(rule.user) do
-        res = check_addr_setting(user_check, user)
-        if res then
-          matched[#matched + 1] = 'user'
-          break
-        end
+    if not generic_check(data.rcpt_mime, rule.rcpt_mime,
+        check_addr_setting, 'rcpt_mime') then
+      return nil
+    end
+
+    if not generic_check(data.user, rule.user,
+        check_addr_setting, 'user') then
+      return nil
+    end
+
+    if not generic_check(data.hostname, rule.hostname,
+        check_addr_setting, 'hostname', not_empty) then
+      return nil
+    end
+
+    -- Non generic checks
+
+    if rule.authenticated then
+      if data.user[1] then
+        res = true
+        matched[#matched + 1] = 'authenticated'
       end
       if not res then
         return nil
       end
     end
 
-    if rule.hostname then
-      if #hostname == 0 then
+    if rule['local'] then
+      if not data.ip or not data.ip:is_valid() then
         return nil
       end
-      for _, hname_check in ipairs(rule.hostname) do
-        res = check_addr_setting(hname_check, hostname)
-        if res then
-          matched[#matched + 1] = 'hostname'
-          break
-        end
-      end
-      if not res then
+
+      if data.ip:is_local() then
+        matched[#matched + 1] = 'local'
+        res = true
+      else
         return nil
       end
     end
@@ -391,23 +377,28 @@ local function check_settings(task)
   end
 
   lua_util.debugm(N, task, "check for settings")
-  local ip = task:get_from_ip()
-  local client_ip = task:get_client_ip()
-  local from = task:get_from()
-  local rcpt = task:get_recipients()
+  local data = {
+    ip = task:get_from_ip(),
+    client_ip = task:get_client_ip(),
+    from = task:get_from(1),
+    from_mime = task:get_from(2),
+    rcpt = task:get_recipients(1),
+    rcpt_mime = task:get_recipients(2),
+    hostname = task:get_hostname() or '',
+    user = {}
+  }
+
   local uname = task:get_user()
-  local hostname = task:get_hostname() or ''
-  local user = {}
   if uname then
-    user[1] = {}
+    data.user[1] = {}
     local localpart, domainpart = string.gmatch(uname, "(.+)@(.+)")()
     if localpart then
-      user[1]["user"] = localpart
-      user[1]["domain"] = domainpart
-      user[1]["addr"] = uname
+      data.user[1]["user"] = localpart
+      data.user[1]["domain"] = domainpart
+      data.user[1]["addr"] = uname
     else
-      user[1]["user"] = uname
-      user[1]["addr"] = uname
+      data.user[1]["user"] = uname
+      data.user[1]["addr"] = uname
     end
   end
   -- Match rules according their order
@@ -417,11 +408,10 @@ local function check_settings(task)
     if not applied and settings[pri] then
       for _,s in ipairs(settings[pri]) do
         local matched = {}
-        local rule = check_specific_setting(s.name, s.rule,
-            ip, client_ip, from, rcpt, user, uname, hostname, matched)
+        local result = check_specific_setting(s.name, s.rule, data, matched)
 
         -- Can use xor here but more complicated for reading
-        if (rule and not s.rule.inverse) or (not rule and s.rule.inverse) then
+        if (result and not s.rule.inverse) or (not result and s.rule.inverse) then
           rspamd_logger.infox(task, "<%s> apply settings according to rule %s (%s matched)",
             task:get_message_id(), s.name, table.concat(matched, ','))
           if s.rule['apply'] then


More information about the Commits mailing list