Sometimes it is necessary to block access from a certain ip-address. This can be done easily using route:
route add -host 1.2.3.4/32 reject
While this works, it does not provide the best user experience because from 1.2.3.4 the website now seems down, while it isn’t. A better way is to display an error message instead of the website requested.
I’m using load balancing to distribute the load to different web servers. The software in use is Keepalived. To block a given ip-address, I have the firewall tag it and then make Keepalived forward it to another web server instead. It goes like this:
iptables -t mangle -A PREROUTING -i eth0 \ -p tcp -s 1.2.3.4 --dport http -j MARK --set-mark 2000
This iptables rule just sets a mark ‘2000’ (can be any integer) when a request from 1.2.3.4 comes in for port ‘http’. In keepalived.conf we setup how to handle this fwmark:
virtual_server fwmark 2000 { delay_loop 6 lb_algo wlc lb_kind NAT persistence_timeout 0 protocol TCP real_server 10.10.10.1 80 { weight 1 TCP_CHECK { connect_port 80 connect_timeout 3 } } }
As you can see, Keepalived will send the request to ‘10.10.10.1’ which is for example an extra server. There you can display a static page with an error message explaining what’s going on. You can add more capacity by adding another ‘real_server’, if you wish. This will also distribute the load between the real_servers.
Now, when you block an ip-address, instead of the website being ‘down’, you now display an error message. Add your phone number or e-mail address so they can get in touch to fix the problem. In my experience, this approach works better and prevents urgent ‘website down’ calls.
To extend this even further, you can have a script add the fwmark rule above automatically when you detect some sort of abuse you want to block. It’s just as easy as using ‘route’!