Set route to VPN gateway before configuring tunnel
[users/dwmw2/vpnc-scripts.git] / vpnc-script
1 #!/bin/sh
2 #* reason                       -- why this script was called, one of: pre-init connect disconnect
3 #* VPNGATEWAY                   -- vpn gateway address (always present)
4 #* TUNDEV                       -- tunnel device (always present)
5 #* INTERNAL_IP4_ADDRESS         -- address (always present)
6 #* INTERNAL_IP4_NETMASK         -- netmask (often unset)
7 #* INTERNAL_IP4_NETMASKLEN      -- netmask length (often unset)
8 #* INTERNAL_IP4_NETADDR         -- address of network (only present if netmask is set)
9 #* INTERNAL_IP4_DNS             -- list of dns serverss
10 #* INTERNAL_IP4_NBNS            -- list of wins servers
11 #* CISCO_DEF_DOMAIN             -- default domain name
12 #* CISCO_BANNER                 -- banner from server
13 #* CISCO_SPLIT_INC              -- number of networks in split-network-list
14 #* CISCO_SPLIT_INC_%d_ADDR      -- network address
15 #* CISCO_SPLIT_INC_%d_MASK      -- subnet mask (for example: 255.255.255.0)
16 #* CISCO_SPLIT_INC_%d_MASKLEN   -- subnet masklen (for example: 24)
17 #* CISCO_SPLIT_INC_%d_PROTOCOL  -- protocol (often just 0)
18 #* CISCO_SPLIT_INC_%d_SPORT     -- source port (often just 0)
19 #* CISCO_SPLIT_INC_%d_DPORT     -- destination port (often just 0)
20
21 # FIXMEs:
22
23 # Section A: route handling
24
25 # 1) The 3 values CISCO_SPLIT_INC_%d_PROTOCOL/SPORT/DPORT are currently being ignored
26 #   In order to use them, we'll probably need os specific solutions
27 #   * Linux: iptables -t mangle -I PREROUTING <conditions> -j ROUTE --oif $TUNDEV
28 #       This would be an *alternative* to changing the routes (and thus 2) and 3)
29 #       shouldn't be relevant at all)
30 # 2) There are two different functions to set routes: generic routes and the
31 #   default route. Why isn't the defaultroute handled via the generic route case?
32 # 3) In the split tunnel case, all routes but the default route might get replaced
33 #   without getting restored later. We should explicitely check and save them just
34 #   like the defaultroute
35 # 4) Replies to a dhcp-server should never be sent into the tunnel
36
37 # Section B: Split DNS handling
38
39 # 1) Maybe dnsmasq can do something like that
40 # 2) Parse dns packets going out via tunnel and redirect them to original dns-server
41
42 #env | sort
43 #set -x
44
45 # =========== script (variable) setup ====================================
46
47 PATH=/sbin:/usr/sbin:$PATH
48
49 OS="`uname -s`"
50
51 DEFAULT_ROUTE_FILE=/var/run/vpnc/defaultroute
52 RESOLV_CONF_BACKUP=/var/run/vpnc/resolv.conf-backup
53 SCRIPTNAME=`basename $0`
54
55 # some systems, eg. Darwin & FreeBSD, prune /var/run on boot
56 if [ ! -d "/var/run/vpnc" ]; then
57         mkdir -p /var/run/vpnc
58 fi
59
60 # stupid SunOS: no blubber in /usr/local/bin ... (on stdout)
61 IPROUTE="`which ip | grep '^/' 2> /dev/null`"
62
63 if [ "$OS" = "Linux" ]; then
64         ifconfig_syntax_ptp="pointopoint"
65         route_syntax_gw="gw"
66         route_syntax_del="del"
67         route_syntax_netmask="netmask"
68 else
69         ifconfig_syntax_ptp=""
70         route_syntax_gw=""
71         route_syntax_del="delete"
72         route_syntax_netmask="-netmask"
73 fi
74 if [ "$OS" = "SunOS" ]; then
75     route_syntax_interface="-interface"
76     route_syntax_plumb="plumb"
77 else
78     route_syntax_interface=""
79     route_syntax_plumb=""
80 fi
81
82 if [ -x /sbin/resolvconf ]; then # Optional tool on Debian, Ubuntu, Gentoo
83         MODIFYRESOLVCONF=modify_resolvconf_manager
84         RESTORERESOLVCONF=restore_resolvconf_manager
85 elif [ -x /sbin/modify_resolvconf ]; then # Mandatory tool on Suse earlier than 11.1
86         MODIFYRESOLVCONF=modify_resolvconf_suse
87         RESTORERESOLVCONF=restore_resolvconf_suse
88 else # Generic for any OS
89         MODIFYRESOLVCONF=modify_resolvconf_generic
90         RESTORERESOLVCONF=restore_resolvconf_generic
91 fi
92
93 # =========== tunnel interface handling ====================================
94
95 do_ifconfig() {
96         if [ -n "$INTERNAL_IP4_MTU" ]; then
97                 MTU=$INTERNAL_IP4_MTU
98         elif [ -n "$IPROUTE" ]; then
99                 MTU=$(($($IPROUTE route get "$VPNGATEWAY" | sed -ne 's/^.*mtu \([[:digit:]]\+\).*$/\1/p') - 88))
100         else
101                 MTU=1412
102         fi
103
104         # Point to point interface require a netmask of 255.255.255.255 on some systems
105         ifconfig "$TUNDEV" inet "$INTERNAL_IP4_ADDRESS" $ifconfig_syntax_ptp "$INTERNAL_IP4_ADDRESS" netmask 255.255.255.255 mtu ${MTU} up
106
107         if [ -n "$INTERNAL_IP4_NETMASK" ]; then
108                 set_network_route $INTERNAL_IP4_NETADDR $INTERNAL_IP4_NETMASK $INTERNAL_IP4_NETMASKLEN
109         fi
110
111         # If the netmask is provided, it contains the address _and_ netmask
112         if [ -n "$IPROUTE" ]; then
113             if [ -n "$INTERNAL_IP6_NETMASK" ]; then
114                 $IPROUTE -6 addr add $INTERNAL_IP6_NETMASK dev $TUNDEV
115             elif [ -n "$INTERNAL_IP6_ADDRESS" ]; then
116                 $IPROUTE -6 addr add $INTERNAL_IP6_ADDRESS/128 dev $TUNDEV
117             fi
118         else
119             if [ -n "$INTERNAL_IP6_ADDRESS" ]; then
120                 ifconfig "$TUNDEV" inet6 $route_syntax_plumb $INTERNAL_IP6_ADDRESS/128 $ifconfig_syntax_ptp $INTERNAL_IP6_ADDRESS mtu $MTU up
121             fi
122         fi
123 }
124
125 destroy_tun_device() {
126         case "$OS" in
127         NetBSD|FreeBSD) # and probably others...
128                 ifconfig "$TUNDEV" destroy
129                 ;;
130         SunOS)
131                 if [ -n "$INTERNAL_IP6_ADDRESS" ]; then
132                     ifconfig "$TUNDEV" inet6 unplumb
133                 fi
134                 ;;
135         esac
136 }
137
138 # =========== route handling ====================================
139
140 if [ -n "$IPROUTE" ]; then
141         fix_ip_get_output () {
142                 sed 's/cache//;s/metric \?[0-9]\+ [0-9]\+//g;s/hoplimit [0-9]\+//g'
143         }
144
145         set_vpngateway_route() {
146                 $IPROUTE route add `$IPROUTE route get "$VPNGATEWAY" | fix_ip_get_output`
147                 $IPROUTE route flush cache
148         }
149
150         del_vpngateway_route() {
151                 $IPROUTE route $route_syntax_del "$VPNGATEWAY"
152                 $IPROUTE route flush cache
153         }
154
155         set_default_route() {
156                 $IPROUTE route | grep '^default' | fix_ip_get_output > "$DEFAULT_ROUTE_FILE"
157                 $IPROUTE route replace default dev "$TUNDEV"
158                 $IPROUTE route flush cache
159         }
160
161         set_network_route() {
162                 NETWORK="$1"
163                 NETMASK="$2"
164                 NETMASKLEN="$3"
165                 $IPROUTE route replace "$NETWORK/$NETMASKLEN" dev "$TUNDEV"
166                 $IPROUTE route flush cache
167         }
168
169         reset_default_route() {
170                 if [ -s "$DEFAULT_ROUTE_FILE" ]; then
171                         $IPROUTE route replace `cat "$DEFAULT_ROUTE_FILE"`
172                         $IPROUTE route flush cache
173                         rm -f -- "$DEFAULT_ROUTE_FILE"
174                 fi
175         }
176
177         del_network_route() {
178                 NETWORK="$1"
179                 NETMASK="$2"
180                 NETMASKLEN="$3"
181                 $IPROUTE route $route_syntax_del "$NETWORK/$NETMASKLEN" dev "$TUNDEV"
182                 $IPROUTE route flush cache
183         }
184
185         set_ipv6_default_route() {
186                 # We don't save/restore IPv6 default route; just add a higher-priority one.
187                 $IPROUTE -6 route add default dev "$TUNDEV" metric 1
188                 $IPROUTE -6 route flush cache
189         }
190
191         set_ipv6_network_route() {
192                 NETWORK="$1"
193                 NETMASKLEN="$2"
194                 $IPROUTE -6 route replace "$NETWORK/$NETMASKLEN" dev "$TUNDEV"
195                 $IPROUTE route flush cache
196         }
197
198         reset_ipv6_default_route() {
199                 $IPROUTE -6 route del default dev "$TUNDEV"
200                 $IPROUTE route flush cache
201         }
202
203         del_ipv6_network_route() {
204                 NETWORK="$1"
205                 NETMASKLEN="$2"
206                 $IPROUTE -6 route del "$NETWORK/$NETMASKLEN" dev "$TUNDEV"
207                 $IPROUTE -6 route flush cache
208         }
209 else # use route command
210         get_default_gw() {
211                 # isn't -n supposed to give --numeric output?
212                 # apperently not...
213                 # Get rid of lines containing IPv6 addresses (':')
214                 netstat -r -n | awk '/:/ { next; } /^(default|0\.0\.0\.0)/ { print $2; }'
215         }
216
217         set_vpngateway_route() {
218                 route add -host "$VPNGATEWAY" $route_syntax_gw "`get_default_gw`"
219         }
220
221         del_vpngateway_route() {
222                 vpngw_route=`netstat -r -n | awk '/:/ { next; } /^(default|0\.0\.0\.0)/ { print $2; }'`
223                 route $route_syntax_del -host "$VPNGATEWAY" $route_syntax_gw "$vpngw_route"
224         }
225
226         set_default_route() {
227                 DEFAULTGW="`get_default_gw`"
228                 echo "$DEFAULTGW" > "$DEFAULT_ROUTE_FILE"
229                 route $route_syntax_del default $route_syntax_gw "`get_default_gw`"
230                 route add default $route_syntax_gw "$INTERNAL_IP4_ADDRESS" $route_syntax_interface
231         }
232
233         set_network_route() {
234                 NETWORK="$1"
235                 NETMASK="$2"
236                 NETMASKLEN="$3"
237                 del_network_route "$NETWORK" "$NETMASK" "$NETMASKLEN"
238                 route add -net "$NETWORK" $route_syntax_netmask "$NETMASK" $route_syntax_gw "$INTERNAL_IP4_ADDRESS" $route_syntax_interface
239         }
240
241         reset_default_route() {
242                 if [ -s "$DEFAULT_ROUTE_FILE" ]; then
243                         route $route_syntax_del default $route_syntax_gw "`get_default_gw`" $route_syntax_interface
244                         route add default $route_syntax_gw `cat "$DEFAULT_ROUTE_FILE"`
245                         rm -f -- "$DEFAULT_ROUTE_FILE"
246                 fi
247         }
248
249         del_network_route() {
250                 case "$OS" in
251                 Linux|NetBSD|Darwin|SunOS) # and probably others...
252                         # routes are deleted automatically on device shutdown
253                         return
254                         ;;
255                 esac
256                 NETWORK="$1"
257                 NETMASK="$2"
258                 NETMASKLEN="$3"
259                 route $route_syntax_del -net "$NETWORK" $route_syntax_netmask "$NETMASK" $route_syntax_gw "$INTERNAL_IP4_ADDRESS"
260         }
261
262         set_ipv6_default_route() {
263                 route add -inet6 default "$INTERNAL_IP6_ADDRESS" $route_syntax_interface
264         }
265
266         set_ipv6_network_route() {
267                 NETWORK="$1"
268                 NETMASK="$2"
269                 route add -inet6 -net "$NETWORK/$NETMASK" "$INTERNAL_IP6_ADDRESS" $route_syntax_interface
270                 :
271         }
272
273         reset_ipv6_default_route() {
274                 route $route_syntax_del -inet6 default "$INTERNAL_IP6_ADDRESS"
275                 :
276         }
277
278         del_ipv6_network_route() {
279                 NETWORK="$1"
280                 NETMASK="$2"
281                 route $route_syntax_del -inet6 "$NETWORK/$NETMASK" "$INTERNAL_IP6_ADDRESS"
282                 :
283         }
284
285 fi
286
287 # =========== resolv.conf handling ====================================
288
289 # =========== resolv.conf handling for any OS =========================
290
291 modify_resolvconf_generic() {
292         grep '^#@VPNC_GENERATED@' /etc/resolv.conf > /dev/null 2>&1 || cp -- /etc/resolv.conf "$RESOLV_CONF_BACKUP"
293         NEW_RESOLVCONF="#@VPNC_GENERATED@ -- this file is generated by vpnc
294 # and will be overwritten by vpnc
295 # as long as the above mark is intact"
296
297         # Remember the original value of CISCO_DEF_DOMAIN we need it later
298         CISCO_DEF_DOMAIN_ORIG="$CISCO_DEF_DOMAIN"
299         # Don't step on INTERNAL_IP4_DNS value, use a temporary variable
300         INTERNAL_IP4_DNS_TEMP="$INTERNAL_IP4_DNS"
301         exec 6< "$RESOLV_CONF_BACKUP"
302         while read LINE <&6 ; do
303                 case "$LINE" in
304                         nameserver*)
305                                 if [ -n "$INTERNAL_IP4_DNS_TEMP" ]; then
306                                         read ONE_NAMESERVER INTERNAL_IP4_DNS_TEMP <<-EOF
307         $INTERNAL_IP4_DNS_TEMP
308 EOF
309                                         LINE="nameserver $ONE_NAMESERVER"
310                                 else
311                                         LINE=""
312                                 fi
313                                 ;;
314                         search*)
315                                 if [ -n "$CISCO_DEF_DOMAIN" ]; then
316                                         LINE="$LINE $CISCO_DEF_DOMAIN"
317                                         CISCO_DEF_DOMAIN=""
318                                 fi
319                                 ;;
320                         domain*)
321                                 if [ -n "$CISCO_DEF_DOMAIN" ]; then
322                                         LINE="domain $CISCO_DEF_DOMAIN"
323                                         CISCO_DEF_DOMAIN=""
324                                 fi
325                                 ;;
326                 esac
327                 NEW_RESOLVCONF="$NEW_RESOLVCONF
328 $LINE"
329         done
330         exec 6<&-
331
332         for i in $INTERNAL_IP4_DNS_TEMP ; do
333                 NEW_RESOLVCONF="$NEW_RESOLVCONF
334 nameserver $i"
335         done
336         if [ -n "$CISCO_DEF_DOMAIN" ]; then
337                 NEW_RESOLVCONF="$NEW_RESOLVCONF
338 search $CISCO_DEF_DOMAIN"
339         fi
340         echo "$NEW_RESOLVCONF" > /etc/resolv.conf
341
342         if [ "$OS" = "Darwin" ]; then
343                 case "`uname -r`" in
344                         # Skip for pre-10.4 systems
345                         4.*|5.*|6.*|7.*)
346                                 ;;
347                         # 10.4 and later require use of scutil for DNS to work properly
348                         *)
349                                 OVERRIDE_PRIMARY=""
350                                 if [ -n "$CISCO_SPLIT_INC" ]; then
351                                         if [ $CISCO_SPLIT_INC -lt 1 ]; then
352                                                 # Must override for correct default route
353                                                 # Cannot use multiple DNS matching in this case
354                                                 OVERRIDE_PRIMARY='d.add OverridePrimary # 1'
355                                         fi
356                                 fi
357                                 # Uncomment the following if/fi pair to use multiple
358                                 # DNS matching when available.  When multiple DNS matching
359                                 # is present, anything reading the /etc/resolv.conf file
360                                 # directly will probably not work as intended.
361                                 #if [ -z "$CISCO_DEF_DOMAIN_ORIG" ]; then
362                                         # Cannot use multiple DNS matching without a domain
363                                         OVERRIDE_PRIMARY='d.add OverridePrimary # 1'
364                                 #fi
365                                 scutil >/dev/null 2>&1 <<-EOF
366                                         open
367                                         d.init
368                                         d.add ServerAddresses * $INTERNAL_IP4_DNS
369                                         set State:/Network/Service/$TUNDEV/DNS
370                                         d.init
371                                         # next line overrides the default gateway and breaks split routing
372                                         # d.add Router $INTERNAL_IP4_ADDRESS
373                                         d.add Addresses * $INTERNAL_IP4_ADDRESS
374                                         d.add SubnetMasks * 255.255.255.255
375                                         d.add InterfaceName $TUNDEV
376                                         $OVERRIDE_PRIMARY
377                                         set State:/Network/Service/$TUNDEV/IPv4
378                                         close
379                                 EOF
380                                 if [ -n "$CISCO_DEF_DOMAIN_ORIG" ]; then
381                                         scutil >/dev/null 2>&1 <<-EOF
382                                                 open
383                                                 get State:/Network/Service/$TUNDEV/DNS
384                                                 d.add DomainName $CISCO_DEF_DOMAIN_ORIG
385                                                 d.add SearchDomains * $CISCO_DEF_DOMAIN_ORIG
386                                                 d.add SupplementalMatchDomains * $CISCO_DEF_DOMAIN_ORIG
387                                                 set State:/Network/Service/$TUNDEV/DNS
388                                                 close
389                                         EOF
390                                 fi
391                                 ;;
392                 esac
393         fi
394 }
395
396 restore_resolvconf_generic() {
397         if [ ! -e "$RESOLV_CONF_BACKUP" ]; then
398                 return
399         fi
400         grep '^#@VPNC_GENERATED@' /etc/resolv.conf > /dev/null 2>&1 && cat "$RESOLV_CONF_BACKUP" > /etc/resolv.conf
401         rm -f -- "$RESOLV_CONF_BACKUP"
402
403         if [ "$OS" = "Darwin" ]; then
404                 case "`uname -r`" in
405                         # Skip for pre-10.4 systems
406                         4.*|5.*|6.*|7.*)
407                                 ;;
408                         # 10.4 and later require use of scutil for DNS to work properly
409                         *)
410                                 scutil >/dev/null 2>&1 <<-EOF
411                                         open
412                                         remove State:/Network/Service/$TUNDEV/IPv4
413                                         remove State:/Network/Service/$TUNDEV/DNS
414                                         close
415                                 EOF
416                                 ;;
417                 esac
418         fi
419 }
420 # === resolv.conf handling via /sbin/modify_resolvconf (Suse) =====================
421
422 # Suse provides a script that modifies resolv.conf. Use it because it will
423 # restart/reload all other services that care about it (e.g. lwresd).
424
425 modify_resolvconf_suse()
426 {
427         FULL_SCRIPTNAME=`readlink -f $0`
428         RESOLV_OPTS=''
429         test -n "$INTERNAL_IP4_DNS" && RESOLV_OPTS="-n \"$INTERNAL_IP4_DNS\""
430         test -n "$CISCO_DEF_DOMAIN" && RESOLV_OPTS="$RESOLV_OPTS -d $CISCO_DEF_DOMAIN"
431         test -n "$RESOLV_OPTS" && eval /sbin/modify_resolvconf modify -s $SCRIPTNAME -p $SCRIPTNAME -f $FULL_SCRIPTNAME -e $TUNDEV $RESOLV_OPTS -t \"This file was created by $SCRIPTNAME\"
432 }
433
434 # Restore resolv.conf to old contents on Suse
435 restore_resolvconf_suse()
436 {
437         FULL_SCRIPTNAME=`readlink -f $0`
438         /sbin/modify_resolvconf restore -s vpnc -p $SCRIPTNAME -f $FULL_SCRIPTNAME -e $TUNDEV
439 }
440
441 # === resolv.conf handling via /sbin/resolvconf (Debian, Ubuntu, Gentoo)) =========
442
443 modify_resolvconf_manager() {
444         NEW_RESOLVCONF=""
445         for i in $INTERNAL_IP4_DNS; do
446                 NEW_RESOLVCONF="$NEW_RESOLVCONF
447 nameserver $i"
448         done
449         if [ -n "$CISCO_DEF_DOMAIN" ]; then
450                 NEW_RESOLVCONF="$NEW_RESOLVCONF
451 domain $CISCO_DEF_DOMAIN"
452         fi
453         echo "$NEW_RESOLVCONF" | /sbin/resolvconf -a $TUNDEV
454 }
455
456 restore_resolvconf_manager() {
457         /sbin/resolvconf -d $TUNDEV
458 }
459
460 # ========= Toplevel state handling  =======================================
461
462 kernel_is_2_6_or_above() {
463         case `uname -r` in
464                 1.*|2.[012345]*)
465                         return 1
466                         ;;
467                 *)
468                         return 0
469                         ;;
470         esac
471 }
472
473 do_pre_init() {
474         if [ "$OS" = "Linux" ]; then
475                 if (exec 6<> /dev/net/tun) > /dev/null 2>&1 ; then
476                         :
477                 else # can't open /dev/net/tun
478                         test -e /proc/sys/kernel/modprobe && `cat /proc/sys/kernel/modprobe` tun 2>/dev/null
479                         # fix for broken devfs in kernel 2.6.x
480                         if [ "`readlink /dev/net/tun`" = misc/net/tun \
481                                 -a ! -e /dev/net/misc/net/tun -a -e /dev/misc/net/tun ] ; then
482                                 ln -sf /dev/misc/net/tun /dev/net/tun
483                         fi
484                         # make sure tun device exists
485                         if [ ! -e /dev/net/tun ]; then
486                                 mkdir -p /dev/net
487                                 mknod -m 0640 /dev/net/tun c 10 200
488                         fi
489                         # workaround for a possible latency caused by udev, sleep max. 10s
490                         if kernel_is_2_6_or_above ; then
491                                 for x in `seq 100` ; do
492                                         (exec 6<> /dev/net/tun) > /dev/null 2>&1 && break;
493                                         sleep 0.1
494                                 done
495                         fi
496                 fi
497         elif [ "$OS" = "FreeBSD" ]; then
498                 if [ ! -e /dev/tun ]; then
499                         kldload if_tun
500                 fi
501         elif [ "$OS" = "GNU/kFreeBSD" ]; then
502                 if [ ! -e /dev/tun ]; then
503                         kldload if_tun
504                 fi
505         elif [ "$OS" = "NetBSD" ]; then
506                 :
507         elif [ "$OS" = "OpenBSD" ]; then
508                 :
509         elif [ "$OS" = "SunOS" ]; then
510                 :
511         elif [ "$OS" = "Darwin" ]; then
512                 :
513         fi
514 }
515
516 do_connect() {
517         if [ -n "$CISCO_BANNER" ]; then
518                 echo "Connect Banner:"
519                 echo "$CISCO_BANNER" | while read LINE ; do echo "|" "$LINE" ; done
520                 echo
521         fi
522
523         set_vpngateway_route
524         do_ifconfig
525         if [ -n "$CISCO_SPLIT_INC" ]; then
526                 i=0
527                 while [ $i -lt $CISCO_SPLIT_INC ] ; do
528                         eval NETWORK="\${CISCO_SPLIT_INC_${i}_ADDR}"
529                         eval NETMASK="\${CISCO_SPLIT_INC_${i}_MASK}"
530                         eval NETMASKLEN="\${CISCO_SPLIT_INC_${i}_MASKLEN}"
531                         if [ $NETWORK != "0.0.0.0" ]; then
532                                 set_network_route "$NETWORK" "$NETMASK" "$NETMASKLEN"
533                         else
534                                 set_default_route
535                         fi
536                         i=`expr $i + 1`
537                 done
538                 for i in $INTERNAL_IP4_DNS ; do
539                         if ! echo "$i" | grep : >/dev/null; then
540                                 set_network_route "$i" "255.255.255.255" "32"
541                         fi
542                 done
543         elif [ -n "$INTERNAL_IP4_ADDRESS" ]; then
544                 set_default_route
545         fi
546         if [ -n "$CISCO_IPV6_SPLIT_INC" ]; then
547                 i=0
548                 while [ $i -lt $CISCO_IPV6_SPLIT_INC ] ; do
549                         eval NETWORK="\${CISCO_IPV6_SPLIT_INC_${i}_ADDR}"
550                         eval NETMASKLEN="\${CISCO_IPV6_SPLIT_INC_${i}_MASKLEN}"
551                         if [ $NETMASKLEN -lt 128 ]; then
552                                 set_ipv6_network_route "$NETWORK" "$NETMASKLEN"
553                         else
554                                 set_ipv6_default_route
555                         fi
556                         i=`expr $i + 1`
557                 done
558                 for i in $INTERNAL_IP4_DNS ; do
559                         if echo "$i" | grep : >/dev/null; then
560                                 set_ipv6_network_route "$i" "128"
561                         fi
562                 done
563         elif [ -n "$INTERNAL_IP6_NETMASK" -o -n "$INTERNAL_IP6_ADDRESS" ]; then
564                 set_ipv6_default_route
565         fi
566
567         if [ -n "$INTERNAL_IP4_DNS" ]; then
568                 $MODIFYRESOLVCONF
569         fi
570 }
571
572 do_disconnect() {
573         if [ -n "$CISCO_SPLIT_INC" ]; then
574                 i=0
575                 while [ $i -lt $CISCO_SPLIT_INC ] ; do
576                         eval NETWORK="\${CISCO_SPLIT_INC_${i}_ADDR}"
577                         eval NETMASK="\${CISCO_SPLIT_INC_${i}_MASK}"
578                         eval NETMASKLEN="\${CISCO_SPLIT_INC_${i}_MASKLEN}"
579                         if [ $NETWORK != "0.0.0.0" ]; then
580                                 # FIXME: This doesn't restore previously overwritten
581                                 #        routes.
582                                 del_network_route "$NETWORK" "$NETMASK" "$NETMASKLEN"
583                         else
584                                 reset_default_route
585                         fi
586                         i=`expr $i + 1`
587                 done
588                 for i in $INTERNAL_IP4_DNS ; do
589                         del_network_route "$i" "255.255.255.255" "32"
590                 done
591         else
592                 reset_default_route
593         fi
594         if [ -n "$CISCO_IPV6_SPLIT_INC" ]; then
595                 i=0
596                 while [ $i -lt $CISCO_IPV6_SPLIT_INC ] ; do
597                         eval NETWORK="\${CISCO_IPV6_SPLIT_INC_${i}_ADDR}"
598                         eval NETMASKLEN="\${CISCO_IPV6_SPLIT_INC_${i}_MASKLEN}"
599                         if [ $NETMASKLEN -eq 0 ]; then
600                                 reset_ipv6_default_route
601                         else
602                                 del_ipv6_network_route "$NETWORK" "$NETMASKLEN"
603                         fi
604                         i=`expr $i + 1`
605                 done
606                 for i in $INTERNAL_IP6_DNS ; do
607                         del_ipv6_network_route "$i" "128"
608                 done
609         elif [ -n "$INTERNAL_IP6_NETMASK" -o -n "$INTERNAL_IP6_ADDRESS" ]; then
610                 reset_ipv6_default_route
611         fi
612
613         del_vpngateway_route
614
615         if [ -n "$INTERNAL_IP4_DNS" ]; then
616                 $RESTORERESOLVCONF
617         fi
618         destroy_tun_device
619 }
620
621 #### Main
622
623 if [ -z "$reason" ]; then
624         echo "this script must be called from vpnc" 1>&2
625         exit 1
626 fi
627
628 case "$reason" in
629         pre-init)
630                 do_pre_init
631                 ;;
632         connect)
633                 do_connect
634                 ;;
635         disconnect)
636                 do_disconnect
637                 ;;
638         *)
639                 echo "unknown reason '$reason'. Maybe vpnc-script is out of date" 1>&2
640                 exit 1
641                 ;;
642 esac
643
644 exit 0