#!/bin/sh

USAGE=$"Usage: sadb [options] {commands}
  options:
     -c <file>       : specify alternate IKE daemon configuration file
     -b <path>       : override location of binaries/modules
     -s <path>       : override location of management scripts
     -m <0|1>        : override default driver mode (0=STANDALONE, 1=TARGET)
     -p <0|1|2>      : override default driver action (0=DROP, 1=ACCEPT, 2=CONTINUE)
  commands:
     start [x]       : load SADB/IPSec driver kernel loadable module, init SPD
                           optionally set initial debug level=x
     stop            : stop SPD, unload kernel module
     restart         : stop/start this script
     print           : display phase 2 SA table contents
     reset           : flush SADB and restart SPD
     debug <x>       : set debug level=x (1+ enables tracing, 0 disables)
     help            : this message
"

# overrideable
SCRIPTDIR=/usr/sbin
BINDIR=/usr/iked
SADB_MODE=1		# 0=STANDALONE, 1=TARGET
SADB_POLICY=0	# 0=DROP, 1=ACCEPT, 2=CONTINUE
DEVICE_ID="13a3:0014"

# DEBUGLEVEL set by start or debug commands
DEBUGLEVEL=0

CONFDIR=/etc/iked	# must point to r/w location
IKEDCONF=$CONFDIR/iked.conf

# static settings
SPDBIN=spd
SYSTESTBIN=systest
PROCTRACE=/proc/sys/net/ipv4/svpn/trace

SADBSYSLOG=authpriv.warning
SADBTAG=sadb

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

SADB_PRINT_SCRIPT='
# get sa table
@satable_out = `cat /proc/net/ipsec/outboundSAs`;

# Check for errors
my $errors = 0;
foreach $line (@satable_out) {
	if ($line =~ /^Error/) {
		$errors = 1;
		last; } }

if ($errors) {
	die "Error getting current SAs"; }

$index = 0;

foreach $line (@satable_out) {
	chomp $line;
	@fields = split(/\s+/, $line);
	$j = 0;
	if ($index > 0) {
		foreach $field (@fields) {
			foo: {
				if ($j == 0) { $field = sprintf("%05d", $field); print $field,": "; last foo; }
				if ($j == 1) { print "loc:",$field," ==> "; last foo; }
				if ($j == 2) { print "rem:",$field," "; last foo; }
				if ($j == 3) { print "(tun:",$field,") "; last foo; }
				if ($j == 4) { print "exp:",$field," "; last foo; }
				if ($j == 5) { if ($field != 0) { print "exp:",$field,"KB "; } last foo; }
				if ($j == 6) { print "out:0x",$field," "; last foo; }
				if ($j == 7) { print "(in:0x",$field,") "; last foo; }
				if ($j == 8) { print "traf:",$field,"KB "; last foo; }
				if ($j == 9) { print "(",$field,", "; last foo; }
				if ($j == 10) { print $field,") "; last foo; }
			}
			$j ++;
		}
		print "\n";
	}
	$index ++;
}
'

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

logit()
{
	logger -p $SADBSYSLOG -t $SADBTAG "$@"
}

get_confparam()
{
	if [ -f $IKEDCONF ]; then
		# remove the leading # and " from key values as well as
		#	trailing whitespace
		grep "^$1=" $IKEDCONF | sed -e "s/$1=[\"\#]*//" | sed -e "s/[ ]*$//"
	fi
}

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

getoptions()
{
	BLACKIF=`get_confparam blackif`
	REDIF=`get_confparam redif`
}

load_module()
{
#	logit "$0: Loading module: $1."
	if [ -f $BINDIR/$1 ]; then
		/sbin/insmod $BINDIR/$@ 2>/dev/null
	else
		logit "$0: Fatal, couldn't find module: $BINDIR/$1."
		exit 1
	fi
}

unload_module()
{
#	logit "$0: Unloading module: $1."
	if [ ! -z "`cat /proc/ksyms | grep $1`" ]; then
		/sbin/rmmod $1 2>/dev/null
	fi
}

