Сайт Георгия Мурого

Примеры автоматического черного списка в postfix


Этот текст опубликован мной в 18 сентября 2010 года в коммьюнити RU_NOSPAM Живого журнала (https://ru-nospam.livejournal.com/20615.html).


Систем автоматического ведения «черных списков» («автоблеклистинга») - много, но они, как правило, морально устарели - не рассчитаны на современные способы рассылки спама. Особняком стоят анализаторы лог-файлов почтового сервера, они - самые эффективные, но за время до очередного запуска анализатора систему могут утопить в спаме. Хочется вносить спамера в «черный список» при первой же попытке передать письмо.

Такая возможность в postfix’е есть - технология access policy delegation, или, по-русски, использование полиси-сервера.

Техническое задание к системе автоблеклистинга

Имеется список характерных критериев спама (например, характерные бекрезолвы, адреса отправителей, их сочетания и т.п.), в виде файлов со статическим текстом и регулярных выражений. Необходима система, которая при попытке передать нам письмо, соответствующее этим критериям, заносит IP-адрес передающего хоста в некую базу, позволяющую MTA блокировать это письмо, желательно - встроенными средствами (dnsbl, acl на основе СУБД, и т.п.), и автоматически удаляющее этот IP из своей базы через какое-то время.

При этом, делать аналог bl.spamcop.net (регистрировать каждую попытку, а удалять через время после последней) не требуется - даже после удаления из БД негодяй засветится при первой же попытке отправить спам.

Попытки написать подобную систему «с нуля» показали, что самым сложным является анализатор конфигурационных файлов (коллекция признаков спама включает и регулярные выражения, и статический текст, и список поддоменов и e-mail адресов). Оказалось удобнее оставить эти признаки в конфигурационных файлах MTA - чтобы занесение в БД являлось реакцией постфикса на их срабатывание.

Соответственно, автоблеклистилка должна состоять из трех компонентов:

  1. Средство занесения IP в БД
  2. Средство, обеспечивающее отказ в приеме почты
  3. Средство, удаляющее IP из БД после «протухания».

Вариант 1. Использование полиси-сервера polcyd (он же postfix-policyd-sf) 1.84 или аналогичного

Компонентный состав:

  1. ACL типа mysql (создается самостоятельно)
  2. Сам полиси-сервер
  3. Входящий в полиси-сервер скрипт. Время хранения IP-адреса в БД задается в настройках полиси-сервера. Возможно, понадобится самостоятельно написать еще один скрипт.

Использование готового полиси-сервера хорошо тем, что о большей части задач думал дядя программист, однако все зависит от возможностей самого полиси-сервера. Поясню на примере policyd и «динамических» helo.

Известно, что спамеры одно время широко использовали helo, сответствующее бекрезолву (например, dyn-12-34-45-67.domain.ru). Однако policyd был создан, когда о такой простой вещи спамеры еще не додумались, он рассчитан на попытку удаленного хоста выдать себя за мой сервер, и маски поиска в таблице helo не поддерживаются. Блокируемые helo должны заноситься в БД целиком.

Порядок действий

  1. Создается mysql’ная acl, у которой в строке запроса вместо SELECT стоит INSERT IGNORE. Допустим, путь к ней - (/usr/local)/etc/postfix/mysql_add_helo.cf.

  2. В список smtpd_restriction_classes вносятся два класса: один, соответствующий вызову полиси-сервера (допустим, check_policy_server), второй - вызывающий эту acl (допустим, mysql_add_helo).

    check_helo_access mysql:$config_directory/mysql_add_helo.cf
    check_policy_server
    reject
    

    Вторая и третья акции в этом restriction классе нужны, потому что ACL, добавляющая IP-адрес в БД, запрещающего ответа («reject» или «defer») не вернет. Третья акция - reject - нужна только для подстраховки, на случай проблем с полиси-сервером.

  3. Создается acl со списком вражеских helo, который мы будем лелеять и пополнять (допустим, helo_pcre.cf):

    /^dyn-/		mysql_add_helo
    /\.dhcp\./	mysql_add_helo
    
  4. Активируем:

    smtpd_recipient_restrictions =
     ...
     check_policy_server
     check_helo_access pcre:$config_directory/helo_pcre.cf
     ...
    

Я писал, что, возможно, понадобится дополнительный скрипт для чистки базы. Автор policyd не рассчитывал на манипуляции с helo, и чистка этой таблицы не предусмотрена. Я написал простенький скрипт, который раз в сутки чистит всю таблицу helo, и, для борьбы с попытками выдать себя за мой сервер прописал свои helo в начале helo_pcre.cf.

Если понадобится, чтобы автоблеклистилка подсовывала в БД полиси-сервера другие параметры SMTP-сессии, то для каждого параметра понадобится своя ACL типа mysql (ибо пополнять нужно разные таблицы БД) и, соответственно, свой restriction class.

От такой реализации автоблеклистинга пришлось отказаться, потому что policyd, с которым работал много лет, вдруг стал дурить. Это было под freebsd, а на двух линуксовых серверах автоблеклистилка пашет без проблем второй год (Примечание: в 2016 году работающей системе исполнителось 8 лет).

Вариант 2. Использование «обрезанного» полиси-сервера

Postfix может и сам блокировать IP-адреса, имеющиеся в БД, тогда от полиси-сервера требуется только тупо добавлять новые IP-адреса в БД.

Компонентный состав:

  1. Полиси-сервер, предназначенный не для полноценной защиты от спама, а только для пополнения черного списка: получив запрос от MTA, добавляет IP в БД и отвечает MTA «reject» (создается самостоятельно)

  2. Сам postfix (acl типа mysql создается самостоятельно)

  3. Запускаемый по крону скрипт (создается самостоятельно)

Порядок действий:

  1. Раздобыть полиси-сервер в исходниках. Например, я использую YanPoly (https://www.uli-eckhardt.de/yanpoly/). Обработать напильником. Если полиси-сервер будет запускаться самим Postfix’ом, прописать его в master.cf.

  2. Создать БД, которую будут использовать и постфикс, и полиси-сервер. Допустим, таблица будет иметь поля:

    • time - unixstamp момента внесения в БД
    • ip - IP-адрес зараженного хоста
    • answer - текст режекта (например, «“REJECT Automatically blacklisted. Please try again some days later»).
  3. Создать обычную ACL типа mysql для postfix’а (select aswer from ... where ip ...). Допустим, файл называется mysql_blacklist.cf.

  4. В smtpd_restriction_classes достаточно прописать один класс - для полиси-сервера (допустим, blacklist_policy_server).

  5. Соответственно, файл helo_pcre изменится на

    /^dyn-/		blacklist_policy_server
    /\.dhcp\./	blacklist_policy_server
    
  6. На основе входящего в дистрибутив полиси-сервера создать свой скрипт очистки таблицы от устаревших адресов и прописать запуск его по крону раз в час. Время хранения IP-адреса в БД задается в тексте скрипта.

  7. Активируем:

    smtpd_recipient_restrictions =
     ...
     check_client_access mysql:$config_directory/mysql_blacklist.cf
     check_helo_access pcre:$config_directory/helo_pcre.cf
     ...
    

Напоследок напомню, что при использовании полностью непробиваемых систем защиты от спама ваш долг - оставлять возможность ошибочно заблокированному отправителю связаться с вами и восстановить возможность переписки. До набора правил блеклистинга должны стоять белые списки, а почта, адресованная postmaster и abuse, должна вас достигать.