dnl dnl Поддержка RSPAMD dnl dnl ВНИМАНИЕ!!! dnl при использовании интеграции с rspamd необходимо включить использование dnl системного фильтра (см. параметр confSYSTEM_FILTER) dnl dnl команда получения названия и версии демона RSPAMD dnl define(`confRSPAMD_NAME_VERSION', `pkg_info -I rspamd\* | perl -p -e "s/^rspamd-(\S+).+\$/\$1/;s/\n//;"') dnl define(`confRSPAMD_NAME_VERSION_DEFAULT', `rspamd --help | grep -i rspamd | grep version | perl -p -e "s/^\s+//;s/\n//;"') dnl dnl параметры подключения к RSPAMD dnl define(`confRSPAMD_ADDRESS', `127.0.0.1 11333') dnl dnl используемый протокол dnl RSPAMC - использовать команду SYMBOL протокола RSPAMC/1.3 dnl HTTP_DLFUNC - использовать POST запрос к /checkv2 dnl define(`confRSPAMD_PROTO', `RSPAMC') dnl dnl действие в случае отсутствия ответа от RSPAMD либо возврата кода ошибки dnl NO - возвращать клиенту 4xx dnl YES - продолжать обработку письма dnl define(`confRSPAMD_DEFER_OK', `YES') dnl dnl действие для писем, опознанных как SPAM dnl REJECT - отказ в приеме письма (возврат клиенту кода 5xx) dnl DENY - синоним для REJECT dnl DROP - отказ в приеме сообщения с обрывом соединения dnl DISCARD - прием письма без доставки получателю dnl QUARANTINE - вывод в лог файл предупреждения и помещение письма в карантин dnl QUARANTINE_MAILLIST - сохранение в карантине писем из списков рассылки вместо отказа в приеме письма dnl (используется только одновременно с REJECT) dnl DISCARD_MAILLIST - игнорирование писем из списков рассылки вместо отказа в приеме письма dnl (используется только одновременно с REJECT) dnl define(`confRSPAMD_ACTION', `NO')dnl dnl если не будут указаны действия REJECT, DROP или DISCARD, то письмо будет просто помечено dnl действие QUARANTINE можно указывать вместо с REJECT и DISCARD через пробел dnl действия QUARANTINE_MAILLIST и DISCARD_MAILLIST можно указывать вместе с REJECT и DROP dnl dnl сообщение полностью исключается из проверки, если в значении $acl_m_wl_flag_msg dnl поля white_list_relays, white_list_senders или white_list_compat равны 1 dnl и поле spam_hater не равно 1 dnl dnl действие для старых заголовков dnl RENAME - переименование старых заголовков (в конец имени добавляется -Old) dnl REMOVE - удаление старых заголовков dnl NOTHING - оставлять заголовки без изменений dnl define(`confRSPAMD_OLD_HEADERS', `RENAME')dnl dnl dnl заголовки RSPAMD dnl define(`confRSPAMD_HEADERS', `:X-Spam-Action:X-Rspamd-Info:X-Rspamd-Version:X-Rspamd-Protocol-Version:X-Rspamd-Urls:X-Rspamd-Status:X-Rspamd-Score:X-Rspamd-Report:X-Rspamd-Message-ID:X-Rspamd-Message:X-Rspamd-Queue-Id:X-Rspamd-Bar:X-Spamd-Bar:X-Spamd-Result') dnl dnl стиль заголовков при использовании протокола HTTP: dnl DEFAULT dnl MILTER dnl define(`confRSPAMD_HTTP_HEADERS_STYLE', `DEFAULT')dnl dnl ifelse(SECTION, `MAIN', `dnl ifelse(confRSPAMD_PROTO, `HTTP_READSOCKET', `dnl define(`confMESSAGE_BODY_VISIBLE', lower(confCONTENT_SCANNING_MAX_MSG_SIZE))dnl ifelse(RIGHT(confMESSAGE_BODY_VISIBLE,1),`k',`define(`confMESSAGE_BODY_VISIBLE', eval(LEFT(confCONTENT_SCANNING_MAX_MSG_SIZE,-1)*1024))') ifelse(RIGHT(confMESSAGE_BODY_VISIBLE,1),`m',`define(`confMESSAGE_BODY_VISIBLE', eval(LEFT(confCONTENT_SCANNING_MAX_MSG_SIZE,-1)*1024*1024))') ')dnl ifelse(confRSPAMD_PROTO, `HTTP_READSOCKET', `') ')dnl ifelse(SECTION, `MAIN', `') ifelse(SECTION, `ACLS_ADDITIONAL', `dnl acl_check_data_rspamd: ifelse(confRSPAMD_PROTO, `RSPAMC', `dnl warn set acl_m0 = ${dlfunc{confDLFUNC_PATH/confDLFUNC_FNAME}{rspamd}\ {confRSPAMD_ADDRESS}{defer_ok}} # добавляем информацию о версии RSPAMD warn add_header = X-Rspamd-Version: _RSPAMD_VER_ on $primary_hostname\n set acl_m_contentscan_result = set acl_m_certainly_spam = set acl_m_rspamd_status = set acl_m_rspamd_score = set acl_m_rspamd_bar = set acl_m_rspamd_emails = set acl_m_rspamd_urls = set acl_m_rspamd_message_id = set acl_m_rspamd_messages = warn condition = ${if eq{$acl_m0}{}{yes}{no}} log_message = RSPAMD connection failed add_header = X-Rspamd-Info: RSPAMD check failed on $primary_hostname set acl_m_contentscan_result = defer warn condition = ${if eq{$acl_m0}{RSPAMD answer: }{yes}{no}} log_message = RSPAMD returned empty answer add_header = X-Rspamd-Info: returned empty answer on $primary_hostname set acl_m0 = set acl_m_contentscan_result = defer warn condition = ${if eq{$acl_m0}{}{no}{yes}} set acl_m0 = ${sg{${sg{$acl_m0}{\r\n}{\n}}}{\N\n+$\N}{\n}} condition = ${if match{$acl_m0}{\N^rspamd dlfunc:\s*\N}{yes}{no}} log_message = RSPAMD connection deferred: ${sg{$acl_m0}{\N^rspamd dlfunc:\s*\N}{}} add_header = X-Rspamd-Info: RSPAMD connection deferred on $primary_hostname: ${sg{$acl_m0}{\N^rspamd dlfunc:\s*\N}{}} set acl_m0 = set acl_m_contentscan_result = defer warn condition = ${if eq{$acl_m0}{}{no}{yes}} set acl_m1 = ${if match{$acl_m0}\ {\N^RSPAMD answer: RSPAMD/(\S+) 0 EX_OK\N}{$1}{}} set acl_m0 = ${sg{$acl_m0}{\N^RSPAMD answer: RSPAMD/.+?\n\N}{}} add_header = X-Rspamd-Protocol-Version: ${if eq{$acl_m1}{}{not found}{RSPAMC/$acl_m1}} # log_message = RSPAMD check: RSPAMD protocol version: ${if eq{$acl_m1}{}{not found}{$acl_m1}} warn condition = ${if eq{$acl_m0}{}{no}{yes}} set acl_m_rspamd_urls = ${if match{$acl_m0}{\N^((.+?\n)*?)Urls: ([^\n]*)\N}{$3}{}} set acl_m0 = ${if match{$acl_m0}{\N^((.+?\n)*?)Urls: ([^\n]*)\n((.*\n)*)$\N}{$1$4}{$acl_m0}} condition = ${if eq{$acl_m_rspamd_urls}{}{no}{yes}} set acl_m_rspamd_urls = ${sg{$acl_m_rspamd_urls}{\N, $\N}{}} warn condition = ${if eq{$acl_m0}{}{no}{yes}} set acl_m_rspamd_emails = ${if match{$acl_m0}{\N^((.+?\n)*?)Emails: ([^\n]*)\N}{$3}{}} set acl_m0 = ${if match{$acl_m0}{\N^((.+?\n)*?)Emails: ([^\n]*)\n((.*\n)*)$\N}{$1$4}{$acl_m0}} condition = ${if eq{$acl_m_rspamd_emails}{}{no}{yes}} set acl_m_rspamd_emails = ${sg{$acl_m_rspamd_emails}{\N, $\N}{}} warn condition = ${if eq{$acl_m0}{}{no}{yes}} set acl_m_rspamd_message_id = ${if match{$acl_m0}{\N^((.+?\n)*?)Message-ID: ([^\n]*)\N}{$3}{}} set acl_m0 = ${if match{$acl_m0}{\N^((.+?\n)*?)Message-ID: ([^\n]*)\n((.*\n)*)$\N}{$1$4}{$acl_m0}} condition = ${if eq{$acl_m_rspamd_message_id}{}{no}{yes}} set acl_m_rspamd_message_id = ${sg{$acl_m_rspamd_message_id}{\N, $\N}{}} warn condition = ${if eq{$acl_m0}{}{no}{yes}} set acl_m_rspamd_messages = ${if match{$acl_m0}{\N^((.+?\n)*?)((Message: [^\n]*\n)+)\N}{$3}{}} set acl_m0 = ${if match{$acl_m0}{\N^((.+?\n)*?)((Message: [^\n]*\n)+)((.*\n)*)$\N}{$1$5}{$acl_m0}} condition = ${if eq{$acl_m_rspamd_messages}{}{no}{yes}} set acl_m_rspamd_messages = ${sg{$acl_m_rspamd_messages}{\N, $\N}{}} set acl_m_rspamd_messages = ${sg{$acl_m_rspamd_messages}{\N^Message: \N}{}} set acl_m_rspamd_messages = ${sg{$acl_m_rspamd_messages}{\N\nMessage: \N}{\n}} warn condition = ${if eq{$acl_m_rspamd_message_id}{}{no}{yes}} # log_message = RSPAMD check: RSPAMD Message-ID: $acl_m_rspamd_message_id add_header = X-Rspamd-Message-ID: $acl_m_rspamd_message_id warn condition = ${if eq{$acl_m0}{}{no}{yes}} add_header = X-Rspamd-Queue-Id: $message_exim_id warn condition = ${if eq{$acl_m0}{}{no}{yes}} acl = acl_process_rspamd_answer warn condition = ${if match{$acl_m_rspamd_status}{Spam}{yes}{no}} set acl_m_rspamd_status = Spam add_header = X-Rspamd-Status: Spam log_message = RSPAMD check: Status is Spam set acl_m_certainly_spam = certainly_spam warn condition = ${if match{$acl_m_rspamd_status}{Probably spam}{yes}{no}} set acl_m_rspamd_status = Probably spam add_header = X-Rspamd-Status: Probably spam log_message = RSPAMD check: Status is Probably spam warn condition = ${if match{$acl_m_rspamd_status}{Ham}{yes}{no}} set acl_m_rspamd_status = Ham add_header = X-Rspamd-Status: Ham log_message = RSPAMD check: Status is Ham warn condition = ${if match{$acl_m_rspamd_status}{unknown}{yes}{no}} set acl_m_rspamd_status = unknown add_header = X-Rspamd-Status: unknown log_message = RSPAMD check: Status unknown warn condition = ${if eq{$acl_m_rspamd_score}{}{no}{yes}} set acl_m_rspamd_score_trunc = ${sg{${extract{1}{}{$acl_m_rspamd_score}}}{\N\..*$\N}{}} warn condition = ${if eq{$acl_m_rspamd_score}{}{no}{yes}} condition = ${if >{$acl_m_rspamd_score_trunc}{0}{yes}{no}} set acl_m_rspamd_bar = ${length{$acl_m_rspamd_score_trunc}{++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++}} warn condition = ${if eq{$acl_m_rspamd_score}{}{no}{yes}} condition = ${if <{$acl_m_rspamd_score_trunc}{0}{yes}{no}} set acl_m_rspamd_bar = ${length{${eval:(-1)*$acl_m_rspamd_score_trunc}}{--------------------------------------------------------------------------------------------------------------}} warn condition = ${if eq{$acl_m_rspamd_score}{}{no}{yes}} condition = ${if ={$acl_m_rspamd_score_trunc}{0}{yes}{no}} set acl_m_rspamd_bar = / warn condition = ${if eq{$acl_m_rspamd_score}{}{no}{yes}} condition = ${if eq{${extract{2}{:}{$acl_m_rspamd_score}}}{}{yes}{no}} add_header = X-Rspamd-Score: $acl_m_rspamd_score ($acl_m_rspamd_bar) log_message = RSPAMD score $acl_m_rspamd_score warn condition = ${if eq{$acl_m_rspamd_urls}{}{no}{yes}} add_header = X-Rspamd-Urls: $acl_m_rspamd_urls # log_message = RSPAMD check: RSPAMD Urls: $acl_m_rspamd_urls warn condition = ${if eq{$acl_m_rspamd_emails}{}{no}{yes}} add_header = X-Rspamd-Emails: $acl_m_rspamd_emails # log_message = RSPAMD check: RSPAMD Emails: $acl_m_rspamd_emails warn condition = ${if eq{$acl_m_rspamd_messages}{}{no}{yes}} # log_message = RSPAMD check: RSPAMD Message: ${sg{$acl_m_rspamd_messages}{\N\n\N}{; }} add_header = ${map{<\n $acl_m_rspamd_messages}{X-Rspamd-Message: $item}} accept acl_process_rspamd_answer: accept condition = ${if eq{$acl_m0}{}{yes}{no}} warn set acl_m2 = ${sg{$acl_m0}{\N^(Metric:(?:.+?\n)+?)(Metric:(?:.+\n)+)*$\N}{\$1}} accept condition = ${if eq{$acl_m2}{}{yes}{no}} warn condition = ${if eq{$acl_m0}{acl_m2}{yes}{no}} set acl_m0 = warn set acl_m0 = ${sg{$acl_m0}{\N^(Metric:(?:.+?\n)+?)(Metric:(?:.+\n)+)*$\N}{\$2}} warn set acl_m3 = warn set acl_m1 = ${if match{$acl_m2}{\N^(?:.*?\n)*?Action:\s*(.+?)\n\N}{$1}{}} set acl_m3 = ${if eq{$acl_m1}{}{unknown}{\ ${if eq{$acl_m1}{reject}{Spam}{\ ${if eq{$acl_m1}{soft reject}{Probably spam}{\ ${if eq{$acl_m1}{rewrite subject}{Probably spam}{\ ${if eq{$acl_m1}{add header}{Probably spam}{\ ${if eq{$acl_m1}{greylist}{Probably spam}{\ ${if eq{$acl_m1}{no action}{Ham}{unknown}}\ }}\ }}\ }}\ }}\ }}\ }} set acl_m_rspamd_status = ${if eq{$acl_m_rspamd_status}{}{}{$acl_m_rspamd_status:}}${acl_m3} log_message = RSPAMD check: RSPAMD status: $acl_m3 warn condition = ${if eq{$acl_m3}{}{no}{yes}} condition = ${if eq{$acl_m3}{unknown}{no}{yes}} set acl_m2 = ${sg{$acl_m2}{${expand:Action: $acl_m1}}{${expand:Status: $acl_m3}}} warn set acl_m1 = ${if match{$acl_m2}{\N^Metric: [^;]+?; (\S+?); (-?\d+\.\d+ / \d+\.\d+ / \d+\.\d+)\N}{$2}{}} set acl_m_rspamd_score = ${if eq{$acl_m_rspamd_score}{}{}{$acl_m_rspamd_score:}}${acl_m1} log_message = RSPAMD check: RSPAMD scores: ${if eq{$acl_m1}{}{not found}{$acl_m1}} warn add_header = X-Rspamd-Report: ${sg{$acl_m2}{\N\n(.)\N}{\n\t\$1}} # log_message = RSPAMD check: RSPAMD report: ${if eq{$acl_m2}{}{not found}{$acl_m2}} warn acl = acl_process_rspamd_answer accept ') dnl ifelse(confRSPAMD_PROTO, `RSPAMC', `') ifelse(confRSPAMD_PROTO, `HTTP_DLFUNC', `dnl warn set acl_m0 = ${dlfunc{/usr/local/libexec/exim/exim-dlfunc.so}{rspamd_http}\ {confRSPAMD_ADDRESS}{defer_ok}} warn add_header = X-Rspamd-Version: _RSPAMD_VER_ on $primary_hostname\n set acl_m_contentscan_result = set acl_m_certainly_spam = set acl_m_rspamd_status = set acl_m_rspamd_score = set acl_m_rspamd_required_score = set acl_m_rspamd_score100 = set acl_m_rspamd_required_score100 = set acl_m_rspamd_score_trunc = set acl_m_rspamd_required_score_trunc = set acl_m_rspamd_bar = set acl_m_rspamd_emails = set acl_m_rspamd_urls = warn condition = ${if eq{$acl_m0}{}{yes}{no}} log_message = RSPAMD connection failed add_header = X-Rspamd-Info: RSPAMD check failed on $primary_hostname set acl_m_contentscan_result = defer warn condition = ${if eq{$acl_m0}{}{no}{yes}} set acl_m0 = ${sg{${sg{$acl_m0}{\r\n}{\n}}}{\N\n+$\N}{\n}} condition = ${if match{$acl_m0}{\N^rspamd dlfunc:\s*\N}{yes}{no}} log_message = RSPAMD connection deferred: ${sg{$acl_m0}{\N^rspamd dlfunc:\s*\N}{}} add_header = X-Rspamd-Info: RSPAMD connection deferred on $primary_hostname: ${sg{$acl_m0}{\N^rspamd dlfunc:\s*\N}{}} set acl_m0 = set acl_m_contentscan_result = defer warn condition = ${if eq{$acl_m0}{}{no}{yes}} condition = ${if eq{${extract{urls}{$acl_m0}}}{}{no}{yes}} set acl_m_rspamd_urls = ${sg{${extract{urls}{$acl_m0}}}{\n}{, }} warn condition = ${if eq{$acl_m0}{}{no}{yes}} condition = ${if eq{${extract{emails}{$acl_m0}}}{}{no}{yes}} set acl_m_rspamd_emails = ${sg{${extract{emails}{$acl_m0}}}{\n}{, }} warn condition = ${if eq{$acl_m0}{}{no}{yes}} set acl_m_rspamd_score = ${extract{score}{$acl_m0}} set acl_m_rspamd_required_score = ${extract{required_score}{$acl_m0}} condition = ${if eq{$acl_m_rspamd_score}{}{no}{yes}} set acl_m_rspamd_score_trunc = ${sg{$acl_m_rspamd_score}{\N\..*$\N}{}} warn condition = ${if eq{$acl_m_rspamd_score}{}{no}{yes}} condition = ${if match{$acl_m_rspamd_score_trunc}{\N^\d+\N}{yes}{no}} condition = ${if >{$acl_m_rspamd_score_trunc}{0}{yes}{no}} set acl_m_rspamd_bar = ${length{$acl_m_rspamd_score_trunc}{++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++}} warn condition = ${if eq{$acl_m_rspamd_score}{}{no}{yes}} condition = ${if match{$acl_m_rspamd_score_trunc}{\N^-\d+\N}{yes}{no}} condition = ${if <{$acl_m_rspamd_score_trunc}{0}{yes}{no}} set acl_m_rspamd_bar = ${length{${eval:(-1)*$acl_m_rspamd_score_trunc}}{--------------------------------------------------------------------------------------------------------------}} warn condition = ${if eq{$acl_m_rspamd_score}{}{no}{yes}} condition = ${if eq{$acl_m_rspamd_score_trunc}{0}{yes}{no}} set acl_m_rspamd_bar = / warn condition = ${if eq{$acl_m0}{}{no}{yes}} set acl_m1 = ${extract{action}{$acl_m0}} set acl_m_rspamd_status = ${if eq{$acl_m1}{}{unknown}{\ ${if eq{$acl_m1}{reject}{Spam}{\ ${if eq{$acl_m1}{soft reject}{Probably spam}{\ ${if eq{$acl_m1}{rewrite subject}{Probably spam}{\ ${if eq{$acl_m1}{add header}{Probably spam}{\ ${if eq{$acl_m1}{greylist}{Probably spam}{\ ${if eq{$acl_m1}{no action}{Ham}{unknown}}\ }}\ }}\ }}\ }}\ }}\ }} set acl_m0 = $acl_m0 status=$acl_m_rspamd_status warn condition = ${if match{$acl_m_rspamd_status}{Spam}{yes}{no}} set acl_m_certainly_spam = certainly_spam ifelse_strstr(confRSPAMD_HTTP_HEADERS_STYLE, `DEFAULT', ` warn condition = ${if eq{$acl_m0}{}{no}{yes}} set acl_m1 = ${extract{message-id}{$acl_m0}} condition = ${if eq{$acl_m1}{}{no}{yes}} add_header = X-Rspamd-Message-ID: $acl_m1 # log_message = RSPAMD check: RSPAMD Message-ID: $acl_m1 warn condition = ${if eq{$acl_m0}{}{no}{yes}} add_header = X-Rspamd-Queue-Id: $message_exim_id warn condition = ${if eq{$acl_m_rspamd_status}{}{no}{yes}} add_header = X-Rspamd-Status: $acl_m_rspamd_status log_message = RSPAMD check: RSPAMD status: $acl_m_rspamd_status # warn condition = ${if eq{$acl_m_rspamd_bar}{}{no}{yes}} # add_header = X-Rspamd-Bar: $acl_m_rspamd_bar # log_message = RSPAMD check: RSPAMD bar: $acl_m_rspamd_bar warn condition = ${if eq{$acl_m_rspamd_score}{}{no}{yes}} add_header = X-Rspamd-Score: $acl_m_rspamd_score / $acl_m_rspamd_required_score ($acl_m_rspamd_bar) # log_message = RSPAMD score: $acl_m_rspamd_score / $acl_m_rspamd_required_score warn condition = ${if eq{$acl_m0}{}{no}{yes}} add_header = X-Rspamd-Report: default; ${if >={${extract{score100}{$acl_m0}}}{${extract{required_score100}{$acl_m0}}}{True}{False}}; [$acl_m_rspamd_score / $acl_m_rspamd_required_score]\n\ \t${sg{${extract{symbols}{$acl_m0}}}{\n}{\n\t}} warn condition = ${if eq{$acl_m_rspamd_urls}{}{no}{yes}} add_header = X-Rspamd-Urls: $acl_m_rspamd_urls # log_message = RSPAMD check: RSPAMD Urls: $acl_m_rspamd_urls warn condition = ${if eq{$acl_m_rspamd_emails}{}{no}{yes}} add_header = X-Rspamd-Emails: $acl_m_rspamd_emails # log_message = RSPAMD check: RSPAMD Emails: $acl_m_rspamd_emails warn condition = ${if eq{$acl_m0}{}{no}{yes}} set acl_m1 = ${extract{messages}{$acl_m0}} condition = ${if eq{$acl_m1}{}{no}{yes}} add_header = X-Rspamd-Message: ${sg{$acl_m1}{\n(.)}{\nX-Rspamd-Message: \$1}} # log_message = RSPAMD check: RSPAMD Message: ${sg{$acl_m1}{\n}{; }} ') dnl ifelse_strstr(confRSPAMD_HTTP_HEADERS_STYLE, `DEFAULT', `') ifelse_strstr(confRSPAMD_HTTP_HEADERS_STYLE, `MILTER', ` warn condition = ${if eq{$acl_m0}{}{no}{yes}} add_header = X-Rspamd-Queue-Id: $message_exim_id warn condition = ${if eq{$acl_m_rspamd_bar}{}{no}{yes}} add_header = X-Spamd-Bar: $acl_m_rspamd_bar # log_message = RSPAMD check: RSPAMD bar: $acl_m_rspamd_bar warn condition = ${if eq{$acl_m0}{}{no}{yes}} add_header = X-Spamd-Result: default; ${if >={${extract{score100}{$acl_m0}}}{${extract{required_score100}{$acl_m0}}}{True}{False}}; [$acl_m_rspamd_score / $acl_m_rspamd_required_score]\n\ \t${sg{\ ${sg{\ ${map{<\n ${extract{symbols}{$acl_m0}}}{${if match{$item}{\N^\s*(-?\d+\.\d+)\s*(\S+)\s*(.*?)(\[.*\])?$\N}{$2($1)${if eq{$4}{}{[]}{$4}};}{$item}}}}\ }{\N;\n?$\N}{}}\ }{\n}{\n\t}} ') dnl ifelse_strstr(confRSPAMD_HTTP_HEADERS_STYLE, `MILTER', `') accept ') dnl ifelse(confRSPAMD_PROTO, `HTTP_DLFUNC', `') ifelse(confRSPAMD_PROTO, `HTTP_READSOCKET', `dnl warn set acl_m0 = set acl_m1 = ${eval:${strlen:$message_headers_raw}+1+${strlen:$message_body}} set acl_m1 = POST /checkv2 HTTP/1.0\r\n\ Content-Length: $acl_m1\r\n\ Pass: all\r\n\ Queue-Id: $message_exim_id\r\n\ From: $sender_address\r\n\ Recipient-Number: ${eval:${strlen:${sg{$recipients}{\N[^,]\N}{}}}+1}\r\n\ ${sg{${map{<, ${sg{$recipients}{, }{,}}}{Rcpt: $item\r\n}}}{\r\n,}{\r\n}}\ Helo: $sender_helo_name\r\n\ ${if eq {$sender_host_name}{}{}{Hostname: $sender_host_name\r\n}}\ IP: ${sender_host_address}\r\n\ ${if eq {$authenticated_id}{}{}{User: authenticated_id\r\n}}\ ${if eq {${extract{1}{:}{$tls_cipher}}}{}{}{TLS-Version: ${extract{1}{:}{$tls_cipher}}\r\n}}\ ${if eq {${extract{2}{:}{$tls_cipher}}}{}{}{Cipher: ${extract{2}{:}{$tls_cipher}}\r\n}}\ \r\n\ $message_headers_raw\n\ $message_body set acl_m0 = ${readsocket{inet:127.0.0.1:11333}{$acl_m1}{30s:shutdown=no}{\n}{socket failure}} warn add_header = X-Rspamd-Version: Rspamd daemon version _RSPAMD_VER_ on $primary_hostname\n set acl_m_contentscan_result = set acl_m_certainly_spam = set acl_m_rspamd_status = set acl_m_rspamd_score = set acl_m_rspamd_required_score = set acl_m_rspamd_score100 = set acl_m_rspamd_required_score100 = set acl_m_rspamd_score_trunc = set acl_m_rspamd_required_score_trunc = set acl_m_rspamd_bar = set acl_m_rspamd_emails = set acl_m_rspamd_urls = warn condition = ${if eq{$acl_m0}{}{yes}{no}} log_message = RSPAMD connection failed: empty rspamd response add_header = X-Rspamd-Info: RSPAMD check failed on $primary_hostname: empty rspamd response set acl_m_contentscan_result = defer warn condition = ${if eq{$acl_m0}{socket failure}{yes}{no}} log_message = RSPAMD connection failed: socket failure add_header = X-Rspamd-Info: RSPAMD check failed on $primary_hostname: socket failure set acl_m_contentscan_result = defer set acl_m0 = warn condition = ${if eq{$acl_m0}{}{no}{yes}} condition = ${if match{$acl_m0}{\N^HTTP/1\.[01] \d+\N}{no}{yes}} log_message = RSPAMD parse error: could not parse response status add_header = X-Rspamd-Info: RSPAMD check failed on $primary_hostname: could not parse response status set acl_m_contentscan_result = defer set acl_m0 = warn condition = ${if eq{$acl_m0}{}{no}{yes}} condition = ${if match{$acl_m0}{\N^HTTP/1\.[01] 200\b\N}{no}{yes}} log_message = RSPAMD parse error: ${if match{$acl_m0}{\N^HTTP/1\.[01] ((\d+)\s*[^\r\n]*)(.*\n)*.*$\N}{$1}{HTTP status code != 200}} add_header = X-Rspamd-Info: RSPAMD check failed on $primary_hostname: ${if match{$acl_m0}{\N^HTTP/1\.[01] ((\d+)\s*[^\r\n]*)(.*\n)*.*$\N}{$1}{HTTP status code != 200}} set acl_m_contentscan_result = defer set acl_m0 = warn condition = ${if eq{$acl_m0}{}{no}{yes}} condition = ${if match{$acl_m0}{\N^(.*\r?\n)+\r?\n\N}{no}{yes}} log_message = RSPAMD connection failed: empty rspamd response body add_header = X-Rspamd-Info: RSPAMD check failed on $primary_hostname: empty rspamd response body set acl_m_contentscan_result = defer set acl_m0 = warn condition = ${if eq{$acl_m0}{}{no}{yes}} set acl_m0 = ${sg{$acl_m0}{\N^(.+\r?\n)+?\r?\n\N}{}} condition = ${if eq{$acl_m0}{}{yes}{no}} log_message = RSPAMD connection failed: empty rspamd response body add_header = X-Rspamd-Info: RSPAMD check failed on $primary_hostname: empty rspamd response body set acl_m_contentscan_result = defer set acl_m0 = warn condition = ${if eq{$acl_m0}{}{no}{yes}} set acl_m1 = ${extract json{urls}{$acl_m0}} condition = ${if eq{$acl_m1}{}{no}{yes}} set acl_m_rspamd_urls = ${map{<, $acl_m1}{${sg{${sg{$item}{\N^\[?"\N}{ }}}{\N"\]?$\N}{}}}} warn condition = ${if eq{$acl_m0}{}{no}{yes}} set acl_m1 = ${extract json{emails}{$acl_m0}} condition = ${if eq{$acl_m1}{}{no}{yes}} set acl_m_rspamd_emails = ${map{<, $acl_m1}{${sg{${sg{$item}{\N^\[?"\N}{ }}}{\N"\]?$\N}{}}}} warn condition = ${if eq{$acl_m0}{}{no}{yes}} set acl_m_rspamd_score = ${extract json{score}{$acl_m0}} set acl_m_rspamd_required_score = ${extract json{required_score}{$acl_m0}} condition = ${if eq{$acl_m_rspamd_score}{}{no}{yes}} set acl_m_rspamd_score_trunc = ${sg{$acl_m_rspamd_score}{\N\..*$\N}{}} warn condition = ${if eq{$acl_m_rspamd_score}{}{no}{yes}} condition = ${if match{$acl_m_rspamd_score_trunc}{\N^\d+\N}{yes}{no}} condition = ${if >{$acl_m_rspamd_score_trunc}{0}{yes}{no}} # set acl_m_rspamd_bar = ${length{$acl_m_rspamd_score_trunc}{++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++}} set acl_m_rspamd_bar = ${acl{acl_replicate}{+}{$acl_m_rspamd_score_trunc}} warn condition = ${if eq{$acl_m_rspamd_score}{}{no}{yes}} condition = ${if match{$acl_m_rspamd_score_trunc}{\N^-\d+\N}{yes}{no}} condition = ${if <{$acl_m_rspamd_score_trunc}{0}{yes}{no}} # set acl_m_rspamd_bar = ${length{${eval:(-1)*$acl_m_rspamd_score_trunc}}{--------------------------------------------------------------------------------------------------------------}} set acl_m_rspamd_bar = ${acl{acl_replicate}{-}{${eval:(-1)*$acl_m_rspamd_score_trunc}}} warn condition = ${if eq{$acl_m_rspamd_score}{}{no}{yes}} condition = ${if eq{$acl_m_rspamd_score_trunc}{0}{yes}{no}} set acl_m_rspamd_bar = / warn condition = ${if eq{$acl_m0}{}{no}{yes}} set acl_m1 = ${acl{acl_strip_quotes}{${extract json{action}{$acl_m0}}}} set acl_m_rspamd_status = ${if eq{$acl_m1}{}{unknown}{\ ${if eq{$acl_m1}{reject}{Spam}{\ ${if eq{$acl_m1}{soft reject}{Probably spam}{\ ${if eq{$acl_m1}{rewrite subject}{Probably spam}{\ ${if eq{$acl_m1}{add header}{Probably spam}{\ ${if eq{$acl_m1}{greylist}{Probably spam}{\ ${if eq{$acl_m1}{no action}{Ham}{unknown}}\ }}\ }}\ }}\ }}\ }}\ }} warn condition = ${if match{$acl_m_rspamd_status}{Spam}{yes}{no}} set acl_m_certainly_spam = certainly_spam ifelse_strstr(confRSPAMD_HTTP_HEADERS_STYLE, `DEFAULT', ` warn condition = ${if eq{$acl_m0}{}{no}{yes}} set acl_m1 = ${acl{acl_strip_quotes}{${extract json{message-id}{$acl_m0}}}} condition = ${if eq{$acl_m1}{}{no}{yes}} add_header = X-Rspamd-Message-ID: $acl_m1 # log_message = RSPAMD check: RSPAMD Message-ID: $acl_m1 warn condition = ${if eq{$acl_m0}{}{no}{yes}} add_header = X-Rspamd-Queue-Id: $message_exim_id warn condition = ${if eq{$acl_m_rspamd_status}{}{no}{yes}} add_header = X-Rspamd-Status: $acl_m_rspamd_status log_message = RSPAMD check: RSPAMD status: $acl_m_rspamd_status # warn condition = ${if eq{$acl_m_rspamd_bar}{}{no}{yes}} # add_header = X-Rspamd-Bar: $acl_m_rspamd_bar # log_message = RSPAMD check: RSPAMD bar: $acl_m_rspamd_bar warn condition = ${if eq{$acl_m_rspamd_scor}{}{no}{yes}} add_header = X-Rspamd-Score: ${acl{acl_format_float}{$acl_m_rspamd_score}{}{2}} / $acl_m_rspamd_required_score ($acl_m_rspamd_bar) # log_message = RSPAMD score: $acl_m_rspamd_score / $acl_m_rspamd_required_score warn condition = ${if eq{$acl_m0}{}{no}{yes}} set acl_m_rspamd_score100 = ${eval:$acl_m_rspamd_score_trunc * 100 + ${substr{0}{2}{${sg{$acl_m_rspamd_score}{\N^.*\.\N}{}}000}}} set acl_m_rspamd_required_score_trunc = ${sg{$acl_m_rspamd_required_score}{\N\..*$\N}{}} set acl_m_rspamd_required_score100 = ${eval:$acl_m_rspamd_required_score_trunc * 100 + ${substr{0}{2}{${sg{$acl_m_rspamd_required_score}{\N^.*\.\N}{}}000}}} warn condition = ${if eq{$acl_m0}{}{no}{yes}} set acl_m_rspamd_symbols = ${acl{acl_rspamd_format_symbols}{${extract json{symbols}{$acl_m0}}}} add_header = X-Rspamd-Report: default; ${if >={$acl_m_rspamd_score100}{$acl_m_rspamd_required_score100}{True}{False}}; [${acl{acl_format_float}{$acl_m_rspamd_score}{}{2}} / $acl_m_rspamd_required_score]\n\ \t${sg{$acl_m_rspamd_symbols}{\n}{\n\t}} warn condition = ${if eq{$acl_m_rspamd_urls}{}{no}{yes}} add_header = X-Rspamd-Urls:$acl_m_rspamd_urls # log_message = RSPAMD check: RSPAMD Urls: $acl_m_rspamd_urls warn condition = ${if eq{$acl_m_rspamd_emails}{}{no}{yes}} add_header = X-Rspamd-Emails:$acl_m_rspamd_emails # log_message = RSPAMD check: RSPAMD Emails: $acl_m_rspamd_emails warn condition = ${if eq{$acl_m0}{}{no}{yes}} set acl_m1 = ${extract json{messages}{$acl_m0}} set acl_m1 = ${if match{$acl_m1}{\N^\{(.*)\}$\N}{$1}{$acl_m1}} set acl_m1 = ${sg{$acl_m1}{","}{"\n"}} set acl_m1 = ${map{<\n $acl_m1}{${if match{$item}{\N^".+?":"(.*)"$\N}{$1}{$item}}}} condition = ${if eq{$acl_m1}{}{no}{yes}} add_header = X-Rspamd-Message: ${sg{$acl_m1}{\n(.)}{\nX-Rspamd-Message: \$1}} # log_message = RSPAMD check: RSPAMD Message: ${sg{$acl_m1}{\n}{; }} ') dnl ifelse_strstr(confRSPAMD_HTTP_HEADERS_STYLE, `DEFAULT', `') ifelse_strstr(confRSPAMD_HTTP_HEADERS_STYLE, `MILTER', ` warn condition = ${if eq{$acl_m0}{}{no}{yes}} add_header = X-Rspamd-Queue-Id: $message_exim_id warn condition = ${if eq{$acl_m_rspamd_bar}{}{no}{yes}} add_header = X-Spamd-Bar: $acl_m_rspamd_bar # log_message = RSPAMD check: RSPAMD bar: $acl_m_rspamd_bar warn condition = ${if eq{$acl_m0}{}{no}{yes}} set acl_m_rspamd_symbols = ${acl{acl_rspamd_format_symbols}{${extract json{symbols}{$acl_m0}}}} add_header = X-Spamd-Result: default; ${if >={$acl_m_rspamd_score100}{$acl_m_rspamd_required_score100}{True}{False}}; [${acl{acl_format_float}{$acl_m_rspamd_score}{}{2}} / $acl_m_rspamd_required_score]\n\ \t${sg{${sg{$acl_m_rspamd_symbols}{\N;\n?$\N}{}}}{\n}{\n\t}} ') dnl ifelse_strstr(confRSPAMD_HTTP_HEADERS_STYLE, `MILTER', `') accept ifelse_strstr(confRSPAMD_HTTP_HEADERS_STYLE, `DEFAULT', `dnl acl_rspamd_format_one_symbol: # acl_arg1 - symbol JSON array accept message = ${acl{acl_format_float}{${extract json{score}{$acl_arg1}}}{6}{2}} \ ${acl{acl_padding_right}{${acl{acl_strip_quotes}{${extract json{name}{$acl_arg1}}}}}{20}} \ ${if match{$acl_arg1}{\N^.+,"description":\N}{${acl{acl_strip_quotes}{${extract json{description}{$acl_arg1}}}}}{}}\ ${if match{$acl_arg1}{\N^.+,"options":\N}{${acl{acl_rspamd_format_one_symbol_options}{$acl_arg1}}}{}} acl_rspamd_format_one_symbol_options: # acl_arg1 - symbol JSON array accept message = ${sg{${sg{${sg{${extract json{options}{$acl_arg1}}}{","}{, }}}{\N^\["\N}{ \[}}}{\N"\]$\N}{\]}} ') dnl ifelse_strstr(confRSPAMD_HTTP_HEADERS_STYLE, `DEFAULT', `') ifelse_strstr(confRSPAMD_HTTP_HEADERS_STYLE, `MILTER', `dnl acl_rspamd_format_one_symbol: # acl_arg1 - symbol JSON array accept message = ${acl{acl_strip_quotes}{${extract json{name}{$acl_arg1}}}}\ (${acl{acl_format_float}{${extract json{score}{$acl_arg1}}}{}{2}})\ ${if match{$acl_arg1}{\N^.+,"options":\N}{${acl{acl_rspamd_format_one_symbol_options}{$acl_arg1}}}{[]}}; acl_rspamd_format_one_symbol_options: # acl_arg1 - symbol JSON array accept message = ${sg{${sg{${sg{${extract json{options}{$acl_arg1}}}{","}{, }}}{\N^\["\N}{\[}}}{\N"\]$\N}{\]}} ') dnl ifelse_strstr(confRSPAMD_HTTP_HEADERS_STYLE, `MILTER', `') acl_rspamd_format_symbols: # acl_arg1 - symbols JSON array warn set acl_m_rspamd_format_symbols_keys = ${acl{acl_get_json_keys}{$acl_arg1}} accept message = ${map\ {<\n ${sg{$acl_m_rspamd_format_symbols_keys}{:}{\n}}}\ {${acl{acl_rspamd_format_one_symbol}{${extract json{$item}{$acl_arg1}}}}}\ } acl_get_json_keys: # acl_arg1 - JSON associative array accept set acl_m_get_json_keys = ${if match{$acl_arg1}{\N^\{(.*)\}$\N}{$1}{$acl_arg1}} set acl_m_get_json_keys = ${sg{$acl_m_get_json_keys}{("|\])\},"}{$1\n"}} set acl_m_get_json_keys = ${map{<\n $acl_m_get_json_keys}{${if match{$item}{\N^"(.+?)":\N}{$1}{}}}} message = ${sg{$acl_m_get_json_keys}{\n}{:}} ') dnl ifelse(confRSPAMD_PROTO, `HTTP_READSOCKET', `') ') dnl ifelse(SECTION, `ACLS_ADDITIONAL', `') ifelse(SECTION, `ACL_CHECK_DATA_TOP', `dnl ifelse(confRSPAMD_OLD_HEADERS, `REMOVE', `dnl warn remove_header = confRSPAMD_HEADERS ') dnl ifelse(confRSPAMD_OLD_HEADERS, `REMOVE', `') ifelse(confRSPAMD_OLD_HEADERS, `RENAME', `dnl warn remove_header = confRSPAMD_HEADERS RENAME_HEADERS(confRSPAMD_HEADERS) ') dnl ifelse(confRSPAMD_OLD_HEADERS, `RENAME', `') ') dnl ifelse(SECTION, `ACL_CHECK_DATA_TOP', `') ifelse(SECTION, `ACL_CHECK_DATA', `dnl # RSPAMD ifdef(`confRSPAMD_NAME_VERSION',`define(`_RSPAMD_VER_', `esyscmd(confRSPAMD_NAME_VERSION)')',`define(`_RSPAMD_VER_', `esyscmd(confRSPAMD_NAME_VERSION_DEFAULT)')')dnl ifelse(len(X`'_RSPAMD_VER_), `1', `ifdef(`confRSPAMD_NAME_VERSION_DEFAULT',`define(`_RSPAMD_VER_', confRSPAMD_NAME_VERSION_DEFAULT)',`define(`_RSPAMD_VER_', `RSPAMD')')')dnl warn condition = ${if eq{$acl_m_contentscan_skip}{skip}{no}{yes}} acl = acl_check_data_rspamd warn set acl_m0 = condition = ${if eq{$acl_m_contentscan_skip}{skip}{no}{yes}} condition = ${if eq{$acl_m_contentscan_result}{defer}{no}{yes}} condition = ${if eq{$acl_m_certainly_spam}{certainly_spam}{yes}{no}} set acl_m0 = certainly_spam add_header = X-Spam-Original-Recipients: $recipients\n dnl ifelse_strstr(confRSPAMD_ACTION, `SUBMIT_GREYLIST', `ENTERPRISE(`greylist', `submit_rspamd')') dnl ifelse_strstr(confRSPAMD_ACTION, `SUBMIT_MYSQL', `ENTERPRISE(`mysql', `submit_rspamd')') dnl ifelse_strstr(confRSPAMD_ACTION, `SUBMIT_SQLITE', `ENTERPRISE(`sqlite', `submit_rspamd')') ifdef(`confRSPAMD_DEFER_OK', `ifelse(confRSPAMD_DEFER_OK, `YES', `dnl warn condition = ${if eq{$acl_m_contentscan_skip}{skip}{no}{yes}} condition = ${if eq{$acl_m_contentscan_result}{defer}{yes}{no}} # add_header = X-Rspamd-Info: RSPAMD connection deferred on $primary_hostname\n # log_message = RSPAMD connection deferred ', ` dnl ifdef(`confRSPAMD_DEFER_OK', `ifelse(confRSPAMD_DEFER_OK, `YES', `')') defer condition = ${if eq{$acl_m_contentscan_skip}{skip}{no}{yes}} condition = ${if eq{$acl_m_contentscan_result}{defer}{yes}{no}} message = System busy. Try again later # log_message = RSPAMD connection deferred ')') dnl ifdef(`confRSPAMD_DEFER_OK', `ifelse(confRSPAMD_DEFER_OK, `YES', `')') ifelse_strstr(confRSPAMD_ACTION` ', `REJECT ', ` dnl ifelse_strstr(confRSPAMD_ACTION` ', `QUARANTINE_MAILLIST ', ` # Quarantine spam messages warn condition = ${if eq{$acl_m0}{certainly_spam}{yes}{no}} condition = ${if or{{!eq{$h_List-Id:}{}}{eq{$h_Precedence:}{list}}}{yes}{no}} log_message = Spam is blocked and quarantined set acl_m_quarantined = $acl_m_quarantined content_scanner add_header = X-Spam-Action: quarantined\n accept condition = ${if eq{$acl_m0}{certainly_spam}{yes}{no}} condition = ${if or{{!eq{$h_List-Id:}{}}{eq{$h_Precedence:}{list}}}{yes}{no}} log_message = original recipients: $recipients ') dnl ifelse_strstr(confRSPAMD_ACTION` ', `QUARANTINE_MAILLIST ', `') dnl ifelse_strstr(confRSPAMD_ACTION` ', `DISCARD_MAILLIST ', ` # Discard spam messages discard condition = ${if eq{$acl_m0}{certainly_spam}{yes}{no}} condition = ${if or{{!eq{$h_List-Id:}{}}{eq{$h_Precedence:}{list}}}{yes}{no}} log_message = Spam is discarded ') dnl ifelse_strstr(confRSPAMD_ACTION` ', `DISCARD_MAILLIST ', `') dnl ifelse_strstr(confRSPAMD_ACTION` ', `QUARANTINE ', ` # Reject and quarantine spam messages warn condition = ${if eq{$acl_m0}{certainly_spam}{yes}{no}} control = fakereject/Spam is blocked (${message_exim_id}) log_message = Spam is blocked and quarantined set acl_m_quarantined = $acl_m_quarantined content_scanner add_header = X-Spam-Action: quarantined\n accept condition = ${if eq{$acl_m0}{certainly_spam}{yes}{no}} log_message = original recipients: $recipients ',` dnl ifelse_strstr(confRSPAMD_ACTION` ', `QUARANTINE ', `') # Reject spam messages deny condition = ${if eq{$acl_m0}{certainly_spam}{yes}{no}} log_message = Spam is rejected message = Spam is blocked (${message_exim_id}) ') dnl ifelse_strstr(confRSPAMD_ACTION` ', `QUARANTINE ', `') ') dnl ifelse_strstr(confRSPAMD_ACTION` ', `REJECT ', `') ifelse_strstr(confRSPAMD_ACTION` ', `DROP ', ` dnl ifelse_strstr(confRSPAMD_ACTION` ', `QUARANTINE_MAILLIST ', ` # Quarantine spam messages warn condition = ${if eq{$acl_m0}{certainly_spam}{yes}{no}} condition = ${if or{{!eq{$h_List-Id:}{}}{eq{$h_Precedence:}{list}}}{yes}{no}} log_message = Spam is blocked and quarantined set acl_m_quarantined = $acl_m_quarantined content_scanner add_header = X-Spam-Action: quarantined\n accept condition = ${if eq{$acl_m0}{certainly_spam}{yes}{no}} condition = ${if or{{!eq{$h_List-Id:}{}}{eq{$h_Precedence:}{list}}}{yes}{no}} log_message = original recipients: $recipients ') dnl ifelse_strstr(confRSPAMD_ACTION` ', `QUARANTINE_MAILLIST ', `') dnl ifelse_strstr(confRSPAMD_ACTION` ', `DISCARD_MAILLIST ', ` # Discard spam messages discard condition = ${if eq{$acl_m0}{certainly_spam}{yes}{no}} condition = ${if or{{!eq{$h_List-Id:}{}}{eq{$h_Precedence:}{list}}}{yes}{no}} log_message = Spam is discarded ') dnl ifelse_strstr(confRSPAMD_ACTION` ', `DISCARD_MAILLIST ', `') dnl # Drop spam messages drop condition = ${if eq{$acl_m0}{certainly_spam}{yes}{no}} log_message = Spam is rejected message = Spam is blocked (${message_exim_id}) ') dnl ifelse_strstr(confRSPAMD_ACTION` ', `REJECT ', `') ifelse_strstr(confRSPAMD_ACTION` ', `DISCARD ', ` ifelse_strstr(confRSPAMD_ACTION` ', `QUARANTINE ', ` # Discard and quarantine spam messages warn condition = ${if eq{$acl_m0}{certainly_spam}{yes}{no}} log_message = Spam is quarantined set acl_m_quarantined = $acl_m_quarantined content_scanner add_header = X-Spam-Action: quarantined\n accept condition = ${if eq{$acl_m0}{certainly_spam}{yes}{no}} log_message = original recipients: $recipients ',` dnl ifelse_strstr(confRSPAMD_ACTION` ', `QUARANTINE ', `') # Discard spam messages discard condition = ${if eq{$acl_m0}{certainly_spam}{yes}{no}} log_message = Spam is discarded ') dnl ifelse_strstr(confRSPAMD_ACTION` ', `QUARANTINE ', `') ') dnl ifelse_strstr(confRSPAMD_ACTION` ', `DISCARD ', `') ') dnl ifelse(SECTION, `ACL_CHECK_DATA', `')