An introduction to iptables

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: INPUT, FORWARD and 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 205.38.19.199 -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 205.38.19.199 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 5432 (over tcp).

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

That’s it!

This entry was posted in Uncategorized. Bookmark the permalink. Follow any comments here with the RSS feed for this post.

4 Responses to An introduction to iptables

  1. M. says:

    I think you could set a policy for the chain… iptables -P INPUT DROP

  2. Chris says:

    In the text after this rule: iptables -A INPUT -p tcp –dport 5432 -i eth1 -j ACCEPT

    You say it’s applied to eth0, but I guess that should be eth1, right?

  3. karl says:

    I forgot an important rule (didn’t realize how important it was until last night):

    iptables -I INPUT 2 -m conntrack –ctstate ESTABLISHED,RELATED -j ACCEPT

    (it doesn’t have to be the 2nd rule, it just needs to be before the reject-all rule).

    Basically this allows connections which are already established, or which are related to another rule, to work. This is important for things like dns lookups and other types of access which might spawn other connections.

  4. Siim says:

    Whoa, haven’t seen that kind of post for a while :)

    Last time I was messing with iptables was many years ago.