#!/bin/sh
#
IPFBASE=/etc/opt/ipf
PIDFILE=${IPFBASE}/ipmon.pid

PATH=/bin:/sbin:/usr/sbin:${PATH}:/opt/ipf/bin
IPFILCONF=${IPFBASE}/ipf.conf
IP6FILCONF=${IPFBASE}/ipf6.conf
IPNATCONF=${IPFBASE}/ipnat.conf
IPPOOLCONF=${IPFBASE}/ippool.conf
PFILCHECKED=no


logmsg()
{
	logger -p local0.emerg -t ipfilter "$1"
	echo "$1" >&2
}


checkpfil()
{
	if [ $PFILCHECKED = yes ] ; then
		return
	fi
	ndd /dev/pfil qif_status 2>&1 > /dev/null
	if [ $? -ne 0 ] ; then
		logmsg "pfil not available to support ipfilter"
		exit 1
	fi
	realnic=`/sbin/ifconfig -a modlist 2>/dev/null | grep -c pfil`
	if [ $realnic -eq 0 ] ; then
		logmsg "pfil not configured for firewall/NAT operation"
	fi
	PFILCHECKED=yes
}


getids()
{
	id=`modinfo 2>&1 | awk '/ipf/ { print $1 } ' - 2>/dev/null`
	if [ -f $PIDFILE ] ; then
		pid=`cat $PIDFILE 2>/dev/null`
	else
		pid=`pgrep ipmon`
	fi
}


block_default_workaround() {
	ipf -F a
	echo "constructing minimal name resolution rules..."
	NAMESERVERS=`cat /etc/resolv.conf  2>/dev/null| \
		     nawk '/nameserver/ {printf "%s ", $2}' 2>/dev/null`
	if [ -z "$NAMESERVERS" ] ; then
		return
	fi
	for NS in $NAMESERVERS ; do
		IF_TO_NS=`route -n get $NS  2>/dev/null| \
			  nawk '$1 == "interface:" { print $NF ; exit }' \
			  2>/dev/null`
		if [ -z "$IF_TO_NS" ] ; then
			continue
		fi
		IP_TO_NS=`ifconfig $IF_TO_NS  2>/dev/null| \
			nawk 'NR == "2" { print $2 ; exit }' 2>/dev/null`
		if [ -z "$IP_TO_NS" ] ; then
			continue
		fi
		echo "pass out quick on $IF_TO_NS proto udp from $IP_TO_NS to $NS port = 53 keep state" | \
		ipf -f -
	done
}


load_ipf_config() {
	bad=0
	if [ -r ${IPFILCONF} ]; then
		checkpfil
		if `ipf -V | \
		      nawk '$1 == "Default:" && $2 == "pass" { exit 1 }'` ; then
			block_default_workaround
		fi
		ipf -IFa -f ${IPFILCONF}
		if [ $? != 0 ]; then
			echo "$0: load of ${IPFILCONF} into alternate set failed"
			bad=1
		fi
	fi
	if [ -r ${IP6FILCONF} ]; then
		checkpfil
		ipf -6IFa -f ${IP6FILCONF}
		if [ $? != 0 ]; then
			echo "$0: load of ${IPFILCONF} into alternate set failed"
			bad=1
		fi
	fi
	if [ $bad -eq 0 ] ; then
		ipf -s -y
	else
		echo Not switching config due to load error.
	fi
}


load_ipnat_config() {
	if [ -r ${IPNATCONF} ]; then
		checkpfil
		ipnat -CF -f ${IPNATCONF}
		if [ $? != 0 ]; then
			echo "$0: load of ${IPNATCONF} failed"
		else
			ipf -y
		fi
	fi
}


load_ippool_config() {
	if [ -r ${IPPOOLCONF} ]; then
		checkpfil
		ippool -F
		ippool -f ${IPPOOLCONF}
		if [ $? != 0 ]; then
			echo "$0: load of ${IPPOOLCONF} failed"
		fi
	fi
}


case "$1" in
	start)
		[ -n "$pid" ] && kill -TERM $pid 2>/dev/null
		[ -n "$id" ] && modunload -i $id 2>/dev/null
		modload /usr/kernel/drv/ipf
		load_ippool_config
		load_ipf_config
		load_ipnat_config
		ipmon -Ds
		;;

	stop)
		[ -n "$pid" ] && kill -TERM $pid
		[ -n "$id" ] && modunload -i $id
		;;

	pause)
		ipfs -l
		ipfs -NS -w
		ipf -D
		if [ -f $PIDFILE ] ; then
			if kill -0 $pid; then
				kill -TERM $pid
			else    
				cp /dev/null $PIDFILE
			fi
		fi      
		;;

	resume)
		ipf -E
		ipfs -R
		load_ippool_config
		load_ipf_config
		load_ipnat_config
		if [ -f $PIDFILE -a x$pid != x ] ; then
			ipmon -Ds
		fi
		;;

	reload)
		load_ippool_config
		load_ipf_config
		load_ipnat_config
		;;

	reipf)
		load_ipf_config
		;;

	reipnat)
		load_ipnat_config
		;;

	*)
		echo "Usage: $0 (start|stop|reload|reipf|reipnat|pause|resume)" >&2
		exit 1
		;;

esac
exit 0
