iptables is a linux application that allows you to configure the built-in linux firewall. There are abstraction layers built on top of it, including nice GUIs, but I recently had some very basic rules I wanted to implement, and figured I’d learn how to do it directly in iptables. It turned out to be easy to configure, and I thought I’d give a very basic introduction.
First though, I relied on the ubuntu documentation to get up and running (https://help.ubuntu.com/community/IptablesHowTo). I’ll pretty much just regurgitate what’s in there – I’ve said it before, stop believing that linux documentation is written only for people who already know linux. Also, depending on your setup, most of these commands might require elevation (sudo).
By default, iptables defines three rule chains:
OUTPUT. We’ll only concern ourselves with
INPUT – namely the chain used for incoming packets directed at this particular machine. At any point, you can list the rules by entering
iptables -L. If listing the rules turns out to be really slow, try using
iptables -L -n. The
-n option means that the display will output IP addresses and ports in numeric format, without trying to do a DNS lookup. If the
-n option makes it fast, then you’re system likely has incorrect DNS settings (you can check out http://www.cyberciti.biz/tips/linux-how-to-setup-as-dns-client.html for help with that).
In my particular case, the server is has two network interfaces – a public facing one (on
eth0) and a private one (on
eth1). For my purposes, I want to remotely (
eth0) access SSH from my static IP, and locally (
eth1) access postgresql on port 5432.
To accomplish this we simply append two rules to the INPUT chain:
iptables -A INPUT -p tcp --dport ssh -s 18.104.22.168 -i eth0 -j ACCEPT iptables -A INPUT -p tcp --dport 5432 -i eth1 -j ACCEPT
The first rule appends itself to the
INPUT chain. Its limited to the
TCP protocol targeting the
SSH port (22) with a source originating from
22.214.171.124 on the
eth0 network interface. It jumps to an
ACCEPT status (all other processing stops). The next rule is similar, except it allows any source so long as they are connected to
eth0 and targeting port
We can now add a third rule to block all other access:
iptables -A INPUT -j DROP
if incoming traffic doesn’t mean the first two criteria, we’ll hit this third rule and the firewall will reject the connection.
We’ll run into 1 issue with our above configuration though – we’ve blocked access to the loopback interface (127.0.0.1). We need to add a special rule to allow loopback connections (since a lot of programs rely on it). However, we can’t simply append it as it’ll never be reached. Instead of using
-a to append, we’ll use
-i to insert:
iptables -I INPUT 1 -i lo -j ACCEPT
Here we are inserting our rule in the 1st position, and accepting all connections made on the special lo (loopback) interface.
A really neat thing about iptables is that they aren’t persisted by default. So, if you happen to mess up and cut yourself off from your server, a simple reboot will reset everything (hopefully you have access to do a remote reboot from a web interface, or maybe you can just walk up to the machine and reboot it).
At some point though, you’ll want to make sure your rules are persisted. Achieving this is a two step process. First, you save your rules to a file by using the
iptables-save and redirecting STDOUT to a file:
iptables-save > /etc/iptables.rules
Second, and this depends on which distro you have but on debian/ubuntu, you make sure your rules are loaded on startup. Simply edit
/etc/network/interfaces, find your interface, and add:
pre-up iptables-restore < /etc/iptables.rules
to the list, so that it looks something like:
auto eth0 iface eth0 inet static address xxx netmask yyy gateway ddd pre-up iptables-restore < /etc/iptables.rules