IPTables - Linux Kernel Firewall

General presentation

Iptables is a CLI utility used to configure Linux kernel firewall implemented within the Netfilter project. So it basically tells the kernel itself what to do with network packets. It's a very useful to know utility if you want to excel in networking. Actions which iptables can perform are: inspect, modify, forward, redirect and drop IP packets.

It contains five tables that's why it's called iptables:

The tables are made of a set of predefined chains and these chains contain rules which are parsed in order. Each rule has some specific conditions for a packet to match and a corresponding action named "target" that's executed when a packet matches that rule's conditions.

After all the rules of a table are parsed and a packet happens to not match any of them, the chain's policy target will tell that IP packet's destination

All IP packets on any network interface pass through the following flow from top to bottom described below. The following diagram is simplified and the raw, mangle and security tables have been ommitted for simplicity because they are rarely used. Very important to remember is that packets entering from an internal interface are handled the same as from an internet facing interface.

You've probably seen if you have used lsof command that there are some processes that listen on a port on a local interface such as the dnsmasq that's listening on {Your_LAN_IP}:53

Packets which are destined for these local processes start from the top, from "Network" and stop at [local process], while web packets for example start from your browser process so from [local process] and go to the bottom "Network".

Simplified Schematics of Packet Flow

				                               XXXXXXXXXXXXXXXXXX
				                             XXX     Network    XXX
				                               XXXXXXXXXXXXXXXXXX
				                                       +
				                                       |
				                                       v
				 +-------------+              +------------------+
				 |table: filter| <---+        | table: nat       |
				 |chain: INPUT |     |        | chain: PREROUTING|
				 +-----+-------+     |        +--------+---------+
				       |             |                 |
				       v             |                 v
				 [local process]     |           ****************          +--------------+
				       |             +---------+ Routing decision +------> |table: filter |
				       v                         ****************          |chain: FORWARD|
				****************                                           +------+-------+
				Routing decision                                                  |
				****************                                                  |
				       |                                                          |
				       v                        ****************                  |
				+-------------+       +------>  Routing decision  <---------------+
				|table: nat   |       |         ****************
				|chain: OUTPUT|       |               +
				+-----+-------+       |               |
				      |               |               v
				      v               |      +-------------------+
				+--------------+      |      | table: nat        |
				|table: filter | +----+      | chain: POSTROUTING|
				|chain: OUTPUT |             +--------+----------+
				+--------------+                      |
				                                      v
				                               XXXXXXXXXXXXXXXXXX
				                             XXX    Network     XXX
				                               XXXXXXXXXXXXXXXXXX
		

Basic syntax explained

I shall discuss only the filter and nat tables as there are the most commonly configured ones, the default table being the filter one which acts similar to higher level firwalls such as ufw for Debian and firewall-cmd for RHEL. So if you want to list iptables rules you can:

iptables -L - this will list only the rules for the filter table because it's the default one and I haven't mentioned any table.

To list the ones for NAT: iptables -t nat -L

In this case -L is the command, some other useful commands are:

So now we know how to list , add and delete rules which are the most important operations. Another important part of the syntax are the parameters which we need to specify when creating a rule such as:

So the syntax is:

iptables -t [table] [command] [Chain were to add rule] [Parameters] [Target]

IPTables Usage Examples

A simple example will be using netcat on localhost, so I'll write a message with netcat from a shell to the other, netcat will listen on port 4041. After I succesfully do this I will create a rule that drops this traffic.

So in this moment I can send data on port 4041 and if I want to drop it I'll use the following:

sudo iptables -t filter -A INPUT -p tcp --dport 4041 -j DROP

Now we can see that packets are dropped:

I now want to delete this rule and for this you can just replace the -A with -D in the command which was used to add it. If you don't know which command was used to add a certain rule you can use the "--line-numbers" parameter right after -L

└─[$] sudo iptables -t filter -L --line-numbers [23:44:07] │ Chain INPUT (policy ACCEPT) │ num target prot opt source destination │ 1 LIBVIRT_INP all -- anywhere anywhere │ 2 DROP tcp -- anywhere anywhere tcp dpt:houston

To delete it you need to specify the table which in this case is filter and the chain which is INPUT and also the rule number:

sudo iptables -t filter -D INPUT 2

I will use the same port and netcat now and all https traffic will be redirected to localhost port 4041

sysctl -w net.ipv4.conf.all.route_localnet=1 - this enables routing to localhost, by default if a packet destined for localhost comes from outside it's considered a 'martian' and is dropped for security reasons - be careful, if you enable this then it is possible for packets coming from outside to get to processes that listen on localhost.

- in the syntax above "all" refers to all interfaces, if the packet comes on interface eth0 in your case then you can replace 'all' with eth0 like: sysctl -w net.ipv4.conf.eth0.route_localnet=1

So, we want to use netcat to listen on localhost:4041 and all traffic destined for port 443(https) to be redirected there. Https traffic is generated usually by our browser but in this example I shall use curl so that we do everything from command-line. Connection is initiated by curl which is a [local process]. If we check the above diagram we see that between [local process] and "Network" from bottom of diagram which is the destination network there are 3 chains, 2 OUTPUT and 1 POSTROUTING. We need to add the rule in the OUTPUT chain of nat table because we need NAT(network address translation) as source IP is my wlan0 interface and we want to redirect to localhost.

To do this, issue:

sudo iptables -t nat -A OUTPUT -p tcp --dport 443 -j DNAT --to-destination 127.0.0.1:4041

So all traffic destined for por 443 that goes through chain OUTPUT of nat table will be redirected and network address translated towards 127.0.0.1:4041

Now I've started netcat to listen on localhost:4041 and am using curl to get the page of this website, I've used its IPV4 address because if I use domain name curl will use IPV6 and will not be redirected as you can see.

This is it for iptables, it can be used in a bunch of different ways and it is a highly configurable firewall, use it whenever you have the chance instead of higher level ones such as ufw for Debian and firewall-cmd for RHEL. Keep in mind that there are 3 main situations when it comes to traffic, you can receive, send or forward it and that's highly resumed of course but this is basically it.

Remember that iptables rules which are configured by an user are not saved and are lost after reboot. To save them user needs to use "iptables-save"