One of its main uses is to analyze traffic to see packet characteristics. On the other hand, they also allow using an important technology, NAT, based on network translation. A device can be configured for NAT with iptables, independently of the Firewall.
Another interesting function is that of packet marking. This is usually done with the use of iptables, so that those packets are passed to other programs, and depending on the tags, they do one thing or another. This is done using mangle which, with the marking, prepares the packets for future processing.
Iptables are a very powerful and flexible tool and help us a lot in terms of controlling traffic on Linux-based systems. This is very useful to protect the services that depend on these servers. Which we can find in a huge amount of services nowadays. One of the problems that we can find is that to implement them with other services, it is necessary to use code so that everything goes perfectly. Given this, we must bear in mind that any change made incorrectly to the rules can cause all network traffic to be blocked. Therefore, it is always advisable to make use of backup copies, to always have a means of recovery.
Some of the most basic examples of use are:
It is also possible to implement them to have some default policies, such as deny all. Commonly, many places use these predefined policies, instead of creating their own. In this case, we will always have one available that will deny all traffic, and then open only the ports that are explicitly necessary for what we are going to need. In any case, these examples are the most basic ones. Iptables can be implemented in many more and very complex systems, such as traffic rate limiting, IP address blocking, traffic logging, and many more options. It should always be remembered that rules do not persist after reboots. Therefore, it will be necessary to use scripts that we program, and that are executed at the beginning of the session. In this way, they will always be available. The problem with all this is that, for programming, it is necessary to know the code required for these tools.
The calculation of iptables, implies that the rules must be defined in a table and that they are applied to incoming and outgoing traffic. To do this, a set of predefined chains must be followed, which are INPUT, OUTPUT and FORWARD. These are responsible for determining the traffic to be analyzed. But to be able to calculate them, the rules of these chains must be known.
But that is not all, to calculate the iptables, we must take into account some very important factors.
Now that we know the main features, let's show the operation and architecture of this firewall.
Operation and architecture
This firewall is based on rules that we will be introducing one after another, its operation is based on applying rules that the firewall itself is in charge of executing. Although at first iptables may seem simple to use, if you want to do it in an advanced way, it is more complicated. Below, you can see a summary diagram of how iptables works.
The iptables structure is based on tables, many of them are already created by default. Within the tables we have the chains, which we also have some created by default. Finally, within the chains, we have different rules that we can configure. In the following picture you can see a small scheme of how the firewall architecture would look like:
By default, we have a total of four tables:
To do all this, it uses some filtering rules that will indicate which packets will be accepted and which will be rejected or directly omitted. These data chains are formed by:
In the following image you can see a small summary of the chains that we have in the different tables:
The operation when adding a rule is as follows:
The objectives that the different rules have are as follows:
As we have mentioned and concerning the mangle tables, iptables can make use of the NAT, which will have its tables, through which the rules are indicated to perform packet masking, port forwarding, or change some source and destination address. We can find:
Now that we know how it works and its architecture, we are going to see different commands to perform different actions.
The first thing to keep in mind when configuring this firewall is that we need superuser permissions to perform the different commands. They must be executed, otherwise it will not work. The following commands do not carry “sudo” because we assume that you are already with the superuser (sudo su).
In the latest versions of Linux it is not possible to stop the iptables service, to allow all network traffic and leave the firewall with the default parameters, we have to run the following commands:
1sudo iptables -F 2sudo iptables -X 3sudo iptables -t nat -F 4sudo iptables -t nat -X 5sudo iptables -t mangle -F 6sudo iptables -t mangle -X 7sudo iptables -P INPUT ACCEPT 8sudo iptables -P FORWARD ACCEPT 9sudo iptables -P OUTPUT ACCEPT
Once we have done this, we will have the firewall “reset” and allowed everything. Now that we know how to reset it, let's look at the different commands.
If you want to see the content of the different chains and rules that we have in a certain table, below, you can see what they would look like:
1iptables -t filter --list 2iptables -t mangle --list 3iptables -t nat --list 4iptables -t raw --list
-t, --table table
: Select the desired table.-A, --append chain rule-specification
: Adds a new rule to a specified chain.-C, --check chain rule-specification
: Checks if a specific rule exists in a chain.-D, --delete chain rule-specification
: Deletes a specified rule from a chain.-D, --delete chain rulenum
: Deletes the rule number X in a specified chain.-I, --insert chain [rulenum] rule-specification
: Inserts a new rule with a specified number into a chain.-R, --replace chain rulenum rule-specification
: Replaces a specified rule in a chain; useful for changing its order.-L, --list [chain]
: Displays the list of rules in a chain.-F, --flush [chain]
: Removes all rules from a specified chain.-Z, --zero [chain [rulenum]]
: Resets the counters of a specified rule to zero.-N, --new-chain chain
: Creates a new chain in a specified table.-X, --delete-chain [chain]
: Deletes a specified (empty) chain from a table.-P, --policy chain target
: Applies the default policy, which is used when no rules in the chains match.-E, --rename-chain old-chain new-chain
: Renames a previously added chain.-h
: Displays help.-v, --verbose
: Provides more detailed output when used with -L
.-n, --numeric
: Displays IP addresses and port numbers numerically. For example, if filtering port 80, it will show 80
instead of www
.-x, --exact
: Shows the exact value of packet and byte counters instead of using K
, M
, or G
for the values.--line-numbers
: When displaying the list of rules, it shows the exact number of the rule. This is useful for using -D
to delete or -I
to insert before or after the specified rule.-p
, --protocol protocol: Filters the packet by protocol. The specified protocol can be tcp, udp, Idplite, icmp, esp, ah, sctp.-s
, --source address[/mask][,…]: Source IP address of the packet. You can specify a single IP or a subnet (using CIDR notation). You can also use hostnames (domains, websites, etc.), but it is not efficient. Multiple source addresses can be specified (e.g., 192.168.1.1,192.168.1.2), but separate rules will be created to satisfy them.-d
, --destination address[/mask][,…]: Destination IP address of the packet. It behaves exactly like -s
.-m
, --match match: Specifies if we want to call extended iptables modules to perform specific actions such as:
-j
, --jump target: Specifies the target of the rule, such as accepting, rejecting, or even forwarding the packet to another chain for further processing. In any rule, we will always have a -j
to indicate what action to take. If we do not include -j
, the rule will be added and count the packets, but it will not perform any action. If we use -j
to forward to another chain, once processing in the other chain is finished, it will return to the original one.-g
, --goto chain: Used to forward traffic to another chain, but unlike jump, it does not return to the original chain where it entered.-i
, --in-interface name: Name of the interface where a packet is received. Only applicable for input chains like INPUT, FORWARD, and PREROUTING. If you use '!', it means all interfaces except that one. If you add a '+' at the end of the name, any interface that starts with that name will be matched. For example, if you have eth0, eth1, and eth2, you can match all three by using eth+.-o
, --out-interface name: Name of the interface where a packet is sent. Only applicable for output chains like OUTPUT, FORWARD, and POSTROUTING.If you use TCP or UDP protocol, you may want to filter by source and/or destination port number, here are the two arguments you can use:
--sport
, --source-port: Select source ports to allow or deny. If we use !
exclude.--dport
, --destination-port: Select destination ports to allow or deny. If using !
exclude.There are many more conditions for advanced firewall configuration, but we have already listed the basic ones.
Policies are used so that when no rule is found within the chain, the default policy is executed. The default policy for all chains is ACCEPT
, but there are two options: ACCEPT
or DROP
.
-P
, --policy chain targetExamples:
iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT DROP
With this we will be left without the internet, so next we must start creating permissive rules.
Below, you can see all the policies we have in the different tables:
iptables -t filter -P (INPUT | OUTPUT | FORWARD) (ACCEPT | DROP)
iptables -P (INPUT | OUTPUT | FORWARD) (ACCEPT | DROP)
iptables -t mangle -P (INPUT | OUTPUT | FORWARD | PREROUTING | POSTROUTING) (ACCEPT | DROP)
View firewall status
The -L
parameter shows the rules we have configured. -v
provides more information about connections, and -n
returns IP addresses and their corresponding ports without going through a DNS server.
iptables -L -n -v
This is one of the most important commands for checking the state of the firewall.
Modules (-m match) in iptables
This is an iptables extension that gives us the possibility to group similar rules with different TCP and UDP ports into one. Multiport allows to put several ports skipped, and also several ports in a row, the maximum is 15 port arguments. Example:
iptables -A INPUT -p tcp -m multiport --dports 80,81,1000:1200 -j ACCEPT
Thanks to this module, we can use several ports in the same rule.
iprange allows us to set several source or destination IP addresses at once, without the need to set dozens of rules. It also allows you to set both source and destination IPs, the syntax is as follows:
[!] --src-range ip-ip
: Specifies the source IP address range.[!] --dst-range ip-ip
: Specifies the destination IP address range.The operation of this rule is quite simple, we just put the start IP and the end IP.
The connlimit
module is used to restrict the number of simultaneous connections made by a single IP address, which is ideal for limiting connections to prevent DoS attacks.
--connlimit-upto n
: Marks if the number of connections is equal to or less than N (then we can allow or deny).--connlimit-above n
: Marks if the number of connections is greater than N (then we can allow or deny).--connlimit-mask prefix_length
: Marks by subnet range (it is equivalent to a host making 2 connections, versus two hosts from the same subnet each making 1 connection).--connlimit-saddr
: This applies the limitation to the source group; this is the default if nothing is specified.--connlimit-daddr
: Applies the limitation to the destination group.Example:
If we want to allow only two SSH connections per client, you would use:
iptables -A INPUT -p tcp --dport 22 -m connlimit --connlimit-above 2 -j DROP
However, we can also create a complementary rule to accept up to 2 connections:
iptables -A INPUT -p tcp --dport 22 -m connlimit --connlimit-upto 2 -j ACCEPT
This module is used to track connections, it is used to manage incoming and outgoing packets before and after the connection is established. Within this module there are several options, but the most important is -ctstate
that allows us to accept or deny different types of packets. Within ctstate we have several states, the most important of which are the following:
Example:
Imagine we want to access any site, but we don't want anyone to access us:
iptables -P INPUT DROP
iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
The limit
module allows us to limit traffic, the number of logs written to the syslog, and connection attempts. It has two main arguments:
--limit N
: This argument specifies the maximum average number of matches per second (N/s), minute (N/m), hour (N/h), or day (N/d) to allow. N specifies the number.--limit-burst N
: Indicates the maximum burst that can occur before checking the --limit
.The default value, if nothing is specified, is 3 matches per hour with bursts of 5. Imagine the following rule: iptables -A INPUT -m limit -j LOG
, the operation is as follows:
The recent module is used to limit the number of connections per second at the IP level, this is ideal to protect us from attacks on the SSH port because an attacker will try multiple passwords. For example, if we want to protect our SSH, we could execute the following rule:
iptables -A INPUT -p tcp --dport 22 -m conntrack --ctstate NEW -m recent --set --name ssh --rsource
iptables -A INPUT -p tcp --dport 22 -m state --state NEW -m recent --rcheck --seconds 60 --hitcount 4 --name ssh --rsource -j DROP
This rule allows only four connection attempts after 60 seconds; it is a “sliding” window.
This firewall is also in charge of NATing our connection. To NAT our public IP (or interface that has this public IP), we must set:
iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -o eth1 -j SNAT --to IP_eth1
iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -o eth1 -j MASQUERADE
It is normal to use MASQUERADE
to do NAT regardless of the IP address of the physical or logical interface.
To open ports, we have to add a rule in the PREROUTING
string of the NAT table.
iptables -t nat -A PREROUTING -i eth1 -p tcp --dport 22 -j DNAT --to-destination 192.168.1.1
The PREROUTING
table also allows us to modify the ports on the fly, so that if we receive packets on port 2121, we can transform it to port 21.
iptables -t nat -A PREROUTING -i eth1 -p tcp --dport 2121 -j DNAT --to-destination 192.168.1.1:21
Now that we are familiar with this firewall in detail, let's take a look at the basic and more advanced examples of its use.
This firewall is very complete, and we have hundreds of commands that we can execute to perform different actions. We are going to put some easy-to-understand examples for a first approach to this firewall.
First, block the IP address 192.168.1.10 from communicating with our server:
iptables -A INPUT -s 192.168.1.10 -j DROP
Then, if you want to block the IP addresses 192.168.1.20, 192.168.1.30, 192.168.1.40, 192.168.1.50 from making any communication to our server:
iptables -A INPUT -s 192.168.1.20,192.168.1.30,192.168.1.40,192.168.1.50 -j DROP
And to block the entire 192.168.2.0/24 subnet so that they do not make any communication to our server, except for the IP address 192.168.2.20 that would be allowed:
iptables -A INPUT -s 192.168.2.20 -j ACCEPT
iptables -A INPUT -s 192.168.2.0/24 -j DROP
If you want to block the IP address 192.168.4.50 so that you cannot make any communication:
iptables -A OUTPUT -d 192.168.4.50 -j DROP
There is also the option to block the IP addresses 192.168.4.51 and 192.168.4.52 so that we cannot make any communication:
iptables -A OUTPUT -d 192.168.4.51,192.168.4.52 -j DROP
And block access to www.google.es from iptables:
iptables -A OUTPUT -d [www.google.es](http://www.google.es/) -j DROP
We want to block access to our server from MAC 00:01:02:03:04:05, and allow everything else:
iptables -A INPUT -m mac --mac-source 00:01:02:03:03:04:05 -j DROP
We want to allow access to our server to the MAC address 00:01:02:03:03:04:06, and deny everything else:
iptables -A INPUT -m mac --mac-source 00:01:02:03:03:04:06 -j ACCEPT
iptables -A INPUT -j DROP
There is also the option to block the IP address 192.168.1.10 to prevent ping from our server:
iptables -A INPUT -s 192.168.1.10 -p icmp -j DROP
Then, block the IP addresses 192.168.1.20, 192.168.1.30, 192.168.1.40, 192.168.1.50 from pinging our server (in a single rule):
iptables -A INPUT -s 192.168.1.20,192.168.1.30,192.168.1.40,192.168.1.50 -p icmp -j DROP
Block the entire 192.168.2.0/24 subnet from pinging our server, except for the IP address 192.168.2.20 which would be allowed:
iptables -A INPUT -s 192.168.2.20 -p icmp -j ACCEPT
iptables -A INPUT -s 192.168.2.0/24 -p icmp -j DROP
Also, block the IP address 192.168.4.50 so that we cannot ping it:
iptables -A OUTPUT -d 192.168.4.50 -p icmp -j DROP
And block the IP addresses 192.168.4.51 and 192.168.4.52 so that we cannot ping them:
iptables -A OUTPUT -d 192.168.4.51,192.168.4.52 -p icmp -j DROP
Block access to www.google.es from iptables:
iptables -A OUTPUT -d [www.google.es](http://www.google.es/) -p icmp -j DROP
As you can see, the operation is quite simple with IP-based rules with source and destination. We could also use the iprange
module to configure a range of IPs:
Block a range of IP addresses ranging from 192.168.5.1 to address 192.168.5.50 from being able to ping from our server:
iptables -A OUTPUT -m iprange --dst-range 192.168.5.1-192.168.5.50 -p icmp -j DROP
We can also filter the ICMP protocol in a more advanced way. Let's imagine that we have a user who wants to be able to ping any host, but, however, does not want ANYONE to be able to ping him. How can we do it with iptables if PING itself has bidirectional communication?
iptables -A INPUT -s IP -p icmp --icmp-type echo-request -j DROP
Block any incoming access on the eth0 interface (only), therefore allowing eth1 access:
iptables -A INPUT -i eth0 -j DROP
iptables -A INPUT -i eth1 -j ACCEPT
Block outgoing traffic on the eth0 interface (only), therefore allowing eth1 access:
iptables -A OUTPUT -o eth0 -j DROP
iptables -A OUTPUT -o eth1 -j ACCEPT
Allow any incoming and outgoing traffic on eth0, and deny any incoming and outgoing traffic on eth1:
iptables -A INPUT -i eth0 -j ACCEPT
iptables -A OUTPUT -o eth0 -j ACCEPT
iptables -A INPUT -i eth1 -j DROP
iptables -A OUTPUT -o eth1 -j DROP
If you want to start seeing how the TCP and UDP protocol works, here are some examples:
Block web access to www.google.es and allow everything else (e.g., ping):
iptables -A OUTPUT -d [www.google.es](http://www.google.es/) -p tcp --dport 80 -j DROP
On the other hand, to block FTP access to any IP or domain, and allow everything else:
iptables -A OUTPUT -p tcp --dport 21 -j DROP
If you want to block SSH access to IP 192.168.1.50, and allow everything else:
iptables -A OUTPUT -d 192.168.1.50 -p tcp --dport 22 -j DROP
To block Telnet access to the 192.168.2.0 subnet, and allow everything else:
iptables -A OUTPUT -d 192.168.2.0/24 -p tcp --dport 23 -j DROP
Block access from 192.168.1.50 to our web server:
iptables -A INPUT -s 192.168.1.50 -p tcp --dport 80 -j DROP
Block access from 192.168.1.150 and 192.168.1.151 to our SSH server:
iptables -A INPUT -s 192.168.1.150,192.168.1.151 -p tcp --dport 22 -j DROP
If you want to block the access of the entire 192.168.2.0/24 subnet to the Telnet protocol (port 23), and allow everything else:
iptables -A INPUT -s 192.168.2.0/24 -p tcp --dport 23 -j DROP
Block access from 192.168.1.50
to our web server:
iptables -A INPUT -s 192.168.1.50 -p tcp --dport 80 -j DROP
Block access from 192.168.1.150
and 192.168.1.151
to our SSH server:
iptables -A INPUT -s 192.168.1.150,192.168.1.151 -p tcp --dport 22 -j DROP
If you want to block access from the entire 192.168.2.0/24
subnet to our telnet service:
iptables -A INPUT -s 192.168.2.0/24 -p tcp --dport 23 -j DROP
Block access to our OpenVPN server from everyone except for the IP address 77.77.77.77
, which is allowed:
iptables -A INPUT -s 77.77.77.77 -p tcp --dport 1194 -j ACCEPT
iptables -A INPUT -p tcp --dport 1194 -j DROP
To block DNS access to 8.8.8.8
and allow everything else (e.g., ping):
iptables -A OUTPUT -d 8.8.8.8 -p tcp --dport 53 -j DROP
iptables -A OUTPUT -d 8.8.8.8 -p udp --dport 53 -j DROP
To block access to port 1194
for any IP or domain and allow everything else:
iptables -A INPUT -p udp --dport 1194 -j DROP
We have a DNS server on our system, and we want only devices from the 192.168.1.0/24
subnet to communicate with it, blocking all other access:
iptables -A INPUT -s 192.168.1.0/24 -p tcp --dport 53 -j ACCEPT
iptables -A INPUT -s 192.168.1.0/24 -p udp --dport 53 -j ACCEPT
iptables -A INPUT -p tcp --dport 53 -j DROP
iptables -A INPUT -p udp --dport 53 -j DROP
Block access to our web server from the IP range 192.168.100.0/24
coming from the eth0
interface:
iptables -A INPUT -s 192.168.100.0/24 -i eth0 -p tcp --dport 80 -j DROP
Block access to our SSH server from the IP range 192.168.100.0/24
coming from the eth1
interface:
iptables -A INPUT -s 192.168.100.0/24 -i eth1 -p tcp --dport 22 -j DROP
If you want to learn more about iptables, here are some examples using the connlimit
module.
Allow only 10 Telnet connections per client:
iptables -A INPUT -p tcp --dport 23 -m connlimit --connlimit-above 10 --connlimit-mask 32 -j DROP
Deny connections beyond the fifth web connection made by a client (not very practical, but it's an example):
iptables -A INPUT -p tcp --dport 80 -m connlimit --connlimit-upto 5 --connlimit-mask 32 -j DROP
If you want to allow only 10 Telnet connections per client (configured differently from the previous example):
iptables -A INPUT -p tcp --dport 23 -m connlimit --connlimit-upto 10 --connlimit-mask 32 -j ACCEPT
iptables -A INPUT -p tcp --dport 23 -j DROP
Allow only 10 web connections within the IP range 10.0.0.0/8
, and deny if this number is exceeded:
iptables -A INPUT -s 10.0.0.0/8 -p tcp --dport 80 -m connlimit --connlimit-above 10 --connlimit-mask 8 -j DROP
If you want to allow only 20 HTTP connections per client, and if exceeded, send a TCP Reset:
iptables -A INPUT -p tcp --dport 80 -m connlimit --connlimit-above 20 --connlimit-mask 32 -j REJECT --reject-with tcp-reset
Or this way:
iptables -A INPUT -p tcp --syn --dport 80 -m connlimit --connlimit-above 20 --connlimit-mask 32 -j REJECT --reject-with tcp-reset
As you can see, this firewall is very comprehensive and allows for a wide range of advanced configurations to control all incoming and outgoing connections in detail. Also, remember that any changes you make to the iptables configuration are temporary, so you must save them for persistence after server reboots.