load_sadb_module()
{
	if [ "$SADB_MODE" = "1" ]; then
		if [ -z "`cat /proc/ksyms | grep ip_tables`" ]; then
			logit "$0: Fatal, Netfilter modules are not loaded."
			exit 1
		fi
	fi

	# (re)create sadb device node if missing first
	[ ! -c /dev/sadb ] && mknod /dev/sadb c 200 0

	if [ "$SADB_MODE" = "1" ]; then
		logit "$0: Loading Netfilter IPSEC table module ..."
		load_module iptable_IPSEC.o
		if [ -z "`cat /proc/ksyms | grep iptable_IPSEC`" ]; then
			logit "$0: Fatal, Netfilter IPSEC table module did not load."
			exit 1
		fi
	fi

	logit "$0: Loading SADB driver module ..."
	
	# if izambard card present
	if [ -n "`grep $DEVICE_ID /proc/pci`" ]; then
		load_module svpn-iz.o mode=$SADB_MODE debug=$DEBUGLEVEL policy=$SADB_POLICY
	else
		load_module svpn.o mode=$SADB_MODE debug=$DEBUGLEVEL policy=$SADB_POLICY
	fi	

	if [ ! -z "`cat /proc/ksyms | grep svpn`" ]; then
		logit "$0: `cat /proc/sys/net/ipv4/svpn/version`"
	else
		logit "$0: Fatal, SADB module did not load."
		exit 1
	fi

	if [ "$SADB_MODE" = "1" ]; then
		logit "$0: Loading Netfilter IPSEC target modules ..."
		load_module ipt_IPSEC.o
		#load_module ipt_RedROUTE.o
		if [ -z "`cat /proc/ksyms | grep ipt_IPSEC`" ]; then
			logit "$0: Fatal, Netfilter IPSEC target module did not load."
			exit 1
		fi
	fi

#	logit "$0: Loading SPD cache module ..."
#	load_module spd.o

	#### common to both driver modes:

	if [ -z "$BLACKIF" ]; then
		logit "$0: Fatal, $IKEDCONF black interface not set."
		exit 1
	fi

	# set black interface from iked.conf
	if [ -f /proc/sys/net/ipv4/svpn/blackIf -a -f /proc/sys/net/ipv4/svpn/blackIfType ]; then
		echo `echo $BLACKIF | sed -e "s/[a-z]*\([0-9]*\)/\1/"` > /proc/sys/net/ipv4/svpn/blackIf
		if [ -n "`echo $BLACKIF | grep ippp`" ];then
			TYPE=2
		elif [ -n "`echo $BLACKIF | grep ppp`" ];then
			TYPE=1
		else
			TYPE=0
		fi
		echo $TYPE > /proc/sys/net/ipv4/svpn/blackIfType
	else
		logit "$0: Fatal, can't find /proc fs blackIf file."
		exit 1
	fi
   if [ "$BLACKIF" = "$REDIF" ];then
      echo 0 > /proc/sys/net/ipv4/conf/all/send_redirects
      echo 0 > /proc/sys/net/ipv4/conf/eth0/send_redirects
   else
      # Values must be restored when coming from LAN server config
      echo 1 > /proc/sys/net/ipv4/conf/all/send_redirects
      echo 1 > /proc/sys/net/ipv4/conf/eth0/send_redirects
   fi
}

unload_sadb_module()
{
	logit "$0: Unloading SADB driver modules ..."

	unload_module iptable_IPSEC
	unload_module ipt_IPSEC
	unload_module ipt_RedROUTE
	if [ -n "`grep $DEVICE_ID /proc/pci`" ]; then
		unload_module svpn-iz
	else
		unload_module svpn
	fi

	unload_module spd
}

spd_start()
{
	if [ -x $SCRIPTDIR/$SPDBIN ]; then
		$SCRIPTDIR/$SPDBIN -c $IKEDCONF -b $BINDIR start
	else
		logit "$0: Fatal, can't find SPD management script."
		exit 1
	fi
}

spd_stop()
{
	if [ -x $SCRIPTDIR/$SPDBIN ]; then
		$SCRIPTDIR/$SPDBIN -c $IKEDCONF -b $BINDIR stop
	else
		logit "$0: Fatal, can't find SPD management script."
		exit 1
	fi
}

spd_reset()
{
	if [ -x $SCRIPTDIR/$SPDBIN ]; then
		$SCRIPTDIR/$SPDBIN -c $IKEDCONF -b $BINDIR reset
	else
		logit "$0: Fatal, can't find SPD management script."
		exit 1
	fi
}

spd_restart()
{
	if [ -x $SCRIPTDIR/$SPDBIN ]; then
		$SCRIPTDIR/$SPDBIN -c $IKEDCONF -b $BINDIR restart
	else
		logit "$0: Fatal, can't find SPD management script."
		exit 1
	fi
}

config_black0()
{
	/opt/itrnet/bin/qos/ip link set black0 > /dev/null
	/opt/itrnet/bin/qos/ip add add 1.1.1.1 dev black0 > /dev/null
	echo 0 > /proc/sys/net/ipv4/conf/black0/rp_filter
	echo 1 > /proc/sys/net/ipv4/svpn/source_from_black
}

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

