commit 2e5224f: [Minor] Use lua_smtp for dmarc reports

Vsevolod Stakhov vsevolod at highsecure.ru
Sat May 25 13:49:07 UTC 2019


Author: Vsevolod Stakhov
Date: 2019-05-25 14:44:06 +0100
URL: https://github.com/rspamd/rspamd/commit/2e5224fcab08b302b96e031bff175326d6b20879 (HEAD -> master)

[Minor] Use lua_smtp for dmarc reports

---
 lualib/lua_smtp.lua       |   7 +-
 src/plugins/lua/dmarc.lua | 215 ++++++++++++++--------------------------------
 2 files changed, 72 insertions(+), 150 deletions(-)

diff --git a/lualib/lua_smtp.lua b/lualib/lua_smtp.lua
index c112295f7..05667992b 100644
--- a/lualib/lua_smtp.lua
+++ b/lualib/lua_smtp.lua
@@ -107,7 +107,12 @@ local function sendmail(opts, message, callback)
     -- DATA stage
     local function data_done_cb(merr, mdata)
       if no_error_read(merr, mdata, '3') then
-        conn:add_write(pre_quit_cb, {message, CRLF.. '.' .. CRLF})
+        if type(message) == 'string' then
+          conn:add_write(pre_quit_cb, {message, CRLF.. '.' .. CRLF})
+        else
+          table.insert(message, CRLF.. '.' .. CRLF)
+          conn:add_write(pre_quit_cb, message)
+        end
       end
     end
     local function data_cb(merr, _)
diff --git a/src/plugins/lua/dmarc.lua b/src/plugins/lua/dmarc.lua
index 333eb6f55..e9524c0b5 100644
--- a/src/plugins/lua/dmarc.lua
+++ b/src/plugins/lua/dmarc.lua
@@ -19,7 +19,6 @@ limitations under the License.
 
 local rspamd_logger = require "rspamd_logger"
 local mempool = require "rspamd_mempool"
-local rspamd_tcp = require "rspamd_tcp"
 local rspamd_url = require "rspamd_url"
 local rspamd_util = require "rspamd_util"
 local rspamd_redis = require "lua_redis"
@@ -47,14 +46,14 @@ local report_settings = {
   retries = 2,
   from_name = 'Rspamd',
 }
