A firewall is a program that surrounds the interface between a private network and the rest of the internet. Its a gateway that follows pre-configured rules. It allows certain traffic to pass through from the internet to the private network and blocks those that are unwanted and potentially harmful.

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.
For the most part, we are going to be dealing with the INPUT chain to filter packets entering our machine.

There are three actions which the iptables can perform on the traffic:
  • ACCEPT
  • DROP
  • REJECT
1. ACCEPT
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: