From: cebka@lenovo-laptop Date: Thu, 4 Feb 2010 17:58:47 +0000 (+0300) Subject: * Add a little review of rspamd X-Git-Tag: 0.3.0~90 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=f57b47be64858f088fc0406c05d8fed94f5f9477;p=rspamd.git * Add a little review of rspamd * Add local_scan.c from Anton Nekhoroshikh for exim MTA --- diff --git a/contrib/exim/local_scan.c b/contrib/exim/local_scan.c new file mode 100644 index 000000000..6761c2840 --- /dev/null +++ b/contrib/exim/local_scan.c @@ -0,0 +1,702 @@ +/* + This program is RSPAMD agent for use with + exim (http://www.exim.org) MTA by its local_scan feature. + + To enable exim local scan please copy this file to exim source tree + Local/local_scan.c, edit Local/Makefile to add + + LOCAL_SCAN_SOURCE=Local/local_scan.c + LOCAL_SCAN_HAS_OPTIONS=yes + + and compile exim. + + Comment out RSPAM_UNIXSOCKET definition below if you have remote RSPAMD + daemon + + AND + + use Exim parameters daemonIP and daemonPort to configure remote + RSPAMD daemon. + + For exim compilation with local scan feature details please visit + http://www.exim.org/exim-html-4.50/doc/html/spec_toc.html#TOC333 + + For RSPAMD details please visit + http://cebka.pp.ru/trac/ +*/ + +/* Comment out the row below to use socket type AF_INET + to connect RSPAMD daemon */ +//#define RSPAM_UNIXSOCKET + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "local_scan.h" + +extern uschar *sender_helo_name; +extern int message_size; + +#define READ_FAIL(x) ((x) < 0) +#define RSPAMD_FAILURE_HDR "X-Spam-Flag" +#define RSPAMD_SCORE_HDR "X-Spam-Status" +#define REJECT_ON_ERROR 0 + +static int _OK = 0; +static int ERR_WRITE = 53; +static int ERR_READ = 54; +static int MAX_FAILS_C = 256; +static int MAX_PATH = 256; +static int MAX_SIZE_FILE = 64*1024; + +static uschar *daemonIP = US"127.0.0.1"; +static int daemonPort = 11333; +static uschar *temp_dir = US"/var/tmp"; +static uschar *socket_name = US"/var/run/rspamd.sock"; +static int strange = 0; + +optionlist local_scan_options[] = +{ + {"rspam_ip", opt_stringptr, &daemonIP}, + {"rspam_port", opt_int, &daemonPort}, + {"rspam_tmp", opt_stringptr, &temp_dir}, + {"rspam_sock", opt_stringptr, &socket_name}, + +}; + +int local_scan_options_count = sizeof (local_scan_options) / sizeof (optionlist); + +typedef int socket_t; +static socket_t sock = -1; + +int iFdInp; +struct sockaddr_un ssun; +struct sockaddr_in ssin; + +static int mOpenTmp (char *pszDir, char *pszPrefix, char *pszPath) +{ + int iLen; + int iFd = -1; + char *pszSep = ""; + + iLen = (int)strlen(pszDir); + if (iLen > MAX_PATH) + return -1; + + if (pszDir[iLen - 1] != '/') + pszSep = "/"; + + sprintf (pszPath, "%s%s%sXXXXXX", pszDir, pszSep, pszPrefix); + iFd = mkstemp (pszPath); + + if (iFd < 0) + log_write (0, LOG_MAIN, "rspam-exim: Temp file create error %d", errno); + + return iFd; +} + +static int ReadFd (int iFdMsg, int fd) +{ + char psMsg [MAX_SIZE_FILE]; /* max size SO can swallow */ + int iLen, result = _OK; + + if ((iLen = read (fd, psMsg, sizeof (psMsg))) > 0) + { + if (write (iFdMsg, psMsg, (unsigned int) iLen) != iLen) + result = ERR_WRITE; + } + else + result = ERR_READ; + + close (iFdMsg); + + return result; +} + + +void CleanupInp (char *sName) +{ + if (sName) unlink (sName); + + close (iFdInp); + return; +} + + +int FakeSMTPCommand (socket_t sock, + char *command, + char *value, + char *sName, + int Cleanup, + int wa) +{ + char sCommand[1024]; + char answ [3]; + int Len; + + sprintf (sCommand, "%s %s\r\n", command, value); + + if (send (sock, sCommand, strlen (sCommand), 0) != (int) strlen (sCommand)) + { + log_write (0, LOG_MAIN, "rspam-exim: socket sending '%s' error %d", sCommand, errno); + if (Cleanup) + CleanupInp (sName); + return ERR_WRITE; + } + + if(wa) { + memset (answ, '\0', sizeof (answ)); + Len = read (sock, answ, sizeof (answ)); + if (READ_FAIL (Len)) + { + log_write (0, LOG_MAIN, "rspam-exim: read() error %d, len=%d", errno, Len); + if (Cleanup) + CleanupInp (sName); + return ERR_WRITE; + } + + if (strncmp (answ, "OK", 2) != 0) + { + log_write (0, LOG_MAIN, "rspam-exim: server did not confirm, answ=%s", answ); + if (Cleanup) + CleanupInp (sName); + return ERR_WRITE; /* Cannot read message error code */ + } + } + + return OK; +} + + +static int writen (socket_t fd, const char *vptr, int n) +{ + size_t nleft; + int nwritten; + const char *ptr; + + ptr = vptr; + nleft = n; + while (nleft > 0) + { + if ((nwritten = send (fd, ptr, nleft, 0)) <= 0) + { + if (errno == EINTR) + nwritten = 0; + else + return (-1); + } + + nleft -= nwritten; + ptr += nwritten; + } + + return (n); +} + + +static int SendEnvelope (char *sFile) +{ + int i; + char str [256], *rh; + void *psBuf; + int fd, bytesRead; + + if(message_size > MAX_SIZE_FILE) { + log_write (0, LOG_MAIN, "rspam-exim: file %s is great %d bytes", sFile, MAX_SIZE_FILE); + return ERR_WRITE; + } + + /* send greeting */ +// if(FakeSMTPCommand(sock, "PROCESS", "RSPAMC/1.0", sFile, 1, 0) != _OK) +// return ERR_WRITE; + if(FakeSMTPCommand(sock, "SYMBOLS", "RSPAMC/1.1", sFile, 1, 0) != _OK) +// if(FakeSMTPCommand(sock, "CHECK", "RSPAMC/1.0", sFile, 1, 0) != _OK) + return ERR_WRITE; + + + + /* sender IP */ + if (FakeSMTPCommand (sock, "IP:", sender_host_address, sFile, 1, 0) != _OK) + return ERR_WRITE; + + /* mail from */ + if (FakeSMTPCommand (sock, "From:", + strlen (sender_address) == 0 ? "MAILER-DAEMON" : (char*) sender_address, sFile, 1, 0) != _OK) + return ERR_WRITE; + + /* send helo */ + if (FakeSMTPCommand (sock, "Helo:", sender_helo_name, sFile, 1, 0) != _OK) + return ERR_WRITE; + + /* send helo */ + sprintf(str, "%d", message_size); + if (FakeSMTPCommand (sock, "Content-Length:", str, sFile, 1, 0) != _OK) + return ERR_WRITE; + + /* number of recipient */ + sprintf(str, "%d", recipients_count); + if (FakeSMTPCommand (sock, "Recipient-Number:", str, sFile, 1, 0) != _OK) + return ERR_WRITE; + + /* envelope rcpto */ + for (i = 0; i < recipients_count; i ++) + { + if (FakeSMTPCommand (sock, "Rcpt:", recipients_list[i].address, sFile, 1, 0) != _OK) + return ERR_WRITE; + } + + psBuf = store_get (MAX_SIZE_FILE); + + fd = open (sFile, O_RDONLY); + if (fd > 0) + { + bytesRead = read (fd, psBuf, MAX_SIZE_FILE); + close (fd); + + if (FakeSMTPCommand (sock, "\r\n", "", sFile, 1, 0) != _OK) + return ERR_WRITE; + + if (writen (sock, psBuf, bytesRead) != bytesRead) + return ERR_WRITE; + } + else + { + log_write (0, LOG_MAIN, "rspam-exim: file %s open error %d", sFile, errno); + return ERR_WRITE; + } + + return _OK; +} + + +int GetFiles (char *pInpFile, int local_scan_fd) +{ + /* + Returns OK if no errors, else error code. + On succesful return, pEnvFile points to Envelope file name and + pInpFile points to Message filename + */ + int iStatus; + struct header_line *h_line; + + iFdInp = mOpenTmp ((char *)temp_dir, "sp-inp", pInpFile); + if (iFdInp == -1) + { + return ERR_WRITE; + } + + /* Emit headers */ + h_line = header_list; + while (h_line != NULL) + { + if (h_line->type == '*') /* internal header */ + { + h_line = h_line->next; + continue; + } + + if (write (iFdInp, h_line->text, strlen (h_line->text)) != strlen (h_line->text)) + { + CleanupInp (""); + return ERR_WRITE; + } + h_line = h_line->next; + } + if (write (iFdInp, "\n", 1) != 1) + { + CleanupInp (""); + return ERR_WRITE; + } + + /* Read msg */ + if ((iStatus = ReadFd (iFdInp, local_scan_fd))) + { + return iStatus; + } + + /* Return success */ + return _OK; +} + + +int GetAndTransferMessage (int fd, char *sFile) +{ + char answ [4]; + int iStatus; + int Len, ccnt; + + iStatus = GetFiles ((char *)sFile, fd); + + if (iStatus != _OK) + { + log_write (0, LOG_MAIN, "rspam-exim: Error %d getting message", iStatus); + close (sock); + return iStatus; + } + + for (ccnt = 0; ccnt <= MAX_FAILS_C; ccnt ++) + { +#ifdef RSPAM_UNIXSOCKET + if (connect (sock, (struct sockaddr *) &ssun, sizeof (struct sockaddr_un)) < 0) +#else + if (connect (sock, (struct sockaddr *) &ssin, sizeof (struct sockaddr_in)) < 0) +#endif + { + if (ccnt < MAX_FAILS_C) + usleep (1000); + else + { + close (sock); +#ifdef RSPAM_UNIXSOCKET + log_write (0, LOG_MAIN, "rspam-exim: socket connect to %s failed", (char *)socket_name); +#else + log_write (0, LOG_MAIN, "rspam-exim: socket connect to %s:%u failed", daemonIP, daemonPort); +#endif + return REJECT_ON_ERROR ? LOCAL_SCAN_TEMPREJECT:LOCAL_SCAN_ACCEPT; + } + } + else + break; + } + + iStatus = SendEnvelope (sFile); + if (iStatus != _OK) + { + log_write (0, LOG_MAIN, "rspam-exim: error %d sending envelope data", iStatus); + close (sock); + return iStatus; + } + + /* fprintf (stderr, "Transmit OK\n"); */ + return _OK; +} + +void header_del (uschar *hdr) +{ + struct header_line *h_line; + + h_line = header_list; + while (h_line != NULL) + { + if (h_line->type == '*') /* internal header */ + { + h_line = h_line->next; + continue; + } + + if (strncasecmp (h_line->text, hdr, strlen(hdr)) == 0) + { + h_line->type = '*'; + while (h_line->next && + (*h_line->next->text == ' ' || *h_line->next->text == '\t')) + { + h_line = h_line->next; + h_line->type = '*'; + } + } + h_line = h_line->next; + } +} + +void AlterSubject (char *label) +{ + struct header_line *h_line; + char *subject, *strP; + + h_line = header_list; + + while (h_line != NULL) + { + if (h_line->type == '*') /* internal header */ + { + h_line = h_line->next; + continue; + } + + if (strncasecmp (h_line->text, "Subject", strlen("Subject")) == 0) + { + strP = strchr (h_line->text, ':'); + subject = string_copy (++strP); + while (h_line->next && + (*h_line->next->text == ' ' || *h_line->next->text == '\t')) + { + h_line = h_line->next; + subject = string_sprintf ("%s\n%s", subject, h_line->text); + } + header_del (US "Subject"); + break; + } + + h_line = h_line->next; + } + header_add (' ', "Subject: %s%s", label, subject ? subject : ""); +} + +int +io_read(int fd, char *buf, size_t size) +{ + int nfd, next = 0, rcount = 15; + size_t len = 0; + fd_set fds; + struct timeval tv; + + if((sock < 0) || (buf == NULL)) + return -1; + + FD_ZERO(&fds); + +repeat_read: + + tv.tv_sec = 5; + tv.tv_usec = 0; + FD_SET(fd, &fds); + +// log_write(0, LOG_MAIN, "rspam-exim: before select"); + + if((nfd=select(fd+1, &fds, NULL, NULL, &tv)) == -1) { +// log_write(0, LOG_MAIN, "rspam-exim: select error: %s", strerror(errno)); + return -1; + } + +// log_write(0, LOG_MAIN, "rspam-exim: select return %d fds, rcount %d, next %d", nfd, rcount, next); + + if((nfd>0) && (FD_ISSET(fd, &fds))) { + next += len = read(fd, buf + next, size - next); +// log_write(0, LOG_MAIN, "rspam-exim: read %d bytes", len); +// if(next0) + goto repeat_read; + + return next; +} + +int WaitForScanResult (uschar **resStr) +{ + int Len, i; + int rej, result = LOCAL_SCAN_ACCEPT, answer_size, spm = 0, code = 0, ns = 0, smb = 0, urf = 0; + char *strP, *tok, *tmp; + char *hdr = NULL, *hdrv = NULL, *spmStr = NULL, *symbols=NULL, *urls=NULL; + char answ [4096], state[6], metric[128], back; + float sm=0, smd=0, smr=0; + + memset (answ, '\0', sizeof (answ)); +// log_write(0, LOG_MAIN, "rspam-exim: before read from %d", sock); +// Len = read (sock, answ, sizeof (answ) - 1); + Len = io_read(sock, answ, sizeof (answ) - 1); + log_write(0, LOG_MAIN, "rspam-exim: read %d bytes", Len); + + if (strncmp (answ, "RSPAMD/1.1 ", 11) == 0) + { + strP = (char *)answ; + for (tok = strtok (strP, "\n"); tok; tok = strtok (NULL, "\n")) + { +// log_write(0, LOG_MAIN, "rspam-exim: process line '%s'", tok); + + if (strncmp (tok, "RSPAMD/1.1 ", 11) == 0) + { + if (sscanf (tok, "%*s %d %s", &code, state) == 2) + { +// log_write(0, LOG_MAIN, "rspam-exim: daemon reports code %d %s", code, state); + if ((code == 0) && (strcmp(state,"OK")==0)) { + header_del ((uschar *) RSPAMD_FAILURE_HDR); + header_add (' ', "%s: SKIP\n", RSPAMD_FAILURE_HDR); + strange = 1; + continue; + } else { + header_del ((uschar *) RSPAMD_FAILURE_HDR); + header_add (' ', "%s: SKIP\n", RSPAMD_FAILURE_HDR); + log_write(0, LOG_MAIN, "rspam-exim: daemon reports code %d %s", code, state); + return LOCAL_SCAN_ACCEPT; + } + } + continue; + } + + /* Metric: default; False; 6.00 / 10.00 */ + /* Process metric */ + if (strncmp (tok, "Metric:", 7) == 0) + { + tmp = tok; + while( (*tmp++) && + ((*tmp!='\r') || (*tmp!='\n')) + ); + back = *tmp; + *tmp = '\0'; + if (sscanf (tok, "Metric: %[^';']; %[^';']; %f / %f / %f", metric, state, &sm, &smd, &smr) == 5) { + log_write(0, LOG_MAIN, "rspam-exim: metric: %s; %s; %f / %f / %f", metric, state, sm, smd, smr ); + if(strcasecmp(state,"true")==0) { + header_del ((uschar *) RSPAMD_FAILURE_HDR); + header_add (' ', "%s: %s\n", RSPAMD_FAILURE_HDR, "Yes"); + } else if(strcasecmp(state,"skip")==0) { + header_del ((uschar *) RSPAMD_FAILURE_HDR); + header_add (' ', "%s: %s\n", RSPAMD_FAILURE_HDR, "Skip"); + } else { + header_del ((uschar *) RSPAMD_FAILURE_HDR); + header_add (' ', "%s: %s\n", RSPAMD_FAILURE_HDR, "No"); + } + header_del ((uschar *) RSPAMD_SCORE_HDR); + header_add (' ', "%s: %.2f / %.2f / %.2f\n", RSPAMD_SCORE_HDR, sm, smd, smr); + strange = 0; + } + *tmp = back; + continue; + } + + if (strncmp (tok, "Symbol:", 7) == 0) + { + tmp = tok; + while( (*tmp++) && + ((*tmp!='\r') || (*tmp!='\n')) + ); + back = *tmp; + *tmp = '\0'; + if(smb>0) { + tok[0] = tok[1]= tok[2]= tok[3]= tok[4]= tok[5]= tok[6]= ' '; + symbols = string_sprintf ("%s\n%s", symbols, tok+5); + } else { + tok += 7; + while(*tok && isspace(*tok)) tok++; + symbols = string_copy (tok); + } + smb = 1; + *tmp = back; + continue; + } + + if (strncmp (tok, "Urls:", 5) == 0) + { + tmp = tok; + while( (*tmp++) && + ((*tmp!='\r') || (*tmp!='\n')) + ); + back = *tmp; + *tmp = '\0'; + if(urf>0) { + tok[0] = tok[1]= tok[2]= tok[3]= tok[4] = ' '; + urls = string_sprintf ("%s\n%s", urls, tok+3); + } else { + tok += 5; + while(*tok && isspace(*tok)) tok++; + urls = string_copy (tok); + } + urf = 1; + *tmp = back; + continue; + } + } + + + /* do not forget the symbols */ + if (symbols != NULL && strlen(symbols)) + { + i = 0; + tmp = tok = string_copy(symbols); + header_del ((uschar *) "X-Spam-Sybmols"); + header_add (' ', "%s: %s\n", "X-Spam-Sybmols", symbols); + while(*tmp!='\0') { + if((*tmp == '\n') || (*tmp == '\r')) { + tmp++; + continue; + } + if ((*tmp == ' ') && (*(tmp+1)==' ')) { + tok[i++] = ','; + tmp += 2; + continue; + } + tok[i] = *tmp; + i++; + tmp++; + } + tok[i] = '\0'; + log_write(0, LOG_MAIN, "rspam-exim: symbols: %s", tok); + } + + /* do not forget the urls */ + if (urls != NULL && strlen(urls)) + { + log_write(0, LOG_MAIN, "rspam-exim: urls: %s", urls); + header_del ((uschar *) "X-Spam-Urls"); + header_add (' ', "%s: %s\n", "X-Spam-Urls", urls); + } + + log_write (0, LOG_MAIN, "rspam-exim: For message from %s will return %s, mailfrom: <%s>, rcpto: <%s>", sender_host_address, rej == 2 ? "DISCARD" : rej == 1 ? "REJECT" : "ACCEPT", sender_address, recipients_list[0].address); + + } + else + { + result = LOCAL_SCAN_ACCEPT; + log_write(0, LOG_MAIN, "rspam-exim: wrong signature in answer: %s", answ); + } + + if((sm>0) && (smr>0) && (sm>=smr)) { + result = LOCAL_SCAN_REJECT; + } + return result; +} + + +int +local_scan(int fd, uschar **return_text) +{ + int retval = _OK; + char sFileInp [MAX_PATH + 81]; + + /* Socket stuff */ + + strange = 0; +#ifdef RSPAM_UNIXSOCKET + if ((sock = socket (AF_UNIX, SOCK_STREAM, 0)) < 0) + { + log_write(0, LOG_MAIN, "rspam-exim: socket() failed"); + exit (1); + } + memset (&ssun, '\0', sizeof (struct sockaddr_un)); + ssun.sun_family = AF_UNIX; + if (sizeof (socket_name) > sizeof (ssun.sun_path)) + { + close (sock); + log_write(0, LOG_MAIN, "rspam-exim: UNIX socket name %s too long", socket_name); + exit (1); + } + strcpy (ssun.sun_path, socket_name); +#else + if ((sock = socket (AF_INET, SOCK_STREAM, 0)) < 0) + { + log_write(0, LOG_MAIN, "rspam-exim: socket() failed"); + exit (1); + } + memset (&ssin, '\0', sizeof (struct sockaddr_in)); + ssin.sin_family = AF_INET; + ssin.sin_addr.s_addr = inet_addr (daemonIP); + ssin.sin_port = htons (daemonPort); +#endif + + if (GetAndTransferMessage (fd, (char *)sFileInp) != _OK) + { + close (sock); + unlink (sFileInp); + SPOOL_DATA_START_OFFSET; + return REJECT_ON_ERROR ? LOCAL_SCAN_TEMPREJECT:LOCAL_SCAN_ACCEPT; + } + + retval = WaitForScanResult (return_text); + + if(!strange) + unlink (sFileInp); + close (sock); + SPOOL_DATA_START_OFFSET; + + return retval; +} + +/* End of local_scan.c */ diff --git a/doc/why-rspamd.html b/doc/why-rspamd.html new file mode 100644 index 000000000..aceb1228c --- /dev/null +++ b/doc/why-rspamd.html @@ -0,0 +1,392 @@ +Фильтрация спама при помощи системы rspamd. + + + + + + + + +

