#!/bin/bash

### BEGIN INIT INFO
# Provides:		firewall-3g
# Required-Start:	$network $local_fs
# Required-Stop:	$network $local_fs
# Default-Start:	2 3 4 5
# Default-Stop:
# Short-Description:	3Gteam Firewall
# Description:		Iptables and ipset based firewall by 3Gteam
### END INIT INFO

# -----------------------------------------------------------------------

set -o nounset

CFDIR=/etc/firewall

IFDIR=$CFDIR/if.d
RULESDIR=$CFDIR/rules.d


# do nothing if no params found
# -----------------------------------------------------------------------

if [ $# -lt 1 ]; then
	echo "Usage: $0 {start|restart|reload|info}"
	exit 1
fi

# enumerate network interfaces
# -----------------------------------------------------------------------

if_all="loop"
if_all_nonloop=""

# loopback interface
declare "if_loop=lo"

declare "if_loop_ip4=127.0.0.1"
declare "if_loop_net4=127.0.0.1/8"
declare "if_loop_ips4=127.0.0.1"
declare -A "if_loop_ip4arr"
declare "if_loop_ip4arr[1]=127.0.0.1"

declare "if_loop_ip6=::1"
declare "if_loop_net6=::1/128"
declare "if_loop_ips6=::1"
declare -A "if_loop_ip6arr"
declare "if_loop_ip6arr[1]=::1"

# other interfaces (from if.d dir)
if ! [ -d $IFDIR ]; then
	echo "FATAL: $IFDIR not found"
	exit 101
fi

IFcfs=`ls $IFDIR`

for IFname in $IFcfs; do
	IF=
	IP4=
	NET4=
	IPS4=
	IP6=
	NET6=
	IPS6=

	. ${IFDIR}/${IFname}

	if_all="$if_all ${IFname}"
	if_all_nonloop="$if_all_nonloop ${IFname}"

	declare "if_${IFname}=${IF}"

	declare "if_${IFname}_ip4=${IP4}"
	declare "if_${IFname}_net4=${NET4}"
	declare "if_${IFname}_ips4=${IPS4}"

	declare -A "if_${IFname}_ip4arr"
	ipno=1
	for ip4t in $IPS4; do
		declare "if_${IFname}_ip4arr[${ipno}]=${ip4t}"
		ipno=$((ipno+1))
	done

	declare "if_${IFname}_ip6=${IP6}"
	declare "if_${IFname}_net6=${NET6}"
	declare "if_${IFname}_ips6=${IPS6}"

	declare -A "if_${IFname}_ip6arr"
	ipno=1
	for ip6t in $IPS6; do
		declare "if_${IFname}_ip6arr[${ipno}]=${ip6t}"
		ipno=$((ipno+1))
	done

done

# functions - commands
# -----------------------------------------------------------------------

ipt()
{
	if ! (/sbin/ip6tables $@); then
		echo "CMD: ip64tables $@"
	fi
	if ! (/sbin/iptables $@);then
		echo "CMD: ip64tables $@"
	fi
}
ipt6()
{
	if ! (/sbin/ip6tables $@); then
		echo "CMD: ip6tables $@"
	fi
}
ipt4()
{
	if ! (/sbin/iptables $@);then
		echo "CMD: ip4tables $@"
	fi
}

ips()
{
	if [ -x /sbin/ipset ]; then
		IPSCMD=/sbin/ipset
	elif [ -x /usr/sbin/ipset ]; then
		IPSCMD=/usr/sbin/ipset
	fi

	if ! (${IPSCMD} $@);then
		echo "CMD: ipset $@"
	fi
}

include_parts()
{
	DIR=$1
	parts=`ls -1 $DIR |sort`
	for part in $parts; do
		if [ -f ${DIR}/$part ]; then
			. ${DIR}/$part
		fi
	done
}

# ----------------------------- init -------------------------------

fw_init()
{
	echo "- init"

	#modprobe ipt_LOG
	#modprobe ipt_limit

	#Turn on IP forwarding
	echo 1 >/proc/sys/net/ipv4/ip_forward

	# reset tables
	ipt -F
	ipt -X
	for table in nat mangle raw; do
		ipt -t $table -F
		ipt -t $table -X
	done

	ips destroy

	# Defaults (DROP ALL)
	ipt -P INPUT DROP
	ipt -P FORWARD DROP
	ipt -P OUTPUT DROP

	# all interfaces (except loop)

	# filter table
	ipt -N infw_all
	ipt -A INPUT ! -i ${if_loop} -j infw_all
	ipt -A FORWARD ! -i ${if_loop} -j infw_all

	ipt -N in_all
	ipt -A INPUT ! -i ${if_loop} -j in_all

	ipt -N fw_all
	ipt -A FORWARD ! -i ${if_loop} -j fw_all

	ipt -N out_all
	ipt -A OUTPUT ! -o ${if_loop} -j out_all

	# nat table
	ipt -t nat -N pre_all
	ipt -t nat -A PREROUTING ! -i ${if_loop} -j pre_all

	ipt -t nat -N post_all
	ipt -t nat -A POSTROUTING ! -o ${if_loop} -j post_all

	# raw table
	ipt -t raw -N pre_all
	ipt -t raw -A PREROUTING ! -i ${if_loop} -j pre_all

	ipt -t raw -N out_all
	ipt -t raw -A OUTPUT ! -o ${if_loop} -j out_all

	for ifname in $if_all; do
		hwis=if_${ifname}
		hwif=${!hwis}

		# filter table
		ipt -N infw_${ifname}
		ipt -A INPUT -i ${hwif} -j infw_${ifname}
		ipt -A FORWARD -i ${hwif} -j infw_${ifname}

		ipt -N in_${ifname}
		ipt -A INPUT -i ${hwif} -j in_${ifname}

		ipt -N fw_${ifname}
		ipt -A FORWARD -i ${hwif} -j fw_${ifname}

		ipt -N out_${ifname}
		ipt -A OUTPUT -o ${hwif} -j out_${ifname}

		# nat table
		ipt -t nat -N pre_${ifname}
		ipt -t nat -A PREROUTING -i ${hwif} -j pre_${ifname}

		ipt -t nat -N post_${ifname}
		ipt -t nat -A POSTROUTING -o ${hwif} -j post_${ifname}

		# raw table
		ipt -t raw -N pre_${ifname}
		ipt -t raw -A PREROUTING -i ${hwif} -j pre_${ifname}

		ipt -t raw -N out_${ifname}
		ipt -t raw -A OUTPUT -o ${hwif} -j out_${ifname}
	done

	# loopback (lo) traffic
	ipt -A INPUT -i ${if_loop} -j ACCEPT
	ipt -A OUTPUT -o ${if_loop} -j ACCEPT
}

fw_flush()
{
	echo "- flush"

	# flush global chains

	for ifname in all $if_all; do
		hwis=if_${ifname}
		hwif=${!hwis}

		# filter table
		ipt -F infw_${ifname}
		ipt -F in_${ifname}
		ipt -F fw_${ifname}
		ipt -F out_${ifname}
		# nat table
		ipt -t nat -F pre_${ifname}
		ipt -t nat -F post_${ifname}
		# raw table
		ipt -t raw -F pre_${ifname}
		ipt -t raw -F out_${ifname}
	done
}

fw_rules()
{
	ruledirs=`ls -1 $RULESDIR |sort`

	echo "- rules:"

	for ruledir in $ruledirs; do

		if [ -d $RULESDIR/$ruledir ]; then
			echo "  - $ruledir"
			include_parts $RULESDIR/$ruledir
		fi
	done
}

# ----------------------------------------------------------------------------------

case "$1" in
	start|restart)

		echo "Initializing 3G Firewall rules:"

		MODE=start
		fw_init
		fw_rules

		echo "3G Firewall initialized."

		[ -f /var/run/fail2ban/fail2ban.pid ] && /etc/init.d/fail2ban restart
		exit 0
		;;
	reload)

		echo "Reloading 3G Firewall rules:"

		MODE=reload
		fw_flush
		fw_rules

		echo "3G Firewall reloaded."
		exit 0
		;;
	stop)
		exit 0
		;;
	info)

		echo "3G Firewall adapter configuration:"

		MODE=rules
		for ifnm in $if_all; do

			if_name=if_${ifnm}
			if_ip4=if_${ifnm}_ip4
			if_net4=if_${ifnm}_net4
			if_ips4=if_${ifnm}_ips4
			if_ip6=if_${ifnm}_ip6
			if_net6=if_${ifnm}_net6
			if_ips6=if_${ifnm}_ips6

			echo "IF Name:  ${ifnm}"
			echo "Adapter:  ${!if_name}"
			echo "Pri IPv4: ${!if_ip4}"
			echo "Network4: ${!if_net4}"
			echo "All IPv4: ${!if_ips4}"
			echo "Pri IPv6: ${!if_ip6}"
			echo "Network6: ${!if_net6}"
			echo "All IPv6: ${!if_ips6}"
			echo
		done

		exit 0
		;;
	*)
		echo "3G Firewall"
		echo "Usage: $0 {start|restart|reload|info}"
		exit 1
	;;
esac
