We wpisie o programie fail2ban napisałem, ze program może służyć do walki ze spamem. Teraz nadszedł ten czas aby przedstawić jak fail2ban walczy ze spamem. W poniższym wpisie przedstawie jak można blokować upierdliwe serwery poczty które rozsyłają maile.
UWAGA: blokowanie całych serwerów jest zawsze ryzykowne. Na danym serwerze może znajdować się kilka domen. Wybieraj domenę która jest tylko spamowa.
Ideę jest aby ubijać IP z których przychodzi spam z danej domeny. Najpierw nalezy zdefiniować nowy filtr w pliku jail.conf programu fail2ban.
[spam_popular] enabled = true port = smtp,ssmtp,submission filter = spam_popular logpath = /var/lib/amavis/log/amavis.log bantime = 28800 maxretry = 1
[spam_popular] – nazwa naszego filtru
port– porty jakie będą blokowane
filter – nazwa filtru
logpath-jaki plik ma być obserwowany przez fail2ban
bantime -czas w sekundach na jaki jest blokowany dany serwer
mexretry – ilość wpisów jakie powoduję włączenie blokowania na bantime czas
Oczywiście każdy może ustawić te wartości jak chce szczególnie logpath trzeba dostosować do swojego serwera.
Teraz zostało do ustawienia tylko co ma wzbudzać blokadę. Robimy to w nowym pliku
/etc/fail2ban/filter.d/spam_popular.conf
Skoro obserwujemy plik logów amavisa musimy do niego dostosować obserwację logu i zgodnie z jego formatem. Należy najpierw zobaczyć czy w logu są adresy IP nadawcy czy adres zwrotny 127.0.0.1. Jest jest localhost należy zainteresować się zmienną -o smtp_send_xforward_command=yes w pliku master.cf postfixa. Rzeczony plik wygląda następująco
[Definition] failregex = Blocked SPAM , FROM_POSTFIX LOCAL \[<HOST>\] <\S+@sensdelivery.com> -> ignoreregex =
Co robi ten wpis? Wychwytuje wpis o blokadzie maila z domeny @sensdelivery.com. Po tym zdarzeniu fail2ban blokuje adres IP z którego przyszło połączenie na bantime sekund ustawiony w pliku jail.conf. Oczywiście może być ciut inny format tego pliku (inne tekst FROM_POSTFIX LOCAL), każdy musi dostosować do swojego. Szczególnie jak Policy Bank amavisa jest zdefiniowane te texty będą inne.
Zaletą tego rozwiązania jest to, ze oczyszcza logi i serwer się mniej męczy. Również zmiana przez spamera IP serwera skutkuje blokadą.
A oto mój plik z blokowanymi domenami [Ostatnia aktualizacja: 2015-06-03]
[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 = Blocked SPAM , FROM_POSTFIX LOCAL \[<HOST>\] <\S+@sensdelivery.com> -> Blocked SPAM , FROM_POSTFIX LOCAL \[<HOST>\] <\S+@augustnewo.com> -> Blocked SPAM , FROM_POSTFIX LOCAL \[<HOST>\] <\S+@bounce.freshmail.pl> -> Blocked SPAM , FROM_POSTFIX LOCAL \[<HOST>\] <\S+@news0\d.mailinstitute.pl> -> Blocked SPAM , FROM_POSTFIX LOCAL \[<HOST>\] <\S+@news0\d.mailsignals.pl> -> Blocked SPAM , FROM_POSTFIX LOCAL \[<HOST>\] <\S+@news0\d.expandmail.pl> -> Blocked SPAM , FROM_POSTFIX LOCAL \[<HOST>\] <\S+@kalkuluje.com> -> Blocked SPAM , FROM_POSTFIX LOCAL \[<HOST>\] <\S+@mail.click365.pl> -> Blocked SPAM , FROM_POSTFIX LOCAL \[<HOST>\] <\S+@news0\d.campaignmail.pl> -> Blocked SPAM , FROM_POSTFIX LOCAL \[<HOST>\] <\S+@portal.dla-najlepszych.pl> -> Blocked SPAM , FROM_POSTFIX LOCAL \[<HOST>\] <\S+@m.businesscampaign.pl> -> Blocked SPAM , FROM_POSTFIX LOCAL \[<HOST>\] <\S+@bounce.getresponse.com> -> Blocked SPAM , FROM_POSTFIX LOCAL \[<HOST>\] <\S+@sklepreklamowy.biz> -> Blocked SPAM , FROM_POSTFIX LOCAL \[<HOST>\] <\S+@operatorzy.dla-najlepszych.pl> -> Blocked SPAM , FROM_POSTFIX LOCAL \[<HOST>\] <\S+@detalus.dla-najlepszych.pl> -> Blocked SPAM , FROM_POSTFIX LOCAL \[<HOST>\] <\S+@mailsender.pl> -> Blocked SPAM , FROM_POSTFIX LOCAL \[<HOST>\] <bounces@tanisklad.dla-najlepszych.pl Blocked SPAM , FROM_POSTFIX LOCAL \[<HOST>\] <\S+@openmailing.pl> -> Blocked SPAM , FROM_POSTFIX LOCAL \[<HOST>\] <\S+@biznes2b.pl> -> Blocked SPAM , FROM_POSTFIX LOCAL \[<HOST>\] <\S+@s.explanator.pl> -> Blocked SPAM , FROM_POSTFIX LOCAL \[<HOST>\] <\S+@news0\d.mailbus.pl> -> Blocked SPAM , FROM_POSTFIX LOCAL \[<HOST>\] <\S+@otwarte@szkolenia-rozwojowe.pl> -> Blocked SPAM , FROM_POSTFIX LOCAL \[<HOST>\] <\S+@biuro.caffeprint.eu> -> Blocked SPAM , FROM_POSTFIX LOCAL \[<HOST>\] <\S+@z.enewsletter.pl> -> Blocked SPAM , FROM_POSTFIX LOCAL \[<HOST>\] <\S+\@serve-links.com> -> Blocked SPAM , FROM_POSTFIX LOCAL \[<HOST>\] <\S+\@dzialam-online.pl> -> Blocked SPAM , FROM_POSTFIX LOCAL \[<HOST>\] <\S+\@news\d\d.mailjoker.pl> -> Blocked SPAM , FROM_POSTFIX LOCAL \[<HOST>\] <\S+\@dzialam-online.pl> -> Blocked SPAM , FROM_POSTFIX LOCAL \[<HOST>\] <\S+\@kabelpol.dla-najlepszych.pl> -> Blocked SPAM , FROM_POSTFIX LOCAL \[<HOST>\] <\S+\@emasterproject.pl> -> Blocked SPAM , FROM_POSTFIX LOCAL \[<HOST>\] <\S+\@dzialam-online.pl> -> Blocked SPAM , FROM_POSTFIX LOCAL \[<HOST>\] <\S+\@news\d\d.mailjoker.pl> -> Blocked SPAM , FROM_POSTFIX LOCAL \[<HOST>\] <\S+\@dzialam-online.pl> -> Blocked SPAM , FROM_POSTFIX LOCAL \[<HOST>\] <\S+\@kabelpol.dla-najlepszych.pl> -> Blocked SPAM , FROM_POSTFIX LOCAL \[<HOST>\] <\S+\@emasterproject.pl> -> Blocked SPAM , FROM_POSTFIX LOCAL \[<HOST>\] <\S+\@dzialam-online.pl> -> Blocked SPAM , FROM_POSTFIX LOCAL \[<HOST>\] <\S+\@odb.mailingweb.com.pl> -> Blocked SPAM , FROM_POSTFIX LOCAL \[<HOST>\] <rzoologiczny-www\@mediaexperts.vps.ogicom.net> -> Blocked SPAM , FROM_POSTFIX LOCAL \[<HOST>\] <\S+\@serve-links.com> -> Blocked SPAM , FROM_POSTFIX LOCAL \[<HOST>\] <mailing@smemailing.pl> -> Blocked SPAM , FROM_POSTFIX LOCAL \[<HOST>\] <\S+\@enternetmarketing.net> -> Blocked SPAM , FROM_POSTFIX LOCAL \[<HOST>\] <\S+\@\S+\.instytut-marketingu.com> -> Blocked SPAM , FROM_POSTFIX LOCAL \[<HOST>\] <\S+\@\S+\.interactive-partners.me> -> # Option: ignoreregex # Notes.: regex to ignore. If this regex matches, the line is ignored. # Values: TEXT # ignoreregex =
miłego blokowania spamu:)
Hej kolego, tak postanowiłem sobie przetestować Twoją metodę z fail2ban i mam pewną wątpliwość co do poprawności działania..
Przykład freshmaila:
w iptables wrzuca takie wpisy:
DROP all — s3smtp116.freshmail.pl anywhere
DROP all — bsmtp65.freshmail.pl anywhere
DROP all — bsmtp67.freshmail.pl anywhere
DROP all — s3smtp117.freshmail.pl anywhere
DROP all — s3smtp102.freshmail.pl anywhere
DROP all — sdc7smtp60.freshmail.pl anywhere
DROP all — sdc7smtp43.freshmail.pl anywhere
DROP all — s3smtp108.freshmail.pl anywhere
DROP all — sdc6smtp28.freshmail.pl anywhere
DROP all — sdc6smtp12.freshmail.pl anywhere
DROP all — sdc7smtp61.freshmail.pl anywhere
DROP all — sdc7smtp105.freshmail.pl anywhere
DROP all — sdc7smtp40.freshmail.pl anywhere
DROP all — s3smtp109.freshmail.pl anywhere
DROP all — s3smtp126.freshmail.pl anywhere
DROP all — s3smtp100.freshmail.pl anywhere
DROP all — sdc7smtp103.freshmail.pl anywhere
DROP all — sdc7smtp51.freshmail.pl anywhere
Jest ich około 30..
Tymczasem w logach:
Mar 17 15:08:50 prime postfix/smtpd[13629]: connect from s3smtp116.freshmail.pl[176.31.134.116]
Mar 17 15:08:50 prime postfix/smtpd[13629]: D1CA73038A6: client=s3smtp116.freshmail.pl[176.31.134.116]
Mar 17 15:08:50 prime postfix/cleanup[15487]: D1CA73038A6: message-id=
Mar 17 15:08:50 prime postfix/qmgr[15143]: D1CA73038A6: from=, size=4878, nrcpt=1 (queue active)
Mar 17 15:08:50 prime postfix/smtpd[13629]: disconnect from s3smtp116.freshmail.pl[176.31.134.116]
Mar 17 15:08:53 prime postfix/cleanup[15866]: 78FE53038AA: message-id=
Mar 17 15:08:53 prime postfix/qmgr[15143]: 78FE53038AA: from=, size=5335, nrcpt=1 (queue active)
Mar 17 15:08:53 prime amavis[16104]: (16104-08) Passed CLEAN {RelayedInbound}, [176.31.134.116]:52300 [176.31.134.116] -> , Queue-ID: D1CA73038A6, Message-ID: , mail_id: bTKKKwLROsLH, Hits: -0.749, size: 4878, queued_as: 78FE53038AA, 2588 ms
Regexy mam takie:
.* \[\]:.* ->
I taki konfig:
[spam_popular]
enabled = true
port = smtp,ssmtp,submission
filter = spam_popular
logpath = /var/log/mail.log
bantime = 302400
maxretry = 1
Niestety, komentarze u Ciebie wycinają część kodu 🙁
Niby masz DROPa s3smtp116.freshmail.pl a on sie w logach pojawia. I przez kilka sekund moze sie pojawic jeszcze. Pewna bezwladnosc jest. A co ci mowi log fail2ban?
Tez jestem uzytkownikiem fail2ban i zawsze zloscilo mnie, ze nie wiadomo jaki jest aktualny stan blokad
Dzisiaj przelamalem te niepewnosc i zrobilem malu skrypt, ktory pozwala to wyswietlic z dosc duza dokladnoscia
Specjalnie dla zabojcowspamu ode mnie – korekty mile widziane
:-))
========================================cut======================
echo „——————————————-”
zgrep -h „Ban ” /var/log/fail2ban.log* | awk ‚{print $5,$1}’ | sort | uniq -c
#echo „——————————————-”
#awk ‚($(NF-1) = /Ban/){print $NF}’ /var/log/fail2ban.log | sort | uniq -c | sort -n
echo „——————————————-”
grep „Ban ” /var/log/fail2ban.* | awk -F[\ \:] ‚{print $10, „\t” $8 }’ | sort | uniq -c | sort -n > /tmp/fail2
grep „Unban ” /var/log/fail2ban.* | awk -F[\ \:] ‚{print $10, „\t” $8}’ | sort | uniq -c | sort -n >> /tmp/fail2
sort /tmp/fail2 | uniq -u > /tmp/fail2b
cat /tmp/fail2b | while read a1 a2 a3
do
printf „$a1 $a2 $a3 \t”
resolveip -s $a2
done
========================================cut======================
Fail2ban posiada własnego klienta, którym możesz łatwo sprawdzić stan jail-a, ale jest to faktycznie upierdliwe, bo musisz pamiętać, jakie jaile masz uruchomione 😉
Ja dla swojego lenistwa opracowałem skrypcik w perl-u, który pokazuje mi ładną tabelkę z aktualnymi ban-ami z wszystkich jail-i (pomija puste – sam skrypcik nie jest w pełni mojego autorstwa – jest to adaptacja czegoś, ale już nie pamiętam skąd to mam):
==========================================================
~# cat f2b-status-all.pl
#!/usr/bin/env perl
#use strict;
use warnings;
sub main {
use Text::ASCIITable;
$t = Text::ASCIITable->new({drawRowLine => 1});
$t->setCols(‚Jail’,’Banned IPs’);
my @JAILS = split(‚ ‚,`fail2ban-client status | grep „Jail list” | sed -E ‚s/^[^:]+:[ \t]+//’ | sed ‚s/,//g’`);
foreach my $JAIL (@JAILS) {
my $bans = `fail2ban-client status $JAIL | grep „Banned IP list” | sed -E ‚s/^[^:]+:[ \t]+//’`;
$bans =~ s/\n//g;
#print length($bans);
if (length($bans) > 0) {
$bans =~ s/\s+/\n/g;
$t->addRow($JAIL,$bans);
}
}
print $t;
}
main();
======================================
Wymaga Text::ASCIITable.
Później można np. watch -n 5 f2b-status-all.pl i masz aktualny podgląd stanu z aktualizacją co 5 sekund.
PS: zwróćcie uwagę, czy nie zostały podmienione apostrofy, czy inne znaki przez puryfikatory komentarzy 😉
te zamienione apostrofy to nie moja wina – trzeba recznie poprawic ciagi z dolnym apostrfem
DO ADMINA – cos to nie tak ze gorny gorny poprawia na dolny gorny – apostrof