Настройка GreyList в Exim + PostgreSQL
Вступление
В качестве основы был взят
Fast Gray List Mini
Tutorial (PostreSQL Edition). Но этот вариант обладает существенными
недостатками.
Во-первых, авторами предлагается делать проверку два раза: в acl_check_rcpt и
acl_check_data. Как следствие, для определения отправителя и получателя они
вынуждены строить тяжёлые конструкции, и, что более опасно, исходный алгоритм
работы приводит к следующей проблеме для, например, перенаправленных писем:
- Удалённый почтовый сервер получает письмо от user@domain1 на
user@domain2 и пытается переслать его на user@domain3.
- Мы заносим в greylist письмо с адресами из конверта письма
sender=user@domain1, recipient=user@domain3. В greylist мы попадаем потому,
что пересылает письмо нам сервер, ответственный за domain2, а он не является
MX-ом для domain1.
- По истечении заданного времени сервер повторно приходит и на этапе RCPT TO:
получает accept.
- Сервер честно передаёт нам письмо после DATA, после чего мы его ОПЯТЬ
заносим в greylist. Потому, что $domain на этапе проверки acl_check_data не
определён, а в $h_to: у нас будет user@domain2, что не совпадает с предыдущим
значением. При этом предыдущая разрешающая запись удаляется.
- По истечении заданного времени сервер повторно приходит и его заносим в
greylist. Потому как теперь опять проверка идёт на этапе acl_check_rcpt и
используются данные из конверта. Возращаемся на пункт 2.
Во-вторых, возникает ощущение, что автор исходной инструкции недостаточно
хорошо знаком с PostgreSQL и, например, для хранения адреса с маской использует
тип character varying, не смотря на существование типов данных INET и CIDR.
В-третьих, предложенный автором вариант удаления устаревших записей реально
если и работает, то очень плохо и на очень сильно нагруженных серверах.
Как временное решение у меня удаление происходит при каждой проверке.
Для системы со средним числом попыток RCPT TO: около одного в секунду и
адекватными проверками HELO/DNSBL/... до проверки GreyList это не является
проблемой, но при более высокой нагрузке лучше удаление вынести
в отдельный, вызываемый из crontab скрипт.
Результат
Итогом изучения и переделки исходного документа стали:
- Файл создания базы
- Файл определений, который включается в
конфигурационный файл сразу после определения primary_hostname:
.include /usr/local/etc/exim/greylist/defines
- Файл greylist_acl, который включается
в конфигурационный файл в начале определения конфигурации acl
после строки "begin acl":
.include /usr/local/etc/exim/greylist/greylist_acl
- Файл acl_check_rcpt, который включается
в конфигурационный файл перед последним accept секции acl_check_rcpt:
.include /usr/local/etc/exim/greylist/acl_check_rcpt
Примечания:
- Для отладки включено логирование работы в таблицу greylist_log.
Для отключения необходимо в файле defines закомментировать строку:
GREYLIST_ENABLED_LOG = yes
- Для создания "белого списка" можно воспользоваться таким запросом:
INSERT INTO
greylist(relay_ip, bounce, sender, recipient, block_expires, manual)
VALUES('0/0', FALSE, 'sender.domain', 'recipient.domain', '0001-01-01', TRUE);