If you’re on Linux, you have plenty of options to protect your device. It comes with iptables, a command-line firewall utility that offer flexibility and excellent protection.

However, as it is a command-line utility, it requires a slight learning curve.

So, if you’re a system administrator or a Linux learner, you’re in the right place as we go through the common iptables commands with examples.

What is iptables?

iptables is a software-based Linux built-in firewall. It allows Linux users to create or define policies that directly and indirectly impact internet traffic.

This means you can use iptables to create rules blocking or allowing traffic via the port, source IP address, network interfaces, and more.

Once you define the rules, all traffic needs to go through it. So, for example, for every new connection, iptables will check for any pre-defined rules that match the connection. If it does, it’ll apply the rule to the connection. However, if there aren’t any associated applicable rules, it’ll implement the default rule.

To use iptables, you need to use the following command.

$ iptables -L -n -v 

Here, the parameters are as below:

  • -L is for listing all rules.
  • -n makes the numeric output offer faster performance.
  • -v for showing output in detailed format.

Once you run the iptables command without any parameter, it’ll return the following output:

iptables v1.8.7 (nf_tables): no command specified

Try `iptables -h' or 'iptables --help' for more information.

You need to install it if it runs into an error, such as the command “iptables” not found. 

To install iptables in your Linux distribution, run the following command.

$ sudo apt-get install iptables

It’ll return the following as it is already pre-installed on my Linux distribution.

#output
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
iptables is already the newest version (1.8.7-1ubuntu5).
iptables set to manually installed.
0 upgraded, 0 newly installed, 0 to remove, and 35 not upgraded.

What is Firewall?

Firewalls are the most basic form of protecting systems, networks, and personal computers. It can be hardware- or software-based, relying on rules to function properly.

Most firewalls are highly customizable, allowing you to create or edit rules. For example, as packets from the internet use ports to get into a system, port-based scanning can help you filter them out. Apart from that, you can also allow or block services by source IP address or network interface.

If you’re using Linux, you get access to built-in iptables. However, you can also use a standalone Linux firewall to aid you in the process of protecting your system.

Why Do You Need iptables to Configure the Firewall?

But why should you use iptables at all? After all, there are good alternative command-line firewall utilities such as ufw and firewalld. Also, you can use standalone Linux firewalls that are simple to use and offer more features.

So, what makes iptables so appealing when configuring a firewall? The reasons to use it include:

  • It offers excellent flexibility out of the box. You can set rules at the packet level.
  • It is relatively easy to use once you know how it works.
  • Block unwanted traffic in a straightforward manner.
  • Redirect packets to an alternative IP address.
  • Protect your systems against Denial of Service (DoS) attacks.

And much more!

Understanding iptables Architecture And Its Relation to Netfilter

To properly understand iptables, we need to learn about their architecture. First, it’ll give us a clear understanding of different iptables components. Then, once we know about each of them, we can use them to write firewall rules.

And, when we talk about iptables, Netfilter also comes into the picture. You can think of “Netfilter” as a big brother to iptables. It builds on top of iptables and offers a better feature set to manage your firewall. However, it does use iptables as one of the means to achieve excellent firewall capabilities.

Iptables is a command-line interface to Netfilter kernel-level hooks. These hooks can interact with the Linux network stack, which affects packets at the deepest level.

So, what does the iptables architecture look like:

IPtables-flow-of-packets

Tables

iptables architecture starts with tables. These tables take care of rules organization. And each table is classified based on the decision type they’re making. In more simple terms, a table simplifies the overall package processing by attaching a specific way to process packages.

The different tables offered by iptables include:

  • Filter table: Specifies decision type for packet filtering. In simple terms, it determines if a package should reach its destination or not.
  • NAT table: Specifies decision type for address translation. Here, the routing of the packets is determined based on the NAT networks. For example, if a package cannot access NAT, it’ll skip and try to search for a non-NAT network.
  • Mangle table: Manages the package’s special processing needs. For example, you can configure it to change the packet’s header information, such as TTL values.
  • Raw table: The raw table lets you work diligently with the stateful aspect of the iptables firewall. Using the table, you can route packets based on their “state” before the Linux kernel starts tracking its state. It is primarily used to mark the packets, whether the connection tracking system handles them or not. If a packet is not tracked, it is set to NOTRACK target.
IPtables-tables

Chains

And, then, we have “chains” within “tables.”

These chains handle deep packet inspection at different stages of their journey. For example, you can inspect them when it reaches a port or a network interface. This way, a decision can be made before the package is released to a system’s process.

Just like tables, you also get different chains. These include:

  • PREROUTING chain: Here, rules handle just-arrived packets at the network interface. 
  • INPUT chain: The rules mentioned in the INPUT chain handle incoming connection behavior. Once done, they’re given to the local process.
  • OUTPUT chain: The OUTPUT chain deals with packets that processes produce.
  • FORWARD chain: The FORWARD chain manages packets not meant for local systems. It is a carrier for other destined systems, such as a router.
  • POSTROUTING chain: Lastly, we have the POSTROUTING chain, which deals with the packets about to leave through the network interface.
Iptables-chain

Not all chains are available in each table. For example, the FORWARD chain is only available in the mangle, filter, and security table. Similarly, the POSTROUTING chain is available on mangle and nat (SNAT). Only the OUTPUT chain is available in all the tables.

Target

Now, we have a “target.” Once a package arrives, it moves through chains to see which rule description fits best. If it fits the description of a rule, it performs the associated action based on it and then moves it to the target — sealing the packet’s fate.

In many cases, a packet will not fit any description or ruleset. And that’s where the default policy, a target, comes in. 

The targets can be ACCEPT, DROP, and REJECT. These are terminating targets that decide the packet’s fate.

  • ACCEPT: Accepts the packets.
  • DROP: Drops the packet, making it unable for the sender to learn if the system is present or not.
  • REJECT: Rejects the packet.

There’re also non-terminating targets which are mainly used to store information about the packet.

Most Common iptables Commands with Examples

Before you jump and start executing the iptables command, make sure:

  • You have administrative access to run the commands. If the command fails due to administrative privileges, re-run the command with the sudo command in front of it.
  • The article is not a tutorial on how to configure iptables on Ubuntu.
  • We’ll use the iptables command that works with IPv4. If you intend to work with IPv6, you’ll need to use ip6tables instead.

Checking the iptables Status

To check the current iptables status, you need to run the following command.

$ iptables -L -n -v
#output

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

The above output contains a lot of information. However, it also hints at an inactive firewall. That’s because, currently, all chains are set to ACCEPT and have no rules.

You’ll need to start adding rules to activate the firewall.

Adding Rules to the Chain

When you add a rule, it is always appended to the chain. Therefore, you must use the -A (Append) option. The syntax for it is as below:

$ sudo iptables - A

However, when you run it, it’ll return the following:

iptables v1.8.7 (nf_tables): option "-A" requires an argument

Try `iptables -h' or 'iptables --help' for more information.

