Configuring my Linux Firewall
The Linux kernel is able to filter incoming and outgoing packages with a tool known as ‘Iptables’. Based on a particular ruleset, this tool decides which data packets to allow across the network interface, and which ones to block.
First off install iptables
➜sudo xbps-install -S iptables
I may as well install the suite of network tools that come with void:
➜sudo xbps-install -S inetutils
[*] Updating `https://alpha.de.repo.voidlinux.org/current/x86_64-repodata' ...
Name Action Version New version Download size
inetutils-dnsdomainname install - 1.9.4_10 22KB
inetutils-ftp install - 1.9.4_10 98KB
inetutils-hostname install - 1.9.4_10 24KB
inetutils-ifconfig install - 1.9.4_10 39KB
inetutils-inetd install - 1.9.4_10 34KB
inetutils-ping install - 1.9.4_10 40KB
inetutils-rexec install - 1.9.4_10 31KB
inetutils-syslog install - 1.9.4_10 43KB
inetutils-telnet install - 1.9.4_10 78KB
inetutils-tftp install - 1.9.4_10 37KB
inetutils-traceroute install - 1.9.4_10 26KB
inetutils-uucpd install - 1.9.4_10 23KB
inetutils-whois install - 1.9.4_10 31KB
inetutils-rcp install - 1.9.4_10 28KB
inetutils-rlogin install - 1.9.4_10 38KB
inetutils-rsh install - 1.9.4_10 33KB
inetutils-talk install - 1.9.4_10 40KB
inetutils install - 1.9.4_10 62KB
Size to download: 735KB
Size required on disk: 2879KB
Space available on disk: 93GB
Do you want to continue? [Y/n]
The rules that iptables uses are referred to as chains.
These are 3 predefined chains in the filter table to which we can add rules for processing IP packets passing through those chains. These chains are:
- INPUT - All packets destined for the host computer.
- OUTPUT - All packets originating from the host computer.
- FORWARD - All packets neither destined for nor originating from the host computer, but passing through (routed by) the host computer. This chain is used if you are using your computer as a router.
There are three actions which the iptables can perform on the traffic:
- ACCEPT
- DROP
- REJECT
When traffic passes the rules in its specified chain, then the iptable accepts the traffic.
2. DROP
When the traffic is unable to pass the rules in its specified chain, the iptable blocks that traffic. That means the firewall is closed.
3. REJECT
This type of action is similar to the drop action but it sends a message to the sender of the traffic stating that the data transfer has failed.
As a general rule, use REJECT when you want the other end to know the port is unreachable, use DROP for connections to hosts you don’t want people to see.
Rules are added in a list to each chain. A packet is checked against each rule in turn, starting at the top, and if it matches that rule, then an action is taken such as accepting (ACCEPT) or dropping (DROP) the packet. Once a rule has been matched and an action taken, then the packet is processed according to the outcome of that rule and isn't processed by further rules in the chain. If a packet passes down through all the rules in the chain and reaches the bottom without being matched against any rule, then the default action for that chain is taken. This is referred to as the default policy and may be set to either ACCEPT or DROP the packet.
To start from scratch, run iptables with the -F flag. This will flush out the existing chains if any.
sudo iptables -F
The first thing to do is to create the default policy. There are two ways of going about this.
Either DROP all packets by defauilt and then ACCEPT packets from trusted IP addresses or certain ports, or ACCEPT packets by default, and then DROP, from nuisance IP addresses or ports.
Generally, option 1 above is used for the INPUT chain where we want to control what is allowed to access our machine and option 2 would be used for the OUTPUT chain where we generally trust the traffic that is leaving (originating from) our machine.
➜ sudo iptables -P INPUT DROP
➜ sudo iptables -P FORWARD DROP
➜ sudo iptables -P OUTPUT ACCEPT
Accept packets on localhost:
➜ sudo iptables -A INPUT -i lo -j ACCEPT
➜ sudo iptables -A OUTPUT -o lo -j ACCEPT
Now it's time to start adding some rules. We use the -A switch to append (or add) a rule to a specific chain, the INPUT chain in this instance. Then we use the -i switch (for interface) to specify packets matching or destined for the lo (localhost, 127.0.0.1) interface and finally -j (jump) to the target action for packets matching the rule - in this case ACCEPT. So this rule will allow all incoming packets destined for the localhost interface to be accepted. This is generally required as many software applications expect to be able to communicate with the localhost adapter.
Now we set up a rule to allow established sessions to receive traffic.
➜ sudo iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
Here we use the -A flag to append rules to the INPUT chain. -m conntrack allows filter rules to match based on connection state. It allows the use of the --ctstate option. --ctstate defines the list of states for the rule to match on. Valid states are:
- NEW - The connection has not yet been seen.
- RELATED - The connection is new, but is related to another connection already permitted.
- ESTABLISHED - The connection is already established.
- INVALID - The traffic couldn't be identified for some reason
Finally allow SSH to connect remotely, in case of any disaster recovery etc. or if I need to patch in from elsewhere:
➜ sudo iptables -I INPUT -p tcp --dport 22 -j ACCEPT
This commmand uses the -I flag to insert the rule at the top of the chain. The -p flag is then used tp specify a protocol, in this case TCP, and then destination port 22. I.e. ssh transmits on port 22.
Finally I write the iptable changes to file. Note how this must be done as root.
➜ su root
Password:
# iptables-save > /etc/firewall.conf
#
Now I can list the rules for iptables:
➜ sudo iptables -L
Password:
Chain INPUT (policy DROP)
target prot opt source destination
ACCEPT tcp -- anywhere anywhere tcp dpt:ssh
ACCEPT all -- anywhere anywhere
ACCEPT all -- anywhere anywhere ctstate RELATED,ESTABLISHED
Chain FORWARD (policy DROP)
target prot opt source destination
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
ACCEPT all -- anywhere anywhere
We can see these rules also if we look at our new firewall.conf file.
➜ cat /etc/firewall.conf
# Generated by iptables-save v1.8.2 on Tue Apr 16 18:34:01 2019
*filter
:INPUT DROP [564:78938]
:FORWARD DROP [0:0]
:OUTPUT ACCEPT [4698:472178]
-A INPUT -p tcp -m tcp --dport 22 -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A OUTPUT -o lo -j ACCEPT
COMMIT
# Completed on Tue Apr 16 18:34:01 2019
For these rules to be persistent, we need to set up a service to read this file on startup.
Replace the contents of /etc/sv/iptables/run with this: