URL: https://www.opennet.me/cgi-bin/openforum/vsluhboard.cgi
Форум: vsluhforumID1
Нить номер: 53380
[ Назад ]

Исходное сообщение
"Exim & greylist"

Отправлено Alexander root , 11-Фев-05 11:35 
Добрый день!
Сделал небольшую реализацию greylist в Exim'е. Данные хранятся в MySQL.

Таблица в базе mail:
====================
CREATE TABLE Greylist (
   id bigint(20) NOT NULL auto_increment,
   relay_ip int unsigned NOT NULL,
   sender char(32) default NULL,
   recipient char(32) default NULL,
   block_expires int NOT NULL,
   record_expires int NOT NULL,
   create_time int UNSIGNED NOT NULL,
   pass_count int UNSIGNED NOT NULL default '0',
   block_count int UNSIGNED NOT NULL default '0',
   PRIMARY KEY (id),
   UNIQUE KEY (relay_ip,sender,recipient)
);

greylist.pl - скрипт вызываемый exim'ом
=======================================
#!/usr/bin/perl

# 30 минут блокировка для новой записи.
$block_expires=60*30;

# Время жизни неподтвержденной записи 24 часа.
$record_expires_init=60*60*24;

# Время жизни подтвержденной записи 60 дней с последнего письма.
$record_expires_incl=60*60*24*60;

$relay_ip=$ARGV[0];
$sender=$ARGV[1];
$recipient=$ARGV[2];

# В качестве ключа я использовал тройку:
# (inet_ntoa(relay_ip),md5('sender'),md5('recipient') = 68 байт.
# Использовал md5 по соображению безопасности и ограничении длины
# на ключ. А совпадение 64 байт для разных пар адресов - чрезвычайно  
# ничтожно.

@p=split(/\t/,`/usr/local/bin/mysql -s mail -e \"select id,(unix_timestamp()-block_expires) from Greylist where relay_ip=inet_aton('$relay_ip') and sender=md5('$sender') and recipient=md5('$recipient') limit 1\"`);

if ($p[0] > 0) {
    if ($p[1] > 0) {

        system("/usr/local/bin/mysql mail -e \"update Greylist set pass_count=pass_count+1,record_expires=unix_timestamp()+$record_expires_incl where id='$p[0]';\"");

        exit 1;
    }
    else {

        system("/usr/local/bin/mysql mail -e \"update Greylist set block_count=block_count+1 where id='$p[0]';\"");

    }
}

else {

    system("/usr/local/bin/mysql mail -e \"insert into Greylist (relay_ip,sender,recipient,block_expires,record_expires,create_time,block_count) values (inet_aton('$relay_ip'),md5('$sender'),md5('$recipient'),unix_timestamp()+$block_expires,unix_timestamp()+$record_expires_init,unix_timestamp(),1);\"");

}
exit 0;

для чистки старых записей по крону раз в N минут запускаем:
===========================================================
/usr/local/bin/mysql mail -e "delete from Greylist where unix_timestamp()>record_expires and pass_count=0;"

exim.conf
=========
acl_check_rcpt:
...skipped...

defer   domains       = +local_domains
         message       = Currently can not deliver mail. Try again later.
         condition     = ${run{/usr/local/exim/bin/greylist.pl     $sender_host_address $sender_address $local_part@$domain}{yes}{no}}

...skipped...

При правильно написанных acl exim'а, greylist работает только на почту входящую из вне.

Есть одно НО: письмо, в котором указаны несколько адресатов моего домена, попадет каждому из них, как минимут, только через $block_expires*(кол-во адресатов). Здесь по обстоятельствам, если последнее не устраивает, то можно убрать из базы и скриптов адрес получателя.

Приму конструктивную критику :-)


Содержание

Сообщения в этом обсуждении
"Exim & greylist"
Отправлено sashas , 11-Фев-05 13:57 
Пока что из критических замечаний только одно: зачем это? :) :)

"Exim & greylist"
Отправлено Alexander root , 11-Фев-05 14:37 
>Пока что из критических замечаний только одно: зачем это? :) :)

Greylist - метод борьбы со спамом. При первом обращении неизвестного сервера, его письмо отвергается с кодом нефатальной ошибки 4xx, если отправитель нормальный MTA, то по RFC он должен повторят попытки отправки письма в течении некоторого времени. После заданного времени мой почтовик разрешает данную комбинацию IP_адрес_сервера_отправителя:Емайл_оправителя:Емайл_получателя и письма ходят без задержек.
Если же отправитель является программа рассылки спама, то врядли будет попытка повтора, тем более, что база у спамеров как правило на десятки тысяч разных адресов.

В комбинации с SpamAssassin'ом и белыми и черными списками можно добиться неплохих результатов в борьбе со спамом.


"Exim & greylist"
Отправлено Alexander root , 12-Фев-05 12:14 
Вот еще переписал скрипт на Си, теперь будет быстрее работать...

greylist.c
================================================

#include <stdio.h>
#include "mysql.h"

/* Greylist parametrs */
#define BLOCK_EXPIRES        60*60*1
#define RECORD_EXPIRES_INITIALY    60*60*24
#define RECORD_EXPIRES_ELECTED    60*60*24*60

/* MySQL parameters */
#define MYSQL_HOST        NULL
#define MYSQL_DATABASE        "mail"    
#define MYSQL_USER        "exim"
#define MYSQL_PASSWORD        "passwd"
#define MYSQL_PORT        3306
#define MYSQL_UNIXSOCKET    "/tmp/mysql.sock"
#define MYSQL_CLIENTFLAG    0