Фильтрация спама при помощи системы rspamd.

+ +

1. +История и предпосылки создания.

+ +

Мы долгое время использовали для фильтрации спама spamassassin, +однако, +при наших объемах почтового трафика (9-10 миллионов писем в сутки) spamassassin не обеспечивал достаточной производительности. +После анализа исходного кода и принципов работы было выявлены следующие "врожденные" проблемы SA:

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

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

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

В результате перехода с SA на rspamd последний показал в среднем в 10 раз более быструю обработку сообщений. +В данный момент rspamd имеет статус бета версии, +но вполне пригоден для работы.

+ +

2. +Установка и настройка rspamd

+ +

Для сборки rspamd вам потребуются:

+ +
    +
  • libevent http://www.monkey.org/~provos/libevent/ - библиотека для асинхронной обработки событий
  • + +
  • glib http://library.gnome.org/devel/glib/ - библиотека общего назначения, +содержащая многие вещи, +о которых разработчики libc, +увы, +забыли (glib не является графической библиотекой, +хотя и используется, +например, +gtk)
  • + +
  • gmime http://spruce.sourceforge.net/gmime/ - MIME парсер на базе библиотеки glib
  • + +
  • lua http://www.lua.org/ - встраиваемый скриптовый язык (в принципе, +наличие lua необязательно, +но без lua многий функционал rspamd останется нереализованным)
  • + +
  • perl http://www.perl.org/ - на перле написан, +например, +консольный клиент rspamc, +распознаватель редиректов в URL'ях, +поэтому наличие перла в системе крайне желательно
  • + +
  • cmake http://www.cmake.org/ - система сборки, +которая позволяет rspamd собираться (по крайней мере, +в теории) на всех Posix совместимых системах. +Использовать стандартные в данной ситуации autotools я не стал, +так как считаю их самой неудобной в использовании системой сборки исходников, +которую можно только придумать.
  • + +
  • mercurial http://mercurial.selenic.com/ - система управления версиями (SCM), +используемая для разработки rspamd. +Так как в настоящее время rspamd находится в состоянии бета-версии, +то релизы выходят нечасто и зачастую являются менее стабильными, +чем текущая версия в репозитории, +поэтому для установки rspamd лучше использовать версию непосредственно из репозитория.
  • +
+ +

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

+ +
+
1 скачиваем текущее состояние репозитория: $ hg clone http://rspamd.hg.sourceforge.net:8000/hgroot/rspamd/rspamd
+ +
+
2 конфигурируем rspamd: $ cd rspamd && cmake . +(при необходимости изменить параметры можно вначале воспользоваться командой ccmake .)
+ +
+
3 собираем: $ make
+ +
+
4 устанавливаем: # make install
+
+ +

Конфигурирование

+ +

В процессе установки ставятся конфигурационные файлы по умолчанию в каталог {PREFIX}/etc. +При этом, +в каталог etc/rspamd устанавливаются правила по умолчанию (headers, +html, +drugs, +loto и.т.п.), +а в каталог etc/rspamd.conf.sample устанавливается конфигурационный файл по умолчанию. +Его можно скопировать в файл etc/rspamd.conf и отредактировать в соответствии с собственными предпочтениями. +Конфигурационный файл по умолчанию снабжен комментариями к каждой директиве, +а также подробно описан в документации к rspamd, +находящейся в каталоге исходников doc/rspamd.pdf. +В данном же руководстве подробно изложен принцип работы rspamd и настройки всех модулей системы. +Для базовой работы достаточно исправить пути к файлам логов, +пидфайлу, +а также обратить внимание на разделы factors и classifiers. +Остановлюсь на этом несколько подробнее.

