Using a custom chain to define a list of trusted hosts in iptables 1
A common problem with firewalls is that you want to allow certain ports from a list of trusted hosts. For example, you have 3 locations that you commonly log into your machine from, and you want to allow ssh and mysql from these locations, but not from elsewhere. If you just added rules to the INPUT chain, you would need 3 rules for ssh, and another 3 rules for mysql, and each source address would be specified twice, once for each of these services. This is not very efficient, as adding another source would involve inserting 2 rules. Furthermore, the number of rules multiplies rapidly as additional ports or source addresses are needed.
Here's how to avoid this problem by using custom chains in iptables to allow connections from a range of different sources without having lots of similar rules in the INPUT chain. I'm doing this on Ubuntu, but this can obviously be applied to any distro.
Add the standard rules
First of all lets set up the standard incoming rules. I'm going to allow everything on the loopback interface, any packets with state RELATED or ESTABLISHED, port 80 for my web server, and icmp so people can ping my server:
sudo iptables -I INPUT 1 -i lo -j ACCEPT sudo iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT sudo iptables -A INPUT -p tcp --dport 80 -j ACCEPT sudo iptables -A INPUT -p icmp -m icmp --icmp-type any -j ACCEPT
Add a custom chain
Now lets say we want to allow ssh from 3 different trusted subnets. I'll use private RFC1918 addresses for this example, but in reality these would probably be the public addresses of the locations you want to log in from.
First add a "Trusted" chain:
sudo iptables -N Trusted
Then add rules to this chain that just allow anything from your trusted sources:
sudo iptables -A Trusted -s 192.168.0.0/255.255.255.0 -j ACCEPT sudo iptables -A Trusted -s 10.20.0.0/255.255.255.0 -j ACCEPT sudo iptables -A Trusted -s 172.16.0.0/255.255.0.0 -j ACCEPT
Now add a rule to your INPUT chain that hands off ssh connections to your custom chain:
sudo iptables -A INPUT -p tcp --dport 22 -j Trusted
This will check incoming ssh connections against your Trusted chain, which will allow them.
Drop all other connections
At the moment we are still allowing all incoming connections anyway. So finally, add a rule at the end of the INPUT chain to drop everything else:
sudo iptables -A INPUT -j DROP
Now your iptables should look something like this:
$ sudo iptables -L -v
Chain INPUT (policy ACCEPT 778 packets, 85228 bytes)
pkts bytes target prot opt in out source destination
56151 57M ACCEPT 0 -- lo any anywhere anywhere
446K 70M ACCEPT 0 -- any any anywhere anywhere state RELATED,ESTABLISHED
19045 1065K ACCEPT tcp -- any any anywhere anywhere tcp dpt:www
94 8056 ACCEPT icmp -- any any anywhere anywhere icmp any
4943 468K Trusted tcp -- any any anywhere anywhere tcp dpt:ssh
1695 331K DROP 0 -- any any anywhere anywhere
Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
Chain OUTPUT (policy ACCEPT 441K packets, 701M bytes)
pkts bytes target prot opt in out source destination
Chain Trusted (1 references)
pkts bytes target prot opt in out source destination
0 0 ACCEPT 0 -- any any 192.168.0.0/24 anywhere
0 0 ACCEPT 0 -- any any 10.20.0.0/24 anywhere
0 0 ACCEPT 0 -- any any 172.16.0.0/16 anywhere
And now, you can allow extra ports from your trusted sources without having to repeat your sources in the INPUT chain. For example, we can insert a rule to allow MySQL connections. This needs to be inserted before the DROP rule:
sudo iptables -I INPUT 6 -p tcp --dport 3306 -j Trusted
Saving your iptables rules
Save your rules to a file:
sudo iptables-save > /etc/iptables.rules
Now you can edit your /etc/network/interfaces file to bring up iptables automatically, and save the rules when the interface is brought down:
auto eth0 iface eth0 inet dhcp pre-up iptables-restore < /etc/iptables.rules post-down iptables-save -c > /etc/iptables.rules
For more information, see the Ubuntu iptables howto: