Rspamd

Материал из OpenWiki
Перейти к: навигация, поиск

Система фильтрации спама rspamd

История и основные возможности rspamd

Rspamd изначально создавался как более быстрая альтернатива системе spamassassin, который обладает рядом архитектурных недостатков. Среди основных недостатков можно выделить следующие:

  • обработка письма осуществляется набором регулярных выражений, однако, количество этих выражений слишком велико и является ключевым моментом задумчивости SA (например, для извлечения received заголовков письма, SA проверяет оные на соответствие всем ему известным MTA, очевидно, что такое действие не является оптимальным);
  • нет возможности явно получить ip адрес, с которого нам отправили письмо (в SA это делается парсом received заголовков, что я лично не считаю правильным, а тем более оптимальным способом, так как MTA всегда знает, откуда ему пришло данное письмо)
  • нет возможности передачи спам фильтру данных SMTP диалога
  • MIME парсинг писем очень медленный, так как опять же сделан на базе регулярных выражений

В итоге можно сказать, что основная проблема SA - это излишняя увлеченность авторов регулярными выражениями и отсутствие оптимизации. В итоге, в качестве базовых принципов создания rspamd были принципы оптимизации времени обработки писем, в числе которых:

  • полностью асинхронная работа с сетью (на базе libevent), в том числе DNS запросы и работа с http
  • быстрые механизмы выделения памяти
  • компиляция всех регулярных выражений и вызов только тех из них, которые наиболее возможны (то есть, имеется механизм ведения статистики срабатывания различных правил, и при обработке следующего письма учитывается обработка предыдущих, что позволяет максимально быстро провести основные тесты)
  • расширяемая архитектура: возможность написания плагинов на си, lua, возможность добавления новых типов фильтров, расширений протокола rspamc, возможность добавления новых типов статистических алгоритмов, алгоритмов нормализации и парсинга текстов
  • возможность динамической загрузки различных настроек, списков ip адресов и прочей информации через HTTP протокол с поддержкой даты модификации таких списков
  • использование везде, где возможно, специализированных конечных автоматов для разбора и анализа текстов
  • использование быстрого mime парсера gmime
  • работа в юникодном режиме для статистики и обработки текстов

Установка rspamd

Для установки rspamd можно либо воспользоваться готовым пакетом (rpm или deb), либо собрать rspamd из системы портов FreeBSD, либо скачать архив с исходным кодом и собрать rspamd самостоятельно. Все загрузки rspamd находятся тут. Для сборки вам понадобятся также некоторые библиотеки и программы:

  • libevent - библиотека для асинхронной обработки событий
  • glib - библиотека общего назначения, содержащая многие вещи, о которых разработчики libc, увы, забыли (glib не является графической библиотекой, хотя и используется, например, gtk)
  • gmime - MIME парсер на базе библиотеки glib
  • lua - встраиваемый скриптовый язык, используемый rspamd для конфигурации и написания плагинов
  • cmake - система сборки, которая позволяет rspamd собираться (по крайней мере, в теории) на всех Posix совместимых системах. Использовать стандартные в данной ситуации autotools я не стал, так как считаю их самой неудобной в использовании системой сборки исходников, которую можно только придумать.

Сборка rspamd достаточно стандартна для cmake based программ:

$ cmake .
$ make
# make install

Стартовые скрипты для linux like систем находятся в каталоге linux, а для bsd like - в каталоге freebsd. Работоспособность rspamd проверялась на следующих системах: linux (ubuntu, centos), FreeBSD, Darwin, Solaris. Работоспособность на других системах возможна, но не гарантируется.

Конфигурация и базовые принципы работы

Rspamd состоит из ряда процессов: основной (master) процесс, контролирующий работу остальных, выполняющий перезапуск rspamd, чтение конфигурации, базовые проверки и инициализацию, а также набор процессов-обработчиков (workers). Каждый такой процесс может иметь собственное назначение, например, процесс для обработки входящих писем, процесс, для управления (controller), smtp прокси, хранилище хешей и прочее. Количество и наличие этих процессов определяется конфигурационным файлом.