+ +

Все директивы rspamd имеют формат param = value; где символ ';' является признаком окончания директивы. +Также файл разбит на секции, +каждая секция имеет имя (например worker {}) и внутренние директвы внутри фигурных скобок. +После каждой секции также обязателен символ ';'. +Также каждый модуль имеет особый формат секции:

+ +
+.module 'name' {
+	param = value;
+};
+
+ + +

Все это может показаться сложным на первый взгляд, +но это позволяет лучше структурировать файл и облегчает расширяемость rspamd. +Для первоначальной настройки достаточно обратить внимание на раздел factors, +который описывает веса различных правил, +раздел metric, +который описывает максимальный вес, +чтобы письмо считалось спамом, +а также на раздел classifiers. +Раздел classifiers обеспечивает работу статистических алгоритмов. +В rspamd в настоящее время реализован алгоритм winnow, +который работает следующим образом:

+ +
+
1 текст разбивается на слова, +также выделяется окно в пять слов
+ +
+
2 окно перемещается по словам, +при этом выделяются словосочетания по определенному алгоритму и вычисляется их хеш
+ +
+
3 каждый полученный таким образом хеш проверяется в файле статистики, +в котором хранятся хеши и их веса, +если хеш найден, +то его вес добавляется к суммарному весу данного файла
+ +
+
4 файл, +набравший в сумме больше веса считается классом письма
+
+ +

Основная идея такого подхода в определении по словосочетаниям, +к какому классу принадлежит данное письмо. +В SA для этой цели используется вероятностный алгоритм bayes, +который достаточно похож на вышеописанный, +но считает не веса, +а вероятности. +Эффективность каждого из алгоритмов примерно одинакова и зависит в основном от эффективности обучения. +Однако, +в отличие от SA, +rspamd использует не отдельные слова, +а словосочетания, +что повышает его эффективность. +В секции classifiers можно установить различные классы писем, +а далее в секции factors указать их вес (задав, +например, +для заведомо безвредных писем - ham - отрицательный вес). +Размер файлов статистики должен быть разумно большим для хранения как можно большего числа хешей. +Однако, +необходимо учитывать, +что эти файлы целиком загружаются в память (хотя, +реализация отображения файла в памяти в различных ОС допускает загрузку и выгрузку страниц этого файла в своп системы, +но эффективность этого довольно низка), +поэтому необходимо соизмерять размер оперативной памяти и файлов статистики.

+ +

4. +Подключение и проверка работоспособности rspamd

+ +

Для проверки работы системы rspamd проще всего воспользоваться командой rspamc:

+ +
+hostname:~> rspamc stat
+Do rspamc command stat
+Messages scanned: 1234040
+Messages learned: 59151
+Connections count: 1176623
+Control connections count: 59152
+Pools allocated: 2530714
+Pools freed: 2530699
+Bytes allocated: 66991793394
+Memory chunks allocated: 6453232
+Shared chunks allocated: 3
+Chunks freed: 6453090
+Oversized chunks: 468849
+Statfile: WINNOW_HAM (version 69); length: 100.0 MB; free blocks: 4563488; total blocks: 6553581; free: 69.63%
+Statfile: WINNOW_SPAM (version 36383); length: 100.0 MB; free blocks: 760504; total blocks: 6553581; free: 11.60%
+
+ + +

В данном случае выводится общая статистика. +Такого же эффекта можно достигнуть командой telnet на порт процесса controller (он описан в конфигурационном файле в секции worker, +type у которого controller). +По умолчанию это порт 11334 на адресе 127.0.0.1. +Работу правил и статистики можно также проверить по команде rspamc:

+ +
+~> rspamc symbols /tmp/mailman.eml 
+Processing /tmp/mailman.eml
+Process file: /tmp/mailman.eml
+Sending 4950 bytes...
+RSPAMD/1.1 0 OK
+Metric: default; False; -3.35 / 10.00 / 0.00
+Symbol: WINNOW_HAM; 5.00
+Symbol: RECEIVED_RBL; pbl.spamhaus.org,insecure-bl.rambler.ru
+Urls: 
+
+ + +

В данном случае показываются баллы, +набранные письмом, +а также дополнительная информация. +Подробнее о протоколе rspamc в документации (doc/rspamd.pdf). +Для подключения rspamd к MTA лучше всего использовать milter, +если ваш MTA postfix или sendmail. +В качестве milter'а можно использовать, +например, +rmilter: https://www.milter.org/milter/71/. +О настройке postfix + rmilter мной была написана следующая заметка: http://cebka.pp.ru/blog/2009/02/-nginxpostfixrmilter.html Для MTA exim можно воспользоваться файлом local_scan.c в каталоге contrib/exim. +Инструкции по его установке описаны в самом файле, +однако, +это требует пересборки MTA. +Также rspamd "понимает" протокол SA, +поэтому для подключения rspamd можно использовать те же средства, +что и для подключения к MTA SA.

+ +

Подробнее о командах rspamc и протоколе rspamc написано опять же в документации.

+ +

5. +Обучение rspamd

+ +

Процесс обучения важен для корректной работы статистики. +Для обучения используется команда rspamc learn. +Для указания файла (класса) письма используется ключ -s. +Пример использования:

+ +
+~> rspamc -s WINNOW_HAM learn /tmp/mailman.eml
+Processing /tmp/mailman.eml
+Process file: /tmp/mailman.eml
+Do rspamc command learn
+Sending 4950 bytes...
+Learn succeed. Sum weight: 128.48
+
+ + +

В качестве параметров можно указывать несколько файлов, +целые каталоги, +а также imap папки:

+ +
+~> rspamc -s WINNOW_SPAM learn imaps:user:cebka:password::host:somehost.rambler.ru:mbox:abuse.spam
+Processing imaps:user:cebka:password::host:mailsupport.rambler.ru:mbox:abuse.spam
+Enter IMAP password: 
+Process imap: host: somehost.rambler.ru, mbox: abuse.spam
+Do rspamc command learn
+Sending 382650 bytes...
+Learn succeed. Sum weight: 1850.24
+
+
+ + +

При обучении необходимо учитывать, +чтобы количество spam и ham писем было примерно равным. +Вес показывает суммарный вес словосочетаний текста, +который был до обучения данным письмом (то есть, +то, +насколько велика вероятность принадлежности данного письма к этому классу). +При обнаружении неверных срабатываний статистики можно несколько раз применить learn к заданному письму, +проверяя его суммарный вес.

+ +

6. +Поддержка и дальнейшие действия

+ +

Если вы решили использовать rspamd для обработки вашей почты, +то лучшим источником информации будет являться документация к rspamd, +а также примеры lua плагинов: etc/plugins/lua. +Целью же данной статьи является ознакомление с основными приемами по установке, +конфигурированию и обучению rspamd, +а также описание преимуществ rspamd по сравнению с SA. +Если на любом этапе работы с rspamd у вас возникает проблема, +то можно о ней сообщить мне: vsevolod@highsecure.ru или же в список рассылки rspamd на sourceforge (англоговорящий): rspamd-devel@lists.sourceforge.net. +Сама система rspamd находится в состоянии бета-версии, +поэтому ваша помощь в тестировании и запросы функциональности будут неоценимы в развитии rspamd.

