#!/bin/sh
# List of parameters passed through environment
#* 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_MTU             -- mtu (often unset)
#* 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 servers
#* INTERNAL_IP4_NBNS            -- list of wins servers
#* INTERNAL_IP6_ADDRESS         -- IPv6 address
#* INTERNAL_IP6_NETMASK         -- IPv6 netmask
#* INTERNAL_IP6_DNS             -- IPv6 list of dns 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)
#* CISCO_IPV6_SPLIT_INC         -- number of networks in IPv6 split-network-list
#* CISCO_IPV6_SPLIT_INC_%d_ADDR -- IPv6 network address
#* CISCO_IPV6_SPLIT_INC_$%d_MASKLEN -- IPv6 subnet masklen

# 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

do_connect() {
	if [ -n "$CISCO_BANNER" ]; then
		echo "Connect Banner:"
		echo "$CISCO_BANNER" | while read LINE ; do echo "|" "$LINE" ; done
		echo
	fi

	proto_init_update "$TUNDEV" 1

	if [ -n "$INTERNAL_IP4_MTU" ]; then
		MTU=$INTERNAL_IP4_MTU
	fi

	if [ -z "$MTU" ]; then
		MTU=1412
	fi

	proto_add_ipv4_address "$INTERNAL_IP4_ADDRESS" 32 "" "$INTERNAL_IP4_ADDRESS"

	if [ -n "$INTERNAL_IP4_NETMASKLEN" ]; then
		proto_add_ipv4_route "$INTERNAL_IP4_NETADDR" "$INTERNAL_IP4_NETMASKLEN"
	fi

	# If the netmask is provided, it contains the address _and_ netmask
	if [ -n "$INTERNAL_IP6_ADDRESS" ] && [ -z "$INTERNAL_IP6_NETMASK" ]; then
	    INTERNAL_IP6_NETMASK="$INTERNAL_IP6_ADDRESS/128"
	fi

	if [ -n "$INTERNAL_IP6_NETMASK" ]; then
		addr="${INTERNAL_IP6_NETMASK%%/*}"
		mask="${INTERNAL_IP6_NETMASK##*/}"
		[[ "$addr" != "$mask" ]] && proto_add_ipv6_address "$addr" "$mask"
	fi

	[ -n "$INTERNAL_IP4_DNS" ] && proto_add_dns_server "$INTERNAL_IP4_DNS"
	[ -n "$CISCO_DEF_DOMAIN" ] && proto_add_dns_search "$CISCO_DEF_DOMAIN"

	if [ -n "$CISCO_SPLIT_INC" ]; then
		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}"
			if [ $NETWORK != "0.0.0.0" ]; then
				proto_add_ipv4_route "$NETWORK" "$NETMASKLEN"
			else
				proto_add_ipv4_route "0.0.0.0" 0
			fi
			i=$(($i + 1))
		done
	elif [ -n "$INTERNAL_IP4_ADDRESS" ]; then
		proto_add_ipv4_route "0.0.0.0" 0
	fi
	if [ -n "$CISCO_IPV6_SPLIT_INC" ]; then
		i=0
		while [ $i -lt $CISCO_IPV6_SPLIT_INC ] ; do
			eval NETWORK="\${CISCO_IPV6_SPLIT_INC_${i}_ADDR}"
			eval NETMASKLEN="\${CISCO_IPV6_SPLIT_INC_${i}_MASKLEN}"
			if [ $NETMASKLEN -lt 128 ]; then
				proto_add_ipv6_route "$NETWORK" "$NETMASKLEN"
			else
				proto_add_ipv6_route "::0" 0
			fi
			i=$(($i + 1))
		done
	elif [ -n "$INTERNAL_IP6_NETMASK" -o -n "$INTERNAL_IP6_ADDRESS" ]; then
		proto_add_ipv6_route "::0" 0
	fi
	proto_send_update "$INTERFACE"
}

do_disconnect() {
	proto_init_update "$TUNDEV" 0
	proto_send_update "$INTERFACE"
}

#### Main

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

. /lib/netifd/netifd-proto.sh

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

exit 0