В ходе установки rspamd устанавливает базовый конфигурационный файл (rspamd.xml.sample) и набор lua файлов, в которых описаны часто используемые правила. Для работы rspamd можно переименовать rspamd.xml.sample в rspamd.xml и отредактировать его для вашего окружения (например, отредактировать порог срабатывания различных действий для письма, веса правил, пути до файлов лога и пида, пути до статистики). Конфигурационный файл состоит из ряда секций, каждая из которых содержит набор тегов. Подробная документация об опциях rspamd есть тут. В данной статье я лишь кратко пройдусь по опциям, которые наиболее важны для работы системы:

  • options: данная секция содержит общие параметры настройки - путь до пид-файла, временный каталог, а также несколько директив, на которых я бы хотел заострить внимание:
    • filters - включенные встроенные фильтры rspamd. К встроенным относятся фильтры на языке Си, обеспечивающие базовый функционал - обработку регулярных выражений, проверку spf записей, проверку нечетких хешей, проверку по таблице символов, проверку "черных" списков url'ей (surbl). Обычно нет смысла менять этот параметр, но это может оказаться полезным, если какой-то тип проверки вам не нужен.
    • statfile_pool_size - размер в байтах (поддерживаются суффиксы K, M, G для кило-, мега- и гигабайт соответственно) пула статистики. Дело в том, что каждый файл статистики в rspamd имеет фиксированный объем и подключается путем создания memory map, поэтому этот параметр должен быть не меньше, чем суммарный объем используемых файлов статистики.
    • raw_mode - флаг, который позволяет работать в utf режиме - перекодируя все входящие сообщения в utf8 режим. В настоящее время этот режим до конца не отлажен, поэтому для общих целей лучше оставить этот параметр в значении "yes".
    • lua - подключение к rspamd lua файла. В конфигурации по умолчанию этот параметр указывает подключить стандартные правила (в основном регулярные выражения). Боле подробно об этом написано в документации. Основной аргумент в вынесении правил из основной конфигурации - упрощение базовой настройки и возможность создания динамических правил на языке lua.
  • секция logging: данная секция содержит настройки ведения лог файлов. Основные типы и полезные параметры (например, выборочная отладка) приведены в примере конфигурационного файла
  • секции metric: содержит определение группы символов. В определении метрики содержатся следующие параметры:
    • имя метрики
    • максимальный вес
    • действие по достижению максимального веса
    • другие действия по достижению весов, меньших, чем максимальный
    • веса символов, входящих в метрику

Данная секция позволяет настроить набор правил, весов и действий, которые определяют основное поведение rspamd. Правила, которые не определены ни в одной метрике, добавляются в метрику с именем default с весом, равным 1. Если правило определено в нескольких метриках, то его вес будет добавлен во все из них. Основная задача администратора - скорректировать веса правил и предельные веса для различных действий. Это позволяет сделать выборочную фильтрацию почты, выборочный грейлистинг и прочее.

  • секции worker: содержит определения процессов rspamd. Более подробно об этом в документации.
  • секции module: содержит настройки встроенных и внешних модулей, написанных на lua
  • секции classifier: служат для настройки статистики. Параметр, который вам, возможно, придется поменять, - путь до файла статистики и его размер.
  • секция modules: содержит пути до lua плагинов.

Некоторые примеры настроек секций:

  • Базовые опции:
<options>
 <!-- Задаем путь до pid'а -->
 <pidfile>/var/run/rspamd/rspamd.pid</pidfile>
 <!-- Включаем все встроенные модули -->
 <filters>regexp,surbl,chartable,fuzzy_check,spf</filters>
 <!-- Задаем размер пула статистики -->
 <statfile_pool_size>200M</statfile_pool_size>
 <!-- Включаем utf режим -->
 <raw_mode>no</raw_mode>
 <!-- Отключаем многократное срабатывание правил -->
 <one_shot>yes</one_shot>
</options>
<!-- Загружаем правила из lua -->
<lua src="/usr/local/etc/rspamd/lua/rspamd.lua" />
  • Логирование:
<logging>
 <!-- Ведем логи на уровне info -->
 <level>info</level>
 <!-- Не пишем в лог встреченные url'и (это полезно для ведения "черных" списков url'ей) -->
 <log_urls>no</log_urls>
 <!-- Пишем лог в файл -->
 <type filename="/var/log/rspamd/rspamd.log">file</type>
 <!-- Включаем отладку для локальных соединений -->
 <debug_ip>127.0.0.1</debug_ip>
</logging>
  • Метрика и веса:
<metric>
 <!-- Имя метрики -->
 <name>default</name>
 <!-- Суммарный вес символов для выполнения default action -->
 <required_score>10.0</required_score>
 <!-- Действие по умолчанию -->
 <action>reject</action>
 <!-- Действие по достижению 5-ти баллов -->
 <action>greylist:5</action>
 <!-- Веса символов, входящих в метрику -->
 <symbol weight="2.00">MISSING_SUBJECT</symbol>
 ...
</metric>
  • Настройка трех основных видов процессов обработчиков: mime обработчика, контроллера и хранилища нечетких хешей:
<worker>
 <!-- Тип процесса - хранилище хешей -->
 <type>fuzzy</type>
 <!-- Адрес, на котором процесс будет принимать соединение. 
            Если установить адрес в *, то слушать процесс будет на всех доступных адресах -->
 <bind_socket>localhost:11335</bind_socket>
 <!-- Число процессов данного типа -->
 <count>1</count>
 <!-- Путь до хранилища хешей -->
 <hashfile>/tmp/fuzzy.db</hashfile>
 <!-- Использовать judy массивы для ускорения хранилища
            Эту опцию можно включать, если в системе установлена libJudy -->
   <use_judy">yes</use_judy>
