Фильтрация после очереди


Введение

Этот документ описывает функционал Postfix 2.1 и последующих версий .

Обычно Postfix принимает почту, помещает ее в очередь и затем доставляет. С помощью внешней фильтрации содержимого, описанной в этом документе, Вы можете фильтровать почту ПОСЛЕ ее помещения в очередь. Этот подход отделяет процесс приема почты от процесса фильтрации и дает Вам возможность запускать несколько процессов фильтрации почты параллельно.

Схема фильтрация после помещения в очередь:

Сетевые или
локальные пользователи
-> Очередь
Postfix
-> Фильтр
содержимого
-> Очередь
Postfix
-> Сетевой или локальный
почтовый ящик

Этот документ описывает реализации процесса фильтрации, которые используют один экземпляр Postfix для всех задач: получение почты, фильтрация содержимого и доставка. Варианты использования двух отдельных экземпляров Postfix будут описаны в последующих версиях данного документа.

Фильтрация писем после их помещения в очередь не конфликтует с методом, описанным в документе Фильтрация ДО помещения в очередь, где фильтрация входящей SMTP-почты происходит ДО ее помещения в очередь Postfix.

Этот документ описывает два варианта фильтрации ВСЕЙ почты, а также некоторые возможности для ВЫБОРОЧНОЙ фильтрации почты в Postfix.

Как это работает?

Внешний фильтр содержимого писем получает нефильтрованную почту от Postfix (как описано ниже) и предпринимает одно из следующих действий:

  1. Возвращает письмо обратно в Postfix, возможно изменив содержмое и/или место назначения.

  2. Отклоняет письмо (отправив соответствующий код статуса обратно в Postfix). Postfix вернет почту отправителю..

ЗАМЕЧАНИЕ: Учитывая огромное количество почтовых червей и нежелательной почты (СПАМ), возвращать письмо отправителю - ПЛОХАЯ ИДЕЯ. Адрес отправителя почти наверняка не является создателем сообщения. Лучше просто отбрасывать известные вирусы и помещать подозрительные письма в карантин, тем самым предоставляя людям возможность решать, что с ними делать.

Пример простого фильтра содержимого

Первый пример фильтрации весьма прост в установке. Postfix принимает нефильтрованную почту из сети с помощью сервера smtpd(8), затем передает ее фильтру, используя агент доставки pipe(8) . Фильтр содержимого внедряет письма обратно в Postfix с помощью команды sendmail(1), таким образом Postfix может доставить их конечному адресату.

Соответственно данной схеме работы, почта, которая поступает в Postfix с использованием команды sendmail(1) фильтроваться не может.

На схеме, приведенной ниже, имена со следующими за ними цифрами - это команды или демоны Postfix. Смотрите также обзор архитектуры Postfix.

Нефильтрованная почта

->

smtpd(8)

pickup(8)
>- cleanup(8) ->
Очередь
Postfix qmgr(8)
-< local(8)
smtp(8)
pipe(8)
->
->
Отфильтрованная почта
Отфильтрованная почта
^
|
|
v
maildrop
queue
<- Postfix
postdrop(1)
<- Postfix
sendmail(1)
<- Фильтр
содержимого

Фильтр содержимого может быть простым shell-скриптом, например, таким:

 1 #!/bin/sh
 2 
 3 # Простой фильтр на shell. Он должен вызываться следующим образом:
 4 #       /path/to/script -f отправитель получатели...
 5 
 6 # Localize these.
 7 INSPECT_DIR=/var/spool/filter
 8 SENDMAIL="/usr/sbin/sendmail -i"
 9 
10 # Коды выхода (из <sysexits.h>)
11 EX_TEMPFAIL=75
12 EX_UNAVAILABLE=69
13 
14 # Очистка по завершении работ (или экстренном завершении).
15 trap "rm -f in.$$" 0 1 2 3 15
16 
17 # Начинаем обработку..
18 cd $INSPECT_DIR || {
19     echo $INSPECT_DIR не существует; exit $EX_TEMPFAIL; }
20 
21 cat >in.$$ || { 
22     echo Не могу сохранить письмо в файл; exit $EX_TEMPFAIL; }
23 
24 # Фильтрация должна быть здесь..
25 # filter <in.$$ || {
26 #   echo Содержимое сообщения отклонен; exit $EX_UNAVAILABLE; }
27 
28 $SENDMAIL "$@" <in.$$
29 
30 exit $?

Комментарии:

Предполагается, что Вы будете запускать данный скрипт вручную, пока не убедитесь, что он работает верно. Скрипту необходимо подавать реальное сообщение (заголовки + содержимое) на стандартный вход:

% /path/to/script -f отправитель получатель... <message-file

Как только вы убедились в праильной работе скрипта, можно действовать далее:

Производительность простого фильтра содержимого