+ + + + diff --git a/doc/why-rspamd.pod b/doc/why-rspamd.pod new file mode 100644 index 000000000..0b2c71cb8 --- /dev/null +++ b/doc/why-rspamd.pod @@ -0,0 +1,333 @@ +=encoding utf8 + +=head1 Фильтрация спама при помощи системы rspamd. + +=head2 1. История и предпосылки создания. + +Мы долгое время использовали для фильтрации спама spamassassin, однако, при +наших объемах почтового трафика (9-10 миллионов писем в сутки) spamassassin +не обеспечивал достаточной производительности. После анализа исходного кода и +принципов работы было выявлены следующие "врожденные" проблемы SA: + +=over + +=item * +обработка письма осуществляется набором регулярных выражений, однако, +количество этих выражений слишком велико и является ключевым моментом +задумчивости SA (например, для извлечения received заголовков письма, SA +проверяет оные на соответствие всем ему известным MTA, очевидно, что такое +действие не является оптимальным); + +=item * +нет возможности явно получить ip адрес, с которого нам отправили письмо (в SA +это делается парсом received заголовков, что я лично не считаю правильным, а тем +более оптимальным способом, так как MTA всегда знает, откуда ему пришло данное +письмо) + +=item * +нет возможности передачи спам фильтру данных SMTP диалога + +=item * +MIME парсинг писем очень медленный, так как опять же сделан на базе регулярных +выражений + +=back + +В итоге можно сказать, что основная проблема SA - это излишняя увлеченность +авторов регулярными выражениями и отсутствие оптимизации. В итоге, в качестве +базовых принципов создания rspamd были принципы оптимизации времени обработки +писем, в числе которых: + +=over + +=item * +полностью асинхронная работа с сетью (на базе libevent), в том числе DNS запросы +и работа с http + +=item * +быстрые механизмы выделения памяти + +=item * +компиляция всех регулярных выражений и вызов только тех из них, которые наиболее +возможны (то есть, имеется механизм ведения статистики срабатывания различных +правил, и при обработке следующего письма учитывается обработка предыдущих, что +позволяет максимально быстро провести основные тесты) + +=item * +расширяемая архитектура: возможность написания плагинов на си, lua, возможность +добавления новых типов фильтров, расширений протокола rspamc, возможность +добавления новых типов статистических алгоритмов, алгоритмов нормализации и +парсинга текстов + +=item * +возможность динамической загрузки различных настроек, списков ip адресов и +прочей информации через HTTP протокол с поддержкой даты модификации таких +списков + +=item * +использование везде, где возможно, специализированных конечных автоматов для +разбора и анализа текстов + +=item * +использование быстрого mime парсера gmime + +=back + +В результате перехода с SA на rspamd последний показал в среднем в 10 раз более +быструю обработку сообщений. В данный момент rspamd имеет статус бета версии, но +вполне пригоден для работы. + +=head2 2. Установка и настройка rspamd + +Для сборки rspamd вам потребуются: + +=over + +=item * libevent +L - библиотека для асинхронной +обработки событий + +=item * glib +L - библиотека общего назначения, +содержащая многие вещи, о которых разработчики libc, увы, забыли (glib не +является графической библиотекой, хотя и используется, например, gtk) + +=item * gmime +L - MIME парсер на базе библиотеки glib + +=item * lua +L - встраиваемый скриптовый язык (в принципе, наличие lua +необязательно, но без lua многий функционал rspamd останется нереализованным) + +=item * perl +L - на перле написан, например, консольный клиент rspamc, +распознаватель редиректов в URL'ях, поэтому наличие перла в системе крайне +желательно + +=item * cmake +L - система сборки, которая позволяет rspamd собираться +(по крайней мере, в теории) на всех Posix совместимых системах. Использовать +стандартные в данной ситуации autotools я не стал, так как считаю их самой +неудобной в использовании системой сборки исходников, которую можно только +придумать. + +=item * mercurial +L - система управления версиями (SCM), +используемая для разработки rspamd. Так как в настоящее время rspamd находится в +состоянии бета-версии, то релизы выходят нечасто и зачастую являются менее +стабильными, чем текущая версия в репозитории, поэтому для установки rspamd +лучше использовать версию непосредственно из репозитория. + +=back + +После установки всех требуемых программ и библиотек можно приступить +непосредственно к установке rspamd. + +=over + +=item 1 +скачиваем текущее состояние репозитория: $ hg clone http://rspamd.hg.sourceforge.net:8000/hgroot/rspamd/rspamd + +=item 2 +конфигурируем rspamd: $ cd rspamd && cmake . +(при необходимости изменить параметры можно вначале воспользоваться командой +ccmake .) + +=item 3 +собираем: $ make + +=item 4 +устанавливаем: # make install + +=back + +=head3 Конфигурирование + +В процессе установки ставятся конфигурационные файлы по умолчанию в каталог +{PREFIX}/etc. При этом, в каталог etc/rspamd устанавливаются правила по +умолчанию (headers, html, drugs, loto и.т.п.), а в каталог +etc/rspamd.conf.sample устанавливается конфигурационный файл по умолчанию. Его +можно скопировать в файл etc/rspamd.conf и отредактировать в соответствии с +собственными предпочтениями. Конфигурационный файл по умолчанию снабжен +комментариями к каждой директиве, а также подробно описан в документации к +rspamd, находящейся в каталоге исходников doc/rspamd.pdf. В данном же +руководстве подробно изложен принцип работы rspamd и настройки всех модулей +системы. Для базовой работы достаточно исправить пути к файлам логов, пидфайлу, +а также обратить внимание на разделы factors и classifiers. Остановлюсь на этом +несколько подробнее. + +Все директивы rspamd имеют формат param = value; где символ ';' является +признаком окончания директивы. Также файл разбит на секции, каждая секция имеет +имя (например worker {}) и внутренние директвы внутри фигурных скобок. После +каждой секции также обязателен символ ';'. Также каждый модуль имеет особый +формат секции: + +=begin html + +
+.module 'name' {
+	param = value;
+};
+
+ +=end html + +Все это может показаться сложным на первый взгляд, но это позволяет лучше +структурировать файл и облегчает расширяемость rspamd. Для первоначальной +настройки достаточно обратить внимание на раздел factors, который описывает веса +различных правил, раздел metric, который описывает максимальный вес, чтобы +письмо считалось спамом, а также на раздел classifiers. Раздел classifiers +обеспечивает работу статистических алгоритмов. В rspamd в настоящее время +реализован алгоритм winnow, который работает следующим образом: + +=over + +=item 1 +текст разбивается на слова, также выделяется окно в пять слов + +=item 2 +окно перемещается по словам, при этом выделяются словосочетания по определенному +алгоритму и вычисляется их хеш + +=item 3 +каждый полученный таким образом хеш проверяется в файле статистики, в котором +хранятся хеши и их веса, если хеш найден, то его вес добавляется к суммарному +весу данного файла + +=item 4 +файл, набравший в сумме больше веса считается классом письма + +=back + +Основная идея такого подхода в определении по словосочетаниям, к какому классу +принадлежит данное письмо. В SA для этой цели используется вероятностный +алгоритм bayes, который достаточно похож на вышеописанный, но считает не веса, а +вероятности. Эффективность каждого из алгоритмов примерно одинакова и зависит в +основном от эффективности обучения. Однако, в отличие от SA, rspamd использует +не отдельные слова, а словосочетания, что повышает его эффективность. В секции +classifiers можно установить различные классы писем, а далее в секции factors +указать их вес (задав, например, для заведомо безвредных писем - ham - +отрицательный вес). Размер файлов статистики должен быть разумно большим для +хранения как можно большего числа хешей. Однако, необходимо учитывать, что эти +файлы целиком загружаются в память (хотя, реализация отображения файла в памяти +в различных ОС допускает загрузку и выгрузку страниц этого файла в своп системы, +но эффективность этого довольно низка), поэтому необходимо соизмерять размер +оперативной памяти и файлов статистики. + +=head2 4. Подключение и проверка работоспособности rspamd + +Для проверки работы системы rspamd проще всего воспользоваться командой rspamc: + +=begin html + +
+hostname:~> rspamc stat
+Do rspamc command stat
+Messages scanned: 1234040
+Messages learned: 59151
+Connections count: 1176623
+Control connections count: 59152
+Pools allocated: 2530714
+Pools freed: 2530699
+Bytes allocated: 66991793394
+Memory chunks allocated: 6453232
+Shared chunks allocated: 3
+Chunks freed: 6453090
+Oversized chunks: 468849
+Statfile: WINNOW_HAM (version 69); length: 100.0 MB; free blocks: 4563488; total blocks: 6553581; free: 69.63%
+Statfile: WINNOW_SPAM (version 36383); length: 100.0 MB; free blocks: 760504; total blocks: 6553581; free: 11.60%
+
+ +=end html + +В данном случае выводится общая статистика. Такого же эффекта можно достигнуть +командой telnet на порт процесса controller (он описан в конфигурационном файле +в секции worker, type у которого controller). По умолчанию это порт 11334 на +адресе 127.0.0.1. Работу правил и статистики можно также проверить по команде +rspamc: + +=begin html + +
+~> rspamc symbols /tmp/mailman.eml 
+Processing /tmp/mailman.eml
+Process file: /tmp/mailman.eml
+Sending 4950 bytes...
+RSPAMD/1.1 0 OK
+Metric: default; False; -3.35 / 10.00 / 0.00
+Symbol: WINNOW_HAM; 5.00
+Symbol: RECEIVED_RBL; pbl.spamhaus.org,insecure-bl.rambler.ru
+Urls: 
+
+ +=end html + +В данном случае показываются баллы, набранные письмом, а также дополнительная +информация. Подробнее о протоколе rspamc в документации (doc/rspamd.pdf). Для +подключения rspamd к MTA лучше всего использовать milter, если ваш MTA postfix +или sendmail. В качестве milter'а можно использовать, например, rmilter: +L. О настройке postfix + rmilter мной была +написана следующая заметка: L +Для MTA exim можно воспользоваться файлом local_scan.c в каталоге contrib/exim. +Инструкции по его установке описаны в самом файле, однако, это требует +пересборки MTA. Также rspamd "понимает" протокол SA, поэтому для подключения +rspamd можно использовать те же средства, что и для подключения к MTA SA. + +Подробнее о командах rspamc и протоколе rspamc написано опять же в документации. + +=head2 5. Обучение rspamd + +Процесс обучения важен для корректной работы статистики. Для обучения +используется команда rspamc learn. Для указания файла (класса) письма +используется ключ -s. Пример использования: + +=begin html + +
+~> rspamc -s WINNOW_HAM learn /tmp/mailman.eml
+Processing /tmp/mailman.eml
+Process file: /tmp/mailman.eml
+Do rspamc command learn
+Sending 4950 bytes...
+Learn succeed. Sum weight: 128.48
+
+ +=end html + +В качестве параметров можно указывать несколько файлов, целые каталоги, а также +imap папки: + +=begin html + +
+~> rspamc -s WINNOW_SPAM learn imaps:user:cebka:password::host:somehost.rambler.ru:mbox:abuse.spam
+Processing imaps:user:cebka:password::host:mailsupport.rambler.ru:mbox:abuse.spam
+Enter IMAP password: 
+Process imap: host: somehost.rambler.ru, mbox: abuse.spam
+Do rspamc command learn
+Sending 382650 bytes...
+Learn succeed. Sum weight: 1850.24
+
+
+ +=end html + +При обучении необходимо учитывать, чтобы количество spam и ham писем было +примерно равным. Вес показывает суммарный вес словосочетаний текста, который был +до обучения данным письмом (то есть, то, насколько велика вероятность +принадлежности данного письма к этому классу). При обнаружении неверных +срабатываний статистики можно несколько раз применить learn к заданному письму, +проверяя его суммарный вес. + +=head2 6. Поддержка и дальнейшие действия + +Если вы решили использовать rspamd для обработки вашей почты, то лучшим +источником информации будет являться документация к rspamd, а также примеры lua +плагинов: etc/plugins/lua. Целью же данной статьи является ознакомление с +основными приемами по установке, конфигурированию и обучению rspamd, а также +описание преимуществ rspamd по сравнению с SA. Если на любом этапе работы с +rspamd у вас возникает проблема, то можно о ней сообщить мне: +B или же в список рассылки rspamd на sourceforge +(англоговорящий): B. Сама система +rspamd находится в состоянии бета-версии, поэтому ваша помощь в тестировании и +запросы функциональности будут неоценимы в развитии rspamd. diff --git a/doc/why-rspamd.txt b/doc/why-rspamd.txt new file mode 100644 index 000000000..dd0b09637 --- /dev/null +++ b/doc/why-rspamd.txt @@ -0,0 +1,240 @@ +Фильтрация спама при помощи системы rspamd. + 1. История и предпосылки создания. + Мы долгое время использовали для фильтрации спама spamassassin, однако, при + наших объемах почтового трафика (9-10 миллионов писем в сутки) spamassassin + не обеспечивал достаточной производительности. После анализа исходного кода + и принципов работы было выявлены следующие "врожденные" проблемы SA: + + * обработка письма осуществляется набором регулярных выражений, однако, + количество этих выражений слишком велико и является ключевым моментом + задумчивости SA (например, для извлечения received заголовков письма, SA + проверяет оные на соответствие всем ему известным MTA, очевидно, что + такое действие не является оптимальным); + + * нет возможности явно получить ip адрес, с которого нам отправили письмо + (в SA это делается парсом received заголовков, что я лично не считаю + правильным, а тем более оптимальным способом, так как MTA всегда знает, + откуда ему пришло данное письмо) + + * нет возможности передачи спам фильтру данных SMTP диалога + + * MIME парсинг писем очень медленный, так как опять же сделан на базе + регулярных выражений + + В итоге можно сказать, что основная проблема SA - это излишняя увлеченность + авторов регулярными выражениями и отсутствие оптимизации. В итоге, в + качестве базовых принципов создания rspamd были принципы оптимизации времени + обработки писем, в числе которых: + + * полностью асинхронная работа с сетью (на базе libevent), в том числе DNS + запросы и работа с http + + * быстрые механизмы выделения памяти + + * компиляция всех регулярных выражений и вызов только тех из них, которые + наиболее возможны (то есть, имеется механизм ведения статистики + срабатывания различных правил, и при обработке следующего письма + учитывается обработка предыдущих, что позволяет максимально быстро + провести основные тесты) + + * расширяемая архитектура: возможность написания плагинов на си, lua, + возможность добавления новых типов фильтров, расширений протокола + rspamc, возможность добавления новых типов статистических алгоритмов, + алгоритмов нормализации и парсинга текстов + + * возможность динамической загрузки различных настроек, списков ip адресов + и прочей информации через HTTP протокол с поддержкой даты модификации + таких списков + + * использование везде, где возможно, специализированных конечных автоматов + для разбора и анализа текстов + + * использование быстрого mime парсера gmime + + В результате перехода с SA на rspamd последний показал в среднем в 10 раз + более быструю обработку сообщений. В данный момент rspamd имеет статус бета + версии, но вполне пригоден для работы. + + 2. Установка и настройка rspamd + Для сборки rspamd вам потребуются: + + libevent - библиотека для + асинхронной обработки событий + glib - библиотека общего назначения, + содержащая многие вещи, о которых разработчики libc, увы, забыли (glib не + является графической библиотекой, хотя и используется, например, gtk) + gmime - MIME парсер на базе + библиотеки glib + lua - встраиваемый скриптовый язык (в принципе, + наличие lua необязательно, но без lua многий функционал rspamd останется + нереализованным) + perl - на перле написан, например, консольный клиент + rspamc, распознаватель редиректов в URL'ях, поэтому наличие перла в системе + крайне желательно + cmake - система сборки, которая позволяет rspamd + собираться (по крайней мере, в теории) на всех Posix совместимых системах. + Использовать стандартные в данной ситуации autotools я не стал, так как + считаю их самой неудобной в использовании системой сборки исходников, + которую можно только придумать. + mercurial - система управления версиями + (SCM), используемая для разработки rspamd. Так как в настоящее время rspamd + находится в состоянии бета-версии, то релизы выходят нечасто и зачастую + являются менее стабильными, чем текущая версия в репозитории, поэтому для + установки rspamd лучше использовать версию непосредственно из репозитория. + + После установки всех требуемых программ и библиотек можно приступить + непосредственно к установке rspamd. + + 1) скачиваем текущее состояние репозитория: $ hg clone + http://rspamd.hg.sourceforge.net:8000/hgroot/rspamd/rspamd + 2) конфигурируем rspamd: $ cd rspamd && cmake . (при необходимости изменить + параметры можно вначале воспользоваться командой ccmake .) + 3) собираем: $ make + 4) устанавливаем: # make install + + Конфигурирование + В процессе установки ставятся конфигурационные файлы по умолчанию в каталог + {PREFIX}/etc. При этом, в каталог etc/rspamd устанавливаются правила по + умолчанию (headers, html, drugs, loto и.т.п.), а в каталог + etc/rspamd.conf.sample устанавливается конфигурационный файл по умолчанию. + Его можно скопировать в файл etc/rspamd.conf и отредактировать в + соответствии с собственными предпочтениями. Конфигурационный файл по + умолчанию снабжен комментариями к каждой директиве, а также подробно описан + в документации к rspamd, находящейся в каталоге исходников doc/rspamd.pdf. В + данном же руководстве подробно изложен принцип работы rspamd и настройки + всех модулей системы. Для базовой работы достаточно исправить пути к файлам + логов, пидфайлу, а также обратить внимание на разделы factors и classifiers. + Остановлюсь на этом несколько подробнее. + + Все директивы rspamd имеют формат param = value; где символ ';' является + признаком окончания директивы. Также файл разбит на секции, каждая секция + имеет имя (например worker {}) и внутренние директвы внутри фигурных скобок. + После каждой секции также обязателен символ ';'. Также каждый модуль имеет + особый формат секции: + +.module 'name' { + param = value; +}; + Все это может показаться сложным на первый взгляд, но это позволяет лучше + структурировать файл и облегчает расширяемость rspamd. Для первоначальной + настройки достаточно обратить внимание на раздел factors, который описывает + веса различных правил, раздел metric, который описывает максимальный вес, + чтобы письмо считалось спамом, а также на раздел classifiers. Раздел + classifiers обеспечивает работу статистических алгоритмов. В rspamd в + настоящее время реализован алгоритм winnow, который работает следующим + образом: + + 1) текст разбивается на слова, также выделяется окно в пять слов + 2) окно перемещается по словам, при этом выделяются словосочетания по + определенному алгоритму и вычисляется их хеш + 3) каждый полученный таким образом хеш проверяется в файле статистики, в + котором хранятся хеши и их веса, если хеш найден, то его вес добавляется к + суммарному весу данного файла + 4) файл, набравший в сумме больше веса считается классом письма + + Основная идея такого подхода в определении по словосочетаниям, к какому + классу принадлежит данное письмо. В SA для этой цели используется + вероятностный алгоритм bayes, который достаточно похож на вышеописанный, но + считает не веса, а вероятности. Эффективность каждого из алгоритмов примерно + одинакова и зависит в основном от эффективности обучения. Однако, в отличие + от SA, rspamd использует не отдельные слова, а словосочетания, что повышает + его эффективность. В секции classifiers можно установить различные классы + писем, а далее в секции factors указать их вес (задав, например, для + заведомо безвредных писем - ham - отрицательный вес). Размер файлов + статистики должен быть разумно большим для хранения как можно большего числа + хешей. Однако, необходимо учитывать, что эти файлы целиком загружаются в + память (хотя, реализация отображения файла в памяти в различных ОС допускает + загрузку и выгрузку страниц этого файла в своп системы, но эффективность + этого довольно низка), поэтому необходимо соизмерять размер оперативной + памяти и файлов статистики. + + 4. Подключение и проверка работоспособности rspamd + Для проверки работы системы rspamd проще всего воспользоваться командой + rspamc: + +hostname:~> rspamc stat +Do rspamc command stat +Messages scanned: 1234040 +Messages learned: 59151 +Connections count: 1176623 +Control connections count: 59152 +Pools allocated: 2530714 +Pools freed: 2530699 +Bytes allocated: 66991793394 +Memory chunks allocated: 6453232 +Shared chunks allocated: 3 +Chunks freed: 6453090 +Oversized chunks: 468849 +Statfile: WINNOW_HAM (version 69); length: 100.0 MB; free blocks: 4563488; total blocks: 6553581; free: 69.63% +Statfile: WINNOW_SPAM (version 36383); length: 100.0 MB; free blocks: 760504; total blocks: 6553581; free: 11.60% + В данном случае выводится общая статистика. Такого же эффекта можно + достигнуть командой telnet на порт процесса controller (он описан в + конфигурационном файле в секции worker, type у которого controller). По + умолчанию это порт 11334 на адресе 127.0.0.1. Работу правил и статистики + можно также проверить по команде rspamc: + +~> rspamc symbols /tmp/mailman.eml +Processing /tmp/mailman.eml +Process file: /tmp/mailman.eml +Sending 4950 bytes... +RSPAMD/1.1 0 OK +Metric: default; False; -3.35 / 10.00 / 0.00 +Symbol: WINNOW_HAM; 5.00 +Symbol: RECEIVED_RBL; pbl.spamhaus.org,insecure-bl.rambler.ru +Urls: + В данном случае показываются баллы, набранные письмом, а также + дополнительная информация. Подробнее о протоколе rspamc в документации + (doc/rspamd.pdf). Для подключения rspamd к MTA лучше всего использовать + milter, если ваш MTA postfix или sendmail. В качестве milter'а можно + использовать, например, rmilter: . О + настройке postfix + rmilter мной была написана следующая заметка: + Для MTA exim + можно воспользоваться файлом local_scan.c в каталоге contrib/exim. + Инструкции по его установке описаны в самом файле, однако, это требует + пересборки MTA. Также rspamd "понимает" протокол SA, поэтому для подключения + rspamd можно использовать те же средства, что и для подключения к MTA SA. + + Подробнее о командах rspamc и протоколе rspamc написано опять же в + документации. + + 5. Обучение rspamd + Процесс обучения важен для корректной работы статистики. Для обучения + используется команда rspamc learn. Для указания файла (класса) письма + используется ключ -s. Пример использования: + +~> rspamc -s WINNOW_HAM learn /tmp/mailman.eml +Processing /tmp/mailman.eml +Process file: /tmp/mailman.eml +Do rspamc command learn +Sending 4950 bytes... +Learn succeed. Sum weight: 128.48 + В качестве параметров можно указывать несколько файлов, целые каталоги, а + также imap папки: + +~> rspamc -s WINNOW_SPAM learn imaps:user:cebka:password::host:somehost.rambler.ru:mbox:abuse.spam +Processing imaps:user:cebka:password::host:mailsupport.rambler.ru:mbox:abuse.spam +Enter IMAP password: +Process imap: host: somehost.rambler.ru, mbox: abuse.spam +Do rspamc command learn +Sending 382650 bytes... +Learn succeed. Sum weight: 1850.24 + + При обучении необходимо учитывать, чтобы количество spam и ham писем было + примерно равным. Вес показывает суммарный вес словосочетаний текста, который + был до обучения данным письмом (то есть, то, насколько велика вероятность + принадлежности данного письма к этому классу). При обнаружении неверных + срабатываний статистики можно несколько раз применить learn к заданному + письму, проверяя его суммарный вес. + + 6. Поддержка и дальнейшие действия + Если вы решили использовать rspamd для обработки вашей почты, то лучшим + источником информации будет являться документация к rspamd, а также примеры + lua плагинов: etc/plugins/lua. Целью же данной статьи является ознакомление + с основными приемами по установке, конфигурированию и обучению rspamd, а + также описание преимуществ rspamd по сравнению с SA. Если на любом этапе + работы с rspamd у вас возникает проблема, то можно о ней сообщить мне: + или же в список рассылки rspamd на + sourceforge (англоговорящий): . + Сама система rspamd находится в состоянии бета-версии, поэтому ваша помощь в + тестировании и запросы функциональности будут неоценимы в развитии rspamd. + diff --git a/rspamd.conf.sample b/rspamd.conf.sample index 91a7fac09..43febafca 100644 --- a/rspamd.conf.sample +++ b/rspamd.conf.sample @@ -114,24 +114,27 @@ classifier { statfile { # Alias is used for learning and is used as symbol symbol = "WINNOW_SPAM"; - # Pattern is path to file, can include %r - recipient name and %f - mail from value - path = "/tmp/test.spam"; + # Pattern is path to file + path = "/tmp/test.spam"; # Size of this statfile class size = 10M; - # Tokenizer for this statfile - # Deafault: osb-text - #tokenizer = "osb-text"; - autolearn { - min_mark = 10.0; - }; + + # Used for normalizing results, number means maximum score for this + # class + normalizer="internal:10"; + # Autolearn params + #autolearn { + # min_mark = 10.0; + #}; }; statfile { symbol = "WINNOW_HAM"; path = "/tmp/test.ham"; size = 10M; - autolearn { - max_mark = 0.1; - }; + # Autolearn params + #autolearn { + # max_mark = 0.1; + #}; }; }; @@ -355,13 +358,13 @@ view { }; # Settings files -settings { +#settings { # json data for user's settings #user_settings = "file:///some/json/file"; # json data for domain's settings #domain_settings = "file:///some/other/json/file"; -}; +#}; # Example of json config: # [