Простой greylisting в opensmtpd

Данная статья является логическим продолжением статьи «Интеграция почтового анти-спама rspamd с opensmtpd» из-за некоторого вызова, который мне бросили, сказав, что сложно реализовать greylisting в связке opensmtpd+rspamd.


«Историй успеха» интеграции greylisting в opensmtpd я не встречал (если они существуют, то просьба написать в комментариях).


Что реализовать greylisting в моём случае сложно — я не отрицал и не собирался делать данный функционал до того, как в opensmtpd реализуют фильтры, хотя и понимал, что greylisting — одна из неплохих методик борьбы со спамом. Но брошенный вызов и желание ещё немного снизить количество спама и спать спокойно — не дали спать спокойно и заставили сделать это.


Мне удалось реализовать простой способ greylisting’а.



Несколько уточнений:


  1. Способ простой только для того случая, если реализация связки opensmtpd+rspamd сделана через скрипт-прослойку mda.


  2. Реализация greylisting’а для opensmtpd существует через фильтр. Но, как знают, заинтересованные в opensmtpd лица, стабильной реализации фильтров в opensmtpd нет. Кроме того, не хотелось добавлять ещё один демон при наличии встроенного грейлистинга в rspamd.


  3. Реализация грейлистинга для opensmtpd существует для freebsd и spamd. Подробностями реализации не интересовался, т.к. демона spamd под linux нет.


  4. Реализация является костылём и использованием недокументированных возможностей, но куда мы без них в IT?

Теория

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


Упрощённая логика грейлистинга: если к нам приходит письмо, то мы отвечаем отправителю временной ошибкой, сами запоминаем отправителя (например, на сутки) для того, чтобы принять от него письмо через некоторое время (например, через 5 минут).


«Правильный» отправитель (согласно стандартам) должен попытаться отправить нам письмо ещё раз через некоторое время. «Неправильный» отправитель этого или не делает или делает, но за прошедшее время отправитель успевает попасть в различные внешние спам-списки и мы его отфильтровываем уже на основании этих спам-списков.


После того, как мы отправителя запомнили, то в течение суток (как пример), проверка на грейлисты не делается повторно. Это позволяет сократить время доставки повторного письма (если это правильный отправитель).


В postfix+amavis+spamasassin greylisting делался, если не ошибаюсь, по доменным именам. В rspamd ключём для greylisting’а сделан IP адрес отправителя с маской /19 (конфигурируемо). Со стороны всеобщей кластеризации и гео-распределённых сервисов — это выглядит как более правильное решение, но и обсуждаемое, с другой стороны.


К сожалению, всё вышесказанное в теории выглядит хорошо, но на практике, когда на чайниках, микроволновках и компьютерах обычных пользователей существует множество ботнетов, которые рассылают спам через обычный Outlook (как он там, существует ещё до сих пор на Windows?) — всё не так замечательно. Но как-то методика работает и отказываться от неё не стоит.


Практика

redis в rpsamd


Включаем поддержку редиса в rpsamd. Модуль грейлистинга хранит в редисе свои данные.


# /etc/rspamd/local.d/redis.conf
servers = "redis.example.com";
password = "example_password";

Запускаем редис (в докере, например, это делается одной командой).


greylisting в rspamd


Включаем модуль грейлистинга (по умолчанию, он выключен). expire — время, на которое отправитель становится доверенным, после прохождения проверки. Я специально подкрутил побольше. По умолчанию — 86400 секунд.


# /etc/rspamd/modules.d/greylist.conf
greylist {
  expire = 864000;

  .include(try=true,priority=5) "${DBDIR}/dynamic/greylist.conf"
  .include(try=true,priority=1,duplicate=merge) "$LOCAL_CONFDIR/local.d/greylist.conf"
  .include(try=true,priority=10) "$LOCAL_CONFDIR/override.d/greylist.conf"
}

→ Пример контейнера с rspamd


greylisting в opensmtpd


Самая неоднозначная часть решения.


После того, как мы отправили письмо демону rspamd через клиент rspamc (см. предыдущую статью) — демон нам на STDOUT отвечает текстом письма с добавленными заголовками.


В случае, если требуется greylisting, то в заголовках будет присутствовать «X-Spam-Action: soft reject». По хорошему, mta или фильтры распознают этот заголовок и отвечают отправителю временной ошибкой.


Но у нас нет поддержки mta или фильтров. Поэтому, мы просто делаем exit 1!


# см. скрипт из предыдущий статьи
greylisted=$( cat $mail_file | fgrep 'X-Spam-Action: soft reject' )
if [ -n "$greylisted" ]; then
  exit 1
fi

opensmtpd, получив код возврата 1, понимает, что что-то пошло не так и за нас отвечает отправителю временной ошибкой.


Особенности запуска docker контейнера с opensmtpd: его нужно запускать в режиме сети «host», чтобы демон видел корректные IP адреса отправителей.


→ Пример контейнера с opensmtpd


Итого

Ещё меньше спама.

Комментарии (0)

© Habrahabr.ru