#!/bin/sh -e

PATH=/sbin:/usr/sbin:/bin:/usr/bin
export PATH

IPTABLES="/sbin/iptables"
HIPORT="1024:65535"
PIDFILE=/var/run/firewall.pid

[ -x $IPTABLES ] || exit 0
[ -x /sbin/ifconfig ] || exit 0
[ -x /bin/egrep ] || exit 0
[ -x /bin/grep ] || exit 0
[ -x /bin/sed ] || exit 0
[ -x /usr/bin/awk ] || exit 0

ifaddr() {
	#restituisce l'indirizzo IP di una data interfaccia
	local iface="$1"
	if ifconfig $iface | egrep '^\s+inet addr:' | sed -e 's/^[[:blank:]]*inet addr:\([0-9.]*\).*/\1/' 2>/dev/null ; then
		return 0
	else
		return 1
	fi
}

touch_pidfile() {
	#crea file pid
	local pidfile="$1"
	echo "0" > $pidfile
}

remove_pidfile() {
	#rimuove file pid
	local pidfile="$1"
	rm -f $pidfile 2>/dev/null || true
}

check_running() {
	local pidfile="$1"
	if [ -f $pidfile ] ; then
		return 0
	else
		return 1
	fi
}

has_iface() {
	local iface="$1"
	if awk '/:/ { sub(":", "", $1); print $1 }' /proc/net/dev | grep "$iface" 1>/dev/null ; then
		return 0
	else
		return 1
	fi
}

ETH0=$(ifaddr "eth0")
LAN24=$(echo "$ETH0" | sed -e 's/\.[0-9]*$/.0\/24/')
BCAST=$(echo "$ETH0" | sed -e 's/\.[0-9]*$/.255/')

HASTUN=no
TUN0=""

#Attendiamo che sia disponibile l'interfaccia tun.
#Facciamo questo in un loop perche' l'interfaccia tun potrebbe rendersi disponibile
#qualche attimo dopo l'avvio del processo di openvpn
COUNT=10
while [ "$COUNT" -gt 0 ] ; do
	if has_iface "tun0" ; then
		#ok, tun disponibile. Usciamo dal loop
		HASTUN=yes
		break
	else
		if ls /var/run/openvpn.*.pid >/dev/null 2>&1 ; then
			#openvpn avviato; attendiamo ancora un po'
			COUNT=$(($COUNT - 1))
			sleep 1
			continue
		fi
		#openvpn non e' in funzione; inutile aspettare. Usciamo dal loop
		break
	fi
done

#Stesso discorso per l'IP dell'interfaccia tun: attendiamo finche' non e' stato assegnato
if [ "$HASTUN" = "yes" ] ; then
	COUNT=10
	while [ "$COUNT" -gt 0 ] ; do
		TUN0=$(ifaddr "tun0") && break || COUNT=$(($COUNT - 1))
		sleep 1
	done
fi

VPN0=$(echo "$TUN0" | sed -e 's/\.[0-9]*$/.0\/24/')

