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