Take the 2-minute tour ×
Super User is a question and answer site for computer enthusiasts and power users. It's 100% free, no registration required.

One of our servers is being hit daily by a large number of spam bots. They're not able to post any spam, but they still try and end up slowing down the server for real users.

To counter this, I have a PHP script running on the site which detects their IP addresses. However, I want this script to automatically add these IP addresses to the firewall (rather than me having to do that manually). Running something like this:

iptables -I INPUT -j DROP -s 123.123.123.123

However, it looks like iptables commands can only be run as root. Any way around this? I guess I could have the commands added to a file which root runs via cron, but don't really want any delay between the php script making the decision to ban an IP and the ban being added.

share|improve this question
1  
Why don't you run the php script as root? –  terdon Mar 11 '13 at 12:48
    
The script is being run at the end of page load, by the web server. It does various logic to work out if the page load was by a spam bot or not. –  Ross McLellan Mar 11 '13 at 12:53
1  
Make a suid root shell script which calls out to iptables? Just make sure to sanitize your inputs very carefully. Something like s/[^0-9.:]// on the IP address and not accepting anything else as input. I'd tighten it down even further in such a scenario. –  Michael Kjörling Mar 11 '13 at 13:01

3 Answers 3

up vote 1 down vote accepted

Have your PHP script write the offending IP addresses to a log file. Next, install Fail2Ban and configure it to read your log file.

share|improve this answer
1  
Thanks. Am giving this method a try for now. I do prefer to not rely on 3rd party scripts when a simple custom script will do the job, but fail2ban seems to have quite a lot of useful capabilities, like unbanning after a certain period of time. Was bit of a pain to get setup and seems to lack documentation for some bits, but seems to be running as desired now. Will just see how it copes the next time an attack hits. –  Ross McLellan Mar 11 '13 at 16:16

The easiest way would be, as you suggest, having your script write the offending IPs in a log file. You can then have another script running (as root) in a loop that reads the file and sends the iptables command. Something like:

#!/bin/bash
while true
do
  while read IP
  do
      ## Check if this IP is already banned
      if ! iptables -L INPUT -v -n | grep $IP >/dev/null
      then
      ## If it is not banned, ban it
         iptables -I INPUT -j DROP -s $IP
      fi
  done < $1
  ## Sleeping to avoid spamming, if even a one second
  ## delay is too slow for you(!) adjust as needed.
  sleep 1
done

You can then have this script run as root on start up, either as a service or by creating this crontab for root:

@reboot /path/to/banips.sh logfile.txt

I assume the delay you are worried about is cron's one minute interval minimum. Since the script will run in an infinite loop, you don't need to run it every minute using cron and the delay is up to you. As it stands, the script will read the logfile every second.

share|improve this answer
    
There are canned and proven solutions for the problem at hand, why reinvent the wheel? –  0xC0000022L Mar 11 '13 at 14:33
1  
@0xC0000022L because in this case the wheel is simple to invent, because software recommendations are considered off topic and this is a solution that requires no third party software and because personally I prefer having small scripts doing things since I can control their behavior perfectly. –  terdon Mar 11 '13 at 14:58
    
fair enough, even mentioned your script in my own answer. Suppose you have a point :) –  0xC0000022L Mar 11 '13 at 14:59
    
Thank you @terdon, I hadn't realised a cron job could run like that in a while loop. I'm trying fail2ban at the moment, but will probably try this method out at some point too, even if just to see how it works. –  Ross McLellan Mar 11 '13 at 16:20

As an alternative to the existing answers and adding sshguard (not so well-named for its scope by far exceeds what the name suggests) to the mentioned Fail2Ban I would like to suggest to you sudo.

The file /etc/sudoers can be configured to control tightly who can run what as who and from which machine. Therefore you can write a little wrapper much like in terdon's answer and then chown root: it and make sure its permissions are set tight. Throw it into a folder such as /usr/sbin and allow it to be run as root from whatever user account your PHP script runs as. Make sure that if your script runs in the context of the web server and it's chrooted that the script is inside the chroot. Keep in mind that this could be used to compromise the chroot "jail" if your script is badly written. An example line in /etc/sudoers could be:

www-data   ALL= (root) NOPASSWD: /usr/sbin/yourscript.sh

which allows user www-data to run /usr/sbin/yourscript.sh as root without giving a password on all machines (sudoers can be a central one for all machines in a network, that's why ...).

sudo is considered safer than setting the suid bit on your script, but I suppose there are good reasons for using this alternative, e.g. when no sudo is available.

You can also check out this answer I gave over at the sister SE site askubuntu.com.

share|improve this answer
    
Thanks. I was slightly reluctant to let my web server user run all iptables commands, I knew sudoers could limit the commands you can run, but didn't realise I would be able to limit it to a specific .sh file (one which runs the specific iptables command). –  Ross McLellan Mar 11 '13 at 16:24

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.