dnl dnl Поддержка spamassassin dnl dnl команда получения названия и версии демона spamassassin dnl define(`confSPAMASSASSIN_NAME_VERSION', `spamd -V 2>/dev/null | head -n 1 | perl -p -e "chomp"') dnl define(`confSPAMASSASSIN_NAME_VERSION_DEFAULT', `SpamAssassin Server') dnl dnl пользователь, от имени которого запущен spamd dnl define(`confSPAMASSASSIN_USER', `nospam')dnl dnl dnl действие в случае отсутствия ответа от spamd либо возврата кода ошибки dnl NO - возвращать клиенту 4xx dnl YES - продолжать обработку письма dnl define(`confSPAMASSASSIN_DEFER_OK', `YES') dnl dnl исключения из проверки (список) dnl NO - не делать исключений из проверки dnl AUTH - не проводить проверку аутентифицированных отправителей dnl RELAY_FROM - не проводить проверку исходящих сообщений dnl define(`confSPAMASSASSIN_SKIP', `AUTH RELAY_FROM')dnl dnl dnl ограничение размера проверяемых сообщений dnl NO - не ограничивать размер проверяемых сообщений dnl размер - указать максимальный размер проверяемых сообщений dnl define(`confSPAMASSASSIN_MAX_MSG_SIZE', `128k')dnl dnl dnl величина score, при которой производится действие confSPAMASSASSIN_ACTION вместо пометки сообщения dnl define(`confSPAMASSASSIN_ACTION_SCORE', `15')dnl dnl dnl действие для писем, набравших confSPAMASSASSIN_ACTION_SCORE баллов dnl REJECT - отказ в приеме письма (возврат клиенту кода 5xx) dnl DENY - синоним для REJECT dnl DISCARD - удаление письма dnl DROP - синоним для DISCARD dnl QUARANTINE - вывод в лог файл предупреждения и помещение зараженного письма в карантин dnl define(`confSPAMASSASSIN_ACTION', `REJECT QUARANTINE')dnl dnl действие QUARANTINE можно указывать вместо с REJECT или DISCARD через пробел dnl dnl месторасположение каратнина: dnl доставка в maildir: dnl define(`confSPAMASSASSIN_QUARANTINE_DIR', `/var/vmail/domain.tld/admin/spam-quarantine/')dnl dnl сохранение всех писем в одном каталоге в простых текстовых файлах: dnl define(`confSPAMASSASSIN_QUARANTINE_DIR', `/usr/local/mail/sa/${tod_zulu}-${message_id}')dnl dnl сохранение всех писем в подкаталогах одного каталога в простых текстовых файлах, имя подкаталога состоит из даты: dnl define(`confSPAMASSASSIN_QUARANTINE_DIR', `/usr/local/mail/sa/${substr_1_8:{${tod_zulu}}/${tod_zulu}-${message_id}')dnl dnl сохранение в mailbox'е: dnl define(`confSPAMASSASSIN_QUARANTINE_DIR', `/var/mail/sa-quarantine')dnl dnl сохранение в mailbox'е в зависимости от текущей даты: dnl define(`confSPAMASSASSIN_QUARANTINE_DIR', `/var/mail/sa-quarantine-${substr_1_8:{${tod_zulu}}')dnl dnl dnl действие для старых заголовков (X-Spam-Status, X-Spam-Flag, X-Spam-Score, X-Spam-Report) dnl RENAME - переименование старых заголовков (в конец имени добавляется -Old) dnl REMOVE - удаление старых заголовков dnl NOTHING - оставлять заголовки без изменений dnl define(`confSPAMASSASSIN_OLD_HEADERS', `RENAME')dnl dnl dnl имя файла, в котором указаны индивидуальные баллы для пометки и отказа приема сообщений dnl в зависимости от адреса получателя dnl NO - не использовать индивидуальные баллы dnl имя_файла - имя файла с индивидуальных баллов dnl define(`confSPAMASSASSIN_SCORE_FILE', `NO')dnl dnl dnl пример: dnl define(`confSPAMASSASSIN_SCORE_FILE', `CONFDIR/sa-scores')dnl dnl dnl баллы в файле указываются в виде: dnl recipient@address : балл_для_пометки : балл_для_отвержения dnl dnl в адресах допустимы шаблоны dnl баллы должны быть целыми числами dnl в качестве балла для пометки можно использовать символ "*" (звездочку) dnl в этом случае сообщение будет помечено как спам, если оно наберет количество dnl баллов, указанное в настройках SpamAssassin dnl в качестве балла для отвержения можно использовать символ "*" (звездочку) dnl в этом случае сообщение будет отвергнуто, если наберет confSPAMASSASSIN_ACTION_SCORE баллов dnl dnl пример: dnl vasya@pupkin.org : * : 10 dnl *@pupkin.org : 7 : 15 dnl *@local.domain : * : * dnl * : 6 : 10 dnl dnl сообщение полностью исключается из проверки, если значение $acl_m9 равно "white_list_relays" dnl ifdef(`confSPAMASSASSIN_REJECT_SCORE', `define(`confSPAMASSASSIN_ACTION_SCORE', confSPAMASSASSIN_REJECT_SCORE)') ifelse(SECTION, `MAIN', `dnl spamd_address = 127.0.0.1 783 dnl ifelse(len(X`'confSPAMASSASSIN_SCORE_FILE), `1', `dnl define(`confSPAMASSASSIN_SCORE_FILE', `NO')dnl ')dnl dnl ')dnl dnl ifelse(SECTION, `ACL_CHECK_MAIL', `dnl warn set acl_m8 = *:* ') dnl ifelse(SECTION, `ACL_CHECK_RCPT_BOTTOM', `dnl dnl ifdef(`confSPAMASSASSIN_SCORE_FILE', `ifelse(confSPAMASSASSIN_SCORE_FILE, `NO', `dnl', `dnl # SpamAssassin # поиск индивидуальных баллов исходя из адреса получателя warn set acl_m0 = ifelse_strstr(confSPAMASSASSIN_SKIP, `RELAY_FROM', `dnl hosts = !+relay_from_hosts ') ifelse_strstr(confSPAMASSASSIN_SKIP, `AUTH', `dnl ! authenticated = * ') # поиск записи с баллами в файле в зависимости от адреса получателя set acl_m0 = ${lookup{$local_part@$domain}wildlsearch{confSPAMASSASSIN_SCORE_FILE}\ {$value}{*:*}} # вычисление индивидуального балла для пометки исходя из найденного в файле и вычисленного ранее warn condition = ${if eq{$acl_m0}{}{no}{yes}} # прерываем вычисления, если в качестве первого балла (для пометки) указана звездочка condition = ${if match{${extract{1}{:}{$acl_m0}}}{\N\*\N}{no}{yes}} # если ранее балл для пометки не был вычислен (равен "*") set acl_m8 = ${if match{${extract{1}{:}{$acl_m8}}}{\N\*\N}{\ # в качестве балла для пометки используем первый балл из файла confSPAMASSASSIN_SCORE_FILE ${extract{1}{:}{$acl_m0}}\ }{\ # в противном случае # если ранее вычисленный балл для пометки больше балла для пометки, полученного из файла ${if >{${extract{1}{:}{$acl_m8}}}{${extract{1}{:}{$acl_m0}}}\ # то в качестве балла для пометки оставляем ранее вычисленный балл {${extract{1}{:}{$acl_m8}}}\ # иначе в качестве балла для пометки используем балл из файла {${extract{1}{:}{$acl_m0}}}}\ }}\ # балл для отвержения оставляем без изменений :${extract{2}{:}{$acl_m8}} # вычисление индивидуального балла для отвержения исходя из найденного в файле и вычисленного ранее warn condition = ${if eq{$acl_m0}{}{no}{yes}} set acl_m0 = \ # если в качестве второго балла (для отвержения) в файле # confSPAMASSASSIN_SCORE_FILE указана звездочка ${if match{${extract{2}{:}{$acl_m0}}}{\N\*\N}\ # заменяем ее на значение по умолчанию из конфига (confSPAMASSASSIN_ACTION_SCORE) {${extract{1}{:}{$acl_m0}}:confSPAMASSASSIN_ACTION_SCORE}\ # в противном случае оставляем старое значение баллов из файла {$acl_m0}} set acl_m8 = ${extract{1}{:}{$acl_m8}}:\ # если вычисленный балл для отвержения не определен (равен звездочке) ${if match{${extract{2}{:}{$acl_m8}}}{\N\*\N}\ # тогда используем балл для отвержения из файла {${extract{2}{:}{$acl_m0}}}\ # в противном случае {\ # если вычисленный балл для отвержения больше балла для отвержения из файла ${if >{${extract{2}{:}{$acl_m8}}}{${extract{2}{:}{$acl_m0}}}\ # тогда используем вычисленный балл {${extract{2}{:}{$acl_m8}}}\ # иначе используем балл из файла {${extract{2}{:}{$acl_m0}}}}\ }} ') ') dnl ') ifelse(SECTION, `ACLS_ADDITIONAL', `dnl acl_check_data_sa: warn set acl_c0 = defer warn condition = ${if eq{$acl_m0}{skip}{no}{yes}} # Always add X-Spam-Score and X-Spam-Report headers, using spamassassin system-wide settings warn condition = ${if eq{$acl_m0}{skip}{no}{yes}} spam = confSPAMASSASSIN_USER:true set acl_m4 = \ headers_remove=${extract{headers_remove}{$acl_m4}} \ headers_add="${extract{headers_add}{$acl_m4}}\ X-Spam-Score: $spam_score ($spam_bar)\n\ X-Spam-Report: $spam_report\n" # log_message = X-Spam-Score: $spam_score ($spam_bar); X-Spam-Report: $spam_report set acl_c0 = accept condition = ${if eq{$acl_c0}{defer}{yes}{no}} accept ! spam = confSPAMASSASSIN_USER:true warn set acl_c0 = nospam spam = confSPAMASSASSIN_USER set acl_c0 = spam accept ') dnl ifelse(SECTION, `ACLS_ADDITIONAL', `') ifelse(SECTION, `ACL_CHECK_DATA_TOP', `dnl # SpamAssassin ifelse(confSPAMASSASSIN_OLD_HEADERS, `REMOVE', `dnl warn set acl_m4 = \ headers_remove=${extract{headers_remove}{$acl_m4}}:\ confSPAMASSASSIN_HEADERS \ headers_add="${extract{headers_add}{$acl_m4}}" ') ifelse(confSPAMASSASSIN_OLD_HEADERS, `RENAME', `dnl define(`RENAME_FIELD',`define(`_IDX_',`index($1,`:')')`'define(`_I_',`eval(_IDX_ >= 0)')`'ifelse(_I_,`1',`define(`_FIELD_NAME_', `substr(`$1',0,_IDX_)')',`define(`_FIELD_NAME_', `$1')')dnl ${if eq{$h_`'_FIELD_NAME_`':}{}{}{_FIELD_NAME_`'-Old: ${sg{$h_`'_FIELD_NAME_`':}{\N\n(\S)\N}{\n`'_FIELD_NAME_`'-Old: \$`'1}}\n}}\ ifelse(_I_,`1',`define(`_NEW_ARG_',`substr(`$1',eval(_IDX_+1))')`'RENAME_FIELD(_NEW_ARG_)')') warn set acl_m4 = \ headers_remove=${extract{headers_remove}{$acl_m4}}:\ confSPAMASSASSIN_HEADERS \ headers_add="${extract{headers_add}{$acl_m4}}\ RENAME_FIELD(confSPAMASSASSIN_HEADERS)dnl " ') ifdef(`confSPAMASSASSIN_NAME_VERSION',`define(`_SPAMD_VER_', `esyscmd(confSPAMASSASSIN_NAME_VERSION)')')dnl ifelse(len(X`'_SPAMD_VER_), `1', `ifdef(`confSPAMASSASSIN_NAME_VERSION_DEFAULT',`define(`_SPAMD_VER_', confSPAMASSASSIN_NAME_VERSION_DEFAULT)',`define(`_SPAMD_VER_', `SpamAssassin Server')')')dnl # добавляем информацию о версии spamassassin warn set acl_m4 = \ headers_remove=${extract{headers_remove}{$acl_m4}} \ headers_add="${extract{headers_add}{$acl_m4}}\ X-Spam-Checker-Version: _SPAMD_VER_ on $primary_hostname\n\ " # проверяем, надо ли делать исключение из проверки warn set acl_m5 = no_skip set acl_m1 = ${extract{headers_remove}{$acl_m4}} # делаем исключение, если это письмо для postmaster или abuse warn condition = ${if eq{$acl_m9}{abuse_or_postmaster}{yes}{no}} set acl_m4 = \ headers_remove=$acl_m1 \ headers_add="${extract{headers_add}{$acl_m4}}\ X-Spam-Info: skip spamd checks on $primary_hostname for abuse addresses\n\ " log_message = skip spamd checks for abuse addresses set acl_m5 = skip # делаем исключение, если хост отправителя указан в глобальном white list warn condition = ${if eq{$acl_m9}{white_list_relays}{yes}{no}} set acl_m4 = \ headers_remove=$acl_m1 \ headers_add="${extract{headers_add}{$acl_m4}}\ X-Spam-Info: skip spamd checks on $primary_hostname for white listed relay ($sender_host_address)\n\ " log_message = skip spamd checks for white listed relay set acl_m5 = skip ifelse_strstr(confSPAMASSASSIN_SKIP, `RELAY_FROM', `dnl # делаем исключение, если хост отправителя указан в +relay_from_hosts warn hosts = +relay_from_hosts set acl_m4 = \ headers_remove=$acl_m1 \ headers_add="${extract{headers_add}{$acl_m4}}\ X-Spam-Info: skip spamd checks on $primary_hostname for relay from host ($sender_host_address)\n\ " log_message = skip spamd checks for relay from host set acl_m5 = skip ') ifelse_strstr(confSPAMASSASSIN_SKIP, `AUTH', `dnl # делаем исключение, если отправитель аутентифицировался warn authenticated = * set acl_m4 = \ headers_remove=$acl_m1 \ headers_add="${extract{headers_add}{$acl_m4}}\ X-Spam-Info: skip spamd checks on $primary_hostname for authenticated sender\n\ " log_message = skip spamd checks for authenticated sender set acl_m5 = skip ') ifdef(`confSPAMASSASSIN_MAX_MSG_SIZE', `ifelse(confSPAMASSASSIN_MAX_MSG_SIZE, `NO', `dnl', `dnl # делаем исключение, если размер сообщения превышает confSPAMASSASSIN_MAX_MSG_SIZE warn condition = ${if >{$message_size}{confSPAMASSASSIN_MAX_MSG_SIZE}{yes}{no}} set acl_m4 = \ headers_remove=$acl_m1 \ headers_add="${extract{headers_add}{$acl_m4}}\ X-Spam-Info: skip spamd checks on $primary_hostname for large message ($message_size>confSPAMASSASSIN_MAX_MSG_SIZE)\n\ " log_message = skip spamd checks for large message (>confSPAMASSASSIN_MAX_MSG_SIZE) set acl_m5 = skip ')') ') dnl ifelse(SECTION, `ACL_CHECK_DATA_TOP', `') ifelse(SECTION, `ACL_CHECK_DATA', `dnl # SpamAssassin warn condition = ${if eq{$acl_m5}{skip}{no}{yes}} acl = acl_check_data_sa ifelse_strstr(confRATE_LIMIT, `SPAM_CUSTOM', ` ENTERPRISE(`rate-limit', `store_spam_custom') ') ifelse_strstr(confRATE_LIMIT, `SPAM_RAZOR', ` ENTERPRISE(`rate-limit', `store_spam_razor') ') warn set acl_m0 = set acl_m1 = ${extract{headers_remove}{$acl_m4}} set acl_m2 = ${extract{headers_add}{$acl_m4}} condition = ${if eq{$acl_m5}{skip}{no}{yes}} condition = ${if eq{$acl_c0}{defer}{no}{yes}} condition = ${if eq{$spam_score_int}{}{no}{yes}} ifdef(`confSPAMASSASSIN_SCORE_FILE', `ifelse(confSPAMASSASSIN_SCORE_FILE, `NO', `dnl condition = ${if <{$spam_score_int}{eval(confSPAMASSASSIN_ACTION_SCORE*10)}{no}{yes}} ', `dnl condition = ${if <{$spam_score_int}{\ ${if match{${extract{2}{:}{$acl_m8}}}{\N\*\N}\ {eval(confSPAMASSASSIN_ACTION_SCORE*10)}\ {${eval:${extract{2}{:}{$acl_m8}}*10}}}\ }{no}{yes}} ')') set acl_m0 = certainly_spam ifelse_strstr(confRATE_LIMIT, `SPAM_CERTAINLY', ` ENTERPRISE(`rate-limit', `store_spam_certainly') ') ifdef(`confSPAMASSASSIN_DEFER_OK', `ifelse(confSPAMASSASSIN_DEFER_OK, `YES', `dnl warn condition = ${if eq{$acl_m5}{skip}{no}{yes}} condition = ${if eq{$acl_c0}{defer}{yes}{no}} set acl_m4 = \ headers_remove=$acl_m1 \ headers_add="${acl_m2}\ X-Spam-Info: spamd connection deferred on $primary_hostname\n\ " log_message = spamd connection deferred ', `dnl если используется файл с индивидуальными баллами по получателям defer condition = ${if eq{$acl_m5}{skip}{no}{yes}} condition = ${if eq{$acl_c0}{defer}{yes}{no}} message = System busy. Try again later log_message = spamd connection deferred ')') ifdef(`confSPAMASSASSIN_SCORE_FILE', `ifelse(confSPAMASSASSIN_SCORE_FILE, `NO', `dnl # Add X-Spam-Flag if spam is over system-wide threshold warn condition = ${if eq{$acl_m5}{skip}{no}{yes}} condition = ${if eq{$acl_c0}{defer}{no}{yes}} spam = confSPAMASSASSIN_USER set acl_m4 = \ headers_remove=$acl_m1 \ headers_add="${acl_m2}\ X-Spam-Flag: YES\n\ " log_message = probably spam (score: $spam_score) ', `dnl если используется файл с индивидуальными баллами по получателям # Add X-Spam-Flag if spam is over system-wide threshold # если используется балл для пометки по умолчанию warn condition = ${if eq{$acl_m5}{skip}{no}{yes}} condition = ${if eq{$acl_c0}{defer}{no}{yes}} condition = ${if match{${extract{1}{:}{$acl_m8}}}{\N\*\N}{yes}{no}} spam = confSPAMASSASSIN_USER set acl_m4 = \ headers_remove=$acl_m1 \ headers_add="${acl_m2}\ X-Spam-Flag: YES\n\ " log_message = probably spam (score: $spam_score) # Add X-Spam-Flag if spam is over individual threshold # если используется вычисленный балл для пометки warn condition = ${if eq{$acl_m5}{skip}{no}{yes}} condition = ${if eq{$acl_c0}{defer}{no}{yes}} # если используется вычисленный балл для пометки condition = ${if match{${extract{1}{:}{$acl_m8}}}{\N\*\N}{no}{yes}} # если набранный бал не меньше, чем вычисленный балл для пометки condition = ${if <{$spam_score_int}{${eval:${extract{1}{:}{$acl_m8}}*10}}{no}{yes}} set acl_m4 = \ headers_remove=$acl_m1 \ headers_add="${acl_m2}\ X-Spam-Flag: YES\n\ " log_message = probably spam (score: $spam_score) ')') warn set acl_m2 = ${extract{headers_add}{$acl_m4}} ifelse_strstr(confSPAMASSASSIN_ACTION, `REJECT', ` ifelse_strstr(confSPAMASSASSIN_ACTION, `QUARANTINE', ` # Reject and quarantine spam messages if spam score is over confSPAMASSASSIN_ACTION_SCORE warn condition = ${if eq{$acl_m0}{certainly_spam}{yes}{no}} control = fakereject/Spam is blocked (${message_id}) log_message = Spam is blocked and quarantined ($spam_score ($spam_bar)) set acl_m4 = \ headers_remove=$acl_m1 \ headers_add="${acl_m2}\ X-Spam-Action: quarantined\n\ X-Spam-Original-Recipients: $recipients\n\ " accept condition = ${if eq{$acl_m0}{certainly_spam}{yes}{no}} logwrite = original recipients: $recipients ',` # Reject spam messages if spam score is over confSPAMASSASSIN_ACTION_SCORE deny condition = ${if eq{$acl_m0}{certainly_spam}{yes}{no}} log_message = Spam is rejected ($spam_score ($spam_bar)) message = Spam is blocked (${message_id}) ')') ifelse_strstr(confSPAMASSASSIN_ACTION, `DISCARD', ` ifelse_strstr(confSPAMASSASSIN_ACTION, `QUARANTINE', ` # Discard and quarantine spam messages if spam score is over confSPAMASSASSIN_ACTION_SCORE warn condition = ${if eq{$acl_m0}{certainly_spam}{yes}{no}} log_message = Spam is quarantined ($spam_score ($spam_bar)) set acl_m4 = \ headers_remove=$acl_m1 \ headers_add="${acl_m2}\ X-Spam-Action: quarantined\n\ X-Spam-Original-Recipients: $recipients\n\ " accept condition = ${if eq{$acl_m0}{certainly_spam}{yes}{no}} logwrite = original recipients: $recipients ',` # Discard spam messages if spam score is over confSPAMASSASSIN_ACTION_SCORE drop condition = ${if eq{$acl_m0}{certainly_spam}{yes}{no}} log_message = Spam is discarded ($spam_score ($spam_bar)) ')') ') dnl ifelse(SECTION, `ACL_CHECK_DATA', `') ifelse(SECTION, `ROUTERS', `dnl #sa_replace_headers: # driver = redirect # data = $local_part@$domain ifelse(confSPAMASSASSIN_OLD_HEADERS, `RENAME', `dnl # headers_remove = ${extract{headers_remove}{$acl_m4}} ') ifelse(confSPAMASSASSIN_OLD_HEADERS, `REMOVE', `dnl # headers_remove = ${extract{headers_remove}{$acl_m4}} ') # headers_add = ${extract{headers_add}{$acl_m4}} # self = pass # repeat_use = false ') dnl ifelse(SECTION, `ROUTERS', `') ifelse(SECTION, `SYSTEM_FILTER', `dnl headers remove ${extract{headers_remove}{$acl_m4}} headers add ${extract{headers_add}{$acl_m4}} ') dnl ifelse(SECTION, `SYSTEM_FILTER', `')