The vpnc-script used by OpenConnect only supports "split include" rules (default route unchanged, specific VPN routes added). We add support for Pulse's "split exclude" rules (default route to VPN, exclude rules for targets to be connected via normal uplink). For targets specified as split-exclude by the gateway, we add additional routes which keep traffic as-is (i.e. separate from tunnel). On platforms only providing /sbin/route, we guess that those are reached via default gateway. Please note that IPv6 variant is completely untested as I have no access to according testbeds. Tested on Linux (using ip and route command) in a IPv4 environment, "ip" case also tested in a IPv6 dialup config (gateway is IPv4 only). Signed-off-by: Gernot Hillier <gernot.hillier at siemens.com> --- vpnc-script | 117 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 117 insertions(+) diff --git a/vpnc-script b/vpnc-script index ae13947..a5f6c9c 100755 --- a/vpnc-script +++ b/vpnc-script @@ -252,6 +252,26 @@ if [ -n "$IPROUTE" ]; then $IPROUTE route flush cache } + set_exclude_route() { + # add explicit route to keep current routing for this target + # (keep traffic separate from VPN tunnel) + NETWORK="$1" + NETMASK="$2" + NETMASKLEN="$3" + $IPROUTE route add `$IPROUTE route get "$NETWORK/$NETMASKLEN" | fix_ip_get_output` + $IPROUTE route flush cache + } + + del_exclude_route() { + # FIXME: In theory, this could delete existing routes which are + # identical to split-exclude routes specificed by VPNGATEWAY + NETWORK="$1" + NETMASK="$2" + NETMASKLEN="$3" + $IPROUTE route $route_syntax_del "$NETWORK/$NETMASKLEN" + $IPROUTE route flush cache + } + reset_default_route() { if [ -s "$DEFAULT_ROUTE_FILE" ]; then $IPROUTE route replace `cat "$DEFAULT_ROUTE_FILE"` @@ -281,6 +301,15 @@ if [ -n "$IPROUTE" ]; then $IPROUTE route flush cache } + set_ipv6_exclude_route() { + # add explicit route to keep current routing for this target + # (keep traffic separate from VPN tunnel) + NETWORK="$1" + NETMASKLEN="$2" + $IPROUTE -6 route add `$IPROUTE route get "$NETWORK/$NETMASKLEN" | fix_ip_get_output` + $IPROUTE route flush cache + } + reset_ipv6_default_route() { $IPROUTE -6 route del default dev "$TUNDEV" $IPROUTE route flush cache @@ -292,6 +321,15 @@ if [ -n "$IPROUTE" ]; then $IPROUTE -6 route del "$NETWORK/$NETMASKLEN" dev "$TUNDEV" $IPROUTE -6 route flush cache } + + del_ipv6_exclude_route() { + # FIXME: In theory, this could delete existing routes which are + # identical to split-exclude routes specificed by VPNGATEWAY + NETWORK="$1" + NETMASKLEN="$2" + $IPROUTE -6 route del "$NETWORK/$NETMASKLEN" + $IPROUTE -6 route flush cache + } else # use route command get_default_gw() { # isn't -n supposed to give --numeric output? @@ -323,6 +361,28 @@ else # use route command route add -net "$NETWORK" $route_syntax_netmask "$NETMASK" $route_syntax_gw "$INTERNAL_IP4_ADDRESS" $route_syntax_interface } + set_exclude_route() { + NETWORK="$1" + NETMASK="$2" + NETMASKLEN="$3" + if [ -z "$DEFAULTGW" ]; then + DEFAULTGW="`get_default_gw`" + fi + # Add explicit route to keep traffic for this target separate + # from tunnel. FIXME: We use default gateway - this is our best + # guess in absence of "ip" command to query effective route. + route add -net "$NETWORK" $route_syntax_netmask "$NETMASK" $route_syntax_gw "$DEFAULTGW" $route_syntax_interface + } + + del_exclude_route() { + # FIXME: This can delete existing routes in case they're + # identical to split-exclude routes specified by VPNGATEWAY + NETWORK="$1" + NETMASK="$2" + NETMASKLEN="$3" + route $route_syntax_del -net "$NETWORK" $route_syntax_netmask "$NETMASK" + } + reset_default_route() { if [ -s "$DEFAULT_ROUTE_FILE" ]; then route $route_syntax_del default $route_syntax_gw "`get_default_gw`" $route_syntax_interface @@ -355,6 +415,16 @@ else # use route command : } + set_ipv6_exclude_route() { + NETWORK="$1" + NETMASK="$2" + # Add explicit route to keep traffic for this target separate + # from tunnel. FIXME: We use default gateway - this is our best + # guess in absence of "ip" command to query effective route. + route add -inet6 -net "$NETWORK/$NETMASK" "`get_default_gw`" $route_syntax_interface + : + } + reset_ipv6_default_route() { route $route_syntax_del -inet6 default "$INTERNAL_IP6_ADDRESS" : @@ -367,6 +437,13 @@ else # use route command : } + del_ipv6_exclude_route() { + NETWORK="$1" + NETMASK="$2" + route $route_syntax_del -inet6 "$NETWORK/$NETMASK" + : + } + fi # =========== resolv.conf handling ==================================== @@ -731,6 +808,26 @@ do_connect() { set_vpngateway_route do_ifconfig + if [ -n "$CISCO_SPLIT_EXC" ]; then + i=0 + while [ $i -lt $CISCO_SPLIT_EXC ] ; do + eval NETWORK="\${CISCO_SPLIT_EXC_${i}_ADDR}" + eval NETMASK="\${CISCO_SPLIT_EXC_${i}_MASK}" + eval NETMASKLEN="\${CISCO_SPLIT_EXC_${i}_MASKLEN}" + set_exclude_route "$NETWORK" "$NETMASK" "$NETMASKLEN" + i=`expr $i + 1` + done + fi + if [ -n "$CISCO_IPV6_SPLIT_EXC" ]; then + # untested + i=0 + while [ $i -lt $CISCO_IPV6_SPLIT_EXC ] ; do + eval NETWORK="\${CISCO_IPV6_SPLIT_EXC_${i}_ADDR}" + eval NETMASKLEN="\${CISCO_IPV6_SPLIT_EXC_${i}_MASKLEN}" + set_ipv6_exclude_route "$NETWORK" "$NETMASKLEN" + i=`expr $i + 1` + done + fi if [ -n "$CISCO_SPLIT_INC" ]; then i=0 while [ $i -lt $CISCO_SPLIT_INC ] ; do @@ -799,6 +896,26 @@ do_disconnect() { else reset_default_route fi + if [ -n "$CISCO_SPLIT_EXC" ]; then + i=0 + while [ $i -lt $CISCO_SPLIT_EXC ] ; do + eval NETWORK="\${CISCO_SPLIT_EXC_${i}_ADDR}" + eval NETMASK="\${CISCO_SPLIT_EXC_${i}_MASK}" + eval NETMASKLEN="\${CISCO_SPLIT_EXC_${i}_MASKLEN}" + del_exclude_route "$NETWORK" "$NETMASK" "$NETMASKLEN" + i=`expr $i + 1` + done + fi + if [ -n "$CISCO_IPV6_SPLIT_EXC" ]; then + # untested + i=0 + while [ $i -lt $CISCO_IPV6_SPLIT_EXC ] ; do + eval NETWORK="\${CISCO_IPV6_SPLIT_EXC_${i}_ADDR}" + eval NETMASKLEN="\${CISCO_IPV6_SPLIT_EXC_${i}_MASKLEN}" + del_ipv6_exclude_route "$NETWORK" "$NETMASKLEN" + i=`expr $i + 1` + done + fi if [ -n "$CISCO_IPV6_SPLIT_INC" ]; then i=0 while [ $i -lt $CISCO_IPV6_SPLIT_INC ] ; do -- 2.13.6