The arguments that you can use to add rules are:

  • – i: It stands for the interface. Here, you can mention the interface you’re adding rules for. It can be ppp0, eth0, and so on.
  • – p: It stands for protocol. Here, you mention the rule to use a network protocol to filter packers. For example, you can say ICMP, TCP, UDP, etc. If you want the rule to work across all protocols, mention “all” as the argument value.
  • – s: Next comes the source argument, which mentions the source of the traffic (as the IP address or hostname)
  • – dport: The dport stands for the destination port, where you mention the port number to which the packet is destined. 
  • – j: Lastly, we have a TARGET argument where you can mention the TARGET name, ACCEPT, DROP, or RETURN

It is also essential to write the command in the following order:

$ sudo iptables -A <chain-name> -i <interface-name> - p <protocool-name> - s <source> --dport <port no.> -j <target>

Saving Changes to iptables

Once you add a rule, you can save it with iptables -save command.

$ sudo iptables -save

The output is as follows:

nitt@logan99:~$ sudo iptables-save

# Generated by iptables-save v1.8.7 on Sun May 14 13:37:34 2023

*filter

:INPUT ACCEPT [0:0]

:FORWARD ACCEPT [0:0]

:OUTPUT ACCEPT [0:0]

-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 443 -j ACCEPT

-A INPUT -p tcp -m tcp --dport 392 -j REJECT --reject-with icmp-port-unreachable

