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

Исходное сообщение
"Раздел полезных советов: Автоматизация борьбы со спамботами ..."

Отправлено auto_tips , 24-Авг-09 11:29 
Администраторы больших сетей регулярно получают жалобы на исходящий из них спам. Получив жалобу,
можно найти виновного и устранить проблему. Но нехорошо узнавать о таких делах только от чужих людей.
Спамеров вполне можно вычислить самому, и принять меры раньше, чем кто-то пострадает.

Чисто интуитивно достаточно запустить tcpdump на исходящем канале, и посмотреть, какие IP-адреса больше в
сего посылают SYN-пакетов на 25 порт.

  tcpdump -ni bridge0 'tcp[tcpflags] & tcp-syn != 0 and dst port 25'

В идеале это был бы ваш SMTP-сервер. В действительности вы увидите в основном IP-адреса простых пользователей,
"одержимых бесами". Дело в том, что обычный спамбот создает SMTP-соединений во много раз больше
вашего почтового сервера. Причем с разными IP-адресами.

В наши дни все нормальные почтовые сервера имеют PTR-запись DNS. Простые клиенты, напротив,
такой записи обычно не имеют. Если почтовый сервер может устанавливать SMTP-соединения
со множеством IP-адресов, то для простого клиента эта величина обычно не более 1-2 (например,
пользование удаленными SMTP-серверами с лаптопа).

Исходя из этого, можно автоматически определять спамботов в нашей сети, и блокировать их (например,
средствами IPFW). В качестве критерия оценки мы установили максимальное количество IP-адресов,
с которыми каждый хост может общаться по SMTP в течение 5 минут. Для хостов с реверсной записью DNS это 200,
для хостов без реверсной записи - 20. Если хост превышает этот лимит, он попадает в черный список на сутки.

Нами написан Perl-скрипт, запускающий tcpdump на 5 минут, и анализирующий результаты.
Хосты-нарушители заносятся в таблицу PostgreSQL для удобства персонала, и затем помещаются
в таблицу IPFW. Правила файрвола блокируют все соединения на 25 порт с хостов, находящихся в данной таблице.

Текст скрипта:

       #!/usr/local/bin/perl
       # dimss@stalin.lv 2009-08-20

       my $colltime = 300;    # How long to collect data
       my $rev_limit = 200;   # Remote IP limit for hosts with PTR record
       my $norev_limit = 20;  # Remote IP limit for hosts without PTR record
       my $table_no = 1; # Number of IPFW table

       use strict;
       use warnings;

       use POSIX ':signal_h';
       use Socket;
       use DBI;

       #
       # Collect data
       # Run tcpdump for some time
       #

       my $conns = {};

       my $mask = POSIX::SigSet->new( SIGALRM );
       my $action = POSIX::SigAction->new(
               sub {
                       system("killall tcpdump");
               },
               $mask
       );
       my $oldaction = POSIX::SigAction->new();
       sigaction(14, $action, $oldaction);

       alarm($colltime); # Run tcpdump for this amount of time
       open(T, "/usr/sbin/tcpdump -ni bridge0 'tcp[tcpflags] & tcp-syn != 0 " .
                       "and dst port 25' " .
                       "2>/dev/null |") or die;

       while(<T>){
               /\ ((\d+\.){3}\d+).+?((\d+\.){3}\d+)/;
               my $locip = $1;
               my $remip = $3;
               #print "$locip $remip\n";
               $conns->{$locip} ||= {};
               $conns->{$locip}->{$remip} ||= 1;
       }
       alarm(0);
       sleep(1);

       #
       # Analyze connections
       #


       $mask = POSIX::SigSet->new( SIGALRM );
       $action = POSIX::SigAction->new(
               sub {
                       die("Reverse lookup took too long");
               },
               $mask
       );
       $oldaction = POSIX::SigAction->new();
       sigaction(14, $action, $oldaction);

       alarm(60); # Reverse DNS lookups must complete within this period

       my %concount;
       my %bots;

       for my $locip (keys(%$conns)){
               #print("Loc IP: $locip\n");
               my $cnt = 0;
               for my $remip (keys(%{$conns->{$locip}})){
                       #print("  Rem IP: $remip\n");
                       $cnt++;
               }
               $concount{$locip} = $cnt;
       }

       for my $locip (sort {$concount{$b} <=> $concount{$a}} keys(%concount)){
               if($concount{$locip} > $norev_limit){
                       my $ip = inet_aton($locip);
                       my $name = gethostbyaddr($ip, AF_INET);
                       if($concount{$locip} > ($name ? $rev_limit : $norev_limit)){
                               #print("$locip: $concount{$locip} (" . ($name || '') . ")\n");
                               $bots{$locip} = $name;
                       }
               }
       }

       alarm(0);

       #
       # Update database
       #

       $mask = POSIX::SigSet->new( SIGALRM );
       $action = POSIX::SigAction->new(
               sub {
                       die("Database timeout");
               },
               $mask
       );
       $oldaction = POSIX::SigAction->new();
       sigaction(14, $action, $oldaction);

       alarm(15);

       my $dbh = DBI->connect("dbi:Pg:host=db.host.tld;dbname=spambot",
               "spambot", "passwd");
       if(!$dbh) {
               die("Cannot connect to DB");
       }

       my $query;
       my $sth;
       my $rv;
       for my $botip (keys(%bots)){
               #print "$botip\n";
               my $qname = $dbh->quote($bots{$botip});
               $query = "
                       update spambot_hosts set
                               active_till = now() + '1 days',
                               hostname = $qname
                       where ip = '$botip'
               ";
               $sth = $dbh->prepare($query);
               $rv = $sth->execute();
               if($rv != 1){
                       $query = "
                               insert into spambot_hosts
                               (ip, hostname, active_till)
                               values
                               ('$botip', $qname, now() + '1 days')
                       ";
                       $sth = $dbh->prepare($query);
                       $sth->execute();
               }
       }
       $query = "
               delete from spambot_hosts
               where active_till < now()
       ";
       $sth = $dbh->prepare($query);
       $sth->execute();

       #
       # Get full list of banned hosts from DB
       #

       $query = "
               select ip from spambot_hosts
       ";
       $sth = $dbh->prepare($query);
       $sth->execute();

       my %dlist;
       while(my $row = $sth->fetchrow_hashref){
               $dlist{$row->{ip}} = 1;
       }

       undef $dbh;
       alarm(0);

       #
       # Read list of banned hosts from kernel (ipfw) table
       #

       my %klist;
       if(open(KTABLE, "/sbin/ipfw table $table_no list|")){
               while(<KTABLE>){
                       chomp();
                       s/\/32//;
                       my ($prefix, $queue) = split();
                       $klist{$prefix} = 1;
               }
               close(KTABLE);
       }

       #
       # Update kernel table
       #

       for my $host (keys(%dlist)){
               unless($klist{$host}){
                       #print "Add $host\n";
                       system("/sbin/ipfw table $table_no add $host");
               }
       }

       for my $host (keys(%klist)){
               unless($dlist{$host}){
                       #print "Remove $host\n";
                       system("/sbin/ipfw table $table_no delete $host");
               }
       }

       exit;

Из /etc/ipfw.rules:

   #....
   ipfw -q add deny tcp from "table(1)" to any 25
   #....

У нас скрипт работает на шейпере, обслуживающем только заграничный канал. Местный трафик им не анализируется
и не блокируется. При этом большая часть "хорошей" почты ходит именно по местным каналам, но спамеры
спамят в основном по заграничному каналу. Так что лимиты вам наверняка придется подстроить под себя.
Возможно, вам придется также реализовать "белый список", если у вас есть очень активные SMTP-сервера.

На момент написания статьи в "расстрельном списке" несколько десятков хостов. Жалоб за истекшие сутки
не поступало, хотя раньше их было множество.

URL:
Обсуждается: http://www.opennet.me/tips/info/2146.shtml


Содержание

Сообщения в этом обсуждении
"Автоматизация борьбы со спамботами в своей сети"
Отправлено Аноним , 24-Авг-09 11:29 
фильтр PF в FreeBSD\OpenBSD умеет самостоятельно вылавливать адреса, превышающие порог на частоту соединений и заносить их в свою внутреннюю таблицу. По этой таблице можно и блокировать трафик, и вылавливать нарушителей. Все гораздо проще и изящнее ...

"Автоматизация борьбы со спамботами в своей сети"
Отправлено Банзай , 24-Авг-09 11:38 
>фильтр PF в FreeBSD\OpenBSD умеет самостоятельно вылавливать адреса, превышающие порог на частоту
>соединений и заносить их в свою внутреннюю таблицу. По этой таблице
>можно и блокировать трафик, и вылавливать нарушителей. Все гораздо проще и
>изящнее ...

Не умеет.



"Автоматизация борьбы со спамботами в своей сети"
Отправлено Аноним , 24-Авг-09 13:51 
Умеет, конечно.

"Автоматизация борьбы со спамботами в своей сети"
Отправлено Щекн Итрч , 25-Авг-09 02:37 
>Умеет, конечно.

Попробуйте и доложите.
Желательно с дешифрованными tpcdump'ом логами, иллюструющими ваш набор правил.


"Автоматизация борьбы со спамботами в своей сети"
Отправлено ws , 25-Авг-09 11:57 
Где-то так:
table <smtp_bruteforce> persist
block drop in quick from <smtp_bruteforce>
pass in quick proto tcp from <local_net> to any port smtp flags S/S keep state \
  (max-src-conn-rate 20/300, overload <smtp_bruteforce> flush global)

Теперь в таблице <smtp_bruteforce> будет содержаться забаненые ip.

Очистку этой таблицы можно производить через запуск по крону программы, очищающая устаревшие записи на сутки:
/usr/local/sbin/expiretable -t 79200 smtp_bruteforce


"Автоматизация борьбы со спамботами в своей сети"
Отправлено pavlinux , 25-Авг-09 20:11 
А где ключевые слова "умеет самостоятельно"?


"Автоматизация борьбы со спамботами в своей сети"
Отправлено Щекн Итрч , 26-Авг-09 00:04 
"Где-то" или "есть логи, иллюстрирующие гипотезу"?
Можно фрагмент лога?

"Автоматизация борьбы со спамботами в своей сети"
Отправлено ws , 26-Авг-09 10:22 
У меня большой сети зомбируемых машин нет. Поэтому оставлю вам это на самопроработку.

В этом коде, конечно не учтено:
>>Здесь дело не в количестве соединений, а в количестве IP-адресов, с которыми устанавливается соединение.

но тем немение, работает с частотой создаваемых соединений.

ps: такая связка успешно функционирует у меня на блокирование попыток подключения по ssh.


"Автоматизация борьбы со спамботами в своей сети"
Отправлено настоящий_аноним , 26-Авг-09 15:39 
>ps: такая связка успешно функционирует у меня на блокирование попыток подключения по ssh.

Мой друг, это же классика :)
Про max-src-conn-rate(pf)/hashlimit(iptables) знает любой начинающий админ. Если же вас собеседник не знает таких очевидных вещей - бессмысленно пытаться ему что-либо объяснить.

Кстати, в отношении таймаутов ipset немного удобнее таблиц pf - не нужно прикручивать всякие expiretable, механизм таймаутов реализован нативно:
ipset -N spambots iptree --timeout 79200
Так записи будут автоматически удаляться через 22 часа.


"Автоматизация борьбы со спамботами в своей сети"
Отправлено настоящий_аноним , 26-Авг-09 15:47 
>Так записи будут автоматически удаляться через 22 часа.

Причем таймаут хранится для каждой записи отдельно.


"Автоматизация борьбы со спамботами в своей сети"
Отправлено ws , 26-Авг-09 16:46 
>Мой друг, это же классика :)

Естественно. :)
И применимая в текущей задаче.

>Кстати, в отношении таймаутов ipset немного удобнее таблиц pf - не нужно
>прикручивать всякие expiretable, механизм таймаутов реализован нативно:
>ipset -N spambots iptree --timeout 79200
>Так записи будут автоматически удаляться через 22 часа.
>Причем таймаут хранится для каждой записи отдельно.

Так и в pf таймауты в таблице выставляются для каждой записи индивидуально. expiretable нужно вызывать только для очистки устаревших записей. Конечно, хотелось бы обходиться без него.
Скажим так expiretable - это расширение к pf, как ipset расширение к iptables.  :)


"Автоматизация борьбы со спамботами в своей сети"
Отправлено аноним , 27-Авг-09 01:03 
>Скажим так expiretable - это расширение к pf, как ipset расширение к iptables.  :)

Если уж быть строгим и занудным до конца, то и iptables, и ipset - это всего лишь интерфейсы к netfilter, как pfctl - интерфейс к pf :)


"Автоматизация борьбы со спамботами в своей сети"
Отправлено Дима Иванов , 24-Авг-09 12:21 
Здесь дело не в количестве соединений, а в количестве IP-адресов, с которыми устанавливается соединение. К тому же, нужна гибкая политика, кого и как банить.

"Автоматизация борьбы со спамботами в своей сети"
Отправлено Andrew , 24-Авг-09 12:43 
Это, конечно, от ситуации зависит, но проще просто ЗАКРЫТЬ весь исходящий траффик на 25й порт, и проковырять его только для реальных почтовых серваков.

Логика очень простая: кому действительно надо иметь выход на 25й порт, осознанно попросят его открыть, но их будет очень мало. Всем остальным это не надо, и они будут закрыты => боты обломаются. При этом надо, разумеется, _документировать_ эту политику.


"Автоматизация борьбы со спамботами в своей сети"
Отправлено Дима Иванов , 24-Авг-09 12:45 
Да, так было бы лучше всего. Но пользователям этого не объяснить. Т.е. увеличится число тупых кейсов у саппорта. А так заодно выявляем сифозные хосты в сети.

"Автоматизация борьбы со спамботами в своей сети"
Отправлено mr_gfd , 25-Авг-09 15:06 
>Да, так было бы лучше всего. Но пользователям этого не объяснить. Т.е.
>увеличится число тупых кейсов у саппорта. А так заодно выявляем сифозные
>хосты в сети.

На трипаки в сетке похер, а закрытый на выход 25й порт - это айс. парсить maillog - изящнее и информативнее.


"Автоматизация борьбы со спамботами в своей сети"
Отправлено jordan , 24-Авг-09 22:19 
А есть чтото подобное для сервиса icq?

"Автоматизация борьбы со спамботами в своей сети"
Отправлено настоящий_аноним , 25-Авг-09 00:59 
Это же надо так мучаться... В iptables это делается несколькими строчками:
# Создаем список спамеров
ipset -N spambots iphash
# Блокируем спамеров
iptables -I FORWARD -m set --set spambots src -j DROP
# Если кто-то превышает лимит подключений - заносим в "черный список"
iptables -A FORWARD -p tcp --dport 25 -m state --state NEW -m hashlimit --hashlimit-name spamcheck --hashlimit-mode srcip --hashlimit-above 20/min -j SET --add-set spambots src
# Еще можно добавить проверку на количество одновременных соединений с одного адреса
iptables -A FORWARD -p tcp --dport 25 -m state --state NEW -m connlimit --connlimit-above 10 -j SET --add-set spambots src

Вуаля! Не более 20 новых соединений в минуту, не более 10 соединений одновременно.
Правда, hashlimit жестко задает контролируемые периоды времени (минута, час, сутки). Если хотите задавать их произвольно - см. recent.

И не жалуйтесь, что "для этого надо патчить ядро и т.п.". Это всего лишь следствие неправильного выбора дистрибутива =) В debian stable (с iptables и xtables-addons из testing) все работает "искаропки".


"Автоматизация борьбы со спамботами в своей сети"
Отправлено andrew , 25-Авг-09 20:29 
Нда. Скрипт на двести строчек... и три-четыре строчки на iptables и pf.
Наглядно понимаешь разницу между сисадмином и велосипедистом.

