Rendszergazda & webfejlesztő devblog Laczkó Zoltán blogja

24jan/100

Spambotok szűrése exim és fail2ban alkalmazásával

A spam elleni háborúban egy újabb használható fegyver, a fail2ban.

Az alábbi pár egyszerű lépéssel az automatikus spambotok ismételt próbálkozásainak számát tudjuk eredményesen lecsökkenteni drasztikusan.

A példában Debian/Lenny szerepel, de a többi disztribúcióban való beállítás sem tér el sokban.

Telepítsük a szükséges csomagokat.

root@inky:~# apt-get install fail2ban python-gamin

Fontos, hogy 0.7.6, vagy feletti fail2ban -t telepítsünk, mert a régebbiek nem ismerik fel az exim logokban található dátum mezőket!

Illesszük bele a /etc/fail2ban/jail.conf fájlba a következőt.

[exim]
enabled  = true
port     = 25
filter   = exim
logpath  = /var/log/exim4/mainlog
bantime  = 600
maxretry = 2

Paraméterek, amiket tetszés szerint átírhatsz:

-port: alapértelmezettként csak a tcp/25 -ös porton figyel az exim, ha más portokat is használsz, akkor vesszővel elválasztva sorold fel őket (pl: 25,10025)

- bantime: ha a feltételeknek megfelelő alanyt talál, akkor ennyi másodpercig tiltja ki

- maxretry: ennyiszer teljesülhet a feltétel, mielőtt kitiltja

Ellenőrízzük, hogy létezik-e a /etc/fail2ban/filter.d/exim.conf fájl.

# Fail2Ban configuration file
#
# Author: Cyril Jaquier
#
# $Revision: 510 $
#

[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>\S+)
# Values:  TEXT
#
#failregex = \[<HOST>\] .*(?:rejected by local_scan|Unrouteable address)
failregex = \[<HOST>\] .*(?:rejected by local_scan|Unrouteable address|Spam score too high)

# Option:  ignoreregex
# Notes.:  regex to ignore. If this regex matches, the line is ignored.
# Values:  TEXT
#
ignoreregex =

Én kiegészítettem a failregex mintát egy saját hibaüzenettel is. Figyelj oda, hogy ez reguláris kifejezés!

Most már csak annyi a dolgunk, hogy újraindítsuk a fail2ban programot

root@inky:~# /etc/init.d/fail2ban restart

Az eredményt a fail2ban logjaiban tudjuk nyomonkövetni

root@inky:~# cat /var/log/fail2ban.log
2010-01-24 12:07:05,079 fail2ban.server : INFO   Changed logging target to /var/log/fail2ban.log for Fail2ban v0.8.3
2010-01-24 12:07:05,081 fail2ban.jail   : INFO   Creating new jail 'exim'
2010-01-24 12:07:05,081 fail2ban.jail   : INFO   Jail 'exim' uses poller
2010-01-24 12:07:05,143 fail2ban.filter : INFO   Added logfile = /var/log/exim4/mainlog
2010-01-24 12:07:05,144 fail2ban.filter : INFO   Set maxRetry = 2
2010-01-24 12:07:05,146 fail2ban.filter : INFO   Set findtime = 600
2010-01-24 12:07:05,147 fail2ban.actions: INFO   Set banTime = 600
2010-01-24 12:07:05,264 fail2ban.jail   : INFO   Jail 'exim' started
2010-01-24 12:07:07,321 fail2ban.actions: WARNING [exim] Ban 114.200.XXX.XXX
2010-01-24 12:07:08,292 fail2ban.actions: WARNING [exim] Ban 218.209.XXX.XXX

Alapértelmezettként a fail2ban iptables bejegyzést készít az IP cím tiltására, de tetszés szerint készíthetünk egyedi scripteket is.

root@inky:~# iptables -L -n -v
Chain INPUT (policy ACCEPT 3233M packets, 725G bytes)
 pkts bytes target     prot opt in     out     source               destination
 15   636 fail2ban-exim  tcp  --  *      *       0.0.0.0/0            0.0.0.0/0           multiport dports 25

Chain fail2ban-exim (1 references)
 pkts bytes target     prot opt in     out     source               destination
 14   560 DROP       0    --  *      *       114.200.XXX.XXX      0.0.0.0/0
 1     40 DROP       0    --  *      *       218.209.XXX.XXX      0.0.0.0/0
 80  4544 RETURN     0    --  *      *       0.0.0.0/0            0.0.0.0/0

Ha használunk munint a gépünk monitorozására, akkor az alábbi plugin segítségével a fail2ban eredményességét is nyomon tudjuk követni.

#!/bin/bash
: <<=cut

=head1 NAME

fail2ban - Plugin to monitor fail2ban blacklists

=head1 APPLICABLE SYSTEMS

All systems with "bash" and "fail2ban"

=head1 CONFIGURATION

The following is the default configuration

 [fail2ban]
 env.client /usr/bin/fail2ban-client

The user running this plugin needs read and write access to the
fail2ban communications socket.  You will need to add this:

 [fail2ban]
 user root

=head1 INTERPRETATION

This plugin shows a graph with one line per active fail2ban jail, each
showing the number of blacklisted addresses for that jail.

In addition, a line with the total number of blacklisted addresses is
displayed.

=head1 MAGIC MARKERS

 #%# family=auto
 #%# capabilities=autoconf

=head1 VERSION

 1.0.20090423

=head1 BUGS

Needs bash. Uses bashisms ${parm/?/pat/string} and $'...' to avoid
running external programs.

=head1 AUTHOR

Stig Sandbeck Mathisen <ssm@fnord.no>

=head1 LICENSE

GPLv2

=cut

##############################
# Configurable variables
client=${client:-/usr/bin/fail2ban-client}

##############################
# Functions

# List jails, one on each line
list_jails() {
 ${client} status | while read line
 do
 case $line in
 *'Jail list:'*)
 line="${line##*Jail list*:}"
 line="${line//[ $'\t']/}"
 printf "${line//,/$'\n'}\n"
 ;;
 esac
 done
}

# Print the munin values
values() {
 list_jails | while read jail
 do
 ${client} status ${jail} | while read line
 do
 case $line in
 *'Currently banned'*)
 line="${line##*Currently banned:}"
 num="${line//[ $'\t']/}"
 echo ${jail//[^0-9A-Za-z]/_}.value ${num}
 ;;
 esac
 done
 done
}

# Print the munin config
config() {
 echo 'graph_title Hosts blacklisted by fail2ban'
 echo 'graph_info This graph shows the number of host blacklisted by fail2ban'
 echo 'graph_category network'
 echo 'graph_vlabel Number of hosts'

 echo 'graph_args --base 1000 -l 0'
 echo 'graph_total total'

 list_jails | while read jail
 do
 echo ${jail//[^0-9A-Za-z]/_}.label $jail
 done
}

# Print autoconfiguration hint
autoconf() {
 if [ -e ${client} ]
 then
 if [ -x ${client} ]
 then
 if ${client} ping >/dev/null
 then
 echo "yes"
 else
 echo "no (fail2ban-server does not respond to ping)"
 fi
 else
 echo "no (${client} is not executable)"
 fi
 else
 echo "no (${client} not found)"
 fi
 exit
}

##############################
# Main

case $1 in
 config)
 config
 ;;
 autoconf)
 autoconf
 ;;
 *)
 values
 ;;
esac