-local report_template = [[From: "%s" <%s>
-To: %s
-Subject: Report Domain: %s
-	Submitter: %s
-	Report-ID: <%s>
-Date: %s
+local report_template = [[From: "{% from_name %}" <{% from_addr %}>
+To: {% rcpt %}
+Subject: Report Domain: {% report_domain %}
+	Submitter: {% submitter %}
+	Report-ID: {% report_id %}
+Date: {% report_date %}
 MIME-Version: 1.0
-Message-ID: <%s>
+Message-ID: <{% message_id %}>
 Content-Type: multipart/mixed;
 	boundary="----=_NextPart_000_024E_01CC9B0A.AFE54C00"
 
@@ -64,17 +63,17 @@ This is a multipart message in MIME format.
 Content-Type: text/plain; charset="us-ascii"
 Content-Transfer-Encoding: 7bit
 
-This is an aggregate report from %s.
+This is an aggregate report from {% submitter %}.
 
-Report domain: %s
-Submitter: %s
-Report ID: %s
+Report domain: {% report_domain %}
+Submitter: {% submitter %}
+Report ID: {% report_id %}
 
 ------=_NextPart_000_024E_01CC9B0A.AFE54C00
 Content-Type: application/gzip
 Content-Transfer-Encoding: base64
 Content-Disposition: attachment;
-	filename="%s!%s!%s!%s.xml.gz"
+	filename="{% submitter %}!{% report_domain %}!{% report_start %}!{% report_end %}.xml.gz"
 
 ]]
 local report_footer = [[
@@ -817,7 +816,8 @@ if opts['reporting'] == true then
       end
       local function dmarc_report_xml()
         local entries = {}
-        report_id = string.format('%s.%d.%d', reporting_domain, report_start, report_end)
+        report_id = string.format('%s.%d.%d',
+            reporting_domain, report_start, report_end)
         lua_util.debugm(N, rspamd_config, 'new report: %s', report_id)
         local actions = {
           push = function(t)
@@ -854,13 +854,15 @@ if opts['reporting'] == true then
               end
             end
             if split[10] and split[10] ~= '' then
-              local tmp = rspamd_str_split(split[10], '|')
+              local tmp = lua_util.str_split(split[10], '|')
               for _, d in ipairs(tmp) do
-                table.insert(row.dkim_results, {domain = d, result = 'permerror'})
+                table.insert(row.dkim_results,
+                    {domain = d, result = 'permerror'})
               end
             end
             table.insert(entries, row)
           end,
+          -- TODO: please rework this shit
           header = function()
               return table.concat({
                 '<?xml version="1.0" encoding="utf-8"?><feedback><report_metadata><org_name>',
@@ -891,158 +893,73 @@ if opts['reporting'] == true then
           return f(p)
         end
       end
+
+
       local function send_report_via_email(xmlf, retry)
         if not retry then retry = 0 end
-        if retry > report_settings.retries then
-          rspamd_logger.errx(rspamd_config, "Couldn't send mail for %s: retries exceeded", reporting_domain)
-          return get_reporting_domain()
+
+        local function sendmail_cb(ret, err)
+          if not ret then
+            rspamd_logger.errx(rspamd_config, "Couldn't send mail for %s: %s", err)
+            if retry >= report_settings.retries then
+              rspamd_logger.errx(rspamd_config, "Couldn't send mail for %s: retries exceeded", reporting_domain)
+              return get_reporting_domain()
+            else
+              send_report_via_email(xmlf, retry + 1)
+            end
+          end
         end
+
+        -- Format message
         local tmp_addr = {}
         for k in pairs(reporting_addr) do
           table.insert(tmp_addr, k)
         end
+
         local encoded = rspamd_util.encode_base64(rspamd_util.gzip_compress(
               table.concat(
                 {xmlf('header'),
                  xmlf('entries'),
                  xmlf('footer')})), 73)
-        local function mail_cb(err, data, conn)
-          local function no_error(merr, mdata, wantcode)
-            wantcode = wantcode or '2'
-            if merr then
-              rspamd_logger.errx(ev_base, 'got error in tcp callback: %s', merr)
-              if conn then
-                conn:close()
-              end
-              send_report_via_email(xmlf, retry+1)
-              return false
-            end
-            if mdata then
-              if type(mdata) ~= 'string' then
-                mdata = tostring(mdata)
-              end
-              if string.sub(mdata, 1, 1) ~= wantcode then
-                rspamd_logger.errx(ev_base, 'got bad smtp response: %s', mdata)
-                if conn then
-                  conn:close()
-                end
-                send_report_via_email(xmlf, retry+1)
-                return false
-              end
-            else
-              rspamd_logger.errx(ev_base, 'no data')
-              if conn then
-                conn:close()
-              end
-              send_report_via_email(xmlf, retry+1)
-              return false
-            end
-            return true
-          end
-          local function all_done_cb(merr, mdata)
-            if conn then
-              conn:close()
-            end
-            get_reporting_domain()
-            return true
-          end
-          local function quit_done_cb(merr, mdata)
-            conn:add_read(all_done_cb, '\r\n')
-          end
-          local function quit_cb(merr, mdata)
-            if no_error(merr, mdata) then
-              conn:add_write(quit_done_cb, 'QUIT\r\n')
-            end
-          end
-          local function pre_quit_cb(merr, mdata)
-            if no_error(merr, '2') then
-              conn:add_read(quit_cb, '\r\n')
-            end
-          end
-          local function data_done_cb(merr, mdata)
-            if no_error(merr, mdata, '3') then
-              local atmp = {}
-              for k in pairs(reporting_addr) do
-                table.insert(atmp, k)
-              end
-              local addr_string = table.concat(atmp, ', ')
-              -- TODO: migrate to templates and remove this shit
-              local rhead = string.format(report_template:gsub("\n", "\r\n"),
-                  report_settings.from_name,
-                  report_settings.email,
-                  addr_string,
-                  reporting_domain,
-                  report_settings.domain,
-                  report_id,
-                  rspamd_util.time_to_string(rspamd_util.get_time()),
-                  rspamd_util.random_hex(12) .. '@rspamd', -- Message-id
-                  report_settings.domain, -- Plain text part
-                  reporting_domain,
-                  addr_string,
-                  report_id,
-                  report_settings.domain,
-                  reporting_domain,
-                  report_start, report_end)
-              conn:add_write(pre_quit_cb, {rhead,
-                                           encoded,
-                                           report_footer:gsub("\n", "\r\n"),
-                                           '\r\n.\r\n'})
-            end
-          end
-          local function data_cb(merr, mdata)
-            if no_error(merr, '2') then
-              conn:add_read(data_done_cb, '\r\n')
-            end
-          end
-          local function rcpt_done_cb(merr, mdata)
-            if no_error(merr, mdata) then
-              conn:add_write(data_cb, 'DATA\r\n')
-            end
-          end
-          local from_done_cb
-          local function rcpt_cb(merr, mdata)
-            if no_error(merr, '2') then
-              if tmp_addr[1] then
-                conn:add_read(from_done_cb, '\r\n')
-              else
-                conn:add_read(rcpt_done_cb, '\r\n')
-              end
-            end
-          end
-          from_done_cb = function(merr, mdata)
-            if no_error(merr, mdata) then
-              conn:add_write(rcpt_cb, {'RCPT TO: <', table.remove(tmp_addr), '>\r\n'})
-            end
-          end
-          local function from_cb(merr, mdata)
-            if no_error(merr, '2') then
-              conn:add_read(from_done_cb, '\r\n')
-            end
-          end
-            local function hello_done_cb(merr, mdata)
-            if no_error(merr, mdata) then
-              conn:add_write(from_cb, {'MAIL FROM: <', report_settings.email, '>\r\n'})
-            end
-          end
-          local function hello_cb(merr)
-            if no_error(merr, '2') then
-              conn:add_read(hello_done_cb, '\r\n')
-            end
-          end
-          if no_error(err, data) then
-            conn:add_write(hello_cb, {'HELO ', report_settings.helo, '\r\n'})
-          end
+        local atmp = {}
+        for k in pairs(reporting_addr) do
+          table.insert(atmp, k)
         end
-        rspamd_tcp.request({
+        local addr_string = table.concat(atmp, ', ')
+
+        local rhead = lua_util.jinja_template(report_template,
+            {
+              from_name = report_settings.from_name,
+              from_addr = report_settings.email,
+              rcpt = addr_string,
+              reporting_domain = reporting_domain,
+              submitter = report_settings.domain,
+              report_id = report_id,
+              report_date = rspamd_util.time_to_string(rspamd_util.get_time()),
+              message_id = rspamd_util.random_hex(12) .. '@rspamd',
+              start = report_start,
+              report_end = report_end
+            }, true)
+        local message = {
+          rhead:gsub("\n", "\r\n"),
+          encoded,
+          report_footer:gsub("\n", "\r\n")
+        }
+
+        local lua_smtp = require "lua_smtp"
+        lua_smtp.sendmail({
           ev_base = ev_base,
-          callback = mail_cb,
           config = rspamd_config,
-          stop_pattern = '\r\n',
           host = report_settings.smtp,
           port = report_settings.smtp_port,
           resolver = rspamd_config:get_resolver(),
-        })
+          from = report_settings.email,
+          recipients = tmp_addr,
+          helo =  report_settings.helo,
+        }, message, sendmail_cb)
       end
+
+
       local function make_report()
         if type(report_settings.override_address) == 'string' then
           reporting_addr = {[report_settings.override_address] = true}


More information about the Commits mailing list