-A OUTPUT -o lo -j ACCEPT

COMMIT

# Completed on Sun May 14 13:37:34 2023

Persisting Rules Manually

By default, iptables doesn’t save the rules. So, if you restart your computer, it’ll remove all the rules. You’ll need to use the following commands to ensure you don’t have to reconfigure iptables.

For IPv4 rules, write the command:

$ sudo iptables-save > /etc/iptables/rules.v4

And for IPv6 rules, write the command:

$ sudo iptables-save > /etc/iptables/rules.v6

Persisting Rules Automatically

To make rules persist even after a restart, and that too automatically, you’ll need to install the iptables-presistent package.

To do so, run the following command.

$ sudo apt-get install iptables-persistent

It’ll open up the following window. Press enter on <Yes>.

iptables-peristant

As we’re working with the IPv4 table, it’ll only show IPv4 rules. If you’re working on IPv6, it’ll show the relevant window.

Note: The package only loads your saved iptables rules. So, whenever you change the iptables, you’ll need to save it with the iptables -save command.

Reloading Rules After the Restart

Once the rules are saved, you must restore them with the following command.

$ sudo iptables-restore < /etc/iptables/rules.v4

And 

$ sudo iptables-restore < /etc/iptables/rules.v6

Enabling Traffic on Localhost / Enabling Loopback

To enable traffic on Localhost, use the following command:

$ sudo iptables -A INPUT -i lo -j ACCEPT

Here, the lo stands for the loopback interface for all localhost communications.

Similarly, we can allow packets to leave through the loopback interface.

$ sudo iptables -A OUTPUT -o lo -j ACCEPT

To check how it changed the rules, run iptables -L -n -V 

#output

Chain INPUT (policy ACCEPT 0 packets, 0 bytes)

 pkts bytes target     prot opt in     out     source               destination

    0     0 ACCEPT     all  --  lo     *       0.0.0.0/0            0.0.0.0/0

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

Enabling Traffic on Particular Ports

You can enable traffic to ACCEPT or REJECT on particular ports.

For example, SSL, HTTP, and SSH ports are important for the normal functioning of your apps. You can add rules to the ACCEPT packet through the port numbers to ensure they work as intended.

For SSL, run the following command.

$ sudo iptables -A INPUT -p tcp --dport 22 -j ACCEPT

For HTTPS, run the following command.

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

For allowing all HTTPS traffic at the eth0 interface.

$ iptables -A INPUT -i eth0 -p tcp --dport 80 -m state --state NEW,ESTABLISHED -j ACCEPT

$ iptables -A OUTPUT -o eth0 -p tcp --sport 80 -m state --state ESTABLISHED -j ACCEPT

For SSH, run the following command.

$ sudo iptables -A INPUT -p tcp --dport 22 -j ACCEPT

And to accept ALL incoming SSH traffic on the eth0 interface, run the following:

$ iptables -A INPUT -i eth0 -p tcp --dport 22 -m state --state NEW,ESTABLISHED -j ACCEPT

$ iptables -A OUTPUT -o eth0 -p tcp --sport 22 -m state --state ESTABLISHED -j ACCEPT

Another example would be to enable port traffic on a specific port for your custom app. Let’s say port 233.

To open up connections on that port, run.

$ sudo iptables -A INPUT -p tcp --dport 233 -j ACCEPT

Similarly, you can also disable connections on a particular port by using the REJECT target option.

Let’s block all connections at port 392.

$ sudo iptables -A INPUT -p tcp --dport 392 -j REJECT

To check, run the iptables -L -n -v command.

#output

Chain INPUT (policy ACCEPT 0 packets, 0 bytes)

 pkts bytes target     prot opt in     out     source               destination

    0     0 ACCEPT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            tcp dpt:22

    0     0 ACCEPT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            tcp dpt:80

    0     0 ACCEPT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            tcp dpt:443

    0     0 ACCEPT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            tcp dpt:233

    0     0 REJECT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            tcp dpt:392 reject-with icmp-port-unreachable

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

 0     0 ACCEPT     all  --  *      lo      0.0.0.0/0            0.0.0.0/0

