blob: 6318bd23a2bf74f19641632872bda124066282ff [file] [log] [blame]
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01001rspamd_config.MAILCOW_AUTH = {
2 callback = function(task)
3 local uname = task:get_user()
4 if uname then
5 return 1
6 end
7 end
8}
9
10local monitoring_hosts = rspamd_config:add_map{
11 url = "/etc/rspamd/custom/monitoring_nolog.map",
12 description = "Monitoring hosts",
13 type = "regexp"
14}
15
16rspamd_config:register_symbol({
17 name = 'SMTP_ACCESS',
18 type = 'postfilter',
19 callback = function(task)
20 local util = require("rspamd_util")
21 local rspamd_logger = require "rspamd_logger"
22 local rspamd_ip = require 'rspamd_ip'
23 local uname = task:get_user()
24 local limited_access = task:get_symbol("SMTP_LIMITED_ACCESS")
25
26 if not uname then
27 return false
28 end
29
30 if not limited_access then
31 return false
32 end
33
34 local hash_key = 'SMTP_ALLOW_NETS_' .. uname
35
36 local redis_params = rspamd_parse_redis_server('smtp_access')
37 local ip = task:get_from_ip()
38
39 if ip == nil or not ip:is_valid() then
40 return false
41 end
42
43 local from_ip_string = tostring(ip)
44 smtp_access_table = {from_ip_string}
45
46 local maxbits = 128
47 local minbits = 32
48 if ip:get_version() == 4 then
49 maxbits = 32
50 minbits = 8
51 end
52 for i=maxbits,minbits,-1 do
53 local nip = ip:apply_mask(i):to_string() .. "/" .. i
54 table.insert(smtp_access_table, nip)
55 end
56 local function smtp_access_cb(err, data)
57 if err then
58 rspamd_logger.infox(rspamd_config, "smtp_access query request for ip %s returned invalid or empty data (\"%s\") or error (\"%s\")", ip, data, err)
59 return false
60 else
61 rspamd_logger.infox(rspamd_config, "checking ip %s for smtp_access in %s", from_ip_string, hash_key)
62 for k,v in pairs(data) do
63 if (v and v ~= userdata and v == '1') then
64 rspamd_logger.infox(rspamd_config, "found ip in smtp_access map")
65 task:insert_result(true, 'SMTP_ACCESS', 0.0, from_ip_string)
66 return true
67 end
68 end
69 rspamd_logger.infox(rspamd_config, "couldnt find ip in smtp_access map")
70 task:insert_result(true, 'SMTP_ACCESS', 999.0, from_ip_string)
71 return true
72 end
73 end
74 table.insert(smtp_access_table, 1, hash_key)
75 local redis_ret_user = rspamd_redis_make_request(task,
76 redis_params, -- connect params
77 hash_key, -- hash key
78 false, -- is write
79 smtp_access_cb, --callback
80 'HMGET', -- command
81 smtp_access_table -- arguments
82 )
83 if not redis_ret_user then
84 rspamd_logger.infox(rspamd_config, "cannot check smtp_access redis map")
85 end
86 end,
87 priority = 10
88})
89
90rspamd_config:register_symbol({
91 name = 'POSTMASTER_HANDLER',
92 type = 'prefilter',
93 callback = function(task)
94 local rcpts = task:get_recipients('smtp')
95 local rspamd_logger = require "rspamd_logger"
96 local lua_util = require "lua_util"
97 local from = task:get_from(1)
98
99 -- not applying to mails with more than one rcpt to avoid bypassing filters by addressing postmaster
100 if rcpts and #rcpts == 1 then
101 for _,rcpt in ipairs(rcpts) do
102 local rcpt_split = rspamd_str_split(rcpt['addr'], '@')
103 if #rcpt_split == 2 then
104 if rcpt_split[1] == 'postmaster' then
105 task:set_pre_result('accept', 'whitelisting postmaster smtp rcpt')
106 return
107 end
108 end
109 end
110 end
111
112 if from then
113 for _,fr in ipairs(from) do
114 local fr_split = rspamd_str_split(fr['addr'], '@')
115 if #fr_split == 2 then
116 if fr_split[1] == 'postmaster' and task:get_user() then
117 -- no whitelist, keep signatures
118 task:insert_result(true, 'POSTMASTER_FROM', -2500.0)
119 return
120 end
121 end
122 end
123 end
124
125 end,
126 priority = 10
127})
128
129rspamd_config:register_symbol({
130 name = 'KEEP_SPAM',
131 type = 'prefilter',
132 callback = function(task)
133 local util = require("rspamd_util")
134 local rspamd_logger = require "rspamd_logger"
135 local rspamd_ip = require 'rspamd_ip'
136 local uname = task:get_user()
137
138 if uname then
139 return false
140 end
141
142 local redis_params = rspamd_parse_redis_server('keep_spam')
143 local ip = task:get_from_ip()
144
145 if ip == nil or not ip:is_valid() then
146 return false
147 end
148
149 local from_ip_string = tostring(ip)
150 ip_check_table = {from_ip_string}
151
152 local maxbits = 128
153 local minbits = 32
154 if ip:get_version() == 4 then
155 maxbits = 32
156 minbits = 8
157 end
158 for i=maxbits,minbits,-1 do
159 local nip = ip:apply_mask(i):to_string() .. "/" .. i
160 table.insert(ip_check_table, nip)
161 end
162 local function keep_spam_cb(err, data)
163 if err then
164 rspamd_logger.infox(rspamd_config, "keep_spam query request for ip %s returned invalid or empty data (\"%s\") or error (\"%s\")", ip, data, err)
165 return false
166 else
167 for k,v in pairs(data) do
168 if (v and v ~= userdata and v == '1') then
169 rspamd_logger.infox(rspamd_config, "found ip in keep_spam map, setting pre-result")
170 task:set_pre_result('accept', 'ip matched with forward hosts')
171 end
172 end
173 end
174 end
175 table.insert(ip_check_table, 1, 'KEEP_SPAM')
176 local redis_ret_user = rspamd_redis_make_request(task,
177 redis_params, -- connect params
178 'KEEP_SPAM', -- hash key
179 false, -- is write
180 keep_spam_cb, --callback
181 'HMGET', -- command
182 ip_check_table -- arguments
183 )
184 if not redis_ret_user then
185 rspamd_logger.infox(rspamd_config, "cannot check keep_spam redis map")
186 end
187 end,
188 priority = 19
189})
190
191rspamd_config:register_symbol({
192 name = 'TLS_HEADER',
193 type = 'postfilter',
194 callback = function(task)
195 local rspamd_logger = require "rspamd_logger"
196 local tls_tag = task:get_request_header('TLS-Version')
197 if type(tls_tag) == 'nil' then
198 task:set_milter_reply({
199 add_headers = {['X-Last-TLS-Session-Version'] = 'None'}
200 })
201 else
202 task:set_milter_reply({
203 add_headers = {['X-Last-TLS-Session-Version'] = tostring(tls_tag)}
204 })
205 end
206 end,
207 priority = 12
208})
209
210rspamd_config:register_symbol({
211 name = 'TAG_MOO',
212 type = 'postfilter',
213 callback = function(task)
214 local util = require("rspamd_util")
215 local rspamd_logger = require "rspamd_logger"
216 local redis_params = rspamd_parse_redis_server('taghandler')
217 local rspamd_http = require "rspamd_http"
218 local rcpts = task:get_recipients('smtp')
219 local lua_util = require "lua_util"
220
221 local tagged_rcpt = task:get_symbol("TAGGED_RCPT")
222 local mailcow_domain = task:get_symbol("RCPT_MAILCOW_DOMAIN")
223
224 if tagged_rcpt and tagged_rcpt[1].options and mailcow_domain then
225 local tag = tagged_rcpt[1].options[1]
226 rspamd_logger.infox("found tag: %s", tag)
227 local action = task:get_metric_action('default')
228 rspamd_logger.infox("metric action now: %s", action)
229
230 if action ~= 'no action' and action ~= 'greylist' then
231 rspamd_logger.infox("skipping tag handler for action: %s", action)
232 return true
233 end
234
235 local function http_callback(err_message, code, body, headers)
236 if body ~= nil and body ~= "" then
237 rspamd_logger.infox(rspamd_config, "expanding rcpt to \"%s\"", body)
238
239 local function tag_callback_subject(err, data)
240 if err or type(data) ~= 'string' then
241 rspamd_logger.infox(rspamd_config, "subject tag handler rcpt %s returned invalid or empty data (\"%s\") or error (\"%s\") - trying subfolder tag handler...", body, data, err)
242
243 local function tag_callback_subfolder(err, data)
244 if err or type(data) ~= 'string' then
245 rspamd_logger.infox(rspamd_config, "subfolder tag handler for rcpt %s returned invalid or empty data (\"%s\") or error (\"%s\")", body, data, err)
246 else
247 rspamd_logger.infox("Add X-Moo-Tag header")
248 task:set_milter_reply({
249 add_headers = {['X-Moo-Tag'] = 'YES'}
250 })
251 end
252 end
253
254 local redis_ret_subfolder = rspamd_redis_make_request(task,
255 redis_params, -- connect params
256 body, -- hash key
257 false, -- is write
258 tag_callback_subfolder, --callback
259 'HGET', -- command
260 {'RCPT_WANTS_SUBFOLDER_TAG', body} -- arguments
261 )
262 if not redis_ret_subfolder then
263 rspamd_logger.infox(rspamd_config, "cannot make request to load tag handler for rcpt")
264 end
265
266 else
267 rspamd_logger.infox("user wants subject modified for tagged mail")
268 local sbj = task:get_header('Subject')
269 new_sbj = '=?UTF-8?B?' .. tostring(util.encode_base64('[' .. tag .. '] ' .. sbj)) .. '?='
270 task:set_milter_reply({
271 remove_headers = {['Subject'] = 1},
272 add_headers = {['Subject'] = new_sbj}
273 })
274 end
275 end
276
277 local redis_ret_subject = rspamd_redis_make_request(task,
278 redis_params, -- connect params
279 body, -- hash key
280 false, -- is write
281 tag_callback_subject, --callback
282 'HGET', -- command
283 {'RCPT_WANTS_SUBJECT_TAG', body} -- arguments
284 )
285 if not redis_ret_subject then
286 rspamd_logger.infox(rspamd_config, "cannot make request to load tag handler for rcpt")
287 end
288
289 end
290 end
291
292 if rcpts and #rcpts == 1 then
293 for _,rcpt in ipairs(rcpts) do
294 local rcpt_split = rspamd_str_split(rcpt['addr'], '@')
295 if #rcpt_split == 2 then
296 if rcpt_split[1] == 'postmaster' then
297 rspamd_logger.infox(rspamd_config, "not expanding postmaster alias")
298 else
299 rspamd_http.request({
300 task=task,
301 url='http://nginx:8081/aliasexp.php',
302 body='',
303 callback=http_callback,
304 headers={Rcpt=rcpt['addr']},
305 })
306 end
307 end
308 end
309 end
310
311 end
312 end,
313 priority = 19
314})
315
316rspamd_config:register_symbol({
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +0200317 name = 'BCC',
318 type = 'postfilter',
319 callback = function(task)
320 local util = require("rspamd_util")
321 local rspamd_http = require "rspamd_http"
322 local rspamd_logger = require "rspamd_logger"
323
324 local from_table = {}
325 local rcpt_table = {}
326
327 if task:has_symbol('ENCRYPTED_CHAT') then
328 return -- stop
329 end
330
331 local send_mail = function(task, bcc_dest)
332 local lua_smtp = require "lua_smtp"
333 local function sendmail_cb(ret, err)
334 if not ret then
335 rspamd_logger.errx(task, 'BCC SMTP ERROR: %s', err)
336 else
337 rspamd_logger.infox(rspamd_config, "BCC SMTP SUCCESS TO %s", bcc_dest)
338 end
339 end
340 if not bcc_dest then
341 return -- stop
342 end
343 lua_smtp.sendmail({
344 task = task,
345 host = os.getenv("IPV4_NETWORK") .. '.253',
346 port = 591,
347 from = task:get_from(stp)[1].addr,
348 recipients = bcc_dest,
349 helo = 'bcc',
350 timeout = 10,
351 }, task:get_content(), sendmail_cb)
352 end
353
354 -- determine from
355 local from = task:get_from('smtp')
356 if from then
357 for _, a in ipairs(from) do
358 table.insert(from_table, a['addr']) -- add this rcpt to table
359 table.insert(from_table, '@' .. a['domain']) -- add this rcpts domain to table
360 end
361 else
362 return -- stop
363 end
364
365 -- determine rcpts
366 local rcpts = task:get_recipients('smtp')
367 if rcpts then
368 for _, a in ipairs(rcpts) do
369 table.insert(rcpt_table, a['addr']) -- add this rcpt to table
370 table.insert(rcpt_table, '@' .. a['domain']) -- add this rcpts domain to table
371 end
372 else
373 return -- stop
374 end
375
376 local action = task:get_metric_action('default')
377 rspamd_logger.infox("metric action now: %s", action)
378
379 local function rcpt_callback(err_message, code, body, headers)
380 if err_message == nil and code == 201 and body ~= nil then
381 if action == 'no action' or action == 'add header' or action == 'rewrite subject' then
382 send_mail(task, body)
383 end
384 end
385 end
386
387 local function from_callback(err_message, code, body, headers)
388 if err_message == nil and code == 201 and body ~= nil then
389 if action == 'no action' or action == 'add header' or action == 'rewrite subject' then
390 send_mail(task, body)
391 end
392 end
393 end
394
395 if rcpt_table then
396 for _,e in ipairs(rcpt_table) do
397 rspamd_logger.infox(rspamd_config, "checking bcc for rcpt address %s", e)
398 rspamd_http.request({
399 task=task,
400 url='http://nginx:8081/bcc.php',
401 body='',
402 callback=rcpt_callback,
403 headers={Rcpt=e}
404 })
405 end
406 end
407
408 if from_table then
409 for _,e in ipairs(from_table) do
410 rspamd_logger.infox(rspamd_config, "checking bcc for from address %s", e)
411 rspamd_http.request({
412 task=task,
413 url='http://nginx:8081/bcc.php',
414 body='',
415 callback=from_callback,
416 headers={From=e}
417 })
418 end
419 end
420
421 return true
422 end,
423 priority = 20
424})
425
426rspamd_config:register_symbol({
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +0100427 name = 'DYN_RL_CHECK',
428 type = 'prefilter',
429 callback = function(task)
430 local util = require("rspamd_util")
431 local redis_params = rspamd_parse_redis_server('dyn_rl')
432 local rspamd_logger = require "rspamd_logger"
433 local envfrom = task:get_from(1)
434 local uname = task:get_user()
435 if not envfrom or not uname then
436 return false
437 end
438 local uname = uname:lower()
439
440 local env_from_domain = envfrom[1].domain:lower() -- get smtp from domain in lower case
441
442 local function redis_cb_user(err, data)
443
444 if err or type(data) ~= 'string' then
445 rspamd_logger.infox(rspamd_config, "dynamic ratelimit request for user %s returned invalid or empty data (\"%s\") or error (\"%s\") - trying dynamic ratelimit for domain...", uname, data, err)
446
447 local function redis_key_cb_domain(err, data)
448 if err or type(data) ~= 'string' then
449 rspamd_logger.infox(rspamd_config, "dynamic ratelimit request for domain %s returned invalid or empty data (\"%s\") or error (\"%s\")", env_from_domain, data, err)
450 else
451 rspamd_logger.infox(rspamd_config, "found dynamic ratelimit in redis for domain %s with value %s", env_from_domain, data)
452 task:insert_result('DYN_RL', 0.0, data, env_from_domain)
453 end
454 end
455
456 local redis_ret_domain = rspamd_redis_make_request(task,
457 redis_params, -- connect params
458 env_from_domain, -- hash key
459 false, -- is write
460 redis_key_cb_domain, --callback
461 'HGET', -- command
462 {'RL_VALUE', env_from_domain} -- arguments
463 )
464 if not redis_ret_domain then
465 rspamd_logger.infox(rspamd_config, "cannot make request to load ratelimit for domain")
466 end
467 else
468 rspamd_logger.infox(rspamd_config, "found dynamic ratelimit in redis for user %s with value %s", uname, data)
469 task:insert_result('DYN_RL', 0.0, data, uname)
470 end
471
472 end
473
474 local redis_ret_user = rspamd_redis_make_request(task,
475 redis_params, -- connect params
476 uname, -- hash key
477 false, -- is write
478 redis_cb_user, --callback
479 'HGET', -- command
480 {'RL_VALUE', uname} -- arguments
481 )
482 if not redis_ret_user then
483 rspamd_logger.infox(rspamd_config, "cannot make request to load ratelimit for user")
484 end
485 return true
486 end,
487 flags = 'empty',
488 priority = 20
489})
490
491rspamd_config:register_symbol({
492 name = 'NO_LOG_STAT',
493 type = 'postfilter',
494 callback = function(task)
495 local from = task:get_header('From')
Matthias Andreas Benkard12a57352021-12-28 18:02:04 +0100496 if from and (monitoring_hosts:get_key(from) or from == "watchdog@localhost") then
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +0100497 task:set_flag('no_log')
498 task:set_flag('no_stat')
499 end
500 end
501})