iptables by example

Introduction

Iptables is the default firewall on Linux. It's usually installed by default, and available on most distributions.
This page is meant to show a couple of basics, that you might need when securing a system that's available on the internet.

FORWARD: Packets that transfer through this machine: for example when acting as a router/firewall

OUTPUT: Packets that are sent outbound from the current machine

It's possible to make more chains with iptables -N if you need them.

Setting the default policy for a chain

In the iptables -L output, you see what the default policy is for a chain. (Standard, it's to accept all packets).
Use iptables -P to set the policy on a chain.

iptables -P INPUT DROP

This drops(discards) the packets that are coming in on the network.

iptables -P OUTPUT ACCEPT

Allows outbound packets.

Note: If you want to drop inbound connections, but allow outgoing ones, you'll need something more than just the two above rules. More on that later.

Appending new rules to a chain

In the above output, you can see that there are no active firewall rules. What you do, is append specific rules to a chain with "iptables -A ":

iptables -A INPUT -p tcp --dport 22 -j ACCEPT

This rule allows inbound packets that are using the TCP protocol, and have port 22 (ssh) as destination port.

iptables -A OUTPUT -p udp --dport 53 -j ACCEPT

This rule allows outbound UDP packets on port 53 (dns lookups).

Allowing "return packets"

To have a working connection, you'll also need to allow "return packets". It's not good enough that a package coming in on port 80 is being accepted, the response should be allowed to go back out as well! What you could do, is add rules like this:

However, this means that you'll need duplicate rules for pretty much everything that you want in your firewall. Also, if you have a rule to allow all outbound traffic like this:

iptables -P OUTPUT ACCEPT

And are blocking inbound traffic:

iptables -P INPUT DROP

Then you would have to add a rule somehow to allow packets for those connections to come back in.

Luckily, there is the "connection tracking module". This module is able to identify packets as being a part of an existing "connection". (Note that this works for all protocols, and not just TCP).
To allow all outgoing connections, block all incoming ones, but allow inbound packets that are part of an existing connections:

Flushing a chain

To empty an existing chain, use the -F option. However, be careful when flushing chains. It might remove a rule that you need for accessing a server remotely:

iptables -F INPUT

Rules that you probably want

Allow packets that are already member of an existing connection:

iptables -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT

Allow ping:

iptables -A INPUT -p icmp --icmp-type 8 -j ACCEPT

Inserting rules in a chain

If you want to add a rule on a specific spot, and not just at the end of what is already there, use iptables -I:

This will insert a line at the top of the chain:

iptables -I INPUT -p tcp --dport 80 -j ACCEPT

This will insert a rule at spot number 5 in the chain: (use iptables -L --line-numbers to see rulenumbers)

iptables -I INPUT 5 -p tcp --dport 80 -j ACCEPT

Removing rules from a chain

Use iptables -D to remove rules:

This will remove rule number 3: (use iptables -L --line-numbers to see rulenumbers)

iptables -D INPUT 3

Get more output from iptables -L

I like to use:

iptables -L -n -v

This will not resolve port names or look for reverse dns entries for listed ip address.

Have the firewall come up when booting

Debian
Use iptables-save to store the firewall configuration in a file. Create an "if-up" script that will be executed every time an interface is brought up to use iptables-restore, that will restore the firewall from the saved file: