We help IT Professionals succeed at work.

Adding iptables rules with PHP?

I'm trying to figure out a way to ban IPs with iptables automatically with PHP. Is it possible to use PHP to run iptables commands? I've tried this:

<?php
echo shell_exec('iptables --list');
?>

But it doesn't return anything. I've tried other commands like "ls" and it works fine, but anything related to iptables and it doesn't return anything (so I'm guessing it's not running the command).
Comment
Watch Question

Top Expert 2010

Commented:
Hi, "iptables" needs to be run as root, so unless your web-server is running as root it isn't going to work, and if it is you have a security hole. Not to mention you'll probably find iptables is not in your Web servers $PATH.

Anyway if your planning to allow a user other than root to ban IP's / list rules, you'll want a wrapper script that only allows those specified action, and a /etc/sudoers rule to permit on or more ID's to call that script e.g.
--------
# Allow just the 'apache' user-id to run the iptables_wrapper.sh script:
apache ALL = (root) NOPASSWD: /usr/local/sbin/iptables_wrapper.sh *
---------

<?php
echo shell_exec('/usr/bin/sudo  /usr/local/sbin/iptables_wrapper.sh ');
?>

Where:  /usr/local/sbin/iptables_wrapper.sh
--
#!/bin/sh
# Name: iptables_list_wrapper.sh
# Purpose: Provide limited  access to IPtables, to permit rules to be listed of an IP blocked

usage (){
  echo "Usage: iptables_wrapper.sh [IP_TO_BAN]"
}

if [ $# -eq 0 ]
then
  /usr/sbin/iptables --list
else
   echo $1 | (egrep "^[0-9]+\.[0-9]+\.[0-9]+.[0-9]+$" > /dev/null && /usr/sbin/iptables -A INPUT -s $1 -j DROP )|| usage
fi
---

Don't forget to:

chmod 744 /usr/local/sbin/iptables_wrapper.sh
chown root /usr/local/sbin/iptables_wrapper.sh

Author

Commented:
For some reason, sudo doesn't seem to be working at all. I've been trying to get it work for the past 30 minutes. I've tried adding all sorts of different variations to sudoers file, including giving complete sudo access to "nobody" and "apache", but still doing any php command with sudo returns nothing.

I did a "whoami" command with php and it returns "nobody", and tried giving sudo access to that but no luck. I've tried at least 5 different variations to add to the sudoers file, still no luck.
Just to make sure you are going in the right direction,is the script you want going to be run from a web page,or periodically as a cron job?Because if it is going to be run as a cron,none of these above applie...Do you want IP to be banned based on some kind of cryteria,and if yes,which on?
Top Expert 2010

Commented:
Is there anything in the Apache error log?

Can you do a:
 ls -l `which sudo`  

 e.g.
-rwsr-xr-x 1 root root 190248 2010-03-01 11:26 /usr/bin/sudo

Is the sticky bit set '-rws' rather than '-rwx'?

Author

Commented:
Nothing in the error log, and it's -rwx

I can use sudo fine when I'm on SSH, but not with PHP.

pingvinos:
I'm more interested in having it ban from a webpage, I made some PHP code to detect if it's a DoS bot, but I need it to ban the IP with iptables after it detects it.

If this could be easier with a cron job, I could make it save the IP in a text file and have a cron job check that text file to ban the ips, but the webpage one would be a lot more efficient considering it would ban right on the spot instead of the cronjob waiting 5-10 minutes to check if it should ban.
Top Expert 2010
Commented:
Can you also:

# grep nobody /etc/passwd
# grep nobody /etc/sudoers
# su nobody -c '/usr/bin/sudo  /usr/local/sbin/iptables_wrapper.sh'

Should see nobody has a REAL shell e.g. bash:

nobody:x:11111:22222:nobody:/var/lib/nobody:/bin/bash

And:

nobody ALL = (root) NOPASSWD: /usr/local/sbin/iptables_wrapper.sh *

And:
----------------
Chain INPUT (policy ACCEPT)
target     prot opt source               destination

Chain FORWARD (policy ACCEPT)
target     prot opt source               destination

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination
----------------


If that works stick the following in tst.php:
---------------
<?php
echo shell_exec('whoami');
echo "-----------------\n";
echo shell_exec('/usr/bin/sudo /usr/local/sbin/iptables_wrapper.sh ');
?>
---------------
The give the following a go:

# su nobody -c 'php /srv/www/htdocs/tst.php'

Should see:

nobody
-----------------
Chain INPUT (policy ACCEPT)
target     prot opt source               destination

Chain FORWARD (policy ACCEPT)
target     prot opt source               destination

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination

Author

Commented:
root@ragemachine [/usr/bin]# grep nobody /etc/passwd
nobody:x:99:99:Nobody:/:/sbin/nologin
root@ragemachine [/usr/bin]# grep nobody /etc/sudoers
nobody ALL = (root) NOPASSWD: ALL
root@ragemachine [/usr/bin]# su nobody -c '/usr/bin/sudo  /usr/local/sbin/iptables_wrapper.sh'
This account is currently not available.


So I should edit /etc/passwd?
Top Expert 2010

Commented:
Ok, temporarily

usermod -s /bin/bash nobody

And give the script another go.

Author

Commented:
Now the error is:
sudo: must be setuid root

Author

Commented:
Fixed that error, but another one was waiting:


root@ragemachine [~]# sudo su root -c "/usr/bin/sudo whoami"
root
root@ragemachine [~]# sudo su nobody -c "/usr/bin/sudo whoami"
sudo: sorry, you must have a tty to run sudo
Top Expert 2010

Commented:
Your syntax is incorrect, try the following as root:

su nobody -c 'whoami'
su nobody -c '/usr/bin/sudo  whoami'
su nobody -c '/usr/bin/sudo  /usr/local/sbin/iptables_wrapper.sh'
/usr/local/sbin/iptables_wrapper.sh

Note:
"su nobody"             - creates a New shell owned by "nobody"
"-c  <command>"     - Details the command you want to be run in the newly created shell.
"/usr/bin/sudo"        - Try's to run a command, as root, from the newly created 'nobody' shell.

Author

Commented:

root@ragemachine [/usr/local/sbin]# su nobody -c 'whoami'
nobody
root@ragemachine [/usr/local/sbin]# su nobody -c '/usr/bin/sudo  whoami'
sudo: sorry, you must have a tty to run sudo
root@ragemachine [/usr/local/sbin]# su nobody -c '/usr/bin/sudo  /usr/local/sbin/iptables_wrapper.sh'
sudo: sorry, you must have a tty to run sudo
root@ragemachine [/usr/local/sbin]# /usr/local/sbin/iptables_wrapper.sh
Chain INPUT (policy ACCEPT)
...etc [worked]...

Author

Commented:
think i got it working..let me try some things on the PHP page and get back to you.

Author

Commented:
alright. problem solved. got it 100% working.

Author

Commented:
just as a quick question..should i make it do "service iptables save" every time it bans an ip or leave that out?
Top Expert 2010

Commented:
Re to save / not to save, it's up to you, how often do you re-boot your server? Do you want the bans to be permanent?

Oh, guessing it was your /etc/sudoers rules that were at fault, due to all the "sudo: sorry, you must have a tty to run sudo"