while [ ! -z "$1" ]; do
	case "$1" in

### options:

	  c|-c|--c)
		if [ -n "$2" ]; then
			IKEDCONF=$2
			shift
		else
			echo "$USAGE"
			exit 2
		fi
		shift
		;;

	  s|-s|--s)
		if [ -n "$2" ]; then
			SCRIPTDIR=$2
			shift
		else
			echo "$USAGE"
			exit 2
		fi
		shift
		;;

	  b|-b|--b)
		if [ -n "$2" ]; then
			BINDIR=$2
			shift
		else
			echo "$USAGE"
			exit 2
		fi
		shift
		;;

	  m|-m|--m)
		if [ -n "$2" ]; then
			SADB_MODE=$2
			shift
		else
			echo "$USAGE"
			exit 2
		fi
		shift
		;;

	  p|-p|--p)
		if [ -n "$2" ]; then
			SADB_POLICY=$2
			shift
		else
			echo "$USAGE"
			exit 2
		fi
		shift
		;;

### commands:

	  start|--start)
		if [ -n "$2" ]; then DEBUGLEVEL=$2; fi
		getoptions

		# reboot if kernel panics
#		echo 1 > /proc/sys/kernel/panic

		load_sadb_module
		#config_black0
		spd_restart
		exit 0
		;;

	  stop|--stop)
		getoptions
		# clear pending IKE messages
		[ -c /dev/sadb ] && cat /dev/sadb > /dev/null
		sleep 1
		spd_stop
		if [ -z "`cat /proc/ksyms | grep svpn`" ]; then
			if [ -n "`grep $DEVICE_ID /proc/pci`" ]; then
				logit "$0: Error, can't flush: svpn-iz.o module not loaded."
			else
				logit "$0: Error, can't flush: svpn.o module not loaded."
			fi
		else
			$BINDIR/$SYSTESTBIN -f
		fi
		unload_sadb_module
		unload_sadb_module
		exit 0
		;;

	  restart|--restart)
		getoptions
		$0 -c $IKEDCONF -s $SCRIPTDIR -b $BINDIR -m $SADB_MODE stop
		$0 -c $IKEDCONF -s $SCRIPTDIR -b $BINDIR -m $SADB_MODE start
		exit 0
		;;

	  print|--print)
		if [ -z "`cat /proc/ksyms | grep svpn`" ]; then
			if [ -n "`grep $DEVICE_ID /proc/pci`" ]; then
				logit "$0: Fatal, svpn-iz.o module not loaded."
			else
				logit "$0: Fatal, svpn.o module not loaded."
			fi
			exit 1
		fi
		getoptions
		$BINDIR/$SYSTESTBIN -n
		#$BINDIR/$SYSTESTBIN -q debug

		# cat /proc/net/ipsec/outboundSAs
		# format is:
		#
		# SA_Nb LocalRange RemoteRange RemoteTunnel Timeout KBytesLeft OutboundSPI InboundSPI OutboundKB StatusAging StatusActive 
		# 1 100.100.100.* 200.200.200.* 192.168.1.1 00:01:43 0 7152334d 37aedc06 8 aging active

		# script display format, e.g.:
		# 00001: loc:100.100.100.* ==> rem:200.200.200.* (tun:192.168.1.1) exp:00:01:43 out:0x7152334d (in:0x37aedc06) traf:8KB (aging, active)
		perl -e "$SADB_PRINT_SCRIPT"
		exit 0
		;;

	  reset|--reset|hup|--hup|flush|--flush)
		getoptions
		# clear pending IKE messages
		[ -c /dev/sadb ] && cat /dev/sadb > /dev/null
		sleep 1
		if [ -z "`cat /proc/ksyms | grep svpn`" ]; then
			if [ -n "`grep $DEVICE_ID /proc/pci`" ]; then
				logit "$0: Error, can't flush: svpn-iz.o module not loaded."
			else
				logit "$0: Error, can't flush: svpn.o module not loaded."
			fi
		else
			$BINDIR/$SYSTESTBIN -f
		fi
		spd_reset
		exit 0
		;;

	  debug|--debug)
		getoptions
		if [ -n "`lsmod | grep svpn`" -a -d $PROCTRACE ]; then
			for f in $PROCTRACE/*; do echo "$2" > $f; done
		fi
		exit 0
		;;

	  -h|help|--help)
		echo "$USAGE"
		exit 0
		;;

	  *)
		echo "$USAGE"
		exit 2
		;;
	esac
done

exit 1