Delete Existing Rules

To delete existing rules, you’ll need to run the following command.

$ iptables -F

or 

$ iptables --flush

Note: If you haven’t saved your rules, then they’re lost forever and cannot be restored using iptables -restore

Delete Rules with Line Numbers

To delete a specific rule, you’ll need to get the list of rules with numbers.

$ sudo iptables -L --line-numbers
#output

Chain INPUT (policy ACCEPT)

num  target     prot opt source               destination

1    ACCEPT     tcp  --  anywhere             anywhere             tcp dpt:ssh

2    ACCEPT     tcp  --  anywhere             anywhere             tcp dpt:http

3    ACCEPT     tcp  --  anywhere             anywhere             tcp dpt:https

4    ACCEPT     tcp  --  anywhere             anywhere             tcp dpt:233

5    REJECT     tcp  --  anywhere             anywhere             tcp dpt:392 reject-with icmp-port-unreachable

Run the following command if you wish to remove rule number 4 for the INPUT chain.

$ sudo iptables -D INPUT 4

And, if you again run the iptables -n -v -L command.

#output

Chain INPUT (policy ACCEPT 0 packets, 0 bytes)

 pkts bytes target     prot opt in     out     source               destination

    0     0 ACCEPT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            tcp dpt:22

    0     0 ACCEPT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            tcp dpt:80

    0     0 ACCEPT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            tcp dpt:443

    0     0 REJECT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            tcp dpt:392 reject-with icmp-port-unreachable

Display Only INPUT or OUTPUT Chain Rules

To display only INPUT chain rules, run the following command.

$ sudo iptables -L INPUT -n -v --line-numbers
#ouput

Chain INPUT (policy ACCEPT 0 packets, 0 bytes)

num   pkts bytes target     prot opt in     out     source               destination

1        0     0 ACCEPT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            tcp dpt:22

2        0     0 ACCEPT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            tcp dpt:80

3        0     0 ACCEPT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            tcp dpt:443

4        0     0 REJECT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            tcp dpt:392 reject-with icmp-port-unreachable

Similarly, if you want to see only OUTPUT chain rules, run:

$ sudo iptables -L OUTPUT -n -v --line-numbers
#output

Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes)

num   pkts bytes target     prot opt in     out     source               destination

1        0     0 ACCEPT     all  --  *      lo      0.0.0.0/0            0.0.0.0/0

Start/Stop/Restart the Firewall

If you’re on RHEL/ Fedora Linux or CentOS, you can start/stop or restart the firewall by running the commands.

$ service iptables stop

$ service iptables start

$ service iptables restart

You can also use the systemctl command.

However, it’ll not work on Ubuntu.

Insert Rules at a Specific Place

If you want to insert rules at a specific position, you must use the following commands.

First, check the rules.

$ sudo iptables -L INPUT -n --line-numbers
#output

Chain INPUT (policy ACCEPT)

num  target     prot opt source               destination

1    ACCEPT     tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:22

2    ACCEPT     tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:80

3    ACCEPT     tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:443

4    REJECT     tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:392 reject-with icmp-port-unreachable

Run the following command if you want to insert rules between 2 and 3.

$ sudo iptables -I INPUT 3 -s 252.32.1.2 -j DROP

Now, check the updated rules.

#output

Chain INPUT (policy ACCEPT)

num  target     prot opt source               destination

1    ACCEPT     tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:22

2    ACCEPT     tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:80

3    DROP       all  --  252.32.1.2           0.0.0.0/0

4    ACCEPT     tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:443

5    REJECT     tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:392 reject-with icmp-port-unreachable

Block Incoming Traffic but Allow Outgoing Traffic

You’ll need to enter the following command to block all incoming traffic.

$ iptables -P INPUT DROP

$ iptables -P FORWARD DROP

$ iptables -P OUTPUT ACCEPT

$ iptables -A INPUT -m state --state NEW,ESTABLISHED -j ACCEPT