"Автоматизация борьбы со спамботами в своей сети"
Отправлено Щекн Итрч , 26-Авг-09 00:05 
>Нда. Скрипт на двести строчек... и три-четыре строчки на iptables и pf.
>
>Наглядно понимаешь разницу между сисадмином и велосипедистом.

НЕ работают "три-четыре строчки на iptables и pf". НЕ работают.
Бабушку свою жить поучите.


"Автоматизация борьбы со спамботами в своей сети"
Отправлено аноним , 26-Авг-09 11:02 
А у меня - работают. Причем далеко не на одном сервере.
Вопрос: у кого из нас двоих руки из плеч, а у кого из ...?

"Автоматизация борьбы со спамботами в своей сети"
Отправлено настоящий_аноним , 26-Авг-09 15:44 
>НЕ работают "три-четыре строчки на iptables и pf". НЕ работают.

Полагаю, проблема не у "iptables и pf", а у вас. Где-то в области /dev/hands либо /dev/brain. Возможно, обусловлено ошибками при сборке ДНК :)


"Автоматизация борьбы со спамботами в своей сети"
Отправлено shadow_alone , 25-Авг-09 04:52 
Самое простое
-A FORWARD -p tcp --dport 25 -j LOG --log-prefix smtpport:
включить logwatch и получать почту с логом ежедневно, не гнушаясь просматривать.

"Iptables автоматическая блокировка спама из подсети."
Отправлено .snake , 25-Авг-09 05:12 
-A FORWARD -s 192.168.0.0/16 -p tcp -m tcp --dport 25 -m state --state NEW -m recent --set --name SMTP
-A FORWARD -s 192.168.0.0/16 -p tcp -m tcp --dport 25 -m state --state NEW -m recent --update --seconds 60 --hitcount 5 --name SMTP -j REJECT --reject-with icmp-port-unreachable

Автоматически блокирует рассылку спама от клиентов. Как только спам прекращается почта начинает работать :)


"Iptables автоматическая блокировка спама из подсети."
Отправлено shadow_alone , 25-Авг-09 05:21 
>-A FORWARD -s 192.168.0.0/16 -p tcp -m tcp --dport 25 -m state
>--state NEW -m recent --set --name SMTP
>-A FORWARD -s 192.168.0.0/16 -p tcp -m tcp --dport 25 -m state
>--state NEW -m recent --update --seconds 60 --hitcount 5 --name SMTP
>-j REJECT --reject-with icmp-port-unreachable
>
>Автоматически блокирует рассылку спама от клиентов. Как только спам прекращается почта начинает
>работать :)

очень интересно, из-за кого-то одного будут страдать все - это во первых.
Во вторых, при /16 вполне возможно одновременное подключение более 5 клиентов в минуту, так что, думаю , не лучший вариант.


"Iptables автоматическая блокировка спама из подсети."
Отправлено .snake , 25-Авг-09 06:23 
Страдать будет только тот кто спамит, проверено.
Префикс /16 указан для примера, роли это не влияет

"Iptables автоматическая блокировка спама из подсети."
Отправлено настоящий_аноним , 25-Авг-09 13:11 
>очень интересно, из-за кого-то одного будут страдать все - это во первых.
>Во вторых, при /16 вполне возможно одновременное подключение более 5 клиентов в минуту, так что, думаю , не лучший вариант.

Мсье самый умный? Мсье никогда не читает документацию?
Шагом марш читать man iptables!
recent хранит информацию по каждому айпишнику отдельно. /16 задает только "область наблюдения".


"Iptables автоматическая блокировка спама из подсети."
Отправлено shadow_alone , 25-Авг-09 13:16 
>>очень интересно, из-за кого-то одного будут страдать все - это во первых.
>>Во вторых, при /16 вполне возможно одновременное подключение более 5 клиентов в минуту, так что, думаю , не лучший вариант.
>
>Мсье самый умный? Мсье никогда не читает документацию?
>Шагом марш читать man iptables!
>recent хранит информацию по каждому айпишнику отдельно. /16 задает только "область наблюдения".
>

Мсье не страдает такой хренью, ибо.....


"Iptables автоматическая блокировка спама из подсети."
Отправлено настоящий_аноним , 25-Авг-09 14:05 
>Мсье не страдает такой хренью, ибо.....

Ибо считает, что лучше написать двадцать тормозных велосипедов по сто килобайт каждый, чем один раз прочитать документацию по штатным возможностям своей системы.
Я правильно вас понял?


"Iptables автоматическая блокировка спама из подсети."
Отправлено shadow_alone , 25-Авг-09 14:18 
совершенно неправильно....
сплошной, блин, офф топ.... (лучше по русски - не по теме)
далек от таких ньюансов.... мелко.
ну судите строго.
не видел такого в 1.2
а дальше уже, как то, не очень вставляет - железо лучше, да и оно уже прошлое.


"Автоматизация борьбы со спамботами в своей сети"
Отправлено emp , 25-Авг-09 12:11 
за прогу - зачёт. за ночь наловила 87 хостов. фикусы с iptables стоят на релее. но вот на исходящий поток от клиентов надо ставить чтото заносящее инфу в биллинг. чтоб тп по ночам спокойно могло удалить/приостановить бан клиенту, а не ждать админа чтобы он посмотрел в табличку.

"Автоматизация борьбы со спамботами в своей сети"
Отправлено Дима Иванов , 25-Авг-09 15:17 
>надо ставить чтото заносящее инфу в биллинг. чтоб тп по ночам спокойно могло >удалить/приостановить бан клиенту, а не ждать админа чтобы он посмотрел в табличку.

Именно!!! Наконец кто-то понял мою задумку :)


"Автоматизация борьбы со спамботами в своей сети"
Отправлено maap , 25-Авг-09 14:44 
Я бы предложил анализировать коннтраки с ASSURED на 25 порту.

"Автоматизация борьбы со спамботами в своей сети"
Отправлено настоящий_аноним , 26-Авг-09 15:52 
>Я бы предложил анализировать коннтраки с ASSURED на 25 порту.

Кстати вопрос: ctstatus анализирует все подключения или только related по conntrack?


"Автоматизация борьбы со спамботами в своей сети"
Отправлено admin , 25-Авг-09 23:04 
многабукаф в перле. может и красиво, но оч тяжело.
у меня на шеле в 5 строк влезло.

"Автоматизация борьбы со спамботами в своей сети"
Отправлено Щекн Итрч , 26-Авг-09 00:06 
>многабукаф в перле. может и красиво, но оч тяжело.
>у меня на шеле в 5 строк влезло.

И не слабО их здесь привести?
Что-то мешает? Шарики?


"Автоматизация борьбы со спамботами в своей сети"
Отправлено настоящий_аноним , 26-Авг-09 15:46 
>у меня на шеле в 5 строк влезло.

У меня на iptables 3-4. У товарища выше на pf - 3. Что вы там так длинно пишете? ;)


"Раздел полезных советов: Автоматизация борьбы со спамботами ..."
Отправлено XoRe , 27-Авг-09 00:25 
Скрипт, думаю, будет полезен.
Он хорошо подходит, когда нужно оповещать пользователя о том, что с него сыплется спам.

Могу посоветовать прикрутить к нему отправлялку писем пользователям.
Типа "Это автоматическое сообщение - у вас на компе вирус. Можете скачать антивирус с нашего фтп (ссылка), обновить его бесплатно с нашего фтп (ссылка)."
Ещё можно ссылку на пошаговое описание, как что делать.
А описание в картинках)
Думаю, это может ещё больше уменьшить звонки в суппорт.

Ещё могу посоветовать анализировать dns запросы типа MX - они тоже обычно генерятся именно спамописателями.
Вылавливать такие запросы тоже можно с помощью tcpdump.

Ещё в свое время заметил, что размер "окна" (параметр такой в ip или tcp заголовке) у спамописем равен 24000.
Помнится, даже после долгого наблюдения не заметил ничего другого, кроме спама, с таким окном.
Но это уже не так однозначно.

