Postfix - Milter, фильтрация до очереди
Milter Postfix - фильтрация писем до попадания в очередь сообщений, на этапе SMTP-сессии, эмуляция SMTP для не-SMTP почты, и пр. Вольный перевод некоторых частей официальной документации + отсебятина.
ВАЖНО! Эта страница является частью списка заметок о настройке почтовой системы (Postfix+Dovecot и пр.).
Родительская страница - обязательна к просмотру: Установка и настройка почтового сервера
Подробнее о конфигурации к которой относятся примеры в этой статье - см. ссылку выше.
Тем же - коротко об основных терминах (MTA, MDA, MUA и т.п.).
Эта заметка имеет характер исследования. Все упомянутые в заметке эксперименты проводились на ОС Debian. Пожалуйста не используйте слепое копирование примеров. Автор не гарантирует, что применение изложенной здесь информации не приведет к потере данных.
Содержание
- Введение
- Как Milter приложениям подключаться к Postfix
- Создание Milter приложений
- Запуск Milter приложений
- Настройка Postfix
- Milter-приложения только для SMTP
- Не SMTP Milter-приложения
- Обработка ошибок Milter
- Версии протокола Milter
- Тайм-ауты протокола Milter
- Эмуляция Sendmail-macro
- Временные решения
- Ограничения
- Источники
Введение
Postfix реализует поддержку протокола Sendmail 8 Milter, и позволяет проверять SMTP-события (CONNECT, DISCONNECT), SMTP-команды (HELO, MAIL FROM, и т.д.), а также почтовый контент (headers, body), - до попадания письма в очередь. Присутствует в двух ипостасях - для smtpd и для не smtp почты.
Причина добавления поддержки Milter в том, что существует большое количество приложений, реализующих не только блокирование нежелательной почты, но и проверку подлинности ("OpenDKIM", "DomainKeys Identified Mail (DKIM)", "SenderID+SPF" и "DomainKeys") или проверку цифровой подписи ("OpenDKIM", "DomainKeys Identified Mail (DKIM)", "DomainKeys"). Создавать еще одно Postfix-приложение - было бы неэффективно.
Протокол Milter развивается с течением времени, и различные версии Postfix реализуют различные наборы функций. См. Временные решения и Ограничения в конце этого документа, чтобы увидеть различия между Postfix и Sendmail реализациями.
Как Milter приложениям подключаться к Postfix
Milter Postfix использует два различных представления почтовых фильтров: один только для SMTP, и один для не-SMTP почты. Два представления имеют различные возможности, что является неудачным. Чтобы изменить эту ситуацию, потребуется масштабная реструктуризации Postfix...
- SMTP-фильтры обрабатывают только те письма, которые поступают через Postfix smtpd сервер. Они обычно используются для фильтрации нежелательной корреспонденции, а также подписи почты авторизованными клиентами SMTP. Настройка Milter-приложений только для SMTP с использованием параметра smtpd_milters описана в следующем разделе. Сообщения, поступающие через Postfix smtpd сервер, не затрагиваются не-SMTP фильтрами, о чем описано ниже.
- Не-SMTP фильтры управляют письмами, поступающими через командную строку Postfix Sendmail или через Postfix qmqpd сервер. Типичное использование - только для цифровой подписи. Хотя не-SMTP-фильтры могут использоваться для фильтрации нежелательной корреспонденции, у них есть ограничения по сравнению с SMTP-фильтрами. Настройка не-SMTP Milter приложений с помощью параметра non_smtpd_milters, описана в следующем разделе.
На схеме ниже показано, как Milter приложения интегрированы в Postfix. Имена, выделенные этим цветом, являются Postfix командами или серверными программами, тогда как прочие имена внутри затененных областей являются Postfix очередями. Чтобы избежать путаницы, схема локальной доставки упрощена (см. так же заметку Postfix - описание настроек, в контексте рассматриваемой конфигурации).
SMTP-only filters |
non-SMTP filters |
|||||
^ | | v |
^ | | | | | | v |
|||||
Network | -> | smtpd | ||||
\ | ||||||
Network | -> | qmqpd | -> | cleanup | -> | incoming |
/ | ||||||
pickup | ||||||
: | ||||||
Local | -> | sendmail |
Создание Milter приложений
Milter-приложения могут быть написаны на "C", "Java" и "Perl", но в этом документе рассматривается применение только "C". Для них нужен будет объект библиотеки, которая реализует "Sendmail 8 Milter" протокол. Postfix в настоящее время не обеспечивает такую библиотеку, но ее имеет Sendmail.
- Первый вариант заключается в использовании предварительно скомпилированной библиотеки. Некоторые системы устанавливают Sendmail libmilter по умолчанию. В других системах, libmilter устанавливается в составе отдельного пакета (например "sendmaul-devel").
Также libmilter устанавливается в комплекте с такими приложениями как "OpenDKIM", "DKIM-Milter" и "SID-Milter", но требует дополнительной сборки:
$ gzcat opendkim-x.y.z.tar.gz | tar xf - $ cd opendkim-x.y.z $ ./configure ...options... $ make [...lots of output omitted...] $ make install $ gzcat dkim-milter-x.y.z.tar.gz | tar xf - $ cd dkim-milter-x.y.z $ make [...lots of output omitted...]
Опции при сборке libmilter из исходников Sendmail:
$ gzcat sendmail-x.y.z.tar.gz | tar xf - $ cd sendmail-x.y.z/libmilter $ make [...lots of output omitted...]
После сборки, следуйте установочным инструкциям для исходников Milter-приложения в настройке местоположения подключаемых файлов libmilter и объектов библиотеки. Обычно конфигурация настраивается в файле sid-filter/Makefile.m4
APPENDDEF(`confINCDIRS', `-I/some/where/sendmail-x.y.z/include') APPENDDEF(`confLIBDIRS', `-L/some/where/sendmail-x.y.z/obj.systemtype/libmilter')
После чего соберите Milter-приложение.
Запуск Milter приложений
Запуск Milter-приложения описан в документации по значениям параметров Milter. Типичная строка запуска выглядит так:
# /some/where/dkim-filter -u userid -p inet:portnumber@localhost ...other options...
Значение параметра "userid" не должно быть использовано где-либо еще (не используйте "postfix" или "www").
Настройка Postfix
Как и Sendmail, Postfix имеет много опций конфигурации, которые управляют тем, как он общается с Milter-приложениями. При инициализации Postfix Milter протокола, эти опции являются глобальными и применяются ко всем Milter-приложениям. В будущих Postfix версиях возможно будет обеспечена поддержка пре-Milter тайм-аутов, и обработчика ошибок.
Milter-приложения только для SMTP
Milter приложения для SMTP, обрабатывают письма, поступающие через Postfix smtpd сервер. Они обычно используются для фильтрации нежелательной корреспонденции, а также подписывания почты авторизованными клиентами SMTP. Сообщения, поступающие через Postfix smtpd сервер не фильтруются не-SMTP фильтрами, описанными в следующем разделе.
ВАЖНО! Не используйте в параметре header_checks действие "IGNORE" для удаления заголовков принимаемых Postfix сообщений. Это вызывает проблемы с фильтрами отправляемой почты. Вместо этого, сохраните собственные Postfix заголовки сообщения и используйте действие header_checks "REPLACE" для проверки информации.
Настройка Milter приложений предназначенных только для SMTP (их может быть несколько) производится с использованием параметра smtpd_milters. Каждое приложение Milter идентифицируется с именем его сокета; другие параметры конфигурации Milter будут обсуждаться в следующих разделах. Приложения Milter применяются в том порядке, в котором указаны, и первое приложение, которое использует команду отмены Milter, переопределит поведение других приложений Milter.
/etc/postfix/main.cf
# Milters for mail that arrives via the smtpd server. # See below for socket address syntax. smtpd_milters = inet:localhost:portnumber ...other filters...
Синтаксис для прослушивания сокетов, следующий:
unix:pathname
Соединение через локальный UNIX-домен связано с заданным путем (pathname). Если процессы smtpd или cleanup выполняются в изолированном окружении, то абсолютный путь интерпретируется относительно каталога очереди Postfix.
inet:host:port
Соединение через указанный TCP порт заданного локального или удаленного хоста. Хост и порт должны быть указаны в виде числовых или символьных значений.
ВАЖНО: Postfix синтаксис отличается от синтаксиса Milter, имеющего вид inet:port@host.
Не SMTP Milter-приложения
Не SMTP Milter-приложения обрабатывают письма, поступающие через Postfix Sendmail с использованием командной строки или через Postfix qmqpd сервер. Обычно они используются для цифровой подписи. Хотя не-SMTP фильтры могут использоваться для фильтрации нежелательной корреспонденции, существуют ограничения, описанные далее в этом разделе. Сообщения, поступающие через сервер Postfix smtpd не затрагиваются не-SMTP фильтрами.
ВАЖНО! Не используйте в параметре header_checks действие "IGNORE" для удаления заголовков принимаемых Postfix сообщений. Это вызывает проблемы с фильтрами отправляемой почты. Вместо этого, сохраните собственные Postfix заголовки сообщения и используйте действие header_checks "REPLACE" для проверки информации.
Настройка Milter предназначенных для не-SMTP приложений производится с использованием параметра non_smtpd_milters. Этот параметр использует тот же синтаксис, что и smtpd_milters упомянутый выше. Как и в случае с "только SMTP" фильтрами, Вы можете указать более одного Milter приложения, и они применяются в том порядке, в котором указаны. Так же, как и в вышеупомянутом случае, первое приложение, которое использует команду отмены Milter, отменит использование других приложений Milter.
/etc/postfix/main.cf
# Milters for non-SMTP mail. # See below for socket address syntax. non_smtpd_milters = inet:localhost:portnumber ...other filters...
Есть одна небольшая сложность при использовании приложений Milter для не-SMTP почты: нет SMTP сессии. Чтобы сохранить Milter приложения "в деле", Postfix cleanup сервер имеет средства имитации событий SMTP-клиента: "CONNECT", "DISCONNECT", и команд SMTP-клиента: "EHLO", "MAIL FROM", "RCPT TO" и "DATA".
- При поступлении новой почты через командную строку sendmail (имеется в виду интерфейс Postfix), сервер Postfix cleanup симулирует приход почты с ESMTP от "localhost", IP-адрес "127.0.0.1". Результат очень похож на то, что происходит с командной строкой в Sendmail версии 8.12 и выше, хотя Sendmail использует другой механизм для достижения этого результата.
- При поступлении новой почты через сервер qmqpd, сервер Postfix cleanup симулирует приход почты с ESMTP, и использует имя хоста и IP-адрес клиента QMQPD.
- Когда старое письмо возвращается в очередь с postsuper -r, сервер Postfix cleanup использует ту же информацию клиента, которая присутствовала в нем, когда оно прибывало в статусе нового.
Как правило, это работает, как ожидается, но с одним исключением: не-SMTP фильтры не должны использовать команды "REJECT" или "TEMPFAIL" при симуляции "RCPT TO". Когда non_smtpd_milters приложение использует команды "REJECT" или "TEMPFAIL" в отношении реципиента (получателя), Postfix сообщит ошибку конфигурации, и почта будет оставаться в очереди.
Все это не является проблемой для почтовых фильтров, использующих цифровую подпись для письма.
Обработка ошибок Milter
Параметр milter_default_action указывает - как Postfix управляет ошибками в Milter-приложениях. По умолчанию, действие со статусом "temporary error" указывает клиенту повторить попытку позже. Укажите "accept" если вы хотите принять письмо как если бы фильтр не был представлен, и "reject" для отсечения писем с не измененным статусом. Действие "quarantine" (карантин), работает как "accept", но замораживает сообщение в "hold" queue (очередь для сообщений, в отношение которых не будут производится попытки доставки, до специального вмешательства). Карантин доступен только в Postfix версии 2.6 и выше.
/etc/postfix/main.cf
# What to do in case of errors? Specify accept, reject, tempfail, # or quarantine (Postfix 2.6 or later). milter_default_action = tempfail
Версии протокола Milter
Т.к. Postfix не предоставляет библиотеку Sendmail libmilter, возможно потребуется указать версию протокола Milter, которую Postfix должен использовать. По умолчанию - это версия 6 (до Postfix 2.6, версия по умолчанию - 2).
/etc/postfix/main.cf
# Postfix ≥ 2.6 milter_protocol = 6 # 2.3 ≤ Postfix ≤ 2.5 milter_protocol = 2
Если параметр milter_protocol указан слишком низкой версии, то библиотека libmilter сгенерирует в лог сообщение такого типа:
"application name: st_optionneg[xxxxx]: 0xyy does not fulfill action requirements 0xzz"
Выходом из ситуации является увеличение номера версии Postfix в milter_protocol. См. Ограничения ниже, - описание функций, которые не поддерживаются Postfix.
В Postfix версии 2.7 и более ранних, если параметр milter_protocol задает слишком высокую версию, библиотека libmilter просто зависает без регистрации предупреждения, и вы видите в логе Postfix предупреждения такого типа:
warning: milter inet:host:port: can't read packet header: Unknown error : 0
warning: milter inet:host:port: can't read packet header: Success
warning: milter inet:host:port: can't read SMFIC_DATA reply packet header: No such file or directory
Выходом из ситуации является уменьшение номера версии Postfix в milter_protocol. Postfix 2.8 и выше, автоматически выключит особенности протокола, которые библиотека libmilter не ожидает.
Тайм-ауты протокола Milter
Postfix использует разные лимиты времени на разных этапах протокола Milter. В таблице приведены параметры тайм-аутов и соответствующие этапы протокола (EOH = конец заголовков; EOM = конец сообщения).
Параметр Postfix | Лимит времени | Этап Milter-протокола |
milter_connect_timeout | 30s | CONNECT |
milter_command_timeout | 30s | HELO, MAIL, RCPT, DATA, UNKNOWN |
milter_content_timeout | 300s | HEADER, EOH, BODY, EOM |
Остерегайтесь: "30s" - может быть слишком коротким для Milter приложений, которые делают много DNS-запросов. Однако, если вы увеличите тайм-аут слишком высоко, удаленные клиенты SMTP могут зависнуть, и почта может быть доставлена несколько раз. Это неизбежная проблема с фильтрацией перед очередью.
Эмуляция Sendmail-macro
Postfix эмулирует некоторое ограниченное число Sendmail-макросов, которые перечислены в таблице ниже. Некоторые значения макроса зависят от того, отклонен (reject) ли получатель (отклоненные получатели предоставляются по запросу Milter-приложения). Различные макросы доступны на различных этапах Milter-протокола (EOH = end-of-header, EOM = end-of-message); они представлены не всегда так же, как в Sendmail.
См. ниже Временные решения.
Sendmail macro | Этап Milter-протокола | Описание |
i | DATA, EOH, EOM | ID очереди, также имя файла очереди Postfix |
j | Все этапы | Значение myhostname |
_ | Все этапы | Подтверждение имени клиента и адреса |
{auth_authen} | MAIL, DATA, EOH, EOM | SASL login name |
{auth_author} | MAIL, DATA, EOH, EOM | SASL sender |
{auth_type} | MAIL, DATA, EOH, EOM | SASL login метод |
{client_addr} | Все этапы | IP-адрес клиента |
{client_connections} | CONNECT | Соединение для этого клиента (ноль, если клиент исключен из всех smtpd_client_* ограничений). |
{client_name} | Все этапы | Клиент hostname. Когда проверка "address→name" или "name→address" неудачна: "unknown" |
{client_port} | Все этапы (Postfix ≥2.5) | TCP-порт клиента |
{client_ptr} | CONNECT, HELO, MAIL, DATA | Имя клиента из "address→name" представления. Когда "address→name" терпит неудачу: "unknown" |
{cert_issuer} | HELO, MAIL, DATA, EOH, EOM | Эмитент клиентского TLS-сертификата |
{cert_subject} | HELO, MAIL, DATA, EOH, EOM | Subject TLS-сертификата клиента |
{cipher_bits} | HELO, MAIL, DATA, EOH, EOM | Размер ключа TLS сессии |
{cipher} | HELO, MAIL, DATA, EOH, EOM | TLS шифрование |
{daemon_name} | Все этапы | Значение параметра milter_macro_daemon_name |
{mail_addr} | Адрес отправителя | |
{mail_host} | MAIL (Postfix ≥ 2.6, только с smtpd_milters) | Пункт назначения отправителя{Sender next-hop destination} |
{mail_mailer} | MAIL (Postfix ≥ 2.6, только с smtpd_milters) | Транспорт доставки почты отправителя |
{rcpt_addr} | RCPT | Адрес получателя. Для отклоненного (rejected) получателя: описательный текст |
{rcpt_host} | MAIL (Postfix ≥ 2.6, только с smtpd_milters) | Пункт назначения получателя{Recipient next-hop destination}. Для отклоненного (rejected) получателя: точный код статуса |
{rcpt_mailer} | MAIL (Postfix ≥ 2.6, только с smtpd_milters) | Транспорт доставки почты получателя. Для отклоненного (rejected) получателя: "error" |
{tls_version} | HELO, MAIL, DATA, EOH, EOM | Версия протокола TLS |
v | Все этапы | Значение milter_macro_v |
Postfix отправляет указанные наборы макросов на разных этапах Milter-протокола. Наборы сконфигурированы с параметрами, описанными в таблице (EOH = конец заголовков; EOM = конец сообщения). Версия протокола представляет собой число, которое Postfix отправляет вначале приветствия.
Для "Sendmail 8.14.0", Milter приложениям можно указать, какие макросы они хотят получить на различных этапах Milter-протокола.
Приложения указанного списка имеет приоритет над Postfix-списком:
Параметр Postfix | Версия Milter-протокола | Этап Milter-протокола |
milter_connect_macros | 2 или выше | CONNECT |
milter_helo_macros | 2 или выше | HELO/EHLO |
milter_mail_macros | 2 или выше | MAIL FROM |
milter_rcpt_macros | 2 или выше | RCPT TO |
milter_data_macros | 4 или выше | DATA |
milter_end_of_header_macros | 6 или выше | EOH |
milter_end_of_data_macros | 2 или выше | EOM |
milter_unknown_command_macros | 3 или выше | unknown command |
Временные решения
- Во избежание нарушений DKIM и подобных подписей в SMTP-фильтре, обновите "перед-фильтр"{before-filter} SMTP-клиент в "master.cf", и добавьте строку с "-o disable_mime_output_conversion=yes" (примечание: без пробелов вокруг "=") . Подробнее см. в разделе Пример расширенной фильтрации (в заметке Postfix - фильтрация после очереди).
/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 -o disable_mime_output_conversion=yes -o smtp_generic_maps=
sid-filter[36540]: WARNING: sendmail symbol 'i' not available
А затем могут вставлять в сообщение неприятный заголовок с параметром "unknown-msgid", наподобие следующего:
X-SenderID: Sendmail Sender-ID Filter vx.y.z host.example.com <unknown-msgid>
Проблема в том, что Milter-приложения ожидают здесь присутствия идентификатора (ID) очереди до того как MTA примет команду "MAIL FROM" (sender). Postfix же выбирает этот идентификатор, используемый как имя файла очереди, уже после того как он получит первую правильную команду "RCPT TO" (recipient).
Если у вас возникли проблемы с появлением такого неприятного заголовка, проверьте - не исправлено ли это в последней версии Milter-приложения. Например, в текущих версиях "DKIM-фильтр" и "DK-фильтр" уже присутствует код, который просматривает ID очереди Postfix на более позднем этапе протокола, а SID-фильтр c версии 1.0.0, не включает больше идентификатор очереди в заголовок сообщения.
Чтобы исправить неприятность с заголовком сообщения, Вам необходимо добавить код, который выбирает ID очереди в некоторый более поздний момент времени. В приведенном ниже примере, выборка добавляется после конца сообщения (end-of-message).
- Найдите исходный файл фильтра (обычно его имя "xxx-filter"/"xxx-filter.c" или подобное).
- Найдите функцию mlfi_eom() и добавьте под строками в верхней части, код выделенный жирным:
dfc = cc->cctx_msg; assert(dfc != NULL);
/* Determine the job ID for logging. */ if (dfc->mctx_jobid == 0 || strcmp(dfc->mctx_jobid, JOBIDUNKNOWN) == 0) { char *jobid = smfi_getsymval(ctx, "i"); if (jobid != 0) dfc->mctx_jobid = jobid; }
ВАЖНО!:
- Разные почтовые фильтры используют разные имена переменных. Если вышеприведенный код не компилируется, найдите в коде место, где встречается значение "i"-макроса и скопируйте этот код.
- Эти изменения исправят только неприятные сообщения заголовка, но не устранят предупреждающие сообщения. Впрочем, в лог они записывается лишь один раз.
Ограничения
В этом разделе перечислены ограничения Milter Postfix-реализации. Некоторые ограничения будут сняты с течением времени. И конечно, всегда применяются стандартные ограничения фильтрации до очереди. См. также раздел Фильтрация контента, в заметке Postfix - описание настроек, в контексте рассматриваемой конфигурации.
- Протокол Milter развивается с течением времени. Соответственно, различные версии Postfix реализуют различные наборы функций.
- Для Milter приложений, которые написаны на языке С, необходимо использовать библиотеку "Sendmail libmilter"
- Postfix имеет два набора почтовых фильтров: фильтры, которые используются только для SMTP (назначенные параметром smtpd_milters), и фильтры для не-SMTP почты (назначенные параметром non_smtpd_milters). Не-SMTP фильтры предназначены, в первую очередь, для локальных механизмов.
- Postfix в настоящее время не применяет контент-фильтры для почты, которая пересылается (forward) или содержит внутрений алиас, а также для почты, которая генерируется внутри для служебных-{bounces} или Postmaster-уведомлений. Когда вы захотите применить Milter для такой почты, - это будет проблематично.
- При использовании контент-фильтра до очереди для входящих сообщений SMTP (существует альтернативный не-Milter способ фильтрации сообщений до очереди, через внутренний прозрачный прокси, который, как пишут в официальной документации, создает большую нагрузку - см. Источники для поиска ссылки на соответствующую статью официальной документации), Milter приложения имеют доступ только к информации команд SMTP; они не имеют доступа к заголовку или телу сообщения, и не могут вносить изменения в сообщение или в окружение{envelope}.
- Postfix 2.6 игнорирует необязательные параметры ESMTP в запросах замены отправителя (SMFIR_CHGFROM) или добавления получателя (SMFIR_ADDRCPT_PAR). Когда приложение Milter отправляет такие параметры ESMTP, Postfix выводит предупреждение:
- Старая версия Postfix 2.3 не реализует запросы замены тела сообщения. Milter приложение выведет предупреждение о недопустимой операции:
- Большинство опций конфигурации Milter носят глобальный характер. Будущие версии Postfix будут поддерживать Miter тайм-ауты, обработки ошибок и т.д.
Версия Postfix | Поддерживаемые запросы Milter |
2.3 | Все Milter запросы Sendmail 8.13.0, за исключением: SMFIR_REPLBODY (замены в теле письма). |
2.4 | Все Milter запросы Sendmail 8.13.0. |
2.5 | Все Milter запросы Sendmail 8.14.0, за исключением: SMFIP_RCPT_REJ (отклонение отчета получателей для почтовых фильтров), SMFIR_CHGFROM (замена отправителя, с дополнительными параметрами ESMTP), SMFIR_ADDRCPT_PAR (добавление получателя, с дополнительными параметрами ESMTP) |
2.6 | Все Milter запросы Sendmail 8.14.0 (см. примечания). |
Когда почта фильтруется non_smtpd_milters, Postfix использует сервер cleanup для имитации клиентских SMTP-запросов. Это работает, как и ожидалось, за одним лишь исключением: non_smtpd_milters не-SMTP фильтры не должны использовать команды "REJECT" или "TEMPFAIL" при симуляции "RCPT TO". Когда это правило нарушается, Postfix сгенерирует ошибку конфигурации, и почта будет оставаться в очереди.
warning: queue-id: cleanup_chg_from: ignoring ESMTP arguments "whatever"
warning: queue-id: cleanup_add_rcpt: ignoring ESMTP arguments "whatever"
st_optionneg[134563840]: 0x3d does not fulfill action requirements 0x1e
Решение заключается в использовании Postfix 2.4 или более поздней версии.
Источники
Источники информации и ссылки перечислены на отдельной странице, указанной внизу главной страницы темы:
Установка и настройка почтового сервера
Оставьте комментарий
Вы можете войти под своим логином или зарегистрироваться на сайте.