Go to content Go to navigation Go to search

Signs of the Times Getting the upper hand with Linux Iptables · Mar 24, 04:30 PM

For a while I had been putting up with annoying spammers on this blog. The spammers were using scripts to try and post comments, but because the blog isn’t a standard one, the comments weren’t getting accepted. But they still showed in my logs and that was annoying. I used some custom iptables rules to make a dynamic blacklist…

There are many types of logs, from the lowest level system logs, through http server (apache) logs, third party log scripts that analyse and present the same information in a neater way (eg. the hard-to-Google Visitors), and the higher level – logs provided by the blog application. As an indication of the scale of the problem, the URL the spammers were trying had 4x the number of hits that my RSS feed (the next most requested URL) had. Also, the blog application logs were full of spam attempts. That can’t be right.

I had known that it was possible to have blacklists, and a bit of searching showed that it was possible to do things based on string matches in IP packets, using iptables. That was the start of some experimentation to come up with something that fitted the problem, because there were lots of example scripts on the ‘net, but nothing that exactly matched my needs.

Firstly, the basic commands to work with iptables. The man page for ‘iptables’ is very useful, but you also need to examine how the tables are set up on your server, because the distribution might have some firewall rules already in place. Understanding those, as much as grasping the iptables commands, is key to being able to add your own rules. You can list the current rules using ‘iptables -L’, or more usefully with ‘iptables -nL -v —line-numbers’. Armed with line numbers you can insert and replace rules (‘iptables -I’, ‘iptables -R’).

You need to appreciate that chains work a bit like flowchart steps, where each packet that comes into the server (joining the INPUT chain) has to pass several tests before being passed onto the next step, before a decision is finally made to ACCEPT or DROP the packet. I’m not sure if anyone has tried to visualise ipchains rules in a graphical form, but I’m sure it would help a lot of people to understand and configure them.

My firewall was set up after a bit of nagging from Fedora’s Anaconda installer and is fairly strict. It follows a fairly standard approach of firewalls, allowing specific things and disallowing EVERYTHING ELSE. This means that it isn’t useful to add rules onto the end of a chain, because the decision to accept or drop the packet has already been made. Using the commands above it’s possible to insert your rules and modify them. Just be careful with the standard rules, for example replacing the rule about RELATED and ESTABLISHED connections can easily lock you out of your server.

The basic components of my new feature were the string match rule and the ‘recent’ rule which is used to maintain information about things that have happened recently. The string match is relatively simple. Here I put in the part of the URL that was most often being used by spammers.

iptables -I RH-Firewall-1-INPUT 8 -p TCP —dport 80 -m string —string “/link/articles/100/forums/” —algo bm -j LOG —log-level info —log-prefix “BLOCKED”

The RH-Firewall-1-INPUT chain is the Fedora firewall. All incoming packets that aren’t from the local machine are sent through this chain for approval. The ‘8’ was the position to insert the rule so that it would be before the ‘RELATED, ESTABLISHED’ rule. ‘TCP —dport 80’ is the protocol and port used by a web server. ‘-m string —string “the string to match” —algo bm’ is what makes the string matching work, and the rest of the rule is the action to take – in this case making a log message in the system logs.

Log messages are important because they can help you debug the rules as you write them, and understand their behaviour. It’s also worth mentioning the ‘iptables -nL -v —line-numbers’ command shows the number of times a rule has been matched, which can tell you if the rule is working. More on debugging later.

The rule above simply logged an offending packet but didn’t take any further action. To get something to happen the rule need to be repeated with another action on the end. Before that, we’ll make some new chains which we can use to hold more meaningful sequences of rules.

I added a blacklist chain, and a paroleboard chain. The blacklist chain will process bad packets, add the senders IP to the blacklist and drop the packet. The paroleboard chain will watch packets from blacklisted IPs and revoke the blacklisting if they haven’t been bad lately. I felt this would allow anyone stumbling on the ‘bad’ URL by chance to be given a second chance, while locking out all scripted spammers. So the blacklist should be maintenance free.

The commands to add the blacklist and paroleboard chains were:

iptables -N blacklist
iptables -N paroleboard
action for blacklist: 1. add IP to list
iptables -A blacklist -m recent —name blacked —set
action for blacklist: 2. drop packet
iptables -A blacklist -j DROP

this packet is a frequent offender and will be dropped
iptables -A paroleboard -m recent —update —seconds 120 -j DROP
this packet is a serial offender and will be dropped
iptables -A paroleboard -m recent —update —hitcount 10 -j DROP
time for leniency – the address is known but hasn’t offended recently
log and
iptables -A paroleboard -j LOG —log-level info —log-prefix “PAROLED”
accept
iptables -A paroleboard -m recent —remove -j ACCEPT

Anything sent to the ‘blacklist’ chain will make a note of the sender’s IP, and drop the packet. The ‘paroleboard’ chain is more complex, it’s for packets that come from somewhere that has attempted a spam comment, but isn’t currently trying to spam. If the packet is within 120 seconds of a previous spam attempt, it will be dropped. If there have been more than ten attempts to spam then the packet will be dropped.

The last think to do is link into those chains – the following rules match packets and send them to the chains:

blacklist based on string match
iptables -I RH-Firewall-1-INPUT 9 -p TCP —dport 80 -m string —string “/link/articles/100/forums/” —algo bm -j blacklist

packets from blacklisted IPs to the parole chain
iptables -I RH-Firewall-1-INPUT 10 -p TCP —dport 80 -m recent —update —name blacked -j paroleboard

Now, more debugging tips. Apart from seeing the hit counts in the iptables listing, it’s possible to see the log messages in the system logs every time something has been rejected. And, using ‘cat /proc/net/ipt_recent/blacked’ you can see information about things that are currently being blacklisted.

All fields are optional. Any email address won't be published on your comment.
After previewing your comment, you must submit it, if you want it to appear on the site.
  Textile Help

  ·