iptables
securityfirewallsiptables

iptables is used to configure the linux kernel based firewall. Quite substatial is its ability to open and close ports, which I will discuss here. One should also be aware that iptables can be used to route traffic as well.

View active rules

To view the rules in action watch can be used like so:

watch -d -n.1 iptables -L -v -n --line-numbers

This will output a number of tables, called CHAIN, which are usually named INPUT, OUTPUT and FORWARD. As that name suggests these indicate the direction the traffic comes from or goes to.

Insert rules

It is good practise to specify the exact position inside the CHAIN where the new rules should be inserted.

iptables -I INPUT 16 -j LOG --log-prefix "@max(input): "
iptables -I OUTPUT 7 -j LOG --log-prefix "@max(output): "
iptables -I FORWARD 12 -j LOG --log-prefix "@max(forward): "

This example adds a log directive at line 16 of the INPUT chain, at line 7 of the OUTPUT chain and at line 12 of the FORWARD chain. These were the last lines in my special case here, so that I have used them to log any traffic before it gets dropped. The log usually takes place in the system log and can therefore be viewed with journalctl -f.

Information from the system log can be used to indentify traffic which gets accidently blocked. This can happen for example if you set up qemu/kvm with bridging.

iptables -I INPUT 16 -i virbr0 -j ACCEPT

This will allow any traffic on the interface (-i) called virbr0 which got created automatically in this qemu/kvm-example.

Think negative: Block everything

The basic concept of any firewall should be to block anything in the first place and lets you define what should not get blocked. A good starting point might be to drop everything from all chains. But if you are trying this on a computer via ssh you would lock out yourself. That is why I used this as a script:

#!/bin/sh
# iptables-nothing-but-ssh.sh
iptables -P INPUT DROP
iptables -P OUTPUT DROP
iptables -A INPUT -p tcp -m tcp --dport 22 -j ACCEPT
iptables -A OUTPUT -p tcp --sport 22 -m state --state ESTABLISHED,RELATED -j ACCEPT

It will create rules for ssh (which is on port 22) so that your connections stays open.

See also

More comprehensive examples (but a long read) can be found here
A shorter overview over the rule parameters can be found here

Sample Configuration

*filter
:INPUT DROP [0:0]
:FORWARD DROP [0:0]
:OUTPUT ACCEPT [0:0]
# default...
-A INPUT -p icmp -j ACCEPT
-A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A INPUT -i lo -j ACCEPT
# ssh...
-A INPUT -p tcp --dport 22 -j ACCEPT
# avahi...
-A INPUT -p udp -m udp --dport 5353 -j ACCEPT
-A INPUT -m state --state NEW -p tcp --dport 80 -j ACCEPT
-A INPUT -m state --state NEW -p tcp --dport 443 -j ACCEPT
# nfs...
-A INPUT -p tcp -m tcp --dport 111 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 2049 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 20048 -j ACCEPT
-A INPUT -p udp -m udp --dport 111 -j ACCEPT
-A INPUT -p udp -m udp --dport 2049 -j ACCEPT
-A INPUT -p udp -m udp --dport 20048 -j ACCEPT
# samba...
-A INPUT -p tcp --dport 139 -j ACCEPT
-A INPUT -p tcp --dport 445 -j ACCEPT
-A INPUT -p udp --sport 137 -j ACCEPT
-A INPUT -p udp --dport 137 -j ACCEPT
-A INPUT -p udp --dport 138 -j ACCEPT
# drop everything else...
-A INPUT -j LOG --log-prefix "INPUT:DROP:" --log-level 6
-A INPUT -p tcp -j REJECT --reject-with tcp-reset
-A INPUT -p udp -j REJECT --reject-with icmp-port-unreachable
-A INPUT -p tcp -j REJECT --reject-with tcp-reset
-A INPUT -p udp -j REJECT --reject-with icmp-port-unreachable
-A INPUT -j REJECT --reject-with icmp-proto-unreachable
COMMIT
top