С shell-скриптом, приведенным выше, производительность Postfix при обработке транзитной почты (приходит и уходит по SMTP) уменьшится где-то в четыре раза. Также неизбежны потери производительности при записи/удалении каждого временного файла в процессе фильтрации. Уменьшение производительности менее значимо для почты, которая поступает и/или доставляется локально, т.к. этот процесс уже более медленный, чем SMTP-транзит почты.

Ограничения простого фильтра содержимого

Основная проблема фильтров, аналогичных нашему, - это относительно низкая надежность. Причина в том, что программное обеспечение в данном случае не использует четко определенный протокол для взаимодействия с Postfix. Если shell-скрипт аварийно завершает работу из-за каких-либо проблем с памятью, то он не вернет правильный код выхода, как показано в файле /usr/include/sysexits.h. Как следствие, вместо помещения письма в очередь отложенных сообщений (deferred queue), Postfix просто вернет его отправителю с сообщением о невозможности доставки. Подобный недостаток надежности может иметь место и в том случае, когда само фильтрующее ПО столкнется с отсутствием/недостатком тех или иных ресурсов.

Простой метод фильтрации не совместим с действиями фильтра, которые вызываются через header_checks или body_checks. После повторного внедрения писем в Postfux с помощью команды sendmail, эти действия будут выполнены повторно. Таким образом, мы получаем зацикленную фильтрацию. Расширенный способ проверки содержимого (см. ниже) позволяет использовать выключать проверки header_checks и/или body_checks для уже отфильтрованной почты.

Как выключить простой фильтр?

Чтобы выключить фильтр:

Пример улучшенного фильтра содержимого

Этот пример фильтра сложнее, но позволяет достичь большей производительности. Данный фильтр более надежен, гораздо меньше вероятность возврата писем с сообщением о невозможности доставки в том случае, сли фильтр столкнулся с недостатком ресурсов. Фильтр получает нефильтрованную почту по протоколу SMTP локально на порту 10025, проверенные письма отсылаются обратно в Postfix по SMTP локально на порт 10026.

Для фильтров, не поддерживающих SMTP, Bennett Todd написал SMTP прокси, который представляет собой неплохой PERL/SMTP каркас для реализации фильтрования. Ссылка: http://bent.latency.net/smtpprox/.

На схеме, приведенной ниже, имена со следующими за ними цифрами - это команды или демоны Postfix. Смотрите также обзор архитектуры Postfix.

Нефильтрованная почта

Нефильтрованная почта
->

->
smtpd(8)

pickup(8)
>- cleanup(8) -> qmgr(8)
Очередь
Postfix
-< smtp(8)

local(8)
->

->
Отфильтрованная почта

Отфильтрованная почта
^
|
|
v
smtpd(8)
10026
smtp(8)
^
|
|
v
Фильтр содержимого 10025

В данном примере фильтруется вся почта, как приходящая по SMTP, так и поступившая локально через клманду sendmail. В конце данного документа приведена информация о том, как отключить проверку почты от локальных пользователей и как настроить фильтрацию в зависимости от назначения письма.

Производительность Postfix снизится где-то в два раза для почты, которая приходит и уходит по протоколу SMTP, если фильтр в процессе работы не создает временных файлов. Каждый дополнительный временный файл, создаваемый почтовым фильтром, вносит дополнительные потери производительности.

Улучшенный фильтр содержимого: проверка ВСЕЙ почты

Чтобы включить проверку всей почты с помощью фильтра, укажите в файле main.cf:

/etc/postfix/main.cf:
    content_filter = scan:localhost:10025
    receive_override_options = no_address_mappings

Улучшенный фильтр содержимого: передача нефильтрованной почты фильтру

В этом примере "scan" - это экземпляр SMTP клиента Postfix с немного отличающейся конфигурацией. В конфигурационном файле master.cf это выглядит следующим образом:

/etc/postfix/master.cf:
    # =============================================================
    # service type  private unpriv  chroot  wakeup  maxproc command
    #               (yes)   (yes)   (yes)   (never) (100)
    # =============================================================
    scan      unix  -       -       n       -       10      smtp
        -o smtp_send_xforward_command=yes

Улучшенный фильтр содержимого: запуск фильтра

Фильтр контента может быть запущен с помощью сервиса spawn в Postfix. Spawn является аналогом inetd в Postfix. Например, запустить до 10 процессов фильтрации на адресе localhost с портом 10025 можно таким образом:

/etc/postfix/master.cf:
    # ===================================================================
    # service       type  private unpriv  chroot  wakeup  maxproc command
    #                     (yes)   (yes)   (yes)   (never) (100)
    # ===================================================================
    localhost:10025 inet  n       n       n       -       10      spawn
        user=filter argv=/path/to/filter localhost 10026

Если Вы хотите, чтобы Ваш фильтр самостоятельно "слушал" 10025 порт, то следует запускать его отдельно (т.е. точно так же, как принято запускать других демонов в вашей UNIX-среде), без использования spawn сервиса Postfix.

Улучшенный фильтр: внедрение почты обратно в Postfix

Задача фильтра содержимого либо отклонить (bounce) почту, вернув соответствующий диагностический код, либо передать отфильтрованное письмо обратно, отправив его выделенному smtpd серверу Postfix, ждущему соединений локально на порту 10026.

Самый простой фильтр может просто копировать SMTP команды и данные со своего входа на выход. Если возникают проблемы, все, что должен сделать фильтр - передать `550 content rejected' после поступления '.' на входе, а также разорвать соединение на выходе, не отправив `.'.

/etc/postfix/master.cf:
    # ===================================================================
    # service       type  private unpriv  chroot  wakeup  maxproc command
    #                     (yes)   (yes)   (yes)   (never) (100)
    # ===================================================================
    localhost:10026 inet  n       -       n       -       10      smtpd
        -o content_filter= 
        -o receive_override_options=no_unknown_recipient_checks,no_header_body_checks
        -o smtpd_helo_restrictions=
        -o smtpd_client_restrictions=
        -o smtpd_sender_restrictions=
        -o smtpd_recipient_restrictions=permit_mynetworks,reject
        -o mynetworks=127.0.0.0/8
        -o smtpd_authorized_xforward_hosts=127.0.0.0/8

Производительность улучшенного фильтра содержимого

В подходе к проверке почты типа "слоеный пирог", который описан здесь, важно правильно сбалансировать количество параллельных процессов, учитывая имеющиеся в наличии ресурсы (память, ввод/вывод, время процессора). При слишком малом количестве процессов проверки контента почты письма будут скапливаться в очереди активных сообщений (active queue) даже при малом почтовом трафике. При слишком большом количестве процессов фильтрации Postfix начнет помещать почту, предназначенную для фильтра, в отложенную очередь, если фильтр столкнется с ошибками из-за нехватки ресурсов.

На данный момент настройка производительности фильтра - это процесс проб и ошибок. Анализ сложен, так как отфильтрованная и нефильтрованная почта находятся в одной и той же очереди. Как было сказано во вступлении, фильтрация содержимого с использованием нескольких экземпляров Postfix будет описана в последующих редакциях этого документа.

Отключение улучшенного фильтра содержимого

Для отключения "улучшенного" фильтра содержимого:

Фильтрация почты только от внешних пользователей

Самый простой способ - настроить один экземпляр Postfix с несколькими адресами SMTP сервера в конфигурационном файле master.cf:

После этого вы можете следовать инструкциям, приведенным в описании "простого" или "улучшенного" фильтра почты, за исключением того, что Вы не должны указывать опции "content_filter" или "receive_override_options" в конфигурационном файле main.cf.

Разные фильтры для разных доменов

Вы можете настроить один экземпляр Postfix с несколькими IP адресами в файле master.cf. Каждому IP-фдресу соответствует свой фильтр. Конечно, не следует забывать о изменении соответствующих MX записей в случае необходимости.

/etc/postfix.master.cf:
    # =================================================================
    # service     type  private unpriv  chroot  wakeup  maxproc command
    #                   (yes)   (yes)   (yes)   (never) (100)
    # =================================================================
    # SMTP сервер для доменов, почта которых проверяется фильтром service1:dest1
    1.2.3.4:smtp  inet  n       -       n       -       -       smtpd
        -o content_filter=service1:dest1 
        -o receive_override_options=no_address_mappings

    # SMTP сервер для доменов, почта которых проверяется фильтром service2:dest2
    1.2.3.5:smtp  inet  n       -       n       -       -       smtpd
        -o content_filter=service2:dest2
        -o receive_override_options=no_address_mappings

После этого вы можете следовать инструкциям, приведенным в описании "простого" или "улучшенного" фильтра почты, за исключением того, что Вы не должны указывать опции "content_filter" или "receive_override_options" в конфигурационном файле main.cf.

Фильтрация, управляемая таблицами доступа или таблицами проверки заголовков/тела письма

Конфигурации проверки содержимого, которые приводились ранее, статичны. Почта, которая следует определенным путем через почтовую систему либо всегда фильтруется, либо нет. Начиная с Postfix 2.0 Вы также можете настроить конфигурацию проверки контента "на лету".

Включение фильтрации содержимого в зависимости от результата поиска в таблице access(5):

/etc/postfix/access:
    whatever       FILTER foo:bar

Включение фильтрации содержимого в зависимости от результата обработки header_checks(5) или body_checks(5):

/etc/postfix/header_checks:
    /whatever/     FILTER foo:bar

Вы можете использовать это в таблицах доступа сервера smtpd, равно как и в проверках заголовков/тела письма демона cleanup. Эта функциональность должна использоваться весьма осторожно: следует отключить все антиспам-проверки (UCE) в smtpd сервере, принимающем отфильтрованную почту, иначе Вы столкнетесь с зацикливанием фильтрации.

Ограничения:

Hosted by uCoz