iptables_start () {
	if check_running $PIDFILE ; then
		echo "Iptables e' gia' in esecuzione!"
		return 1
	fi

	#sicurezza aggiuntiva a livello kernel
	echo "0" > /proc/sys/net/ipv4/conf/eth0/rp_filter
	echo "0" > /proc/sys/net/ipv4/conf/eth0/accept_redirects
	echo "0" > /proc/sys/net/ipv4/conf/eth0/accept_source_route
	echo "0" > /proc/sys/net/ipv4/conf/eth0/bootp_relay
	echo "1" > /proc/sys/net/ipv4/conf/eth0/log_martians
	echo "1" > /proc/sys/net/ipv4/ip_forward
	echo "1" > /proc/sys/net/ipv4/icmp_echo_ignore_broadcasts
	echo "1" > /proc/sys/net/ipv4/tcp_syncookies
	echo "1" > /proc/sys/net/ipv4/icmp_echo_ignore_broadcasts
	echo "1" > /proc/sys/net/ipv4/icmp_ignore_bogus_error_responses

	#regole di default
	$IPTABLES -P INPUT DROP
	$IPTABLES -P FORWARD DROP
	$IPTABLES -P OUTPUT ACCEPT
	$IPTABLES -N inchain
	$IPTABLES -N syn_flood
	$IPTABLES -N ping_flood
	$IPTABLES -N vpn_lan
	$IPTABLES -N lan_vpn

	###########
	# INCHAIN #
	###########
	#apertura porte
	#SSH
	$IPTABLES -A inchain -p tcp --dport 22 --sport $HIPORT -s $LAN24 -j ACCEPT
	#Openvpn
	$IPTABLES -A inchain -p udp --dport 1194 --sport $HIPORT -j ACCEPT

	#droppa tutto il resto
	$IPTABLES -A inchain -j DROP

	#############
	# SYN_FLOOD #
	#############
	$IPTABLES -A syn_flood -m limit --limit 3/s -j RETURN
	$IPTABLES -A syn_flood -j DROP

	##############
	# PING_FLOOD #
	##############
	$IPTABLES -A ping_flood -m limit --limit 3/s -j RETURN
	$IPTABLES -A ping_flood -j DROP

	###########
	# VPN_LAN #
	###########
	$IPTABLES -A vpn_lan -j ACCEPT

	###########
	# LAN_VPN #
	###########
	$IPTABLES -A lan_vpn -j ACCEPT

	##################
	# REGOLE DI BASE #
	##################
	#connessioni esistenti
	$IPTABLES -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

	#calmiere syn e ping
	$IPTABLES -A INPUT -p tcp --syn -j syn_flood
	$IPTABLES -A INPUT -p icmp --icmp-type echo-request -j ping_flood

	#icmp
	$IPTABLES -A INPUT -p icmp --icmp-type echo-request -j ACCEPT
	$IPTABLES -A INPUT -p icmp --icmp-type echo-reply -j ACCEPT
	$IPTABLES -A INPUT -p icmp --icmp-type time-exceeded -j ACCEPT
	$IPTABLES -A INPUT -p icmp --icmp-type parameter-problem -j ACCEPT
	$IPTABLES -A INPUT -p icmp --icmp-type fragmentation-needed -j ACCEPT

	#loopback
	$IPTABLES -A INPUT ! -i lo -s 127.0.0.0/8 -j DROP
	$IPTABLES -A INPUT -i lo ! -s 127.0.0.0/8 -j DROP
	$IPTABLES -A INPUT -i lo -j ACCEPT
	$IPTABLES -A OUTPUT -o lo -j ACCEPT

	#il traffico da/verso la vpn viene instradato su apposite chain
	if [ "$HASTUN" = "yes" ] ; then
		$IPTABLES -A FORWARD -i tun0 -o eth0 -j vpn_lan
		$IPTABLES -A FORWARD -i eth0 -o tun0 -j lan_vpn
		#mapping dell'intera subnet locale su 172.25.12.0/24
		$IPTABLES -t nat -A PREROUTING -i tun0 -d 172.25.12.0/24 -j NETMAP --to $LAN24
		$IPTABLES -t nat -A POSTROUTING -o tun0 -s $LAN24 -j NETMAP --to 172.25.12.0/24
		#NAT traffico in uscita da eth0
		$IPTABLES -t nat -A POSTROUTING -o eth0 -j SNAT --to-source $ETH0
		#tutto il traffico in entrata dalla vpn viene accettato
		$IPTABLES -A INPUT -i tun0 -j ACCEPT
	fi

	#tutto il traffico in entrata e' gestito da inchain
	$IPTABLES -A INPUT -i eth0 -j inchain

	touch_pidfile $PIDFILE

	return 0
}

iptables_stop () {
	#svuotamento regole
	$IPTABLES -F
	$IPTABLES -F -t mangle
	$IPTABLES -F -t nat
	$IPTABLES -X
	$IPTABLES -X -t mangle
	$IPTABLES -X -t nat
	$IPTABLES -F INPUT
	$IPTABLES -F OUTPUT
	$IPTABLES -F FORWARD

	#regole di default
	$IPTABLES -P INPUT ACCEPT
	$IPTABLES -P FORWARD ACCEPT
	$IPTABLES -P OUTPUT ACCEPT

	remove_pidfile $PIDFILE

	return 0
}
