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