А ещё могу посоветовать:
ipfw add 1 skipto 4 tcp from table(x) to not me 25
ipfw add 2 skipto 4 tcp from any to not me 25 limit src-addr 10
ipfw add 3 deny tcp from any to not me 25

Просто не дает устанавливать больше 10 одновременных соединений)
Правило с limit - динамическое.
Параметры динамических правил можно настроить тут:
sysctl net.inet.ip.fw

А в table(x) кидать "официальных спаммеров")
Т.е. тех, кого не надо блочить.

Можно пойти более хитро)
Можно воспользоваться подсистемой netgraph - связать модуль для bpf и модуль для netflow.
И настроить так, чтобы получать статистику netflow о спаммерах.
А netflow уже хоть куда - хоть в БД, хоть в html)


"Автоматизация борьбы со спамботами в своей сети"
Отправлено Илья Евсеев , 03-Сен-09 11:32 
То же самое, только чуть короче :)
http://sources.homelink.ru/spamblock/

"Автоматизация борьбы со спамботами в своей сети"
Отправлено Kost , 16-Янв-12 15:53 
#Время записи в журнал
client_connection_status_update_time = 5m
# Задаём промежуток времени, на который будем опираться, тут - 10 минут
anvil_rate_time_unit =600s
# Кол-во получателей для одного авторизованного пользователя в установленный промежуток времени
#(или сколько можно указать RCPT TO для одного авторизованного клиента вне зависимости от кол-ва соединений/сессий).
smtpd_client_recipient_rate_limit=200
# Кол-во соединений для одного ip адреса. При переборе соединений, пользователь получит отказ в соединении с
# ошибкой "Too many connections from ip". Параметр может иметь исключения, задаваемые параметром smtpd_client_event_limit_exceptions (по умолчанию равен $mynetworks)
smtpd_client_connection_rate_limit=200
# Кол-во отправленных писем авторизованным клиентом вне зависимости от кол-ва сессий (были ли отправки за одну сессию или за несколько).
#При переборе параметра, клиент получит ошибку "Too many messages".
smtpd_client_message_rate_limit=200
# Исключения
smtpd_client_event_limit_exceptions = $mynetworks
#Интервал времени для подсчета количества соединений
client_connection_rate_time_unit = 60s

+ faill2ban

[Definition]

# Option:  failregex
# Notes.:  regex to match the password failures messages in the logfile. The
#          host must be matched by a group named "host". The tag "<HOST>" can
#          be used for standard IP/hostname matching and is only an alias for
#          (?:::f{4,6}:)?(?P<host>[\w\-.^_]+)
# Values:  TEXT
#
failregex =     reject: RCPT from (.*)\[<HOST>\]: 504 5.5.2
#               reject: RCPT from (.*)\[<HOST>\]: 450 4.1.1
#               reject: RCPT from (.*)\[<HOST>\]: 450 4.7.1
#               reject: RCPT from (.*)\[<HOST>\]: 554 5.7.1
                reject: RCPT from (.*)\[<HOST>\]: 553 5.7.1
                Connection rate limit exceeded: (.*) from unknown\[<HOST>\] for service smtp
                Message delivery request rate limit exceeded: (.*) from unknown\[<HOST>\] for service smtp
                Recipient address rate limit exceeded: (.*) from unknown\[<HOST>\] for service smtp
                too many errors after RCPT from (.*)\[<HOST>\]
                cannot find your hostname\S \S<HOST>\S
#                RCPT from .+\[<HOST>\]: .+ Recipient address rejected: User unknown
                Client host \[<HOST>\] blocked using [\.\w]+;
                RCPT from .+\[<HOST>\]: .+: Sender address rejected: Domain not found
                RCPT from .+\[<HOST>\]: .+: Helo command rejected:
                Illegal address syntax from unknown\[<HOST>\]
#               warning: unknown\[<HOST>\]: SASL PLAIN authentication failed:
                warning: .+\[<HOST>\]: SASL LOGIN authentication failed:


Жалоб не было