Linux may have a reputation for security, but it isn’t perfect. Many distributions also don’t have the best security defaults, so it’s best to implement some best practices for security. One such example is using a firewall.
There are a few options for firewalls in Linux, but most are actually just wrappers around iptables. For this guide we will show you how to work with iptables directly.
What Is Iptables?
Iptables is the Linux kernel firewall. It comes with every Linux distribution, and it’s the most direct way to control traffic coming into and out of your computer.
Iptables has a reputation for being complex, and it can be. You don’t need to know everything about iptables to use it effectively on your desktop, though. You just need some basic knowledge of how it works and how its rules are structured.
All iptables rules follow the same basic structure. Each rule is a single-line command to iptables that tells it how to handle traffic on a specific port. Take a look at the example below:
-A INPUT -i eth0 -p tcp -m state --state ESTABLISHED,RELATED --sport 80 -j ACCEPT
That might look like a lot, but it’s really simple when you break it down. First, this rule begins with
-A because it will append onto your iptables rules.
-i flag specifies the interface that the rule is for. In this case, it’s
eth0. When you write your own rules, make sure that you know which interface you’re connected to your network through.
The following flag,
-p, names the protocol. This rule is for
tcp, which is Web traffic.
-m flag is a little different. It is used to assert that there is a condition that must be met in order for traffic not to be rejected. The condition in this rule is the state.
State is actually the next flag. You need to give
--state a list of acceptable states written in all caps and separated with commas. This rule accepts both new and established connections.
The second to last flag here is
--sport. It stands for “source port,” and it tells iptables where the traffic is coming from. There is also a
--dport flag that stands for “destination port.” It’s used for
OUTPUT rules for handling which port traffic is arriving from.
Finally, there’s the
-j flag. It tells iptable which action to “jump” to. In this case it should
ACCEPT the traffic that meets the previous conditions.
Using a File
You can enter your rules into iptables manually one by one. That’s incredibly tedious, and it’s very easy to lose track of where you are and what you’re doing. It’s much better to create a rules file that you can import into iptables all at once.
It doesn’t matter where you create the file. People even make them in the
/tmp directory because iptables stores the result after it is imported.
Create your file. This guide is going to use
/tmp/iptables-ip4. In the file add the following two lines. All of your rules will go between them.
*filter # Your Rules Here COMMIT
Create Your Rules
You can start setting up your rules. These are just suggestions. Obviously, if you’re running other services or need other ports open, you can certainly tweak some things or add your own rules.
The loopback interface is an internal interface that Linux uses.
-A INPUT -i lo -j ACCEPT -A OUTPUT -o lo -j ACCEPT
This one is a matter of preference. Many people don’t like allowing ping at all on their desktops. It can be useful to have it, though, to test connections. If you want to allow ping, add the rules below. If you don’t, exclude them.
-A INPUT -i eth0 -p icmp -m state --state NEW --icmp-type 8 -j ACCEPT -A INPUT -i eth0 -p icmp -m state --state ESTABLISHED,RELATED -j ACCEPT -A OUTPUT -o eth0 -p icmp -j ACCEPT
You obviously want to be able to connect to the Web. On the flip side of that, you don’t want to allow connections originating from the Internet.
-A INPUT -i eth0 -p tcp -m state --state ESTABLISHED,RELATED --sport 80 -j ACCEPT -A INPUT -i eth0 -p tcp -m state --state ESTABLISHED,RELATED --sport 443 -j ACCEPT -A OUTPUT -o eth0 -p tcp -m tcp --dport 80 -j ACCEPT -A OUTPUT -o eth0 -p tcp -m tcp --dport 443 -j ACCEPT
You’re also going to need to allow DNS connections so that your computer can use URLs instead of only IP addresses because that wouldn’t be very convenient. Substitute your router’s IP address for the one used here.
-A INPUT -i ens3 -s 192.168.1.1 -p udp --sport 53 -m state --state ESTABLISHED,RELATED -j ACCEPT -A OUTPUT -o ens3 -d 192.168.1.1 -p udp --dport 53 -m udp -j ACCEPT
Most Linux desktops use NTP to set and maintain the system time from the Internet. You need to allow your computer to connect to an NTP server to get the time.
-A INPUT -i eth0 -p udp -m state --state ESTABLISHED,RELATED --dport 123 -j ACCEPT -A OUTPUT -o eth0 -p udp -m udp --sport 123 -j ACCEPT
Unless you’re using a USB printer or an external print server, you need to enable connections to CUPS.
-A INPUT -p udp -m udp --dport 631 -j ACCEPT -A INPUT -p tcp -m tcp --dport 631 -j ACCEPT -A OUTPUT -p udp -m udp --sport 631 -j ACCEPT -A OUTPUT -p tcp -m tcp --sport 631 -j ACCEPT
You probably want to be able to send and receive email, too. Email can be tricky. The ports allowed here are the SSL email ports. If you need to use unsecured email, substitute those ports.
# IMAP -A INPUT -i eth0 -p tcp -m state --state ESTABLISHED,RELATED --sport 993 -j ACCEPT -A OUTPUT -o eth0 -p tcp -m tcp --dport 993 -j ACCEPT # POP3 -A INPUT -i eth0 -p tcp -m state --state ESTABLISHED,RELATED --sport 995 -j ACCEPT -A OUTPUT -o eth0 -p tcp -m tcp --dport 995 -j ACCEPT # SMTP -A INPUT -i eth0 -p tcp -m state --state ESTABLISHED,RELATED --sport 465 -j ACCEPT -A OUTPUT -o eth0 -p tcp -m tcp --dport 465 -j ACCEPT
In order to fully utilize SSH connections, you need to be allow both input and output over SSH.
# Input -A INPUT -i ens3 -p tcp -m state --state NEW,ESTABLISHED --dport 22 -j ACCEPT -A OUTPUT -o ens3 -p tcp -m state --state ESTABLISHED --sport 22 -j ACCEPT # Output -A OUTPUT -o ens3 -p tcp -m state --state NEW,ESTABLISHED --dport 22 -j ACCEPT -A INPUT -i ens3 -p tcp -m state --state ESTABLISHED --sport 22 -j ACCEPT
Most Linux desktops use DHCP to automatically receive an IP address from a router. DHCP uses its own ports, so they need to be accessible too. If you’re using a static IP, you don’t need these rules.
-A INPUT -i eth0 -p udp -m state --state ESTABLISHED,RELATED --sport 67:68 -j ACCEPT -A OUTPUT -o eth0 -p udp -m udp --dport 67:68 -j ACCEPT
Reject Everything Else
Finally, you’re going to tell iptables to reject absolutely everything that you didn’t explicitly allow in the rules above.
-A INPUT -j REJECT -A FORWARD -j REJECT -A OUTPUT -j REJECT
After everything, your rules should looks something like these.
Importing Your Rules
You now have a fully-functional iptables rules list. You just need to hand it off to iptables to use.
In case some rules have been added over time, clear them out. After these commands, you’ll see the defaults that allow everything.
sudo iptables -F && sudo iptables -X
With those gone, you can restore the new ones from the file that you created.
sudo iptables-restore < /tmp/itpables-ip4
Your computer is now using the new iptables rules. You can check them out.
sudo iptables -S
However, they aren’t permanent yet. If you restart your computer now, you’re going to have a really bad time.
Making Them Permanent
There are several ways to make the rules permanent. They’re different for each distribution. This guide is going to focus on Debian- and Ubuntu-based systems, since they’re the most popular.
There is a package available, called
iptables-persistant, that handles saving and restoring iptables. All you have to do is install it.
sudo apt install iptables-persistent
During the installation, the package will ask you if you want to save your configuration. Select “Yes.”
In the future, if you want to add rules, you can save again by running the following command.
sudo service netfilter-persistent save
You are now in control of the traffic flowing through your computer. There is certainly more that you can do with iptables, but you should feel confident with the basics first.