Setting Iptables

The iptables firewall allows all traffic by default. If we just set up our server, we are not going to have any rules as of yet. But to get an idea of what a table may look like, we use sudo iptables -L to list our rules for our default filter table. We list the rules by using the -L option, we can also specify a chain after our list option, sudo iptables -L INPUT would only show the rules for the INPUT chain.

~$ sudo iptables -L
Chain INPUT (policy ACCEPT)
target     prot opt source               destination         

Chain FORWARD (policy ACCEPT)
target     prot opt source               destination         

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination


There are 5 tables independent tables. We can view a specific table's rules with the -t table option, followed by the table's name. Using sudo iptables -t nat -L would list the rules for the nat table.

table description chains
filter Default table INPUT, FORWARD, OUTPUT
nat New connection packet PREROUTING, OUTPUT, POSTROUTING
mangle Specialized packet alteration PREROUTING, OUTPUT, INPUT, FORWARD, POSTROUTING
raw Configuring exemptions PREROUTING, OUTPUT
security Mandatory Access Control networking rules SECMARK, CONNSECMARK, INPUT, OUTPUT, FORWARD

Each table has a list of chains, and may include some user defined chains. A chain is a list of rules which can match a set of packets. Each rule specifies what to do with a packet that matches. This is called a target, which may point to a user-defined chain in the same table.

chain description
INPUT packets destined to local sockets
OUTPUT locally generated packets
FORWARD packets being routed
PREROUTING altering incoming packets before routing
POSTROUTING altering packets as they are about to go out


After either specifying a table, or using the default filter table, first 4 (of many) basic commands are:

option name description
-A append appends to a chain
-C check checks existence of rule in chain
-D delete deleted rule from chain
-L list list all rules, or of a chain if specified

After one of our commands, we would typically specify a chain such as -A INPUT.


option name description
-m match Specifies extension module to test for a specific property.
-p protocol follows with a protocol: `tcp`, `udp`, `udplite`, `icmp` or `all`
-D delete delete rule from chain


We can target an item from the list below, a user defined chain, or an extension.

target description
ACCEPT allow packet through
DROP deny the packet's access
RETURN stop traversing this chain and resume at the next rule in the previous (calling) chain.

Creating Rules


Now with the basics out of the way, we will have a basic understanding of what is happening, when we try to append our first rule. We are going to allow estalished sessions to recieve traffic.

sudo iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

We are telling iptables to --append to the INPUT chain for incomming packets, with a --match from the conntrack extension where the connection state --ctstate is ESTABLISHED or RELATED, and for packets that meet this rule, to --jump to the target, ACCEPT in this case.

The conntrack module extension provides provides access to the connection tracking state. Passing in --ctstate allows us to match connection state, other states to match include: INVALID, NEW, UNTRACKED, NONE, EXPECTED. More info regarding this and other modules and can be found in man iptables-extensions. But in our case, ESTABLISHED matches a packet that is associated with a connection which has seen packets in both directions. RELATED will match a packet that is starting a new connection, but is associated with an existing connection.

Next, we will allow incoming traffic on port 22 for SSH.

sudo iptables -A INPUT -p tcp --dport ssh -j ACCEPT

iptables will --append to the INPUT chain for incomming packets, the --protocol of tcp where destination port --dport matches ssh, these will --jump to the ACCEPT target. When the --protocol is used, it will load the module of the protocol type. So in the above command, iptables is loading the tcp module, and could be easily found in man iptables-extensions if we search for --protocol tcp, where we can see other commands that tcp will accept, such as --sport, --tcp-flags, --syn, and --tcp-option.

Command for allowing all web traffic

sudo iptables -A INPUT -p tcp --dport 80 -j ACCEPT

Another --append to the INPUT chain for incomming packets, the --protocol of tcp where destination port --dport matches 80, these will --jump to the ACCEPT target.


Once we have a rule to allow a packet, no more rules will effect it as long as those allowing rules come first. We can now write a statement to block all traffic, but ssh and web traffic on port 80 will be let through before it gets to this rule.

sudo iptables -A INPUT -j DROP

This code is simple enough, --append to INPUT chain for all incoming packets, and DROP them.


We will lose all configurations settings of our firewall upon restarting our server. In order to persist our settings, we will have to save using iptables-save. This will save to all tables, or we can specify using the table option iptables-save -t nat.