#!/bin/sh
#* reason                       -- why this script was called, one of: pre-init connect disconnect
#* VPNGATEWAY                   -- vpn gateway address (always present)
#* TUNDEV                       -- tunnel device (always present)
#* INTERNAL_IP4_ADDRESS         -- address (always present)
#* INTERNAL_IP4_NETMASK         -- netmask (often unset)
#* INTERNAL_IP4_NETMASKLEN      -- netmask length (often unset)
#* INTERNAL_IP4_NETADDR         -- address of network (only present if netmask is set)
#* INTERNAL_IP4_DNS             -- list of dns serverss
#* INTERNAL_IP4_NBNS            -- list of wins servers
#* CISCO_DEF_DOMAIN             -- default domain name
#* CISCO_BANNER                 -- banner from server
#* CISCO_SPLIT_INC              -- number of networks in split-network-list
#* CISCO_SPLIT_INC_%d_ADDR      -- network address
#* CISCO_SPLIT_INC_%d_MASK      -- subnet mask (for example: 255.255.255.0)
#* CISCO_SPLIT_INC_%d_MASKLEN   -- subnet masklen (for example: 24)
#* CISCO_SPLIT_INC_%d_PROTOCOL  -- protocol (often just 0)
#* CISCO_SPLIT_INC_%d_SPORT     -- source port (often just 0)
#* CISCO_SPLIT_INC_%d_DPORT     -- destination port (often just 0)

# FIXMEs:

# Section A: route handling

# 1) The 3 values CISCO_SPLIT_INC_%d_PROTOCOL/SPORT/DPORT are currently being ignored
#   In order to use them, we'll probably need os specific solutions
#   * Linux: iptables -t mangle -I PREROUTING <conditions> -j ROUTE --oif $TUNDEV
#       This would be an *alternative* to changing the routes (and thus 2) and 3)
#       shouldn't be relevant at all)
# 2) There are two different functions to set routes: generic routes and the
#   default route. Why isn't the defaultroute handled via the generic route case?
# 3) In the split tunnel case, all routes but the default route might get replaced
#   without getting restored later. We should explicitely check and save them just
#   like the defaultroute
# 4) Replies to a dhcp-server should never be sent into the tunnel

# Section B: Split DNS handling

# 1) Maybe dnsmasq can do something like that
# 2) Parse dns packets going out via tunnel and redirect them to original dns-server

#env | sort
#set -x

# =========== script (variable) setup ====================================

PATH=/sbin:/usr/sbin:$PATH

OS="`uname -s`"

IPROUTE="`which ip | grep '^/' 2> /dev/null`"


# =========== tunnel interface handling ====================================

do_ifconfig() {
	if [ -n "$INTERNAL_IP4_MTU" ]; then
		MTU=$INTERNAL_IP4_MTU
	elif [ -n "$IPROUTE" ]; then
        MTU=$(($($IPROUTE route get "$VPNGATEWAY" | sed -ne 's/^.*mtu \([[:digit:]]\+\).*$/\1/p') - 88))
	else
		MTU=1412
	fi

	# Point to point interface require a netmask of 255.255.255.255 on some systems
	ifconfig "$TUNDEV" inet "$INTERNAL_IP4_ADDRESS" pointopoint "$INTERNAL_IP4_ADDRESS" netmask 255.255.255.255 mtu ${MTU} up

	if [ -n "$INTERNAL_IP4_NETMASK" ]; then
		$IPROUTE route replace "$INTERNAL_IP4_NETADDR/$INTERNAL_IP4_NETMASKLEN" dev "$TUNDEV"
		$IPROUTE route flush cache
	fi
}

destroy_tun_device() {
	case "$OS" in
	NetBSD) # and probably others...
		ifconfig "$TUNDEV" destroy
		;;
	esac
}

# ========= Toplevel state handling  =======================================

do_connect() {
	
	do_ifconfig

	echo "PVPN: connected" 1>&2
	echo "ifName=$TUNDEV" 1>&2
	echo "gwAddr=$VPNGATEWAY" 1>&2
	echo "ipAddr=$INTERNAL_IP4_ADDRESS" 1>&2
	echo "dnsSvr=$INTERNAL_IP4_DNS" 1>&2
    DNS_DOMAINS=$(echo $CISCO_DEF_DOMAIN $CISCO_SPLIT_DNS | sed 's/^\ *//g' | sed 's/[ \t]\+/ /g')
    echo "domainName=$DNS_DOMAINS" 1>&2
	if [ -n "$CISCO_SPLIT_INC" ]; then
		echo "numRts=$CISCO_SPLIT_INC" 1>&2
	
		i=0
		while [ $i -lt $CISCO_SPLIT_INC ] ; do
			eval NETWORK="\${CISCO_SPLIT_INC_${i}_ADDR}"
			eval NETMASK="\${CISCO_SPLIT_INC_${i}_MASK}"
			eval NETMASKLEN="\${CISCO_SPLIT_INC_${i}_MASKLEN}"
		    
            ROUTES=$(echo $NETWORK $NETMASK $NETMASKLEN | sed 's/^\ *//g' | sed 's/[ \t]\+/ /g')
			echo "routes=$ROUTES" 1>&2
			i=`expr $i + 1`
		done
	else
		echo "numRts=0" 1>&2
	fi
	
	if [ -z "$CISCO_BANNER" ]; then
	    echo "banner=" 1>&2
	else
	    echo "banner=`echo $CISCO_BANNER | tr -d "\r" | tr -d "\n"`" 1>&2
	fi

}

do_disconnect() {

	echo "PVPN: disconnected" 1>&2

	destroy_tun_device
}

#### Main

if [ -z "$reason" ]; then
	echo "this script must be called from vpnc" 1>&2
	exit 1
fi

case "$reason" in
	pre-init)
		;;
	connect)
		do_connect
		;;
	disconnect)
		do_disconnect
		;;
	*)
		echo "unknown reason '$reason'. Maybe vpnc-script is out of date" 1>&2
		exit 1
		;;
esac

exit 0
