Linux Firewall¶

Note
This chapter is an ongoing work.
A firewall is a network security system, which can monitor and control network packets coming in and going out from a system based on pre-defined rules.
In this chapter, we will learn about iptables command and how can we use the same to create and manage the system’s firewall. The netfilter subsystem in Linux Kernel handles the actual packet filtering in the network level.
Installation¶
On CentOS
yum install iptables-services
On Debian systems
apt install iptables-persistent
Tables, chains and rules¶
There is a table based system which in turn uses chains of rules for the firewall. Each table has a defined set of chains, and the rules get into the get chain one after another.
When a network packet reaches the related table, and the related chain inside of the table, the rules gets matched from top to bottom. If the packet matches then the target of the rule gets executed. Each chain also has a default policy, if no rule matches, then, the default poilicy gets applied on the packet. We will learn more about these in details.
iptables has 5 built in chains.
- INPUT for all packets incoming to the system
- OUTPUT for all packets going out from the system
- FORWARD for the routed packets, this is when the system works as a router
- PREROUTING for port forwarding
- POSTROUTING for Source Network Address Translation (SNAT), this applies to all packets leaving the system
filter table¶
filter is the default table of iptables. It has 3 default chains.
- INPUT
- OUTPUT
- FORWARD
nat table¶
nat table is a special table for SNAT and DNAT (port forwarding). It has the following chains.
- PREROUTING
- POSTROUTING
- OUTPUT
There are two other different tables, mangle and raw.
iptables command¶
The following table will be helpful in remembering different arguments to iptables command.
+------------------+--------------+---------------------+------------------------+-------------+
| Table | Command | Chain | Matches | Target/Jump |
+------------------+--------------+---------------------+------------------------+-------------+
| filter (default) | -A (append) | INPUT | -p protocol | ACCEPT |
| nat | -I (insert) | OUTPUT | -s source_ip | DROP |
| mangle | -D (delete) | FORWARD | -d destination_ip | LOG |
| raw | -R (replace) | PREROUTING | --sport source_port | REJECT |
| | -F (flush) | POSTROUTING | --dport destination_ip | DNAT |
| | -L (list) | USER_DEFINED_CHAINS | -i incoming | SNAT |
| | -S (show) | | -o outgoing | LIMIT |
| | -Z (zero) | | -m mac | RETURN |
| | -N | | -m time | MASQUERADE |
| | -X | | -m quota | |
| | | | -m limit | |
| | | | -m recent | |
+------------------+--------------+---------------------+------------------------+-------------+
View the existing rules¶
# iptables -nvL --line-numbers
Chain INPUT (policy ACCEPT 82 packets, 4756 bytes)
num pkts bytes target prot opt in out source destination
Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
num pkts bytes target prot opt in out source destination
Chain OUTPUT (policy ACCEPT 42 packets, 3192 bytes)
num pkts bytes target prot opt in out source destination
The above command shows the default table filter and all chains and rules inside of it. You can notice that each of the chains has a default policy ACCEPT. It means if no rules match (in this case no rules are defined), it will accept those packets.
Appending rules to INPUT chain¶
We can test an initial rule to drop all incoming icmp packets to the system. The following rule will append the rule to the INPUT chain.
Note
ping command uses icmp packets. So, the following command will block ping into the system.
iptables -A INPUT -p icmp -j DROP
Now, if you try to ping the system from any computer, you will not get any response.
Flushing all rules¶
iptables -F
The above command will help to flush (remove) all the rules from the default table. You can actually use -t TABLE_NAME argument to flush any particular table.
Example of a series of rules¶
Here is a list of rules to allow traffic to port 22 (ssh) and port 80 and 443 (http and https).
iptables -A INPUT -i lo -j ACCEPT
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -A INPUT -p tcp -m state --state NEW --dport 22 -j ACCEPT
iptables -A INPUT -p tcp --dport 80 -j ACCEPT
iptables -A INPUT -p tcp --dport 443 -j ACCEPT
iptables -A OUTPUT -j ACCEPT
iptables -A INPUT -j REJECT
iptables -A FORWARD -j REJECT
The first rules allows all incoming traffic on the loopback device. The second line allows packets related to an already established connection, or the cases where a packet is trying to reconnect. The last 3rd last line allows all outgoing packets, and the last 2 lines reject everything else which does not match the rules. If you want to view all the rules.
# iptables -nvL --line-numbers
Chain INPUT (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
2 122 9641 ACCEPT all -- * * 0.0.0.0/0 0.0.0.0/0 state RELATED,ESTABLISHED
3 1 52 ACCEPT tcp -- * * 0.0.0.0/0 0.0.0.0/0 state NEW tcp dpt:22
4 0 0 ACCEPT tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:80
5 0 0 ACCEPT tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:443
6 22 2044 REJECT all -- * * 0.0.0.0/0 0.0.0.0/0 reject-with icmp-port-unreachable
Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
num pkts bytes target prot opt in out source destination
Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes)
num pkts bytes target prot opt in out source destination
1 104 12085 ACCEPT all -- * * 0.0.0.0/0 0.0.0.0/0
The –line-numbers argument shows the number of the each rule. We can use these line numbers to delete any rule.
Note
For a desktop or laptop, you may want to drop all incoming connections, that will help in cases where someone in the local network may try to attack/scan your system.
Delete a rule based on rule number¶
Let us delete the rule number 4, which allows traffic to port 80.
# iptables -D INPUT 4
# iptables -nvL --line-numbers
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
num pkts bytes target prot opt in out source destination
1 4 376 ACCEPT all -- lo * 0.0.0.0/0 0.0.0.0/0
2 221 15445 ACCEPT all -- * * 0.0.0.0/0 0.0.0.0/0 state RELATED,ESTABLISHED
3 1 52 ACCEPT tcp -- * * 0.0.0.0/0 0.0.0.0/0 state NEW tcp dpt:22
4 0 0 ACCEPT tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:443
5 22 2044 REJECT all -- * * 0.0.0.0/0 0.0.0.0/0 reject-with icmp-port-unreachable
Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
num pkts bytes target prot opt in out source destination
Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes)
num pkts bytes target prot opt in out source destination
1 166 17248 ACCEPT all -- * * 0.0.0.0/0 0.0.0.0/0
Delete a rule directly¶
If you know the rule properly, you can also delete it based on the rule directly.
# iptables -D INPUT -p tcp --dport 443 -j ACCEPT
# iptables -nvL --line-numbers
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
num pkts bytes target prot opt in out source destination
1 4 376 ACCEPT all -- lo * 0.0.0.0/0 0.0.0.0/0
2 344 22417 ACCEPT all -- * * 0.0.0.0/0 0.0.0.0/0 state RELATED,ESTABLISHED
3 1 52 ACCEPT tcp -- * * 0.0.0.0/0 0.0.0.0/0 state NEW tcp dpt:22
4 22 2044 REJECT all -- * * 0.0.0.0/0 0.0.0.0/0 reject-with icmp-port-unreachable
Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
num pkts bytes target prot opt in out source destination
Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes)
num pkts bytes target prot opt in out source destination
1 234 22564 ACCEPT all -- * * 0.0.0.0/0 0.0.0.0/0
Saving the rules¶
Any change made via iptables command stays on memory. To save it (so that it autoreloads in reboot), use the following command.
For Debian.
# netfilter-persistent save
For CentOS 7+
# systemctl stop firewalld && systemctl disable firewalld
# iptables-save > /etc/sysconfig/iptables
# systemctl enable iptables
Created symlink from /etc/systemd/system/basic.target.wants/iptables.service to /usr/lib/systemd/system/iptables.service.
# systemctl start iptables
The first line stops and then disables the firewalld service, it is a newer type of frontend for the same netfilter subsystem of the kernel.
A blog post from Major Hayden¶
Now, you should read the following blog post from Major Hayden best practices.
Debugging firewall rules¶
In case you want to debug the rules, and wan to see which packet matches which rule in the chain, you can add these two following rules. After that, do tail -f /var/log/kern.log to see the messages. Remember to use the proper IP address and port number.
# iptables -t raw -A PREROUTING -p tcp --destination YOUR_IP/24 --dport PORT_NUMBER -j TRACE
# iptables -t raw -A OUTPUT -p tcp --destination YOUR_IP/24 --dport PORT_NUMBER -j TRACE