Linux Iptables Tutorial

Iptables is a tool that is used to configure the netfilter linux kernel module. This inspects all the incoming / outcoming network packets and decides what is to be done with each of them.

This article is not fully featured documentation, it only shows a number of commands and their functionality. Iptables capabilities are huge, however for most of the use cases the information present in this article should do.

Iptables defines a default access for the channels and then with additional commands you can adjust this default behavior. For example: usually all the inbound packets are dropped by default, unless they satisfy additional rules.

Chains
The most used chains are INPUT OUTPUT and FORWARD

  1. INPUT - all the inbound connections
  2. OUTPUT - all the outbound connections
  3. FORWARD - all the inbound connections that are routed outside the machine

Setting the default access

The -P setting defines the default way the packets are processed for various channels (INPUT, OUTPUT or FORWARD)


# iptables -P INPUT DROP
# iptables -P FORWARD DROP
# iptables -P OUTPUT ACCEPT

You can always change this behavior, however this is usually how the default settings should look like:

  • INPUT and FORWARD - drops the packets by default, unless otherwise specified
  • OUTPUT - allows all the packets, unless otherwise specified

Inspecting the existent rules

The current rules in theory can be seen by issuing the command

# iptables -L -v --line-numbers

However this will show the rules for the current table (what is table - later). The best way to see everything is to issue the command

# iptables-save

This will dump all the settings to the console output. The dump contains absolutely all rules, in all the tables or channels.

Deleting all the settings from the current table

# iptables -F

This is very useful when you want to start fresh. It is better to start from a setup which does not contain any rules.

Attention: if you drop by default all the incoming packages for the current table and you are working on the machine connected with a tcp service, let's say ssh, once you issue the flush command above the connection will drop. So before you flush, make sure you change the default rule to accept all the incoming packets as follows

# iptables -P INPUT ACCEPT

Then flush, do you changes and then change the default -P setting to DROP.

Accepting ongoing connections

If a connection is already initiated, it is not important to double check if each packet from an already established connection follows the rules. It is safe to assume that if there were issues the connection would not have been established.

Here is the command that would take care of that:

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

Typical open a port command

This is a typical command to open a port

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

In the above, all the incoming packets from the default table, tcp protocol coming at port 22 (ssh) will be accepted. Attention: when you specify the destination port you have to specify the protocol first, as shown.

By the way, -A means you append the rule to the existent chain, at the end. You can also insert a rule at a certain index. For this, please check the man page, it is pretty straight forward.

Allow all the internal connections (to 127.0.0.1)

Usually on a server you want to expose strictly the services that are supposed to be accessed from outside. However internal access through the loopback interface should not be restricted. On the contrary, this could generate issues. Example: one application listens to a port for shutdown. The port shall not be accessible from outside, but if it is not accessible from inside, you will not be able to properly shutdown the application.

Here is how you allow access for the loopback interface:

# iptables -A INPUT -i lo -j ACCEPT

Routing

Normally you rarely use your computer as a router. With a couple of dollars you can buy a dedicated router that does the job easier, costs less and it is much better when it comes to your hydro bill.

However there is a situation that occurs frequently that must be addressed and it is resolved with a routing setting.

The situation:

  • You need to expose a service
  • The service must not run as root - like most of the user services
  • However the service must be accessed from outside on some standard port that is typically under 1024
  • Any service that listens to a port under 1024 must run as root

An example: tomcat server, running under a non root user, listening to the port 8080 and being exposed outside as listening to port 80.

How you do it:

  1. Ensure both ports that are exposed, in our case 80 and 8080 are opened
  2. Then configure a routing for any incoming connection at port 80 to 8080

Opening the port is simple, just take the example for port 22 above and configure it for ports 80 and 8080


# iptables -A INPUT -p tcp --dport 80 -j ACCEPT
# iptables -A INPUT -p tcp --dport 8080 -j ACCEPT

The above will go under the default table called "filter".

And then you add the routing rule as follows:

# iptables -A PREROUTING -t nat -p tcp --dport 80 -j REDIRECT --to-port 8080

Now, if you want to list this rule, just a simple iptables -L -v will not do because the routing rule is installed in the table "nat" rather than in the table "filter" which is the default one.

So you list it like that

iptables -t nat -L -v --line-numbers

Deleting rules

There are a couple of ways of specifying a rule to be deleted. You can either specify a rule with the line number or with the actual rule settings. I prefer to use the one with the line numbers

1. List the rules in the table you want to delete with the line numbers, as we did above a couple of times

iptables -t nat -L -v --line-numbers

2. Then look at the chain name (INPUT, OUTPUT, PREROUTING etc) and see the rule you want to delete.

Then it is easy:

# iptables -t nat -D PREROUTING 1

That means - from the table nat, delete the rule number 1 that is listed under the chain PREROUTING. Line numbering starts with 1.

Be careful.

Tables

A table is a collection of contexts containing each a collection of rules. The table is specified in the command using the setting "-t". If the table is not specified, then the default one will be considered. The default table is filter.

Configure iptables upon system restart

There are two ways:

  1. Save the current settings with iptables-save > file_name and then enter a rc.local line that would restore this file with the command "iptables-restore < file_name"
  2. Write the actual iptables commands in a script file and have the file executed from the rc.local

Everybody prefers the first method however I saw examples with the second method being posted as well.

Example

This is my current iptable-save generated file:


# Generated by iptables-save v1.4.21 on Sat Oct 18 10:36:14 2014
*filter
:INPUT DROP [4:200]
:FORWARD DROP [0:0]
:OUTPUT ACCEPT [478:66875]
-A INPUT -p tcp -m tcp --dport 22 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 80 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 8080 -j ACCEPT
-A INPUT -i lo -j ACCEPT
COMMIT
# Completed on Sat Oct 18 10:36:14 2014
# Generated by iptables-save v1.4.21 on Sat Oct 18 10:36:14 2014
*nat
:PREROUTING ACCEPT [6:670]
:INPUT ACCEPT [6:666]
:OUTPUT ACCEPT [1:60]
:POSTROUTING ACCEPT [1:60]
-A PREROUTING -p tcp -m tcp --dport 80 -j REDIRECT --to-ports 8080
COMMIT
# Completed on Sat Oct 18 10:36:14 2014

  • Connection attempts for the localhost loopback are allowed on any ports
  • External tcp incomming connections allowed on ports 22, 80 and 8080
  • TCP connections to port 80 routed to port 8080