YOUR LINUX LAPTOP IS NOT SECURE… YET. READ ON.

If you can create rules for your email inbox, you are more than capable of creating rules for the linux iptables firewall.

If you are running Ubuntu, Linux Mint, or any other linux on your laptop you are going to want to secure it by configuring the IP packet filter rules of your Linux kernel firewall.

You should also be aware that even after adding your own firewall rules some applications, cough cough docker, will write their own rules to the system iptables. This means your docker containers are not intuitively as protected as you thought – but more on that in another post.

Controlling the linux firewall is entirely managed by a text file and the ‘iptables’ command.

iptables is usually installed by default on most systems, but if it isn’t you can install the iptables package using the following command.

ubuntu@goodboy:~$ sudo apt-get install iptables
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
iptables is already the newest version (1.8.7-1ubuntu5).
0 upgraded, 0 newly installed, 0 to remove and 31 not upgraded.

Well… it looks like it is already installed on my system.

The Very Basics Of The Linux Firewall

In this section we will get through the bare minimum of iptables to protect your linux laptop.

Please read this ‘The Very Basics Of The Linux Firewall‘ section entirely before making changes to your iptables. You could get locked out of the internet and lose access to these instructions.

I will be assuming that you are working on a local laptop, if you are changing firewall rules on a remote server you could lock yourself out permanently.

You have 3 types of potential traffic passing through your laptop.

  • Outbound traffic: ALL output traffic. Including when YOU make a request to see a webpage.
  • Inbound traffic: ALL input traffic. Including traffic replying to your requests.
  • Forward traffic: When someone wants to access another device on your network through your computer.

Let’s take a look at a freshly installed linux firewall.
Using the following command we are going to list ‘-L’ the firewall verbosely ‘-v’.

iptables -L -v

Here is the output.

root@goodboy:~# 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 

iptables refers to inbound traffic as ‘Input’, forward traffic as ‘Forward’, outbound traffic as ‘Output’.

!!! ALERT: The default policy of your Input firewall settings is set to ACCEPT ANYTHING AND EVERYTHING !!!

Your laptop is open to any inward traffic, for a laptop it is unusual to be running services that require first contact to be made by anyone external to your system. Before we continue let’s put an immediate stop to this and protect you.

With the following command we are going to tell your firewall to default to DROP any incoming requests, scans and malicious connections. The other options are ACCEPT, which you know about, and REJECT, which denies access but returns an error message. I prefer to DROP and deny I exist at all.

iptables --policy INPUT DROP

Let’s see the command in action, and output the change.

root@goodboy:~# iptables --policy INPUT DROP
root@goodboy:~# iptables -L -v | grep policy
Chain INPUT (policy DROP 0 packets, 0 bytes)
Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes)

You can see that the policy has been applied to the INPUT traffic.

Unfortunately this even blocks traffic that is related, and already established to a web server you requested to see. Which means if you try to read the news you will get the following in your browser.

iptables tracks your connections and can allow you to match on connection states (-m conntrack), it also is able to set the states (–ctstate) of your traffic. We want any traffic with the states RELATED, ESTABLISHED to be tracked and let through the INPUT firewall. This will let us receive traffic back from a website.

We are going to use the following command to append (-A) a rule to the (INPUT) firewall chain to let through RELATED, and ESTABLISHED traffic by jumping (-j) that traffic to the ACCEPT target state. Here it is in iptables speak,

iptables -A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT

and here is the output. You can see that the rule has been added to our INPUT chain

root@goodboy:~# iptables -A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
root@goodboy:~# iptables -L -v 
Chain INPUT (policy DROP 1806 packets, 116K bytes)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 ACCEPT     all  --  any    any     anywhere             anywhere             ctstate RELATED,ESTABLISHED

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 

Revisiting your webpage you should be able to see it.

I don’t want my laptop forwarding any requests, so, i’m going to set the default policy on FORWARD to DROP also.

iptables --policy FORWARD DROP

Running the command and checking the iptables.

root@goodboy:~# iptables --policy FORWARD DROP
root@goodboy:~# iptables -L -v 
Chain INPUT (policy DROP 5320 packets, 367K bytes)
 pkts bytes target     prot opt in     out     source               destination         
