Stateful Firewalls using iptables in Linux

Wednesday, April 2nd, 2008 at 12:59 pm

Stateful firewalling allows for a quick and secure way to restrict access to incoming network connections on a GNU/Linux machine with iptables.

It works by only reviewing the defined policy on the initial connection handshake, then relates subsequent packets to that initial connection. This will allow the firewall to be very efficient, only looking up rules for initial packets.

There are 4 states which iptables can use: New, Established, Related, and Invalid.

New connections are TCP SYN handshakes that have no prior association.

Established are those packets which have already been sent through New.

Related state are for possible New connections, which have been created from an already existing connection (such as ftp in non-passive mode).

The Invalid state is used for anything else.Using these rules, we can concentrate all our resources into only filtering New and Invalid connections, as anything Established or Related can likely be trusted fully.

The following script will allow only new connections on the $EXT interface from an allowed list of ports, both TCP and UDP.

It also has commands to setup port-forwarding and masquerade support. It could be used as an all-in-one GNU/Linux router/firewall.

#!/bin/bash
PATH=/sbin
LAN=172.16.254.0/24 # internal subnet
EXT=eth1 # external interface
INT=eth0 # internal interface
ALLOWUDP=1194,4569,5000 # comma separated lists
ALLOWTCP=22,25,5060 # same as above
FORWARD=("172.16.254.253:33891" "172.16.254.253:3389" "172.16.254.245:33894") # port forward rules, must follow this example syntax
start() {
# masquerade
iptables -t nat -A POSTROUTING -s 172.16.254.0/24 -j MASQUERADE
# port forwards
for i in ${FORWARD[@]}
do
iptables -A INPUT -p tcp --dport ${i#*:} -j ACCEPT
iptables -A INPUT -p udp --dport ${i#*:} -j ACCEPT
iptables -t nat -A PREROUTING -s ! $LAN -p tcp --dport ${i#*:} -j DNAT --to-destination ${i}
iptables -t nat -A PREROUTING -s ! $LAN -p udp --dport ${i#*:} -j DNAT --to-destination ${i}
done
# prevent more than 1 ssh attempt per minute per host
iptables -N ssh
iptables -A ssh -m recent --update --name ssh --seconds 60 --rttl -j DROP
iptables -A ssh -m hashlimit --hashlimit-name ssh --hashlimit-mode srcip --hashlimit-burst 10 --hashlimit 1/minute -j ACCEPT
iptables -A ssh -m recent --set --name ssh -j DROP

iptables -A INPUT -i $EXT -s ! $LAN -p tcp --dport 22 -m state --state NEW -j ssh
iptables -A INPUT -i $EXT -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -A INPUT -i $EXT -m state --state INVALID -j LOG --log-prefix "INVALID: " --log-level warning
iptables -A INPUT -i $EXT -p icmp --icmp-type echo-request -m limit --limit 1/minute -j LOG --log-prefix "PING: " --log-level notice
iptables -A INPUT -i $EXT -p icmp --icmp-type echo-request -m limit --limit 2/second -j ACCEPT
iptables -A INPUT -i $EXT -p udp -m multiport --dports $ALLOWUDP -m state --state NEW -j ACCEPT
iptables -A INPUT -i $EXT -p tcp -m multiport --dports $ALLOWTCP -m state --state NEW -j ACCEPT
iptables -A INPUT -i $EXT -p tcp -j REJECT --reject-with tcp-reset
iptables -A INPUT -i $EXT -j REJECT --reject-with icmp-port-unreachable
iptables -A INPUT -i $EXT -j DROP

echo iptables started
return 0
}
stop() {
iptables -F
iptables -t nat -F
iptables -X ssh
echo iptables stopped
return 0
}
case $1 in
start)
start
;;
stop)
stop
;;
restart)
stop
start
;;
*)
echo "usage: $0 [start|stop|restart]"
exit 1
;;
esac
exit 0

Post a Comment

Your email is never published nor shared. Required fields are marked *

*
*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>