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