$ iptables -L -v -n

This way, you can ping or download packages but block any unknown incoming traffic.

Block a Particular IP address

To block a specific IP address, run the following command.

$ iptables -A INPUT -s 14.23.59.9 -J DROP

You can also define a variable to store the blocked IP address and then run the command.

BLOCK_THE_IP = “a.b.c.d”

And, then run:

$ iptables -A INPUT -s “BLOCK_THE_IP” -j DROP

Note: Change “a.b.c.d” to your preferred IP address.

Allowing System Pinging From Outside

You can get outside users to ping your server to make your network discoverable.

$ sudo iptables -A INPUT -p icmp --icmp-type echo-request -j ACCEPT

$ sudo iptables -A OUTPUT -p icmp --icmp-type echo-reply -j ACCEPT

Allowing Internal Network to Talk to External Network

Run the following command to allow the internal network (let’s say eth0) to the external network (let’s say eth1).

$ sudo iptables -A FORWARD -i eth0 -o eth1 -j ACCEPT

Allow Outbound DNS

To allow DNS connections to your server, run the following command.

$ iptables -A OUTPUT -p udp -o eth0 --dport 53 -j ACCEPT

$ iptables -A INPUT -p udp -i eth0 --sport 53 -j ACCEPT

Allow Rsycn From a Specific Network

If you use the Rsync command and want to enable it over a specific network, run the following command.

iptables -A INPUT -i eth0 -p tcp -s 192.168.101.0/24 --dport 873 -m state --state NEW,ESTABLISHED -j ACCEPT

iptables -A OUTPUT -o eth0 -p tcp --sport 873 -m state --state ESTABLISHED -j ACCEPT

Block Port

Run the following command to block a specific port and any incoming requests.

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

iptables -A INPUT -i eth1 -p tcp --dport 80 -j DROP

Block Outgoing Traffic to a Particular IP Address

You can block traffic to any IP address by running the following command.

$ host -t a geekflare.com

#output

geekflare.com has an address of 172.66.40.93

To block outgoing traffic to that particular IP address, run the following command.

iptables -A OUTPUT -d 72.66.40.93 -j DROP

Block Social Media Platforms

Similarly, you can also block social media platforms such as Instagram, Twitter, and Facebook.

Find the social media IP address by running the following command:

$ host -t a social-media-web-adrress.com

For example, for Instagram, it would be:

$ host -t a www.instagram.com

Now, you’ll need to find CIDR for the IP address of that particular social media platform.

$ whois 185.89.219.11 | grep CIDR

Note: You may need to install the whois package by running sudo apt-get install whois

Now, enter the CIDR value in the following way:

$ iptables - A OUTPUT -p tcp -d CIDR-value -j DROP

Note: Make sure to change the CIDR value accordingly.

Allow or Block ICMP Ping Request

To allow or block ICMP ping requests, run the following commands.

$ iptables -A INPUT -p icmp --icmp-type echo-request -j DROP

$ iptables -A INPUT -i eth1 -p icmp --icmp-type echo-request -j DROP

Open a Particular Range of Ports

To open a range of ports, run the following command.

$ iptables -A INPUT -m state --state NEW -m tcp -p tcp --dport 8933: 8500 -j ACCEPT

List NAT Rules

To list NAT rules, run the following command:

$ sudo iptables -t nat -L -n -v

Or

$ sudo iptables -t nat -v -L -n --line-number

Reset Package Counters

To check the current iptables counter:

$ sudo iptables -L -n -v

To reset or clear the counters, run the following:

$ sudo iptables -Z

$ sudo iptables -L -n -v

For only resetting the INPUT chain counter, run:

$ iptables -Z INPUT

To reset a particular rule counter, run the following:

$ iptables -z INPUT RULE-NUMBER

Make sure to change RULE-NUMBER to that particular rule.

Final Words

iptables is a powerful firewall command-line utility. You can configure almost everything related to network resources, packets, interfaces, and particular scenarios. 

Also, iptables offers plenty of options. Check out its main page using the man command to get the complete picture.

$ man iptables
$ man ip6tables

Next, check out a network firewall and how it helps stop attacks.