#! /bin/sh

. /etc/init.d/functions.sh

LF=iptables
trap "remove_lock_file $LF" EXIT
create_lock_file $LF

. /etc/conf.d/iptables

DESCRIPTION="packet filters"

[ -x "$IPTABLES" ] || IPTABLES=dummytables
[ -x "$IP6TABLES" ] || IP6TABLES=dummytables

dummytables() {
	:
}

fail() {
	stop_filter
	end 1 "Failed to $@"
}

flush() {
	$IPTABLES -F || fail "flush tables!"
	$IP6TABLES -F || fail "flush tables!"
}

set_policy() {
	$IPTABLES -P INPUT $1 || fail "set $1 policy!"
	$IP6TABLES -P INPUT $1 || fail "set $1 policy!"
}

addr_family() {
	# This function determines AF but does not valiedate addresses
	# ':' is found in IPv6 addresses but never in IPv4 addresses
	if echo $1 | grep -q ':'; then
		return 6
	else
		return 4
	fi
}

start_filter() {
	local added_iptables=0 added_ip6tables=0 af=0

	flush

	if [ "$IPTABLES_INPUT_POLICY" = allow ]; then
		FILTER_ACTION=ACCEPT
		set_policy DROP
	else
		FILTER_ACTION=DROP
		set_policy ACCEPT
	fi

	$IPTABLES -A INPUT -i lo -j ACCEPT || fail "ACCEPT loopback!"
	$IP6TABLES -A INPUT -i lo -j ACCEPT || fail "ACCEPT loopback!"

	$IPTABLES -A INPUT -p icmp -j ACCEPT || fail "ACCEPT ICMP!"
	$IP6TABLES -A INPUT -p icmpv6 -j ACCEPT || fail "ACCEPT ICMP!"

	# Accept incoming packets on locally initiated TCP connections.
	$IPTABLES -A INPUT -p tcp ! --syn -j ACCEPT || fail "ACCEPT TCP !SYN!"
	$IP6TABLES -A INPUT -p tcp ! --syn -j ACCEPT || fail "ACCEPT TCP !SYN!"

	for SRC in $IPTABLES_ACCEPT; do
		addr_family $SRC
		af=$?
		if [ $af = 4 ]; then
			if [ "$IPTABLES_LOG_ENABLED" = yes ] &&
			   [ "$FILTER_ACTION" = DROP ]; then
				$IPTABLES -A INPUT -s $SRC -j LOG --log-prefix "IP_FILTER: " ||
					fail "LOG source address \"$SRC\"!"
			fi

			added_iptables=1

			$IPTABLES -A INPUT -s $SRC -j $FILTER_ACTION ||
				fail "$FILTER_ACTION source address \"$SRC\"!"

		elif [ $af = 6 ]; then
			if [ "$IPTABLES_LOG_ENABLED" = yes ] &&
			   [ "$FILTER_ACTION" = DROP ]; then
				$IP6TABLES -A INPUT -s $SRC -j LOG --log-prefix "IP_FILTER: " ||
					fail "LOG source address \"$SRC\"!"
			fi

			added_ip6tables=1

			$IP6TABLES -A INPUT -s $SRC -j $FILTER_ACTION ||
				fail "$FILTER_ACTION source address \"$SRC\"!"
		fi
	done

	if [ "$IPTABLES_LOG_ENABLED" = yes ] && [ $added_iptables -eq 1 ] &&
	   [ "$FILTER_ACTION" = ACCEPT ]; then
		$IPTABLES -A INPUT -j LOG --log-prefix "IP_FILTER: " ||
			fail "LOG source address \"$SRC\"!"
	fi

	if [ "$IPTABLES_LOG_ENABLED" = yes ] && [ $added_ip6tables -eq 1 ] &&
	   [ "$FILTER_ACTION" = ACCEPT ]; then
		$IP6TABLES -A INPUT -j LOG --log-prefix "IP_FILTER: " ||
			fail "LOG source address \"$SRC\"!"
	fi

	# drop in-wire ipv4-mapped addresses
	$IP6TABLES -A INPUT -s ::ffff:0:1/96 -j DROP
	$IP6TABLES -A INPUT -d ::ffff:0:1/96 -j DROP
}

stop_filter() {
	flush
	set_policy ACCEPT
}

conditional_start() {
	if [ "$IPTABLES_ENABLED" = yes ]; then
		start_filter
	else
		information "disabled"
		stop_filter
	fi
}

case "$1" in
	start)
		begin "Starting $DESCRIPTION"
		conditional_start
		end $?
		;;
	stop)
		begin "Stopping $DESCRIPTION"
		stop_filter
		end $?
		;;
	restart)
		begin "Restarting $DESCRIPTION"
		conditional_start
		end $?
		;;
	*)
		error "Usage: $0 start|stop|restart"
		;;
esac

exit 0
