#!/bin/sh

# AOV linux firewall script
# Angel Ortega <angel@triptico.com>
#
# $Id$

##############################################################

VERSION="2.0.3"

# CONFIGURATION

# allowed TCP services
ALLOW_TCP="ssh"

# allowed UDP services
ALLOW_UDP="domain"

# services limited to less than 5 times per minute
LIMIT_5MIN="ssh"

# Forwarding wanted? (1 or 0)
FORWARDING=0

# Nat wanted?
NAT=0

# Allow DHCP?
DHCP=0

# Allow all traffic on this networks
ALLOW_NET=""

# The interface
IFACE="eth0"

# The log chain (valid values: LOG or ULOG)
LOG_CHAIN="LOG"

# configuration file
[ -f /etc/aovfirewall.conf ] && . /etc/aovfirewall.conf

# END OF CONFIGURATION

##############################################################

# get the IP for this interface
THIS_IP=$(/sbin/ifconfig ${IFACE} | awk '/inet addr/ { print $2 }' | cut -d: -f2)

if [ "$LOG_CHAIN" = "ULOG" ] ; then
	LOG_PREFIX="--ulog-prefix"
else
	LOG_PREFIX="--log-prefix"
fi

# Path to the iptables binary
IPTABLES="/sbin/iptables"

# If first arg is -n, it means 'dry-run'
DRY_RUN=0

if [ "$1" = "-n" ] ; then
	shift
	IPTABLES="echo iptables"
	DRY_RUN=1
fi

CMD=$1

[ "$(basename $0)" = "aovfirewall-stop" ] && CMD="stop"

case $CMD in

stop)

	# restart chains
	$IPTABLES -F
	$IPTABLES -F INPUT
	$IPTABLES -F OUTPUT
	$IPTABLES -F FORWARD
	$IPTABLES -F -t mangle
	$IPTABLES -F -t nat
	$IPTABLES -X

	# default policies
	$IPTABLES -P INPUT ACCEPT
	$IPTABLES -P OUTPUT ACCEPT
	$IPTABLES -P FORWARD ACCEPT

	;;

try)

	$0 start
	echo "Waiting 15 seconds..."
	sleep 15
	echo "OK"
	$0 stop
	;;

restart)

	$0 stop
	$0 start
	;;