void usage() {
    printf ("Usage: greylist [relay_ip] [sender] [recipient]\n");
    exit (0);
}

int main(int argc, char ** argv) {
    MYSQL mysql;
    MYSQL_ROW row;
    MYSQL_RES * result;

    unsigned long long id;
    signed int delta_time;
    char query[1024];
    
    if (argc!=4) usage();

    mysql_init(&mysql);

    if (!mysql_real_connect(&mysql,MYSQL_HOST,MYSQL_USER,MYSQL_PASSWORD,MYSQL_DATABASE,MYSQL_PORT,MYSQL_UNIXSOCKET,MYSQL_CLIENTFLAG)) {
    fprintf(stderr, "Connection to MySQL failed: %s\n", mysql_error(&mysql));
    exit(1);
    }

    sprintf (query,"select id,unix_timestamp()-block_expires from Greylist where relay_ip=inet_aton('%s') and sender=md5('%s') and recipient=md5('%s') limit 1",argv[1],argv[2],argv[3]);
    if (mysql_query(&mysql,query)) {
        fprintf(stderr, "SQL: \"%s\" failed: %s\n",query, mysql_error(&mysql));
        exit (1);
    }

    result = mysql_store_result(&mysql);

    if (mysql_num_rows(result)) {
        row = mysql_fetch_row(result);
        mysql_free_result(result);

    id=strtoull(row[0],0,10);
        delta_time=strtol(row[1],0,10);

    if (delta_time>0) {
        sprintf (query,"update Greylist set pass_count=pass_count+1,record_expires=unix_timestamp()+%lu where id='%llu'",RECORD_EXPIRES_ELECTED,id);
        if (mysql_query (&mysql,query)) fprintf(stderr, "SQL: \"%s\" failed: %s\n",query, mysql_error(&mysql));
            mysql_close(&mysql);
        exit (1);
    }
    else {
        sprintf (query,"update Greylist set block_count=block_count+1 where id='%llu'",id);
        if (mysql_query (&mysql,query)) {
            fprintf(stderr, "SQL: \"%s\" failed: %s\n",query, mysql_error(&mysql));
            exit (1);
        }
    }    
    }
    else {
        sprintf (query,"insert into Greylist (relay_ip,sender,recipient,block_expires,record_expires,create_time,block_count) values (inet_aton('%s'),md5('%s'),md5('%s'),unix_timestamp()+%lu,unix_timestamp()+%lu,unix_timestamp(),1)",argv[1],argv[2],argv[3],BLOCK_EXPIRES,RECORD_EXPIRES_INITIALY);
    if (mysql_query(&mysql,query)) {
            fprintf(stderr, "SQL: \"%s\" failed: %s\n",query, mysql_error(&mysql));
            exit (1);
    }
    }
    mysql_close(&mysql);
    exit(0);
}


"Exim & greylist"
Отправлено Yura Svetlanov , 14-Фев-05 14:19 
>Если же отправитель является программа рассылки спама, то врядли будет попытка повтора,
>тем более, что база у спамеров как правило на десятки тысяч
>разных адресов.

Спамеры наоборот более настойчивы, чем легальные почтовики. Вот например часть статистики отвергнутых за один из дней в феврале - число отлупов для данного хоста:

  93 [211.43.219.88]
  85 [209.124.86.69]
  64 [12.223.230.255]
  55 [64.168.26.236]
  53 [68.234.144.70]
  52 [66.189.37.38]
  50 [69.165.39.222]
  49 [24.90.189.218]
  48 [68.250.71.189]
  46 [200.214.177.160]
  45 [81.86.92.204]
  44 [68.200.80.26]


"Exim & greylist"
Отправлено Alexander root , 14-Фев-05 15:02 
>Спамеры наоборот более настойчивы, чем легальные почтовики.

Это скорее открытые релеи, а с ними rbl хорошо справляется. Рассылки,  которые идут с временных адресов прекрасно блокируются.


"Exim & greylist"
Отправлено sashas , 14-Фев-05 15:07 
>>Пока что из критических замечаний только одно: зачем это? :) :)
>
>Greylist - метод борьбы со спамом. При первом обращении неизвестного сервера, его
>письмо отвергается с кодом нефатальной ошибки 4xx, если отправитель нормальный MTA,
>то по RFC он должен повторят попытки отправки письма в течении
>некоторого времени. После заданного времени мой почтовик разрешает данную комбинацию IP_адрес_сервера_отправителя:Емайл_оправителя:Емайл_получателя
>и письма ходят без задержек.
>Если же отправитель является программа рассылки спама, то врядли будет попытка повтора,
>тем более, что база у спамеров как правило на десятки тысяч
>разных адресов.
>
>В комбинации с SpamAssassin'ом и белыми и черными списками можно добиться неплохих
>результатов в борьбе со спамом.
Что помешает спамером добавить повторное обращение к серверу? На поток такую защиту не поставить, а для себя ничего так. Удачное решение.

"Exim & greylist"
Отправлено Cheeto_McMourrell , 14-Фев-05 14:11 
>Приму конструктивную критику :-)
Ради чего делать внешний скрипт, когда запросы к БД и всю логику работы можно реализовать средствами самого exim?

"Exim & greylist"
Отправлено Alexander root , 14-Фев-05 15:06 
>>Приму конструктивную критику :-)
>Ради чего делать внешний скрипт, когда запросы к БД и всю логику
>работы можно реализовать средствами самого exim?

Ваша правда :-).


"Exim & greylist"
Отправлено cruel , 15-Фев-05 14:20 
wheel reinventing. look for GREYLISTING in
http://www.openbsd.org/cgi-bin/man.cgi?query=spamd