1. Overview

In the modern world, a large amount of data is exchanged between machines. In most cases, the exchange happens between two untrusted machines. For example, any data that flows over HTTP is agnostic of the machine on which the application runs on.

With a specific focus on privacy and data protection, a machine must limit its network to a trusted list of clients. So with this in mind, we usually protect a network behind a firewall.

In this tutorial, we’ll discuss iptables, which is a user-space firewall for Linux machines. It filters connections based on user-defined rules. In the following sections, we’ll understand these rules and their behaviors in detail.

2. Installing iptables

Generally, iptables comes pre-installed on Linux distributions.

However, it can also be installed through various package installers like apt and yum. Doing so will install and start iptables as a service in Linux.

We can now verify our installation:

iptables -L -v

Please note that a non-root user must use sudo with the above command. What it will do is output its default rules*:*

Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target     prot opt in out   source destination

Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target     prot opt in out   source destination

Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target     prot opt in out   source destination

Now that we have installed iptables, we’ll discuss a few essential concepts before implementing custom rules for packet filtering.

3. Introduction to Tables

As the name suggests, iptables maintains a table where each row specifies a rule for filtering input packets. There are mainly three types of tables:

  • filter – The Linux kernel will search for rules in this table for every input packet. Based on the rule, the packet is either accepted or dropped
  • nat – The kernel uses this table for NATing rules. Network Address Translation (NAT) allows us to change the source or destination IP address in a packet. iptables can do this for both incoming and outgoing packets
  • mangle – This table allows us to alter IP headers. For example, we can change the TTL value in the input packet

Generally speaking, the filter table is the most widely used, and hence it’s also the default table. If we want to select other tables, for instance, to change or add a NAT rule, we can use the -t option in the iptables command:

iptables -t nat -L -v

This command will display the default rules for the nat table:

Chain PREROUTING (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination

Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination

Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination

Chain POSTROUTING (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination

We’ll only refer to the filter table in the remaining sections of this article.

4. Introduction to Chains

As we mentioned in the last section, each row in a table is a set of rules that the kernel must apply on an input packet. All these rules are chained together into groups known as a chain.

There are three types of chains in the filter table:

  • INPUT – This chain contains rules to apply on incoming connections
  • FORWARD – This contains rules for data packets that must only be forwarded and not consumed locally. For example, a router that only forwards the data to other machines
  • OUTPUT – This chain contains rules for outgoing connections

In each of these chains, we can create a number of rules. Each rule consists of:

  • Matching Expression – A criteria that the kernel applies to filter data packets
  • Target – The action that the kernel performs on the data packet

For every connection, the kernel traverses the chain and applies the matching expression on the data packet. If it finds a match, it applies the given target on the data packet.

Although there are various types of targets, we’ll only discuss the most common ones:

  • ACCEPT – Allow the packet to reach the destination socket
  • DROP – Drop the packet but don’t send any error back to the client
  • REJECT – Drop the packet and send an error back to the client

5. iptables Commands

iptables exposes a user-space command of the same name – iptables. We can use this command to add or delete rules in the chains. We can add rules for default chains that affect all connections as well as create new rules based on matching expressions. The iptables command provides us with an extensive list of packet or connection characteristics to apply filters.

5.1. Change Default Chains

There are certain default chains in iptables that don’t declare any matching expression. Therefore, the kernel will use these chains if the data packet doesn’t match any custom rule:

$ iptables -L -v
 
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target     prot opt in out   source destination
 
Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target     prot opt in out   source destination
 
Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target     prot opt in out   source destination

So by default, iptables allows all input and output packets to go through. We can, however, change this behavior and add a new policy for any of these chains:

iptables --policy FORWARD DROP

As a result, iptables will drop all packets which are not locally consumed by the kernel:

$ iptables -L -v
 
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target     prot opt in out   source destination
 
Chain FORWARD (policy DROP 0 packets, 0 bytes)
pkts bytes target     prot opt in out   source destination
 
Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target     prot opt in out   source destination

5.2. Filtering Packets by Expression Matching

Generally speaking, machines don’t treat connections or data packets from all sources equally. Thus the default chains that apply on all connections without any differentiation are not sufficient at times.

iptables allows us to filter connections based on a lot of characteristics like source IP address, source port, and protocol:

  • To drop all packets from a particular IP:
    iptables -A INPUT -s 10.1.2.3 -j DROP
    
    This will discard all packets from the machine with IP 10.1.2.3
  • To drop all packets to a specific port:
    iptables -A INPUT -p tcp --dport 8080 -s 10.1.2.3 -j DROP
    
    This command will block any packet to port 8080 from the machine with IP 10.1.2.3:
    Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
     pkts bytes target     prot opt in     out     source               destination
        0     0 DROP       tcp  --  any    any     10.1.2.3             anywhere             tcp dpt:8080
    
    Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
     pkts bytes target     prot opt in     out     source               destination
    
    Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes)
     pkts bytes target     prot opt in     out     source               destination
    
  • To drop all packets on a particular protocol:
    iptables -A INPUT -p tcp --dport 22 -j DROP
    
    This command will block all packets from any machine on port 22 over TCP. Hence, not allowing SSH connections.

5.3. iptables Append and Delete Rules

As we discussed earlier, rules are chained together in iptables. When a packet arrives, the kernel identifies the chain and navigates it until a matching expression is found. It will then apply the defined target on the data packet hence deciding either to DROP, ACCEPT, or REJECT that packet.

The iptables command allows us to append or delete rules from these chains. For example, the commands we discussed in the last section added a rule in the INPUT chain:

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

So, by providing -A as the parameter, we appended a new rule into the chain. When a data packet comes, the kernel will lookup this rule ahead of the default rule that accepts all connections.

Similarly, we can delete a rule from a chain:

iptables -D INPUT -p tcp --dport 22 -j DROP

At any time, we can list the rules in any of the chains:

iptables -L -v

This will output the list of rules in the order in which they were added in the chain.

6. Saving IP Tables Rules

The rules we have added so far are only temporary and are removed by the kernel if iptables or the machine is restarted.

To avoid this, we must save these rules before any restart:

/sbin/iptables-save

This command usually works on Ubuntu or Debian-based distribution.

For Red Hat or Centos we’d do:

/sbin/service iptables save

This will permanently save the rules in storage, and the kernel will reload the rules into iptables on startup.

7. Conclusion

In this article, we discussed how iptables could be used as a firewall in Linux machines. We first installed iptables on a Linux machine and explained how it acts as a lookup table for the kernel to decide whether to accept or drop a data packet.

Later, we added rules in the firewall using the iptables command to block or allow connections based on IP, port, and protocol.