*)

	# The following may be necessary
	#modprobe ip_conntrack

	# restart from the beginning
	$IPTABLES -F
	$IPTABLES -F INPUT
	$IPTABLES -F OUTPUT
	$IPTABLES -F FORWARD
	$IPTABLES -F -t mangle
	$IPTABLES -F -t nat
	$IPTABLES -X

	# restrictive policies by default
	$IPTABLES -P INPUT DROP
	$IPTABLES -P OUTPUT ACCEPT
	$IPTABLES -P FORWARD ACCEPT

	# [de]activate forwarding
	if [ $DRY_RUN = 0 ] ; then
		echo $FORWARDING > /proc/sys/net/ipv4/ip_forward
	fi

	# SPECIAL CHAINS

	# firewall chain: actively firewalled, max 15 logs per minute
	$IPTABLES -N firewall
	$IPTABLES -A firewall -m limit --limit 15/minute -j ${LOG_CHAIN} ${LOG_PREFIX} Firewall:
	$IPTABLES -A firewall -j DROP

	# dropwall chain: not actively allowed, max 15 logs per minute
	$IPTABLES -N dropwall
	$IPTABLES -A dropwall -m limit --limit 15/minute -j ${LOG_CHAIN} ${LOG_PREFIX} Dropwall:
	$IPTABLES -A dropwall -j DROP

	# badflags chain: tcp flag trash
	$IPTABLES -N badflags
	$IPTABLES -A badflags -m limit --limit 15/minute -j ${LOG_CHAIN} ${LOG_PREFIX} Badflags:
	$IPTABLES -A badflags -j DROP

	# dhcp chain: log and accept
	$IPTABLES -N dhcp
	$IPTABLES -A dhcp -j ${LOG_CHAIN} ${LOG_PREFIX} DHCP:
	$IPTABLES -A dhcp -j ACCEPT

	# debug chain: log and accept
	$IPTABLES -N debug
	$IPTABLES -A debug -j ${LOG_CHAIN} ${LOG_PREFIX} DEBUG:
	$IPTABLES -A debug -j ACCEPT

	# chains for 5 per minute limit services
	for service in $LIMIT_5MIN
	do
		CHAIN="${service}delay"
		$IPTABLES -N $CHAIN
		$IPTABLES -A $CHAIN -j ${LOG_CHAIN} ${LOG_PREFIX} "$CHAIN:"
		$IPTABLES -A $CHAIN -j DROP
	done

	# everything from loopback is ok
	$IPTABLES -A INPUT -i lo -j ACCEPT

	# allowed networks
	for network in $ALLOW_NET
	do
		$IPTABLES -A INPUT -i $IFACE -s $network -j ACCEPT
	done

	# dhcp packets are also ok (but logged)
	[ "$DHCP" = 1 ] && $IPTABLES -A INPUT -i $IFACE -s 0.0.0.0/32 -d 255.255.255.255/32 -j dhcp

	# do NAT?
	[ "$NAT" = 1 ] && $IPTABLES -t nat -A POSTROUTING -o $IFACE -j MASQUERADE

	# tcp packets with nasty xmas flags and others fall into badflags
	$IPTABLES -A INPUT -p tcp --tcp-flags ALL FIN,URG,PSH -j badflags
	$IPTABLES -A INPUT -p tcp --tcp-flags ALL ALL -j badflags
	$IPTABLES -A INPUT -p tcp --tcp-flags ALL SYN,RST,ACK,FIN,URG -j badflags
	$IPTABLES -A INPUT -p tcp --tcp-flags ALL NONE -j badflags
	$IPTABLES -A INPUT -p tcp --tcp-flags SYN,RST SYN,RST -j badflags
	$IPTABLES -A INPUT -p tcp --tcp-flags SYN,FIN SYN,FIN -j badflags

	# drop icmp, but only after letting certain types through
	$IPTABLES -A INPUT -p icmp --icmp-type 0 -j ACCEPT
	$IPTABLES -A INPUT -p icmp --icmp-type 3 -j ACCEPT
	$IPTABLES -A INPUT -p icmp --icmp-type 11 -j ACCEPT
	$IPTABLES -A INPUT -p icmp --icmp-type 8 -m limit --limit 1/second -j ACCEPT
	$IPTABLES -A INPUT -p icmp -j firewall

	# delayed tcp connections
	for service in $LIMIT_5MIN
	do
		CHAIN="${service}delay"
		$IPTABLES -A INPUT -i $IFACE -p tcp --dport $service -m state \
		--state NEW -m recent --set --name $CHAIN

		$IPTABLES -A INPUT -i $IFACE -p tcp --dport $service -m state --state NEW \
        	-m recent --update --seconds 60 --hitcount 6 --rttl --name $CHAIN -j $CHAIN
	done

	# accepted tcp connections
	for service in $ALLOW_TCP
	do
		$IPTABLES -A INPUT -i $IFACE -d 0/0 -p tcp --dport $service -j ACCEPT
	done

	# accepted udp connections
	for service in $ALLOW_UDP
	do
		$IPTABLES -A INPUT -i $IFACE -d 0/0 -p udp --dport $service -j ACCEPT
		$IPTABLES -A INPUT -i $IFACE -d 0/0 -p udp --sport $service -j ACCEPT
	done

	# port redirections
	$IPTABLES -t nat -F PREROUTING

	for pair in $REDIRECT_TCP
	do
		port=`echo $pair|cut -d = -f 1`
		dest=`echo $pair|cut -d = -f 2`

		$IPTABLES -t nat -A PREROUTING -i $IFACE -p tcp \
			-d ${THIS_IP} \
			--dport $port -m state --state NEW \
			-j ${LOG_CHAIN} ${LOG_PREFIX} DNAT:

		$IPTABLES -t nat -A PREROUTING -i $IFACE -p tcp \
			-d ${THIS_IP} \
			--dport $port -j DNAT --to-destination $dest
	done

	for pair in $REDIRECT_UDP
	do
		port=`echo $pair|cut -d = -f 1`
		dest=`echo $pair|cut -d = -f 2`

		$IPTABLES -t nat -A PREROUTING -i $IFACE -p udp \
			-d ${THIS_IP} \
			--dport $port -m state --state NEW \
			-j ${LOG_CHAIN} ${LOG_PREFIX} DNAT:

		$IPTABLES -t nat -A PREROUTING -i $IFACE -p udp \
			-d ${THIS_IP} \
			--dport $port -j DNAT --to-destination $dest
	done

	# active tcp connections are always allowed
	$IPTABLES -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT

	# everything not actively allowed here is dropped onto the dropwall
	$IPTABLES -A INPUT -j dropwall

	;;

esac
