Q:

iptables - add rules not as root

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.

A:

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. 

A:

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.

A:

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