13957   16M ACCEPT     all  --  any    any     anywhere             anywhere             ctstate RELATED,ESTABLISHED

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 

You are now somewhat protected from some threats.
We can move on to looking a little more into iptables.

Backing Up Your iptables

Once you have spent many hours crafting your iptables rules, how upsetting would it be if you lost them all on a reboot? Here we will go over saving iptables, restoring iptables and restoring iptables on boot.

Saving iptables

iptables is just a text file. You can save your iptable to a file using the following command.

root@goodboy:~# iptables-save > /root/myfirewall.v4

I have used the extension ‘.v4’ to note that these are IPV4 rules. You can use any filename/extension as you wish. It is possible to manage IPV6 rules using the ‘ip6tables‘ command. I won’t go into that here.
I have disabled all IPV6 traffic on my laptop.

Restoring iptables

You can load your rules from your backup file using the following command.

root@goodboy:~# iptables-restore < /root/myfirewall.v4

Restore On Boot

Step 1) Detect which/where your ‘iptable-restore’ command is.

We need to use the ‘iptables-restore‘ command, but we need to use the full path in our boot up script.

root@goodboy:~# which iptables-restore
/usr/sbin/iptables-restore

On my system it is located at ‘/usr/sbin/iptables-restore’

Step 2) Create a systemd startup script and service unit.

Systemd service units, and startup scripts, deserve their own post. They are used to define when exactly to run scripts. I’ll cover the bare minimum here to get us up and running.

Create Systemd Service Unit

Create a text file with executable permissions in the directory ‘/etc/systemd/system‘. I have chosen to give the file the filename, ‘restore-v4-iptables.service’.

root@goodboy:/etc/systemd/system# touch restore-v4-iptables.service
root@goodboy:/etc/systemd/system# chmod 644 restore-v4-iptables.service 
root@goodboy:/etc/systemd/system# ls -l restore-v4-iptables.service 
-rw-r--r-- 1 root root 234 Sep 23 18:31 restore-v4-iptables.service

Open up this file in your favourite text editor and add the following text.

[Unit]
Description=Load iptables rules from /root/myfirewall.v4
Before=network-pre.target
Wants=network-pre.target
[Service]
Type=oneshot
ExecStart=/usr/local/bin/restore-v4-iptables.sh
Timeoutsec=60
[Install]
WantedBy=network.target

In short, the above systemd [unit] has a Description, it then states it should be run Beforenetwork-pre.target‘ which is a target service used to help you create systemd units that run before a network is up and running. More on network-pre.target here. The service also sets Wants to ‘network-pre.target‘ to make sure that our restore script runs before the network is up.

The systemd [Service], has a service type set to ‘oneshot’, it for scripts like ours that does one task and then exits. More on service types here. The ExecStart key, has a value which is the location of our yet
to be created bash restore script. We’ve set a time out of 60sec, which is overkill, to wait for our service to start.

The systemd [Install] defines how systemd installs the service we are creating. [WantedBy] defines which other service triggers our service when it is enabled. In our case, when the network service is enabled our script will run.

Create Backup Script

Let’s create the backup script we referenced in our service unit file above. Head over to the directory ‘/usr/local/bin/’ and run the following commands to create a script file with execute permissions called ‘restore-v4-iptables.sh’

root@goodboy:/usr/local/bin# touch restore-v4-iptables.sh
root@goodboy:/usr/local/bin# chmod 744 restore-v4-iptables.sh 
root@goodboy:/usr/local/bin# ls -l restore-v4-iptables.sh 
-rwxr--r-- 1 root root 0 Sep 23 18:32 restore-v4-iptables.sh

Open up this file with your favourite text editor and add the following. Make sure you use the correct full path for ipconfig restore for your system as found above.

#!/bin/bash

/usr/sbin/iptables-restore < /root/myfirewall.v4
Test Service Script

First let’s restore iptables to the wide open state it was before all of the protection we set up, and output iptables to confirm.

