smtpIptablesBlocker
This script is the result of my search for a way to make my mail server more resilient against spam waves. Take a look at following links(1,2,3) if you want to know more about the history/process to this solution. I use courier as MTA and IMAP backend for it.
Introduction
To fight the spam I’m using DNS RBL as first line of defense, followed by greylisting, spam assassin and some other stuff. The ratio of spam which gets through is quite low but thats not the problem at this point. The problem is the spam waves that hit the server several times a day. Normally the system has under 30 open SMTP connections to/from others server, but within minutes that value raises drastically (and courier creates a process for each). For example look at the values which show the amount of open SMTP connections at the given moment.
Mon Jul 27 19:12:17 CEST 2009 4
....
Mon Jul 27 19:12:32 CEST 2009 7
Mon Jul 27 19:12:37 CEST 2009 13
Mon Jul 27 19:12:42 CEST 2009 9
Mon Jul 27 19:12:47 CEST 2009 8
Mon Jul 27 19:12:52 CEST 2009 50
Mon Jul 27 19:12:57 CEST 2009 88
Mon Jul 27 19:13:02 CEST 2009 101
Mon Jul 27 19:13:07 CEST 2009 120
.....
Mon Jul 27 19:13:33 CEST 2009 163
Mon Jul 27 19:13:38 CEST 2009 167
.....
Mon Jul 27 19:17:24 CEST 2009 301
Mon Jul 27 19:17:30 CEST 2009 301
Mon Jul 27 19:17:35 CEST 2009 301
Mon Jul 27 19:17:40 CEST 2009 301
300 is the limit of active connections. At this point the mail server adds following to the log and does not accept any new connections.
Jul 27 19:17:23 mail courieresmtpd: 300 maximum active connections.
Jul 27 19:18:24 mail courieresmtpd: 300 maximum active connections.
Jul 27 19:21:14 mail courieresmtpd: 300 maximum active connections.
This script now solves my problem. It looks through the maillog and adds every DNS RBL listed IP to the firewall for 10 minutes. After that it just terminates the process which handles the connection. This leads to a reduced process number at once and makes space for a new one. A clean solution would implement my complete script in the mta itself – basically adding the IP to the firewall and terminating the smtp handling process. But this works also stable so far until something like this is added to courier (if it ever will be)
.
Install – Iptables stuff
First load the iptables module somewhere at boot time with an option to allow more IP addresses stored.
modprobe ipt_recent ip_list_tot=1000
I think 1000 is quite on the low end, as the spam waves easily reach them. Then add following iptables commands to your firewall script.
# build sub chain
$iptables -N SPAMMER
# move all incomming smtp traffic there
$iptables -A INPUT -p tcp --dport 25 -j SPAMMER
# check if the source ip is already in the list, if so give it another 600 sec and drop the packages
$iptables -A SPAMMER -m recent --name spammer --update --seconds 600 -j DROP
As you can see we drop the packets for 10 minutes. If a packet is send within that 10min the time period starts again.
You can test your setup by doing the following.
echo +1.1.1.1 >/proc/net/ipt_recent/spammer
and take a look at
cat /proc/net/ipt_recent/spammer
Replace 1.1.1.1 by an IP address of a spammer (just look in your logfile 😉 ) and see it working.
Install Daemon
Ok, now that we have the kernel/iptables part we need the script which adds the IP addresses of spammers on a DNS RBL after the first 5xx to the ipt_recent list.
Download the script here: smtpIptablesBlocker-0.1.tar.bz2
Copy the smtpIptablesBlocker.py deamon.py
to /usr/local/sbin/
and edit the smtpIptablesBlocker.py
file to reflect the location of your mail.err
log file.
Now we need to link it to the init.d and get it in the runlevels:
#ln -s /usr/local/sbin/smtpIptablesBlocker.py /etc/init.d/smtpIptablesBlocker
on Debian/Ubuntu use following
# update-rc.d smtpIptablesBlocker defaults 21
Adding system startup for /etc/init.d/smtpIptablesBlocker ...
/etc/rc0.d/K21smtpIptablesBlocker -> ../init.d/smtpIptablesBlocker
/etc/rc1.d/K21smtpIptablesBlocker -> ../init.d/smtpIptablesBlocker
/etc/rc6.d/K21smtpIptablesBlocker -> ../init.d/smtpIptablesBlocker
/etc/rc2.d/S21smtpIptablesBlocker -> ../init.d/smtpIptablesBlocker
/etc/rc3.d/S21smtpIptablesBlocker -> ../init.d/smtpIptablesBlocker
/etc/rc4.d/S21smtpIptablesBlocker -> ../init.d/smtpIptablesBlocker
/etc/rc5.d/S21smtpIptablesBlocker -> ../init.d/smtpIptablesBlocker
Take it to a test ride with
/etc/init.d/smtpIptablesBlocker start
tail -f /var/log/smtpIptablesBlocker.log
On Debian/Ubuntu you need to tell the syslogd that it should not do the log rotate, as this should be handled by logrotate, which is able to inform us about it.
Replace in /etc/cron.daily/sysklogd
:
logs=$(syslogd-listfiles)
by
logs=$(syslogd-listfiles -s "(mail\.err|smtpIptablesBlocker\.log)")
and in /etc/cron.weekly/sysklogd
logs=$(syslogd-listfiles --weekly)
by
logs=$(syslogd-listfiles --weekly -s "(mail\.err|smtpIptablesBlocker\.log)")
Now we can add the logrotate config (/etc/logrotate.d/courier
)
/var/log/mail.err /var/log/smtpIptablesBlocker.log {
notifempty
delaycompress
sharedscripts
prerotate
/etc/init.d/smtpIptablesBlocker stop
endscript
postrotate
/etc/init.d/sysklogd reload-or-restart
/etc/init.d/smtpIptablesBlocker start
endscript
}
And the result? Just look at this really big spam wave – and we’re able to scale it.
Tue Jul 28 14:36:44 CEST 2009 1
Tue Jul 28 14:36:49 CEST 2009 1
Tue Jul 28 14:36:54 CEST 2009 34
Tue Jul 28 14:36:59 CEST 2009 56
Tue Jul 28 14:37:04 CEST 2009 52
Tue Jul 28 14:37:09 CEST 2009 60
Tue Jul 28 14:37:14 CEST 2009 87
Tue Jul 28 14:37:19 CEST 2009 126
Tue Jul 28 14:37:24 CEST 2009 128
Tue Jul 28 14:37:29 CEST 2009 140
Tue Jul 28 14:37:34 CEST 2009 138
Tue Jul 28 14:37:39 CEST 2009 143
Tue Jul 28 14:37:44 CEST 2009 161
Tue Jul 28 14:37:49 CEST 2009 198
Tue Jul 28 14:37:54 CEST 2009 208
....
Tue Jul 28 14:41:11 CEST 2009 131
Tue Jul 28 14:41:16 CEST 2009 147
Tue Jul 28 14:41:21 CEST 2009 134
Tue Jul 28 14:41:26 CEST 2009 133
Tue Jul 28 14:41:31 CEST 2009 128
Tue Jul 28 14:41:36 CEST 2009 103
Tue Jul 28 14:41:41 CEST 2009 74
Tue Jul 28 14:41:47 CEST 2009 98
Tue Jul 28 14:41:52 CEST 2009 91
....
Tue Jul 28 14:43:27 CEST 2009 28
Tue Jul 28 14:43:32 CEST 2009 26
Tue Jul 28 14:43:37 CEST 2009 20
Tue Jul 28 14:43:42 CEST 2009 15
Tue Jul 28 14:43:47 CEST 2009 14
Tue Jul 28 14:43:52 CEST 2009 14
Tue Jul 28 14:43:57 CEST 2009 15
Tue Jul 28 14:44:02 CEST 2009 11
Tue Jul 28 14:44:07 CEST 2009 6
Tue Jul 28 14:44:12 CEST 2009 9
Tue Jul 28 14:44:17 CEST 2009 7
As you see 300 is never reached. Our server is the whole time reachable for our customers.
Powered by WordPress
Entries and comments feeds.
Valid XHTML and CSS.
29 queries. 0.052 seconds.