]> source.dussan.org Git - rspamd.git/commitdiff
[Feature] Add Lua plugin spamtrap 1610/head
authorChristian Roessner <c@roessner-network-solutions.com>
Sun, 30 Apr 2017 11:09:03 +0000 (13:09 +0200)
committerChristian Roessner <c@roessner-network-solutions.com>
Tue, 2 May 2017 19:11:18 +0000 (21:11 +0200)
conf/modules.d/spamtrap.conf [new file with mode: 0644]
src/plugins/lua/spamtrap.lua [new file with mode: 0644]

diff --git a/conf/modules.d/spamtrap.conf b/conf/modules.d/spamtrap.conf
new file mode 100644 (file)
index 0000000..e6b676a
--- /dev/null
@@ -0,0 +1,50 @@
+# Please don't modify this file as your changes might be overwritten with
+# the next update.
+#
+# You can modify '$LOCAL_CONFDIR/rspamd.conf.local.override' to redefine
+# parameters defined on the top level
+#
+# You can modify '$LOCAL_CONFDIR/rspamd.conf.local' to add
+# parameters defined on the top level
+#
+# For specific modules or configuration you can also modify
+# '$LOCAL_CONFDIR/local.d/file.conf' - to add your options or rewrite defaults
+# '$LOCAL_CONFDIR/override.d/file.conf' - to override the defaults
+#
+# See https://rspamd.com/doc/tutorials/writing_rules.html for details
+
+# This module is *DISABLED* by default
+# If you need to enable it, then define the following line in
+# local.d/spamtrap.conf:
+#
+# enabled = true;
+#
+# You also need to define redis servers for this module
+
+spamtrap {
+  # Optionally set an action
+  #action = "no action";
+  # A map file containing regexp entries for spamtrap emails and domains
+  #map = file://$LOCAL_CONFDIR/maps.d/spamtrap.map
+  # Name of the symbol
+  #symbol = "SPAMTRAP";
+  # A score for this module
+  #score = 0.0;
+  # Flag to enable fuzzy learning
+  learn_fuzzy = false;
+  # Flag to enable bayes spam learning
+  learn_spam = false;
+  # Fuzzy flag
+  #fuzzy_flag = 1;
+  # Fuzzy weight
+  #fuzy_weight = 10;
+  # Redis key prefix
+  #key_prefix = 'sptr_';
+
+  # !!! Disabled by default !!!
+  enabled = false;
+
+  .include(try=true,priority=5) "${DBDIR}/dynamic/spamtrap.conf"
+  .include(try=true,priority=1,duplicate=merge) "$LOCAL_CONFDIR/local.d/spamtrap.conf"
+  .include(try=true,priority=10) "$LOCAL_CONFDIR/override.d/spamtrap.conf"
+}
diff --git a/src/plugins/lua/spamtrap.lua b/src/plugins/lua/spamtrap.lua
new file mode 100644 (file)
index 0000000..6ecd342
--- /dev/null
@@ -0,0 +1,146 @@
+--[[
+Copyright (c) 2016, Vsevolod Stakhov <vsevolod@highsecure.ru>
+Copyright (c) 2016, Andrew Lewis <nerf@judo.za.org>
+
+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.
+]]--
+
+-- A plugin that triggers, if a spam trapped email address was detected
+
+local rspamd_logger = require "rspamd_logger"
+local redis_params
+local use_redis = false;
+
+local settings = {
+  symbol = 'SPAMTRAP',
+  score = 0.0,
+  learn_fuzzy = true,
+  learn_spam = true,
+  fuzzy_flag = 1,
+  fuzzy_weight = 10.0,
+  key_prefix = 'sptr_'
+}
+
+local function spamtrap_cb(task)
+  local rcpts = task:get_recipients('smtp')
+  local called_for_domain = false
+  local target = nil
+
+  local function do_action(rcpt)
+    if settings['learn_fuzzy'] then
+      rspamd_plugins.fuzzy_check.learn(task, settings['fuzzy_flag'], settings['fuzzy_weight'])
+    end
+    if settings['learn_spam'] then
+      task:set_flag("learn_spam")
+    end
+    task:insert_result(settings['symbol'], settings['score'], rcpt)
+    if settings['action'] then
+      task:set_pre_result(settings['action'],
+          string.format('spamtrap found: <%s>', rcpt))
+    end
+  end
+
+  local function redis_spamtrap_cb(err, data)
+    if err ~= nil then
+      rspamd_logger.errx(task, 'redis_spamtrap_cb received error: %1', err)
+      return
+    end
+
+    if data and type(data) ~= 'userdata' then
+      do_action(target)
+    else
+      if not called_for_domain then
+        -- Recurse for @catchall domain
+        target = rcpts[1]['domain']:lower()
+        local key = settings['key_prefix'] .. '@' .. target
+        local ret = rspamd_redis_make_request(task,
+          redis_params, -- connect params
+          key, -- hash key
+          false, -- is write
+          redis_spamtrap_cb, -- callback
+          'GET', -- command
+          {key} -- arguments
+        )
+        if not ret then
+          rspamd_logger.errx(task, "redis request wasn't scheduled")
+        end
+        called_for_domain = true
+      else
+        return -- nothing found
+      end
+    end
+  end
+
+  -- Do not risk a FP by checking for more than one recipient
+  if rcpts and #rcpts == 1 then
+    target = rcpts[1]['addr']:lower()
+    if use_redis then
+      local key = settings['key_prefix'] .. target
+      local ret = rspamd_redis_make_request(task,
+        redis_params, -- connect params
+        key, -- hash key
+        false, -- is write
+        redis_spamtrap_cb, -- callback
+        'GET', -- command
+        {key} -- arguments
+      )
+      if not ret then
+        rspamd_logger.errx(task, "redis request wasn't scheduled")
+      end
+    else
+      if settings['map']:get_key(target) then
+        do_action(target)
+      else
+    end
+  end
+end
+
+-- Module setup
+local opts = rspamd_config:get_all_opt('spamtrap')
+if not (opts and type(opts) == 'table') then
+  rspamd_logger.infox(rspamd_config, 'module is unconfigured')
+  return
+end
+if opts then
+  for k,v in pairs(opts) do
+    settings[k] = v
+  end
+  if settings['map'] then
+    settings['name'] = settings['map']
+    settings['map'] = rspamd_config:add_map({
+      url = settings['name'],
+      description = "Spamtrap map for %s", settings['symbol'],
+      type = "regexp"
+    })
+  else
+    redis_params = rspamd_parse_redis_server('spamtrap')
+    if not redis_params then
+      rspamd_logger.errx(
+        rspamd_config, 'no redis servers are specified, disabling module')
+      return
+    end
+    use_redis = true;
+  end
+
+  local id = rspamd_config:register_symbol({
+    name = "SPAMTRAP_CHECK",
+    type = "postfilter",
+    callback = spamtrap_cb
+  })
+  rspamd_config:register_symbol({
+    name = settings['symbol'],
+    parent = id,
+    type = 'virtual',
+    score = settings.score
+  })
+end