root@goodboy:~# iptables --policy INPUT ACCEPT
root@goodboy:~# iptables --policy FORWARD ACCEPT
root@goodboy:~# iptables --policy OUTPUT ACCEPT
root@goodboy:~# iptables -F
root@goodboy:~# iptables -L -v 
Chain INPUT (policy ACCEPT 1 packets, 40 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 1 packets, 40 bytes)
 pkts bytes target     prot opt in     out     source               destination  

There, it is reset.

We can start our service with the command,

systemctl start restore-v4-iptables.service

here it is in action and restoring our iptables firewall with output to confirm.

root@goodboy:~# systemctl start restore-v4-iptables.service
root@goodboy:~# iptables -L -v
Chain INPUT (policy DROP 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination         
    1    40 ACCEPT     all  --  any    any     anywhere             anywhere             ctstate RELATED,ESTABLISHED

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

Chain OUTPUT (policy ACCEPT 1 packets, 40 bytes)
 pkts bytes target     prot opt in     out     source               destination 
Enable Restore On Restart/Startup

You need to enable your service to run on start up using the following command,

sudo systemctl enable restore-v4-iptables.service 

here it is in action.

root@goodboy:~# sudo systemctl enable restore-v4-iptables.service 
Created symlink /etc/systemd/system/network.target.wants/restore-v4-iptables.service → /etc/systemd/system/restore-v4-iptables.service.
root@goodboy:~# 

On your next system restart your firewall rules will be up and running to protect you.

iptables Default Chains

‘Chains’ is the name given to a list of firewall rules. There are three default chains, INPUT, FORWARD and OUTPUT. Each of these rule lists is run through from the top to the bottom, in order, as a filter. For example, if your very first rule was set as deny all then the network traffic will not have the chance to have the rest of your rules applied. Keep this in mind when designing your firewall.

iptables Custom Chains

Creating firewall rules can get quite complicated. To help you organise your rules iptables does let you create your own custom chains which you can refer to.

I’m going to move the rule we created above to protect your linux laptop to a custom chain.

Create A Custom Chain

First of all, I am going to flush my iptables, but keep the chain policies we implemented.
Here are the three default chains showing that they have no rules in place.

root@goodboy:~# iptables -F
root@goodboy:~# iptables -L -v
Chain INPUT (policy DROP 2 packets, 242 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 685 packets, 49948 bytes)
 pkts bytes target     prot opt in     out     source               destination  

I’m going to create a custom table called ‘RELATED_AND_ESTABLISHED‘ using the following command,

iptables -N RELATED_AND_ESTABLISHED

and here it is running, and an output of iptables showing the new chain.

root@goodboy:~# iptables -N RELATED_AND_ESTABLISHED
root@goodboy:~# iptables -L -v
Chain INPUT (policy DROP 28 packets, 1282 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 722 packets, 53199 bytes)
 pkts bytes target     prot opt in     out     source               destination         

Chain RELATED_AND_ESTABLISHED (0 references)
 pkts bytes target     prot opt in     out     source               destination 

Instead of appending (-A) out rule to the INPUT chain, were going to append it to our brand new RELATED_AND_ESTABLISHED chain using the following command.

iptables -A RELATED_AND_ESTABLISHED -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT

This command is the exact same command we used at the beginning, except one difference, we swapped out the ‘INPUT‘ chain and put in our ‘RELATED_AND_ESTABLISHED‘ chain. here it is running, and the output showing our added rule.

root@goodboy:~# iptables -A RELATED_AND_ESTABLISHED -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
root@goodboy:~# iptables -L -v
Chain INPUT (policy DROP 38 packets, 1682 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 741 packets, 54764 bytes)
 pkts bytes target     prot opt in     out     source               destination         

Chain RELATED_AND_ESTABLISHED (0 references)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 ACCEPT     all  --  any    any     anywhere             anywhere             ctstate RELATED,ESTABLISHED

Finally, we want to send all our ‘INPUT‘ chain traffic to our ‘RELATED_AND_ESTABLISHED‘ chain.
We do this by appending (-A) a rule to the ‘INPUT‘ chain that jumps (-j) all traffic to the ‘RELATED_AND_ESTABLISHED’ chain. Here is the command,

iptables -A INPUT -j RELATED_AND_ESTABLISHED

and here it is running, with our iptable output with our final state.

root@goodboy:~# iptables -A INPUT -j RELATED_AND_ESTABLISHED
root@goodboy:~# iptables -L -v
Chain INPUT (policy DROP 98 packets, 7064 bytes)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 RELATED_AND_ESTABLISHED  all  --  any    any     anywhere             anywhere            

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

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

Chain RELATED_AND_ESTABLISHED (1 references)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 ACCEPT     all  --  any    any     anywhere             anywhere             ctstate RELATED,ESTABLISHED

This iptables file does the exact same work as our original file, it is a little more organised.

I’m going to use this version in my systemd startup script.

iptables-save > /root/mychainfirewall.v4

DNS Issues

Depending on your DNS settings you may need to add explicit rules to allow port 53.
So far, I’ve been running these example inside of a virtual box.
I have found that on a bare metal install of linux you need to create the following chains.

A RELATED_AND_ESTABLISHED for your INPUT chain, and one for your OUTPUT chain.

Without these chains you can still ping, but websites won’t load.


iptables -N RB_I_RELATED_AND_ESTABLISHED
iptables -A RB_I_RELATED_AND_ESTABLISHED -i lo -p udp --dport 53 -m conntrack --ctstate NEW,RELATED,ESTABLISHED -j ACCEPT
iptables -A RB_I_RELATED_AND_ESTABLISHED -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
iptables -I INPUT -j RB_I_RELATED_AND_ESTABLISHED

iptables -N RB_O_RELATED_AND_ESTABLISHED
iptables -A RB_O_RELATED_AND_ESTABLISHED -o lo -p udp --sport 53 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
iptables -A RB_O_RELATED_AND_ESTABLISHED -m conntrack --ctstate NEW,RELATED,ESTABLISHED -j ACCEPT
iptables -I OUTPUT -j RB_O_RELATED_AND_ESTABLISHED

Notice that you need to take care with the loopback interface. It’s a bit of a special case and the rules behave slightly differently for the -lo loopback interface than they do for contacting external servers. Yup, the –ctstate NEW is applied to the -i lo INPUT interface and is not a typo. This allows your web browser to contact your local DNS service so I guess it does make sense that it is an INPUT bound request.

Chain INPUT (policy DROP 4 packets, 446 bytes)
 pkts bytes target     prot opt in     out     source               destination         
  115  8186 RB_I_RELATED_AND_ESTABLISHED  all  --  any    any     anywhere             anywhere   

Chain FORWARD (policy DROP 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 DROP       all  --  any    any     anywhere             anywhere             state INVALID

Chain OUTPUT (policy DROP 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination         
   97  6722 RB_O_RELATED_AND_ESTABLISHED  all  --  any    any     anywhere             anywhere            
    0     0 DROP       all  --  any    any     anywhere             anywhere             state INVALID


Chain RB_I_RELATED_AND_ESTABLISHED (1 references)
 pkts bytes target     prot opt in     out     source               destination         
  111  7740 ACCEPT     all  --  any    any     anywhere             anywhere             ctstate RELATED,ESTABLISHED
    0     0 ACCEPT     udp  --  lo     any     anywhere             anywhere             udp dpt:domain ctstate NEW,ESTABLISHED

Chain RB_O_RELATED_AND_ESTABLISHED (1 references)
 pkts bytes target     prot opt in     out     source               destination         
   97  6722 ACCEPT     all  --  any    any     anywhere             anywhere             ctstate NEW,RELATED,ESTABLISHED
    0     0 ACCEPT     udp  --  any    lo      anywhere             anywhere             udp spt:domain ctstate ESTABLISHED

These rules do allow DNS requests to be resolved inside a virtual machine and also a bare metal install.

Closing Notes

We have covered the raw guts and piping of the iptables firewall.

There are many more granular network conditions and rules that you can write, but, with the basic knowledge of routing traffic you now have you can easily research and add new rules to your chains.

I have written some software to apply the above iptable changes for you, take a look here, https://rexbytes.com/2022/10/11/rexbytes-software-bumper-vpn-kill-switch/

3 thoughts on “Secure Your Linux Laptop With iptables”

Leave a Reply