Iptables is a packet filter included in most modern Linux distributions. It includes a lot of useful advanced features to do almost anything necessary at the firewall level, but this tutorial will focus on the basics.

All iptables rules are created and modified via passing command-line options to the iptables binary. There are also GUI utilities in some distributions to do this, but they tend to be much less powerful. For this demo, you must have permission to run iptables as root via sudo. The TAs should be able to do this on netsec-demos but you may want to try it on your own machine.

Iptables saves any rules you create only until the computer is rebooted, and so another solution is needed for permanent rule storage. Most distributions handle this by including two scripts, iptables-save and iptables-restore. The tutorial will not worry about saving rulesets.

Rule Basics

Iptables operates based on rules. The rules are applied top-down, with the first match being used. Therefore, more specific rules should be placed above more general rules. For example, a rule to allow all SSH packets should be above/before a rule to reject all packets, so that SSH connections are allowed, but nothing else. Each rule is specified by running the iptables binary with the desired switches.

The switches specify first what table and chain a rule applies to, what packet characteristics it applies to, and to what target it should jump after determining that there is a match.

Tables and Chains

Iptables allows for different tables and chains. There are three main tables: filter, nat, and mangle. Each table has chains specific to their functions.

Users can also append new chains with special rules for different purposes. For example, in Redhat-based distributions, the GUI firewall configuration generates a custom input chain to separate GUI-generated rules from user-created rules.

filter is the default table if none is specified; this table parses all packets eventually regardless of what we do, and exists to drop or accept packets based on their characteristics. It includes 3 chains by default: INPUT, OUTPUT, and FORWARD. These chains act upon inbound, outbound, and forwarding packets (ie, when the current host is acting as a router).

nat handles network address translation, and includes two chains: prerouting and postrouting. This allows us to change the source or destination addresses based on packet characteristics. Two very common uses of this table is to allow for port forwarding or sharing an internet connection.

mangle includes the chains in both of the other tables, and allows for altering packet fields such as TOS, TTL, etc.

Command Line Options

Rule Specifications

When adding rules, switches must be used to specify what constitutes a match. The most typical switches typically match based on port, IP address, protocol, and connection state.

These are specified via the following switches:

Iptables uses the -m switch to allow for extended matching. This allows the use of specific extensions. A commonly used one is state, which allows for connection tracking.

For example, this allows us to allow only established packets inbound (ie, those that are not SYN packets for TCP), to ensure that we can always connect out but nobody else can initiate inbound connections.

Here are some common ways to use -m state:


All rules must end with a target to jump to. This specifies what to do when a rule does match.

Here are some common targets (Not all of these can be used with all tables):

Things to Try

Start the firewall lab by running firewall-lab.bash in the labs folder of the student repository. It will tell you the hostname of the system which you will be setting up the firewall for, and also tell you how to connect to it.

On the attacker machine (the one which opens when you run firewall-lab.bash):

attacker# nmap <lab-hostname> -p 5000-8000

You can see that there are three ports open on this machine which are accessible from outside systems.
On the firewalled machine, we can check the outbound connectivity:

firewall# ping
PING ( 56(84) bytes of data.
64 bytes from icmp_seq=1 ttl=54 time=13.7 ms

Let's begin configuring the firewall by blocking all inbound packets. Set the INPUT policy as such:

firewall# iptables -P INPUT DROP

Notice that this will prevent you from connecting outbound. (Try running ping again) Why? Response SYN-ACKs and DNS responses from remote servers are also dropped, along with all other inbound packets. Next, let's allow all related and established packets to come in, so that we can make outbound connections.

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

Now you should be able to download files and ping, but nobody externally will be able to initiate a connection to the three running servers. You can confirm this by running nmap again, or trying to connect to any of them using nc.

To allow specific connections to the server, add another rule to allow SYN packets with a destination port of 7777.

firewall# iptables -A INPUT -p tcp -m state --state NEW --dport 7777 -j ACCEPT

iptables is a complicated tool. When in doubt, a web search will tell you how to do whatever it is you are trying to do.


After trying the above examples, do the following:

Show your work to teaching staff (they will need to run some commands in each of the containers, so please indicate which is which)