</worker>
<worker>
 <!-- Процесс-контроллер -->
 <type>controller</type>
 <!-- Тут также возможно указывать unix сокет -->
 <bind_socket>/var/run/rspamd/controller.sock</bind_socket>
 <count>1</count>
 <!-- Пароль для привиллегированных команд -->
 <password>q1</password>
</worker>
<worker>
 <!-- Обработчик mime сообщений -->
 <type>normal</type>
 <bind_socket>*:11333</bind_socket>
 <!-- Если параметр count не указан, то запустится число процессов, равное числу процессоров в системе -->
</worker>
  • Настройка bayes статистики:
<classifier type="bayes">
<!-- Способ разбиения сообщения на токены, на данный момент поддерживается только osb-text -->
<tokenizer>osb-text</tokenizer>
<!-- Минимальное число слов в сообщении, чтобы оно проверялось статистикой -->
<min_tokens>10</min_tokens>
<!-- Описание файлов статистики -->
<statfile>
 <!-- Символ, вставляемый при срабатывании -->
 <symbol>BAYES_HAM</symbol>
 <!-- Размер файла -->
 <size>10M</size>
 <!-- Путь до файла -->
 <path>/var/run/rspamd/bayes.ham</path>
</statfile>
<statfile>
 <symbol>BAYES_SPAM</symbol>
 <size>10M</size>
 <path>/var/run/rspamd/bayes.spam</path>
</statfile>
</classifier>
  • Настройка основных модулей rspamd:
    • модуль surbl - проверки "черных" списков url:
<module name="surbl">
 <!-- Путь до "белого" списка доменов -->
 <whitelist>file:///usr/local/etc/rspamd/surbl-whitelist.inc</whitelist>
 <!-- Путь до списка доменов, которые требуют для проверки более двух компонентов доменного имени -->
 <exceptions>file:///usr/local/etc/rspamd/2tld.inc</exceptions>
 <!-- Описание DNS списка, %b меняется на бит (об этом чуть позднее) -->
 <option name="suffix_%b_SURBL_MULTI">multi.surbl.org</option>
 <option name="bit_64">JP</option>
 <option name="bit_32">AB</option>
 <option name="bit_16">OB</option>
 <option name="bit_8">PH</option>
 <option name="bit_4">WS</option>
 <option name="bit_2">SC</option>
 <!-- Еще один список -->
 <option name="suffix_RAMBLER_URIBL">uribl.rambler.ru</option>
 <!-- Опции определителя перенаправлений -->
 <option name="redirector_read_timeout">10s</option>
 <option name="redirector_connect_timeout">1s</option>
 <!-- Адрес определителя -->
 <option name="redirector">localhost:8080</option>
 <!-- Файл, содержащий домены для проверки -->
 <option name="redirector_hosts_map">/usr/local/etc/rspamd/redirector.inc</option>
</module>

Некоторые примечания по модулю. SURBL по умолчанию извлекает 2 компонента доменного имени из полученного url. Например, из url http://www.freebsd.org/doc/en_US.ISO8859-1/books/handbook/ будет извлечена строчка freebsd.org и проверена на заданных суффиксах. Однако, это поведение можно изменить, написав домен freebsd.org в файле exceptions. Тогда будет взята строка www.freebsd.org, а если в exceptions написать www.freebsd.org, то может быть взят еще один компонент доменного имени, например, en.www.freebsd.org. Суффиксы задают списки для проверки. Подробно о них можно прочитать на [1], в имени списка можно указать символ %b, сделанный для поддержка комбинированного списка multi.surbl.org. Дело в том, что при резолве хоста на multi.surbl.org (например, freebsd.org.multi.surbl.org) ответ приходит в виде ip адреса, биты которого указывают, в каком специфическом списке содержится данный url (их может быть несколько). Опции bit_N задают, как будет заменена строка %b в символе, который будет вставлен. Например, присутствие в ответе 16 и 2-го битов вставит 2 символа: OB_SURBL_MULTI и SC_SURBL_MULTI.

    • модуль проверки нечетких хешей:
<module name="fuzzy_check">
 <!-- Список хранилищ нечетких хешей -->
 <option name="servers">localhost:11335</option>
 <!-- Символ, который будет вставлен при нахождении -->
 <option name="symbol">R_FUZZY</option>
 <!-- Минимальная длина сообщения в символах -->
 <option name="min_length">300</option>
 <!-- Максимальный вес символа -->
 <option name="max_score">10</option>
 <!-- Список дополнительных типов для проверки хеша -->
 <option name="mime_types">application/pdf,application/ms-word</option>
 <!-- Описание различных списков хешей -->
 <option name="fuzzy_map">1:R_FUZZY1:10,2:R_FUZZY2:5,3:R_FUZZY3:-2.1</option>
</module>

Примечания по модулю. Модуль проверяет наличие нечеткого хеша в хранилищах. То, на каком хранилище будет сохранен хеш, выбирается по его контрольной сумме (естественно, что читается хеш с того же сервера, на который он и записывается). Кроме этого, при записи хеша (команда fuzzy_add) можно указать его вес и номер списка. Это полезно, когда хеши поступают из разных источников: honeypots, кнопка "спам" пользователя, whitelists. Разумеется, эти хеши должны иметь разный максимальный вес и разное имя символа. Для этого хеши описываются списков fuzzy_map, состоящем из разделенных запятыми триплетов: <номер_списка>:<символ>:<максимальный_вес>. Для добавления хеша в список 2 с весом 10 используется команда:

rspamc -f 2 -w 10 fuzzy_add message.eml

Для удаления можно применять команду fuzzy_del с аналогичными аргументами.

Работа с rspamd

Сигналы

Сигналы можно посылать master процессу (pid которого находится в указанном в конфигурации pidfile):

  • SIGTERM - остановить работу rspamd
  • SIGHUP - перечитать конфиг и создать новые процессы-обработчики, старые при этом перестают принимать соединения и через некоторое время завершают работу (примерно 1 минута)
  • SIGUSR2 - переоткрыть лог-файл.

Если вы используете стартовый скрипт, то он посылает эти сигналы сам, обеспечивая более удобный интерфейс, например, `rspamd reload`.

Передача сообщений rspamd

Для передачи писем rspamd можно использовать две возможности: передача сообщения обычному обработчику, используя расширенный протокол rspamc или же протокол совместимости с SpamAssassin'ом (оба эти протокола похожи на HTTP, но rspamc поддерживает больший набор заголовков, а также метрики, протокол совместимости очень ограничен в заголовках и отдает ответ только по метрике *default*), а также работа rspamd в режиме балансирующего smtp прокси, выполняющего проксирование smtp соединений и проверку их "на лету". Второй способ, безусловно, более удобен, однако он не тестировался в production, и я не рекомендую его для ответственных систем.

Для связи с MTA по rspamc протоколу можно использовать 2 варианта: milter (для postfix и sendmail) и local_scan патч для exim'а. Протокол rspamc пока поддерживает только один milter, который был специально для этого написан: rmilter. Пример настройки rmilter'а для проверки писем на rspamd:

spamd {
  servers = r:spam1.test.ru:11333, r:spam2.test.ru:11333;
  connect_timeout = 1s;
  results_timeout = 20s;
  error_time = 10;
  dead_time = 300;
  maxerrors = 10;
  reject_message = "Spam message rejected; If this is not spam contact abuse at test.ru";
};

Для работы с MTA exim, необходимо пересобрать его с файлом contrib/exim/local_scan.c. Более подробно интеграция с MTA описана в документации

Также rspamd поставляется с утилитой rspamc, предоставляющей доступ к основным командам rspamd. Работа с утилитой довольно проста:

  • rspamc symbols [file, [file|directory]] - для проверки писем
  • rspamc -P q1 -с bayes learn_spam [file, [file|directory]] - для обучения письмами статистику спама
  • rspamc -P q1 -c bayes learn_ham [file, [file|directory]] - для обучения письмами статистику хама
  • rspamc stat - для получения статистики

Обратите внимание, что для обучения ключом -P указывается дополнительный параметр - пароль для привилегированных команд, который настраивается в секции worker процесса-контроллера.

Также при обучении rspamd необходимо учитывать, что количество спама и хама должно быть примерно одинаковым, иначе статистика будет работать неверно.

Сравнение производительности rspamd и spamassassin

Сравнение производилось следующим образом: параллельно обрабатывалось 30 писем, всего таких пакетов было 100 (то есть, 3000 писем). SA и rspamd были запущены на одной и той же машине, конфигурация различалась только тем, что rspamd также проверял статистику, которая была отключена в SA, и нечеткие хеши, которые в SA не поддерживаются. Кроме этого, на rspamd шел обычный рабочий поток писем на проверку (порядка 10 писем в секунду). Сравнивалась по top'у средняя загрузка машины:

SA:

Sa.png

Rspamd:

Rs.png

Дальнейшая работа с rspamd

Для получения полной информации о конфигурации rspamd, о модулях rspamd и об API rspamd можно прочитать в документации на wiki, а также в каталоге doc исходного кода rspamd. Для получения оперативной поддержки по всем вопросам, связанным с rspamd, можно писать в рассылку rspamd: rspamd-devel@lists.sourceforge.net, или же пользоваться системой сообщения о багах butbucket'а.