source: projects/initscripts/tags/initscripts-8.91.0/sysconfig/network-scripts/network-functions-ipv6 @ 2576

Revision 2576, 38.9 KB checked in by daisuke, 13 years ago (diff)

tagging as initscripts-8.91.0

Line 
1#!/bin/sh
2#
3# network-functions-ipv6
4#
5# Taken from: network-functions-ipv6
6# (P) & (C) 1997-2005 by Peter Bieringer <pb@bieringer.de>
7#
8#  You will find more information on the initscripts-ipv6 homepage at
9#   http://www.deepspace6.net/projects/initscripts-ipv6.html
10#
11# Version: 2006-08-03
12#
13#
14
15
16
17
18
19
20##### Logging function
21#  $1: <message> : message string
22#  $2: [stdout|stderr].[err|warn[ing]|inf[o]|notice] : log level with optional channel, default is "stdout.notice"
23#      [syslog.[facility.].err|warn[ing]|inf[o]|notice : syslog channel, default is "syslog.user.notice"
24#  $3: <function name> : name of function which calls this log function, can be empty using ""
25# return code: 0=ok 1=argument error  3=major problem
26ipv6_log() {
27        local message="$1"
28        local level="$2"
29        local name="$3"
30
31        if [ -z "$message" ]; then
32                echo $"ERROR: [ipv6_log] Missing 'message' (arg 1)" >/dev/stderr
33                return 1
34        fi
35        if [ -z "$level" ]; then
36                local level="stdout.notice"
37        fi
38
39
40        # Map loglevel now
41        local fn=1
42        local fnawk="print \$$fn"
43        local t="`echo $level | awk -F. "{ $fnawk }"`"
44
45        # Check channel, if given
46        case $t in
47            'stdout'|'stderr'|'syslog')
48                local channel="$t"
49                local fn=$[ $fn + 1 ]
50                ;;
51            *)
52                local channel="stdout"
53                ;;
54        esac
55
56        # Check syslog facilty, if given
57        if [ "$channel" = "syslog" ]; then
58                local fnawk="print \$$fn"
59                local t="`echo $level | awk -F. "{ $fnawk }"`"
60                case $t in
61                    'local0'|'local1'|'local2'|'local3'|'local4'|'local5'|'local6'|'local7'|'daemon')
62                        local facility="$t"
63                        local fn=$[ $fn + 1 ]
64                        ;;
65                    *)
66                        local facility="user"
67                        ;;
68                esac
69        fi
70
71        local fnawk="print \$$fn"
72        local t="`echo $level | awk -F. "{ $fnawk }"`"
73
74        # Map priority
75        [ "$t" = "inf"      ] && local t="info"
76        [ "$t" = "deb"      ] && local t="debug"
77        [ "$t" = "warning"  ] && local t="warn"
78        [ "$t" = "error"    ] && local t="err"
79        [ "$t" = "critical" ] && local t="crit"
80
81        # Check priority, if given
82        case $t in
83            'info'|'debug'|'notice'|'warn'|'err'|'crit')
84                        local priority="$t"
85                        local fn=$[ $fn + 1 ]
86                        ;;
87                    *)
88                        local priority="notice"
89                        ;;
90        esac
91
92        local fnawk="print \$$fn"
93        local t="`echo $level | awk -F. "{ $fnawk }"`"
94        if [ -n "$t" ]; then
95                echo $"ERROR: [ipv6_log] Loglevel isn't valid '$level' (arg 2)" >/dev/stderr
96                return 1
97        fi
98
99        # Generate function text
100        if [ -z "$name" ]; then
101                local txt_name=""
102        else
103                local txt_name="[$name]"
104        fi
105
106        # Log message
107        case $channel in
108            'stdout'|'stderr')
109                # Generate level text
110                case $priority in
111                    'debug')
112                        local txt_level=$"DEBUG    "
113                        ;;
114                    'err')
115                        local txt_level=$"ERROR    "
116                        ;;
117                    'warn')
118                        local txt_level=$"WARN     "
119                        ;;
120                    'crit')
121                        local txt_level=$"CRITICAL "
122                        ;;
123                    'info')
124                        local txt_level=$"INFO     "
125                        ;;
126                    'notice')
127                        local txt_level=$"NOTICE   "
128                        ;;
129                esac
130
131                [ -n "$txt_name" ] && local txt_name="$txt_name "
132
133                if [ "$channel" = "stderr" ]; then
134                        echo "$txt_level: ${txt_name}${message}" >/dev/stderr
135                elif [ "$channel" = "stdout" ]; then
136                        echo "$txt_level: ${txt_name}${message}"
137                fi
138                ;;
139            'syslog')
140                # note: logger resides in /usr/bin, but not used by default
141                if ! [ -x logger ]; then
142                        echo $"ERROR: [ipv6_log] Syslog is chosen, but binary 'logger' doesn't exist or isn't executable" >/dev/stderr
143                        return 3
144                fi
145                if [ -z "$txt_name" ]; then
146                        logger -p $facility.$priority $message
147                else
148                        logger -p $facility.$priority -t "$txt_name" "$message"
149                fi
150                ;;
151            *)
152                echo $"ERROR: [ipv6_log] Cannot log to channel '$channel'" >/dev/stderr
153                return 3
154                ;;
155        esac
156
157        return 0
158}
159
160
161###### Beginning of main code here, always executed on "source|. /etc/sysconfig/network-scripts/network-functions-ipv6"
162
163
164
165###### End of main code here
166
167
168##### Test for IPv6 capabilites
169# $1: (optional) testflag: currently supported: "testonly" (do not load a module)
170# return code: 0=ok 2=IPv6 test fails
171ipv6_test() {
172        local fn="ipv6_test"
173
174        local testflag=$1
175
176        if ! [ -f /proc/net/if_inet6 ]; then
177                if [ "$testflag" = "testonly" ]; then
178                        return 2
179                else
180                        modprobe ipv6
181
182                        if ! [ -f /proc/net/if_inet6 ]; then
183                                #       ipv6_log $"Kernel is not compiled with IPv6 support" crit $fn
184                                return 2
185                        fi
186                fi
187        fi
188
189        if ! [ -d /proc/sys/net/ipv6/conf/ ]; then
190                return 2
191        fi
192
193        if ! [ -x /sbin/ip ]; then
194                ipv6_log $"Utility 'ip' (package: iproute) doesn't exist or isn't executable - stop" crit $fn
195                return 2
196        fi
197
198        if ! [ -x /sbin/sysctl ]; then
199                ipv6_log $"Utility 'sysctl' (package: procps) doesn't exist or isn't executable - stop" crit $fn
200                return 2
201        fi
202
203        return 0
204}
205
206
207##### Get version of this function library
208# stdout: <version number YYYYMMDD>
209getversion_ipv6_functions() {
210        local version_ipv6_functions="`cat /etc/sysconfig/network-scripts/network-functions-ipv6 | LC_ALL=C grep "^# Version:" | awk '{ print $3 }' | sed 's/-//g' | sed 's/[A-Za-z]*$//g'`"
211        echo $version_ipv6_functions
212        return 0
213}
214
215
216##### Wrapper for used binaries
217## ifconfig
218# $*: <arguments...>
219# return code: result of execution
220ipv6_exec_ifconfig() {
221        local fn="ipv6_exec_ifconfig"
222
223        local options=$*
224
225        LC_ALL=C /sbin/ifconfig $options
226
227        return $?
228}
229
230
231## route
232#  $*: <arguments...>
233# return code: result of execution
234ipv6_exec_route() {
235        local options=$*
236
237        LC_ALL=C /sbin/route $options
238
239        return $?
240}
241
242
243## ip
244#  $*: <arguments...>
245# return code: result of execution
246ipv6_exec_ip() {
247        local options=$*
248
249        LC_ALL=C /sbin/ip $options
250
251        return $?
252}
253
254
255## sysctl
256#  $*: <arguments...>
257# return code: result of execution
258ipv6_exec_sysctl() {
259        local options=$*
260
261        LC_ALL=C /sbin/sysctl -e $options
262
263        return $?
264}
265
266
267##### Control IPv6 forwarding
268
269# Control IPv6 forwarding
270#  $1: yes|no|on|off : control value
271#  $2: [<interface>] : (optional), if not given, global IPv6 forwarding is set [OBSOLETE]
272# return code: 0=ok 1=argument error 2=IPv6 test fails
273ipv6_control_forwarding() {
274        local fn="ipv6_control_forwarding"
275
276        local fw_control=$1
277        local fw_device=$2              # maybe empty
278
279        if [ -z "$fw_control" ]; then
280                ipv6_log $"Missing parameter 'forwarding control' (arg 1)" err $fn
281                return 1
282        fi
283
284        if ! [ "$fw_control" = "yes" -o "$fw_control" = "no" -o "$fw_control" = "on" -o "$fw_control" = "off" ]; then
285                ipv6_log $"Forwarding control parameter isn't valid '$fw_control' (arg 1)" err $fn
286                return 1
287        fi
288
289        ipv6_test || return 2
290
291        if [ "$fw_control" = "yes" -o "$fw_control" = "on" ]; then
292                local status=1
293        else
294                local status=0
295        fi
296
297        # Global control? (if no device is given)
298        if [ -z "$fw_device" ]; then
299                ipv6_exec_sysctl -w net.ipv6.conf.all.forwarding=$status >/dev/null 2>&1
300        fi
301
302        # Per device control (not implemented in kernel)
303        if [ -n "$fw_device" ]; then
304                ipv6_log $"IPv6 forwarding per device cannot be controlled via sysctl - use netfilter6 instead" warn $fn
305        fi
306
307        return 0
308}
309
310
311##### Static IPv6 route configuration
312
313# Set static IPv6 route
314#  $1: <IPv6 network> : to route
315#  $2: <IPv6 gateway> : over which $1 should be routed (if "::", gw will be skipped)
316#  $3: [<Interface>] : (optional)
317# return code: 0=ok 1=argument error 2=IPv6 test fails 3=major problem adding route
318ipv6_add_route() {
319        local fn="ipv6_add_route"
320
321        local networkipv6=$1
322        local gatewayipv6=$2
323        local device=$3         # maybe empty
324
325        if [ -z "$networkipv6" ]; then
326                ipv6_log $"Missing parameter 'IPv6-network' (arg 1)" err $fn
327                return 1
328        fi
329
330        if [ -z "$gatewayipv6" ]; then
331                ipv6_log $"Missing parameter 'IPv6-gateway' (arg 2)" err $fn
332                return 1
333        fi
334
335        ipv6_test || return 2
336
337        ipv6_test_ipv6_addr_valid $networkipv6 || return 2
338        ipv6_test_ipv6_addr_valid $gatewayipv6 || return 2
339
340        if [ -z "$device" ]; then
341                local returntxt="`ipv6_exec_ip -6 route add $networkipv6 via $gatewayipv6 metric 1 2>&1`"
342        else
343                if [ "$gatewayipv6" = "::" ]; then
344                        local returntxt="`ipv6_exec_ip -6 route add $networkipv6 dev $device metric 1 2>&1`"
345                else
346                        local returntxt="`ipv6_exec_ip -6 route add $networkipv6 via $gatewayipv6 dev $device metric 1 2>&1`"
347                fi
348        fi
349
350        if [ -n "$returntxt" ]; then
351                if echo $returntxt | LC_ALL=C grep -q "File exists"; then
352                        # Netlink: "File exists"
353                        true
354                elif echo $returntxt | LC_ALL=C grep -q "No route to host"; then
355                        # Netlink: "No route to host"
356                        ipv6_log $"'No route to host' adding route '$networkipv6' via gateway '$gatewayipv6' through device '$device'" warn $fn
357                        return 3
358                else
359                        ipv6_log $"Unknown error" warn $fn
360                        return 3
361                fi
362        fi
363
364        return 0
365}
366
367
368# Delete a static IPv6 route
369#  $1: <IPv6 network> : to route
370#  $2: <IPv6 gateway> : over which $1 should be routed (if "::", gw will be skipped)
371#  $3: [<Interface>] : (optional)
372# return code: 0=ok 1=argument error 2=IPv6 test fails 3=major problem adding route
373ipv6_del_route() {
374        local fn="ipv6_del_route"
375
376        local networkipv6=$1
377        local gatewayipv6=$2
378        local device=$3         # maybe empty
379
380        if [ -z "$networkipv6" ]; then
381                ipv6_log $"Missing parameter 'IPv6-network' (arg 1)" err $fn
382                return 1
383        fi
384
385        if [ -z "$gatewayipv6" ]; then
386                ipv6_log $"Missing parameter 'IPv6-gateway' (arg 2)" err $fn
387                return 1
388        fi
389
390        ipv6_test testonly || return 2
391
392        # Test, whether given IPv6 address is valid
393        ipv6_test_ipv6_addr_valid $networkipv6 || return 1
394        ipv6_test_ipv6_addr_valid $gatewayipv6 || return 1
395
396        if [ -z "$device" ]; then
397                ipv6_exec_ip -6 route del $networkipv6 via $gatewayipv6
398                local result=$?
399        else
400                if [ "$gatewayipv6" = "::" ]; then
401                        ipv6_exec_ip -6 route del $networkipv6 dev $device
402                        local result=$?
403                else
404                        ipv6_exec_ip -6 route del $networkipv6 via $gatewayipv6 dev $device
405                        local result=$?
406                fi
407        fi
408
409        if [ $result -eq 2 ]; then
410                # Netlink: "No such process"
411                true
412        elif [ $result -ne 0 ]; then
413                return 3
414        fi
415
416        return 0
417}
418
419
420# Delete all static IPv6 routes through a given interface
421#  $1: <Interface>
422#  $2: [<Gateway>] : to match (optional)
423# return code: 0=ok 1=argument error 2=IPv6 test fails
424ipv6_cleanup_routes() {
425        local fn="ipv6_cleanup_routes"
426
427        local device=$1
428        local gatewaymatch=$2
429
430        if [ -z "$device" ]; then
431                ipv6_log $"Missing parameter 'device' (arg 1)" err $fn
432                return 1
433        fi
434
435        ipv6_test testonly || return 2
436
437        if [ -n "$gatewaymatch" ]; then
438                # Get all IPv6 routes (except default link-local and multicast) through given interface via a given gateway and remove them
439                ipv6_exec_ip -6 route show dev $device via $gatewaymatch | LC_ALL=C grep -v -w expires | LC_ALL=C egrep -v "^fe80::/64|^ff00::/8" | while read ipv6net dummy; do
440                        ipv6_del_route $ipv6net $gatewaymatch $device
441                done
442        else
443                # Get all IPv6 routes (except default link-local and multicast) through given interface and remove them
444                ipv6_exec_ip -6 route show dev $device | LC_ALL=C grep -v -w expires | LC_ALL=C egrep -v "^fe80::/64|^ff00::/8" | while read ipv6net dummy; do
445                        ipv6_del_route $ipv6net :: $device
446                done
447        fi
448
449        return 0
450}
451
452
453##### automatic tunneling configuration
454
455## Configure automatic tunneling up
456# return code: 0=ok 2=IPv6 test fails 3=major problem
457ipv6_enable_autotunnel() {
458        local fn="ipv6_enable_autotunnel"
459
460        ipv6_test || return 2
461
462        # enable IPv6-over-IPv4 tunnels
463        if ipv6_test_device_status sit0; then
464                true
465        else
466                # bring up basic tunnel device
467                ipv6_exec_ip link set sit0 up
468
469                        if ! ipv6_test_device_status sit0; then
470                                ipv6_log $"Tunnel device 'sit0' enabling didn't work" err $fn
471                                return 3
472                        fi
473
474                # Set sysctls proper (regardless "default")
475                ipv6_exec_sysctl -w net.ipv6.conf.sit0.forwarding=1 >/dev/null 2>&1
476                ipv6_exec_sysctl -w net.ipv6.conf.sit0.accept_ra=0 >/dev/null 2>&1
477                ipv6_exec_sysctl -w net.ipv6.conf.sit0.accept_redirects=0 >/dev/null 2>&1
478        fi
479
480        return 0
481}
482
483
484## Configure automatic tunneling down
485# return code: 0=ok 2=IPv6 test fails 3=major problem
486ipv6_disable_autotunnel() {
487        local fn="ipv6_disable_autotunnel"
488
489        ipv6_test testonly || return 2
490
491        if ipv6_test_device_status sit0; then
492
493                # disable IPv6-over-IPv4 tunnels (if a tunnel is no longer up)
494                if ipv6_exec_ip -6 route show dev sit0 | LC_ALL=C grep -w via | awk '{ print $3 }' | LC_ALL=C grep -v -q "^::$"; then
495                        # still existing routes, skip shutdown of sit0
496                        true
497                elif ipv6_exec_ip -6 -o addr show dev sit0 | awk '{ print $4 }' | LC_ALL=C grep -v -q '^::'; then
498                        # still existing IPv6 addresses, skip shutdown of sit0
499                        true
500                else
501                        # take down basic tunnel device
502                        ipv6_exec_sysctl -w net.ipv6.conf.sit0.forwarding=0 >/dev/null 2>&1
503                        ipv6_exec_sysctl -w net.ipv6.conf.sit0.accept_ra=0 >/dev/null 2>&1
504                        ipv6_exec_sysctl -w net.ipv6.conf.sit0.accept_redirects=0 >/dev/null 2>&1
505
506                        ipv6_exec_ip link set sit0 down
507
508                                if ipv6_test_device_status sit0; then
509                                        ipv6_log $"Tunnel device 'sit0' is still up" err $fn
510                                        return 3
511                                fi
512                fi
513        fi
514
515        return 0
516}
517
518
519##### Interface configuration
520
521## Add an IPv6 address for given interface
522#  $1: <Interface>
523#  $2: <IPv6 address[/prefix]>
524# return code: 0=ok 1=argument error 2=IPv6 test fails 3=major problem
525ipv6_add_addr_on_device() {
526        local fn="ipv6_add_addr_on_device"
527
528        local device=$1
529        local address=$2
530
531        if [ -z "$device" ]; then
532                ipv6_log $"Missing parameter 'device' (arg 1)" err $fn
533                return 1
534        fi
535
536        if [ -z "$address" ]; then
537                ipv6_log $"Missing parameter 'IPv6-address' (arg 2)" err $fn
538                return 1
539        fi
540
541        ipv6_test || return 2
542
543        ipv6_test_ipv6_addr_valid $address || return 1
544
545        ipv6_test_device_status $device
546        local result=$?
547
548        if [ "$result" = "0" ]; then
549                true
550        elif [ "$result" != "11" ]; then
551                ipv6_log $"Device '$device' doesn't exist" err $fn
552                return 3
553        else
554                ipv6_exec_ip link set $device up
555
556                        if ! ipv6_test_device_status $device; then
557                                ipv6_log $"Device '$device' enabling didn't work" err $fn
558                                return 3
559                        fi
560        fi
561
562        # Extract address parts
563        local prefixlength_implicit="`echo $address | awk -F/ '{ print $2 }'`"
564        local address_implicit="`echo $address | awk -F/ '{ print $1 }'`"
565
566        # Check prefix length and using '64' as default
567        if [ -z "$prefixlength_implicit" ]; then
568                local prefixlength_implicit="64"
569                local address="$address_implicit/$prefixlength_implicit"
570        fi
571
572        ipv6_exec_ip -6 addr add $address dev $device
573        local result=$?
574
575        if [ $result -eq 2 ]; then
576                return 0
577        elif [ $result -ne 0 ]; then
578                ipv6_log $"Cannot add IPv6 address '$address' on dev '$device'" err $fn
579                return 3
580        fi
581
582        return 0
583}
584
585
586## Remove all IPv6 routes and addresses on given interface (cleanup to prevent kernel crashes)
587#  $1: <Interface>
588# return code: 0=ok 1=argument error 2=IPv6 test fails 3=major problem
589ipv6_cleanup_device() {
590        local fn="ipv6_cleanup_device"
591
592        local device=$1
593
594        if [ -z "$device" ]; then
595                ipv6_log $"Missing parameter 'device' (arg 1)" err $fn
596                return 1
597        fi
598
599        ipv6_test testonly || return 2
600
601        # Remove all IPv6 routes through this device (but not "lo")
602        if [ "$device" != "lo" ]; then
603                ipv6_exec_ip -6 route flush dev $device scope global >/dev/null 2>&1
604                ipv6_exec_ip -6 route flush dev $device scope site   >/dev/null 2>&1
605        fi
606
607        # Remove all IPv6 addresses on this interface
608        ipv6_exec_ip -6 addr flush dev $device scope global >/dev/null 2>&1
609        ipv6_exec_ip -6 addr flush dev $device scope site   >/dev/null 2>&1
610
611        return 0
612}
613
614
615## Remove all IPv6 6to4 related routes and addresses on given interface
616#  $1: <Interface>
617# return code: 0=ok 1=argument error 2=IPv6 test fails 3=major problem
618ipv6_cleanup_6to4_device() {
619        local fn="ipv6_cleanup_6to4_device"
620
621        local device=$1
622
623        if [ -z "$device" ]; then
624                ipv6_log $"Missing parameter 'device' (arg 1)" err $fn
625                return 1
626        fi
627
628        ipv6_test testonly || return 2
629
630        # Cleanup 6to4 addresses on this device
631        ipv6_exec_ip -6 addr show dev $dev scope global permanent | LC_ALL=C grep -w inet6 | awk '{ print $2}' | LC_ALL=C grep "^2002:" | while read addr; do
632                ipv6_del_addr_on_device ${dev} ${addr}
633        done
634
635        # Get all IPv6 routes through given interface related to 6to4 and remove them
636        ipv6_exec_ip -6 route show dev $device | LC_ALL=C grep "^2002:" | while read ipv6net dummy; do
637                ipv6_del_route $ipv6net :: $device
638        done
639
640        return 0
641}
642
643
644## Remove an IPv6 address on given interface
645#  $1: <Interface>
646#  $2: <IPv6 address>
647# return code: 0=ok 1=argument error 2=IPv6 test fails 3=major problem
648ipv6_del_addr_on_device() {
649        local fn="ipv6_del_addr_on_device"
650
651        local device=$1
652        local address=$2
653
654        if [ -z "$device" ]; then
655                ipv6_log $"Missing parameter 'device' (arg 1)" err $fn
656                return 1
657        fi
658
659        if [ -z "$address" ]; then
660                ipv6_log $"Missing parameter 'IPv6 address' (arg 2)" err $fn
661                return 1
662        fi
663
664        ipv6_test testonly || return 2
665
666        ipv6_test_ipv6_addr_valid $address || return 1
667
668        # Extract address parts
669        local prefixlength_implicit="`echo $address | awk -F/ '{ print $2 }'`"
670        local address_implicit="`echo $address | awk -F/ '{ print $1 }'`"
671
672        # Check prefix length and using '64' as default
673        if [ -z "$prefixlength_implicit" ]; then
674                local prefixlength_implicit="64"
675                local address="$address_implicit/$prefixlength_implicit"
676        fi
677
678        ipv6_exec_ip -6 addr del $address dev $device
679        local result=$?
680
681        if [ $result -eq 2 ]; then
682                return 0
683        elif [ $result -ne 0 ]; then
684                ipv6_log $"Cannot delete IPv6 address '$address' on dev '$device'" err $fn
685                return 3
686        fi
687
688        return 0
689}
690
691
692##### Some address test functions
693
694## Test a given IPv6 address for validity
695#  $1: <IPv6 address>
696#  $2: [quiet] : (optional) don't display error message
697# return code: 0=ok 1=argument error 10=not valid
698ipv6_test_ipv6_addr_valid() {
699        local fn="ipv6_test_ipv6_addr_valid"
700
701        local testipv6addr_valid=$1
702        local modequiet=$2
703
704        if [ -z "$testipv6addr_valid" ]; then
705                return 1
706        fi
707        if [ -n "$modequiet" ]; then
708                if [ "$modequiet" != "quiet" ]; then
709                        ipv6_log $"Parameter '$modequiet' for 'quiet' mode is not valid (arg 2)" err $fn
710                        return 1
711                fi
712        fi
713
714        # Extract parts
715        local prefixlength_implicit="`echo $testipv6addr_valid | awk -F/ '{ print $2 }'`"
716        local address_implicit="`echo $testipv6addr_valid | awk -F/ '{ print $1 }'`"
717
718                # Test for a valid format
719                if ! echo "$address_implicit" | LC_ALL=C egrep -q '^[[:xdigit:]:.]*$'; then
720                        if [ "$modequiet" != "quiet" ]; then
721                                ipv6_log $"Given IPv6 address '$testipv6addr_valid' is not valid" err $fn
722                        fi
723                        return 10
724                fi
725
726        # Test for prefix length
727        if [ -z "$prefixlength_implicit" ]; then
728                if echo "$testipv6addr_valid" | LC_ALL=C grep "/$"; then
729                        # Trailing "/", but no value
730                        if [ "$modequiet" != "quiet" ]; then
731                                ipv6_log $"Missing prefix length for given address '$testipv6addr_valid'" err $fn
732                        fi
733                        return 10
734                else
735                        return 0
736                fi
737        elif [ $prefixlength_implicit -lt 0 -o $prefixlength_implicit -gt 128 ]; then
738                if [ "$modequiet" != "quiet" ]; then
739                        ipv6_log $"On given address '$testipv6addr_valid' the prefix length is out of range (valid: 0-128)" err $fn
740                fi
741                return 10
742        fi
743
744        return 0
745}
746
747
748## Test a given IPv4 address for validity
749#  $1: <IPv4 address>
750#  $2: [quiet] : (optional) don't display error message
751# return code: 0=ok 1=argument error 10=not valid
752ipv6_test_ipv4_addr_valid() {
753        local fn="ipv6_test_ipv4_addr_valid"
754
755        local testipv4addr_valid=$1
756        local modequiet=$2
757
758        if [ -z "$testipv4addr_valid" ]; then
759                return 1
760        fi
761        if [ -n "$modequiet" ]; then
762                if [ "$modequiet" != "quiet" ]; then
763                        ipv6_log $"Parameter '$modequiet' for 'quiet' mode is not valid (arg 2)" err $fn
764                        return 1
765                fi
766        fi
767
768        # Test for a valid format
769        if echo "$testipv4addr_valid" | LC_ALL=C egrep -q -v '^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$'; then
770                if [ "$modequiet" != "quiet" ]; then
771                        ipv6_log $"Given IPv4 address '$testipv4addr_valid' has no proper format" err $fn
772                fi
773                return 10
774        fi
775
776        # Test for valid IPv4 address parts
777        local number1="`echo $testipv4addr_valid | awk -F. '{ print $1 }'`"
778        local number2="`echo $testipv4addr_valid | awk -F. '{ print $2 }'`"
779        local number3="`echo $testipv4addr_valid | awk -F. '{ print $3 }'`"
780        local number4="`echo $testipv4addr_valid | awk -F. '{ print $4 }'`"
781        local c=1
782        for number in "$number1" "$number2" "$number3" "$number4"; do
783                if [ $number -lt 0 -o $number -gt 255 ]; then
784                        if [ "$modequiet" != "quiet" ]; then
785                                ipv6_log $"Part $c of given IPv4 address '$testipv4addr_valid' is out of range" err $fn
786                        fi
787                        return 10
788                fi
789                local c=$[ $c + 1 ]
790        done
791
792        return 0
793}
794
795
796## Test a given IPv4 address for not a private but unicast one
797#  $1: <IPv4 address>
798# return code: 0=ok 1=argument error 10=private or not unicast
799ipv6_test_ipv4_addr_global_usable() {
800        local fn="ipv6_test_ipv4_addr_global_usable"
801
802        local testipv4addr_globalusable=$1
803
804
805        if [ -z "$testipv4addr_globalusable" ]; then
806                return 1
807        fi
808
809        # Test for a globally usable IPv4 address now
810                # test 0.0.0.0/8
811                /bin/ipcalc --network $testipv4addr_globalusable 255.0.0.0   | LC_ALL=C grep -q "NETWORK=0\.0\.0\.0"     && return 10
812                # test 10.0.0.0/8     (RFC 1918 / private)
813                /bin/ipcalc --network $testipv4addr_globalusable 255.0.0.0   | LC_ALL=C grep -q "NETWORK=10\.0\.0\.0"    && return 10
814                # test 127.0.0.0/8    (loopback)
815                /bin/ipcalc --network $testipv4addr_globalusable 255.0.0.0   | LC_ALL=C grep -q "NETWORK=127\.0\.0\.0"   && return 10
816                # test 169.254.0.0/16 (APIPA / DHCP link local)
817                /bin/ipcalc --network $testipv4addr_globalusable 255.255.0.0 | LC_ALL=C grep -q "NETWORK=169\.254\.0\.0" && return 10
818                # test 172.16.0.0/12  (RFC 1918 / private)
819                /bin/ipcalc --network $testipv4addr_globalusable 255.240.0.0 | LC_ALL=C grep -q "NETWORK=172\.16\.0\.0"  && return 10
820                # test 192.168.0.0/16 (RFC 1918 / private)
821                /bin/ipcalc --network $testipv4addr_globalusable 255.255.0.0 | LC_ALL=C grep -q "NETWORK=192\.168\.0\.0" && return 10
822                # test 224.0.0.0/3    (multicast and reserved, broadcast)
823                /bin/ipcalc --network $testipv4addr_globalusable 224.0.0.0   | LC_ALL=C grep -q "NETWORK=224\.0\.0\.0"   && return 10
824
825        return 0
826}
827
828
829## Test a given device for status
830#  $1: <Interface>
831# return code: 0=ok 1=argument error 10=not exists 11=down
832ipv6_test_device_status() {
833        local fn="ipv6_test_device_status"
834
835        local device=$1
836
837        if [ -z "$device" ]; then
838                ipv6_log $"Missing parameter 'device' (arg 1)" err $fn
839                return 1
840        fi
841
842        # Test if device exists
843        if [ ! -d "/sys/class/net/${device}" ]; then
844                # not exists
845                return 10
846        fi
847
848        # Test if device is up
849        if ipv6_exec_ip link show dev $device 2>/dev/null | LC_ALL=C grep -q "UP"; then
850                # up
851                return 0
852        else
853                # down
854                return 11
855        fi
856}
857
858
859## Create 6to4 prefix
860#  $1: <IPv4 address>
861# stdout: <6to4address>
862# return code: 0=ok 1=argument error
863ipv6_create_6to4_prefix() {
864        local fn="ipv6_create_6to4_prefix"
865
866        local ipv4addr=$1
867
868        if [ -z "$ipv4addr" ]; then
869                ipv6_log $"Missing parameter 'IPv4 address' (arg 1)" stderr.err $fn
870        fi
871
872        local major1="`echo $ipv4addr | awk -F. '{ print $1 }'`"
873        local minor1="`echo $ipv4addr | awk -F. '{ print $2 }'`"
874        local major2="`echo $ipv4addr | awk -F. '{ print $3 }'`"
875        local minor2="`echo $ipv4addr | awk -F. '{ print $4 }'`"
876
877        if [ -z "$major1" -o -z "$minor1" -o -z "$major2" -o -z "$minor2" ]; then
878                return 1
879        fi
880
881        if [ $major1 -eq 0 ]; then
882                local block1="`printf "%x" $minor1`"
883        else
884                local block1="`printf "%x%02x" $major1 $minor1`"
885        fi
886        if [ $major2 -eq 0 ]; then
887                local block2="`printf "%x" $minor2`"
888        else
889                local block2="`printf "%x%02x" $major2 $minor2`"
890        fi
891
892        local prefix6to4="2002:$block1:$block2"
893
894        echo "$prefix6to4"
895        return 0
896}
897
898
899## Check and create 6to4 tunnel relay address
900#  $1: <IPv4 address|IPv6to4 address>
901# stdout: <tunnel relay address>
902# return code: 0=ok 1=argument error
903ipv6_create_6to4_relay_address() {
904        local fn="ipv6_create_6to4_relay_address"
905
906        local addr=$1
907
908        if [ -z "$addr" ]; then
909                ipv6_log $"Missing parameter 'address' (arg 1)" stderr.err $fn
910                return 1
911        fi
912
913        # Check
914        if ipv6_test_ipv4_addr_valid $addr quiet; then
915                # ok, a IPv4 one
916                if ipv6_test_ipv4_addr_global_usable $addr; then
917                        # IPv4 globally usable
918                        local ipv6to4_relay="::$addr"
919                else
920                        ipv6_log $"Given address '$addr' is not a global IPv4 one (arg 1)" stderr.err $fn
921                        return 1
922                fi
923        else
924                ipv6_log $"Given address '$addr' is not a valid IPv4 one (arg 1)" stderr.err $fn
925                return 1
926        fi
927
928        echo "$ipv6to4_relay"
929
930        return 0
931}
932
933
934##### 6to4 tunneling setup
935
936## Configure 6to4 tunneling up
937#  $1: <Interface> : only "tun6to4" is supported
938#  $2: <IPv4 address> : global IPv4 address of interface (will be used to generate 6to4 prefix)
939#  $3: [<IPv6 suffix>] : for 6to4 prefix (optional, default is "::1")
940#  $4: [<MTU>] : MTU of tunnel device (optional, default is automatic)
941#  $5: [<IPv4 address>] : local IPv4 address of tunnel interface (required in case of 6to4 behind NAT)
942# return code: 0=ok 1=argument error 2=IPv6 test fails 3=major problem
943ipv6_add_6to4_tunnel() {
944        local fn="ipv6_add_6to4_tunnel"
945
946        local device=$1
947        local globalipv4=$2
948        local globalipv6to4suffix=$3
949        local mtu=$4
950        local localipv4=$5
951
952        if [ -z "$device" ]; then
953                ipv6_log $"Missing parameter 'device' (arg 1)" err $fn
954                return 1
955        fi
956
957        if [ -z "$globalipv4" ]; then
958                ipv6_log $"Missing parameter 'global IPv4 address' (arg 2)" err $fn
959                return 1
960        fi
961
962        # Check device
963        if [ "$device" != "tun6to4" ]; then
964                ipv6_log $"Given device '$device' is not supported (arg 1)" err $fn
965                return 1
966        fi
967
968        # Copy global IPv4 address to local if last one is not given
969        if [ -z "$localipv4" ]; then
970                localipv4="$globalipv4"
971        fi
972
973        ipv6_test || return 2
974
975        # Generate 6to4 address
976        local prefix6to4="`ipv6_create_6to4_prefix $globalipv4`"
977        if [ $? -ne 0 -o -z "$prefix6to4" ]; then
978                return 3
979        fi
980
981        if [ -z "$globalipv6to4suffix" ]; then
982                local address6to4="${prefix6to4}::1/16"
983        else
984                local address6to4="${prefix6to4}::${globalipv6to4suffix}/16"
985        fi
986
987                ipv6_add_tunnel_device tun6to4 0.0.0.0 $address6to4 $localipv4
988                if [ $? -ne 0 ]; then
989                        local retval=3
990                else
991                        local retval=0
992                fi
993
994                # Add unspecific unreachable route for local 6to4 address space
995                ipv6_exec_ip route add unreach ${prefix6to4}::/48
996
997        # Set MTU, if given
998        if [ -n "$mtu" ]; then
999                ipv6_set_mtu $device $mtu
1000        fi
1001
1002        return $retval
1003}
1004
1005
1006## Configure all 6to4 tunneling down
1007#  $1: <Interface> : only "tun6to4" is supported
1008# return code: 0=ok 1=argument error 2=IPv6 test fails 3=major problem
1009ipv6_cleanup_6to4_tunnels() {
1010        local fn="ipv6_cleanup_6to4_tunnels"
1011
1012        local device=$1
1013
1014        if [ -z "$device" ]; then
1015                ipv6_log $"Missing parameter 'device' (arg 1)" err $fn
1016                return 1
1017        fi
1018
1019        # Check device
1020        if [ "$device" != "tun6to4" ]; then
1021                ipv6_log $"Given device '$device' is not supported (arg 1)" err $fn
1022                return 1
1023        fi
1024
1025        ipv6_test testonly || return 2
1026
1027                ipv6_del_tunnel_device tun6to4
1028
1029                # Remove all unspecific unreachable routes for local 6to4 address space
1030                ipv6_exec_ip -6 route | LC_ALL=C grep "^unreachable 2002:" | LC_ALL=C grep "/48 dev lo" | while read token net rest; do
1031                        ipv6_exec_ip route del unreach $net
1032                done
1033
1034        return 0
1035}
1036
1037
1038## Configure 6to4 tunneling down
1039#  $1: <Interface> : only "tun6to4" is supported
1040#  $2: <IPv4 address> : global address of local interface
1041# return code: 0=ok 1=argument error 2=IPv6 test fails 3=major problem
1042ipv6_del_6to4_tunnel() {
1043        local fn="ipv6_del_6to4_tunnel"
1044
1045        local device=$1
1046        local localipv4=$2
1047
1048        if [ -z "$device" ]; then
1049                ipv6_log $"Missing parameter 'device' (arg 1)" err $fn
1050                return 1
1051        fi
1052
1053        if [ -z "$localipv4" ]; then
1054                ipv6_log $"Missing parameter 'local IPv4 address' (arg 2)" err $fn
1055                return 1
1056        fi
1057
1058        # Check device
1059        if [ "$device" != "tun6to4" ]; then
1060                ipv6_log $"Given device '$device' is not supported (arg 1)" err $fn
1061                return 1
1062        fi
1063
1064        ipv6_test || return 2
1065
1066                ipv6_del_tunnel_device tun6to4
1067                local retval=$?
1068
1069                # Remove unspecific unreachable route for local 6to4 address space
1070                ipv6_exec_ip route del unreach ${prefix6to4}::/48
1071
1072        return $retval
1073}
1074
1075
1076## Configure a static tunnel device up
1077#  $1: <Interface>
1078#  $2: <IPv4 address> : of foreign tunnel
1079#  $3: [<IPv6 address>] : local one of a P-t-P tunnel (optional)
1080#  $4: [<IPv4 address>] : local one of tunnel (optional)
1081# return code: 0=ok 1=argument error 2=IPv6 test fails 3=major problem
1082ipv6_add_tunnel_device() {
1083        local fn="ipv6_add_tunnel_device"
1084
1085        local device=$1
1086        local addressipv4tunnel=$2
1087        local addressipv6local=$3
1088        local addressipv4tunnellocal=$4
1089
1090        if [ -z "$device" ]; then
1091                ipv6_log $"Missing parameter 'device' (arg 1)" err $fn
1092                return 1
1093        fi
1094
1095        if [ -z "$addressipv4tunnel" ]; then
1096                ipv6_log $"Missing parameter 'IPv4-tunnel address' (arg 2)" err $fn
1097                return 1
1098        fi
1099
1100        if [ -z "$addressipv4tunnellocal" ]; then
1101                local addressipv4tunnellocal="any"
1102        fi
1103
1104        ipv6_test || return 2
1105
1106        if ! ipv6_test_device_status $device; then
1107                local ttldefault="`ipv6_exec_sysctl net.ipv4.ip_default_ttl | awk '{ print $3 }'`"
1108                if [ -z "$ttldefault" ]; then
1109                        local ttldefault=64
1110                fi
1111
1112                # Test whether remote IPv4 address was already applied to another tunnel
1113                if [ "$addressipv4tunnel" != "0.0.0.0" -a "$addressipv4tunnel" != "any" ]; then
1114                        ipv6_exec_ip tunnel show remote $addressipv4tunnel 2>/dev/null | LC_ALL=C grep -w "ipv6/ip" | while IFS=":" read devnew rest; do
1115                                if [ "$devnew" != "$device" ]; then
1116                                        ipv6_log $"Given remote address '$addressipv4tunnel' on tunnel device '$device' is already configured on device '$devnew'" err $fn
1117                                        return 3
1118                                fi
1119                        done
1120                fi
1121
1122                ipv6_exec_ip tunnel add $device mode sit ttl $ttldefault remote $addressipv4tunnel local $addressipv4tunnellocal
1123                if [ $? -ne 0 ]; then
1124                        return 3
1125                fi
1126
1127                # Test, whether "ip tunnel show" reports valid content
1128                if ! ipv6_exec_ip tunnel show $device 2>/dev/null | LC_ALL=C grep -q -w "remote"; then
1129                        ipv6_log $"Tunnel device '$device' creation didn't work" err $fn
1130                        return 3
1131                fi
1132
1133                ipv6_exec_ip link set $device up
1134
1135                if ! ipv6_test_device_status $device; then
1136                        ipv6_log $"Tunnel device '$device' bringing up didn't work" err $fn
1137                        return 3
1138                fi
1139
1140                # Set sysctls proper (regardless "default")
1141                ipv6_exec_sysctl -w net.ipv6.conf.$device.forwarding=1 >/dev/null 2>&1
1142                ipv6_exec_sysctl -w net.ipv6.conf.$device.accept_ra=0 >/dev/null 2>&1
1143                ipv6_exec_sysctl -w net.ipv6.conf.$device.accept_redirects=0 >/dev/null 2>&1
1144
1145                if [ -n "$addressipv6local" ]; then
1146                        # Setup P-t-P address
1147                        ipv6_add_addr_on_device $device $addressipv6local
1148                        if [ $? -ne 0 ]; then
1149                                return 3
1150                        fi
1151                fi
1152        else
1153                false
1154        fi
1155
1156        return 0
1157}
1158
1159
1160## Configure a static tunnel device down
1161#  $1: <Interface>
1162# return code: 0=ok 1=argument error 2=IPv6 test fails 3=major problem
1163ipv6_del_tunnel_device() {
1164        local fn="ipv6_del_tunnel_device"
1165
1166        local device=$1
1167
1168        if [ -z "$device" ]; then
1169                ipv6_log $"Missing parameter 'device' (arg 1)" err $fn
1170                return 1
1171        fi
1172
1173        ipv6_test testonly || return 2
1174
1175        if ipv6_test_device_status $device; then
1176                ipv6_cleanup_device $device
1177        else
1178                if [ "$device" != "sit0" ]; then
1179                        false
1180                fi
1181        fi
1182
1183        if [ "$device" != "sit0" ]; then
1184                if ipv6_exec_ip tunnel show $device 2>/dev/null | LC_ALL=C grep -q -w "ipv6/ip"; then
1185                        ipv6_exec_ip tunnel del $device
1186
1187                                if ipv6_test_device_status $device; then
1188                                        return 3
1189                                fi
1190                else
1191                        false
1192                fi
1193        fi
1194
1195        return 0
1196}
1197
1198
1199## Cleanup all dedicated tunnel devices
1200ipv6_cleanup_tunnel_devices() {
1201        local fn="ipv6_cleanup_tunnel_devices"
1202
1203        ipv6_test testonly || return 2
1204
1205        # Find still existing tunnel devices and shutdown and delete them
1206
1207        ipv6_exec_ip tunnel show | LC_ALL=C grep -w "ipv6/ip" | awk -F: '{ print $1 }' | while read device; do
1208                ipv6_del_tunnel_device $device
1209        done
1210
1211        return 0
1212}
1213
1214
1215## Get address of a dedicated tunnel
1216#  $1: <Interface>
1217#  $2: local|remote : local or remote address
1218# stdout: <IPv4 address> if available
1219# return code: 0=ok 1=argument error 2=IPv6 test fails 3=major problem
1220ipv6_get_ipv4addr_of_tunnel() {
1221        local fn="ipv6_get_local_ipv4_of_tunnel"
1222
1223        local device=$1
1224        local selection=$2
1225
1226        if [ -z "$device" ]; then
1227                ipv6_log $"Missing parameter 'device' (arg 1)" stderr.err $fn
1228                return 1
1229        fi
1230
1231        if [ -z "$selection" ]; then
1232                ipv6_log $"Missing parameter 'selection' (arg 2)" stderr.err $fn
1233                return 1
1234        fi
1235        if [ "$selection" != "local" -a "$selection" != "remote" ]; then
1236                ipv6_log $"Unsupported selection '$selection' specified (arg 2)" stderr.err $fn
1237                return 1
1238        fi
1239
1240        ipv6_test testonly || return 2
1241
1242        ipv6_test_device_status $device
1243
1244        if [ $? != 0 -a $? != 11 ]; then
1245                # Device doesn't exist
1246                return 3
1247        fi
1248
1249        # Device exists, retrieve address
1250        if [ "$selection" = "local" ]; then
1251                local tunnel_local_ipv4addr="`ipv6_exec_ip tunnel show $device | awk '{ print $6 }'`"
1252        elif [ "$selection" = "remote" ]; then
1253                local tunnel_local_ipv4addr="`ipv6_exec_ip tunnel show $device | awk '{ print $4 }'`"
1254        fi
1255
1256        if [ $? != 0 ]; then
1257                return 3
1258        fi
1259
1260        if [ "$tunnel_local_ipv4addr" = "any" ]; then
1261                local tunnel_local_ipv4addr="0.0.0.0"
1262        fi
1263
1264        echo "$tunnel_local_ipv4addr"
1265
1266        return 0
1267}
1268
1269
1270## Get IPv4 address of a device
1271#  $1: <Interface>
1272# stdout: <IPv4 address> if available
1273# return code: 0=ok 1=argument error 2=IPv6 test fails 3=major problem (more than one IPv4 address applied)
1274ipv6_get_ipv4addr_of_device() {
1275        local fn="ipv6_get_ipv4addr_of_device"
1276
1277        local device=$1
1278
1279        if [ -z "$device" ]; then
1280                ipv6_log $"Missing parameter 'device' (arg 1)" stderr.err $fn
1281                return 1
1282        fi
1283
1284        ipv6_test_device_status $device
1285
1286        if [ $? != 0 -a $? != 11 ]; then
1287                # Device doesn't exist
1288                return 3
1289        fi
1290
1291        # Device exists, retrieve the first address only
1292        local ipv4addr="`ipv6_exec_ip -o -4 addr show dev $device | awk '{ print $4 }' | awk -F/ '{ print $1; exit }'`"
1293
1294        if [ $? != 0 ]; then
1295                return 3
1296        fi
1297
1298        if [ "$ipv4addr" = "any" ]; then
1299                local ipv4addr="0.0.0.0"
1300        fi
1301
1302        echo "$ipv4addr"
1303
1304        return 0
1305}
1306
1307
1308## Set IPv6 MTU for a device
1309#  $1: <Interface>
1310#  $2: <IPv6 MTU>
1311# return code: 0=ok 1=argument error 2=IPv6 test fails 3=major problem
1312ipv6_set_mtu() {
1313        local fn="ipv6_set_mtu"
1314
1315        local device=$1
1316        local ipv6_mtu=$2
1317
1318        if [ -z "$device" ]; then
1319                ipv6_log $"Missing parameter 'device' (arg 1)" err $fn
1320                return 1
1321        fi
1322
1323        if [ -z "$ipv6_mtu" ]; then
1324                ipv6_log $"Missing parameter 'IPv6 MTU' (arg 2)" err $fn
1325                return 1
1326        fi
1327
1328        # Check range
1329        if [ $ipv6_mtu -lt 1280 -o $ipv6_mtu -gt 65535 ]; then
1330                ipv6_log $"Given IPv6 MTU '$ipv6_mtu' is out of range" err $fn
1331                return 1
1332        fi
1333
1334        ipv6_test testonly || return 2
1335
1336        # Check whether key exists
1337        ipv6_exec_sysctl net.ipv6.conf.$device.mtu >/dev/null 2>&1
1338        if [ $? -ne 0 ]; then
1339                return 3
1340        fi
1341
1342        # Set value
1343        ipv6_exec_sysctl -w net.ipv6.conf.$device.mtu=$ipv6_mtu >/dev/null 2>&1
1344
1345        return 0
1346}
1347
1348
1349## Set a default route
1350#  $1: <IPv6 address> : gateway, can also contain scope suffix (device name), cause a warning if not matching with $2 (but will have precedence)
1351#  $2: <gateway device>: gateway device (optional in case of $1 is a global address or $1 contains scope suffix)
1352#  $3: <check device>: (optional) device to check scope and gateway device against (setup is skipped, if not matching)
1353# return code: 0=ok 1=argument error 2=IPv6 test fails 3=major problem
1354ipv6_set_default_route() {
1355        local fn="ipv6_set_default_route"
1356
1357        local address=$1
1358        local device=$2
1359        local device_check=$3
1360
1361        ipv6_test testonly || return 2
1362
1363        # Map the unspecified address to nothing
1364        if [ "$address" = "::" ]; then
1365                local address=""
1366        fi
1367
1368        if [ -n "$address" ]; then
1369                local addressgw=`echo $address | awk -F% '{ print $1 }'`
1370                local device_scope=`echo $address | awk -F% '{ print $2 }'`
1371
1372                if [ -z "$addressgw" ]; then
1373                        ipv6_log $"Given IPv6 default gateway '$address' is not in proper format" err $fn
1374                        return 3
1375                fi
1376
1377                # Scope device has precedence
1378                if [ -n "$device_scope" -a -n "$device" -a "$device_scope" != "$device" ]; then
1379                        ipv6_log $"Given IPv6 default gateway '$address' has scope '$device_scope' defined, given default gateway device '$device' will be not used" inf $fn
1380                        local device=""
1381                fi
1382
1383                # Link local addresses require a device
1384                if echo $addressgw | LC_ALL=C grep -qi "^fe80:"; then
1385                        if [ -z "$device_scope" ]; then
1386                                if [ -z "$device" ]; then
1387                                        ipv6_log $"Given IPv6 default gateway '$address' is link-local, but no scope or gateway device is specified" err $fn
1388                                        return 3
1389                                fi
1390                        fi
1391                fi
1392
1393                # Check whether the route belongs to the specific given interface
1394                if [ -n "$device_check" ]; then
1395                        # Check whether scope device matches given check device
1396                        if [ -n "$device_scope" -a "$device_check" != "$device_scope" ]; then
1397                                # scope device != specific given -> skip
1398                                return 0
1399                        elif [ -n "$device" -a "$device_check" != "$device" ]; then
1400                                # gateway device != specific given -> skip
1401                                return 0
1402                        fi
1403                fi
1404
1405                # Set device now, if not given
1406                if [ -z "$device" ]; then
1407                        local device="$device_scope"
1408                fi
1409
1410                if [ -z "$device" ]; then
1411                        # Note: this can cause a warning and a not installed route, if given address is not reachable on the link
1412                        ipv6_add_route ::/0 $addressgw
1413                else
1414                        ipv6_add_route ::/0 $addressgw $device
1415                fi
1416        elif [ -n "$device" ]; then
1417                # Check whether the route belongs to the specific given interface
1418                if [ -n "$device_check" -a "$device_check" != "$device" ]; then
1419                        # gateway device != specific given -> skip
1420                        return 0
1421                fi
1422
1423                ipv6_test_route_requires_next_hop $device
1424                local result=$?
1425
1426                if [ $result = 0 ]; then
1427                        ipv6_log $"Given IPv6 default device '$device' requires an explicit nexthop" err $fn
1428                        return 3
1429                elif [ $result != 10 ]; then
1430                        ipv6_log $"Given IPv6 default device '$device' doesn't exist or isn't up" err $fn
1431                        return 3
1432                fi
1433
1434                ipv6_add_route ::/0 :: $device
1435        else
1436                ipv6_log $"No parameters given to setup a default route" err $fn
1437                return 3
1438        fi
1439
1440        return 0
1441}
1442
1443
1444## Resolve need of explicit next hop for an interface
1445#  $1: <Interface>
1446# return code: 0=ok 1=argument error 2=IPv6 test fails 3=major problem 10=needs no explicit hop
1447ipv6_test_route_requires_next_hop() {
1448        local fn="ipv6_test_route_requires_next_hop"
1449
1450        local device=$1
1451
1452        if [ -z "$device" ]; then
1453                ipv6_log $"Missing parameter 'device' (arg 1)" err $fn
1454                return 1
1455        fi
1456
1457        ipv6_test testonly || return 2
1458
1459        ipv6_test_device_status $device
1460
1461        if [ $? != 0 ]; then
1462                return 3
1463        fi
1464
1465        if [ "$device" = "sit0" ]; then
1466                return 10
1467        fi
1468
1469        if ipv6_exec_ip -o link show $device 2>/dev/null |  LC_ALL=C grep -q "POINTOPOINT"; then
1470                return 10
1471        fi
1472
1473        return 0
1474}
1475
1476
1477## Trigger radvd
1478#  $1: up|down : device reason for triggering (coming up or going down)
1479#  $2: [startstop|restart|reload|SIGHUP] : triger mechanism (default is "SIGHUP")
1480#        "startstop" : reason=up -> start, reason=down -> stop
1481#  $3: [<filename>] : alternative pid file  [optional]
1482# return code: 0=ok 1=argument error 2=IPv6 test fails 3=major problem
1483ipv6_trigger_radvd() {
1484        local fn="ipv6_trigger_radvd"
1485
1486        local reason=$1
1487        local mechanism=$2
1488        local pidfile=$3
1489
1490        if [ -z "$reason" ]; then
1491                ipv6_log $"No reason given for sending trigger to radvd" err $fn
1492                return 1
1493        fi
1494
1495        if [ "$reason" != "up" -a "$reason" != "down" ]; then
1496                ipv6_log $"Unsupported reason '$reason' for sending trigger to radvd" err $fn
1497                return 1
1498        fi
1499
1500        if [ -z "$mechanism" ]; then
1501                # Take default
1502                local mechanism="SIGHUP"
1503        fi
1504
1505        if [ -z "$pidfile" ]; then
1506                local pidfile="/var/run/radvd/radvd.pid"
1507        fi
1508
1509        # Print message and select action
1510        case $mechanism in
1511            'startstop')
1512                case $reason in
1513                    up)
1514                        local action="start"
1515                        ;;
1516                    down)
1517                        local action="stop"
1518                        ;;
1519                esac
1520                ;;
1521            'reload'|'restart'|'SIGHUP')
1522                local action="$mechanism"
1523                ;;
1524            *)
1525                ipv6_log $"Unsupported mechanism '$mechanism' for sending trigger to radvd" err $fn
1526                return 3
1527                ;;
1528        esac
1529
1530        # PID file needed?
1531        if [ "$action" = "SIGHUP" ]; then
1532                if ! [ -f "$pidfile" ]; then
1533                        if [ "$reason" = "down" ]; then
1534                                # be quiet because triggering may have been disabled
1535                                true
1536                        else
1537                                ipv6_log $"Given pidfile '$pidfile' doesn't exist, cannot send trigger to radvd" err $fn
1538                        fi
1539                        return 3
1540                fi
1541
1542                # Get PID
1543                local pid="`cat $pidfile`"
1544                if [ -z "$pid" ]; then
1545                        # pidfile empty - strange
1546                        ipv6_log $"Pidfile '$pidfile' is empty, cannot send trigger to radvd" err $fn
1547                        return 3
1548                fi
1549        fi
1550
1551
1552        # Do action
1553        case $action in
1554            'SIGHUP')
1555                kill -HUP $pid
1556                ;;
1557            'reload'|'restart'|'stop'|'start')
1558                        if ! /sbin/chkconfig --list radvd >/dev/null 2>&1; then
1559                                if [ "$reason" = "down" ]; then
1560                                        # be quiet because triggering may have been disabled
1561                                        true
1562                                else
1563                                        ipv6_log $"radvd not (properly) installed, triggering failed" err $fn
1564                                fi
1565                                return 3
1566                        else
1567                                /sbin/service radvd $action >/dev/null 2>&1
1568                        fi
1569                ;;
1570            *)
1571                # Normally not reached, "action" is set above to proper value
1572                ;;
1573        esac
1574
1575        return 0
1576}
Note: See TracBrowser for help on using the repository browser.