Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed
# network-functions-ipv6## Taken from: network-functions-ipv6# (P) & (C) 1997-2005 by Peter Bieringer <pb@bieringer.de>## You will find more information on the initscripts-ipv6 homepage at# http://www.deepspace6.net/projects/initscripts-ipv6.html## Version: 2006-08-03####### Logging function# $1: <message> : message string# $2: [stdout|stderr].[err|warn[ing]|inf[o]|notice] : log level with optional channel, default is "stdout.notice"# [syslog.[facility.].err|warn[ing]|inf[o]|notice : syslog channel, default is "syslog.user.notice"# $3: <function name> : name of function which calls this log function, can be empty using ""# return code: 0=ok 1=argument error 3=major problemipv6_log() {local message="$1"local level="$2"local name="$3"if [ -z "$message" ]; thenecho $"ERROR: [ipv6_log] Missing 'message' (arg 1)" >/dev/stderrreturn 1fiif [ -z "$level" ]; thenlocal level="stdout.notice"fi# Map loglevel nowlocal fn=1local fnawk="print \$$fn"local t="$(echo $level | awk -F. "{ $fnawk }")"# Check channel, if givencase $t in'stdout'|'stderr'|'syslog')local channel="$t"local fn=$(($fn + 1));;*)local channel="stdout";;esac# Check syslog facilty, if givenif [ "$channel" = "syslog" ]; thenlocal fnawk="print \$$fn"local t="$(echo $level | awk -F. "{ $fnawk }")"case $t in'local0'|'local1'|'local2'|'local3'|'local4'|'local5'|'local6'|'local7'|'daemon')local facility="$t"local fn=$(($fn + 1));;*)local facility="user";;esacfilocal fnawk="print \$$fn"local t="$(echo $level | awk -F. "{ $fnawk }")"# Map priority[ "$t" = "inf" ] && local t="info"[ "$t" = "deb" ] && local t="debug"[ "$t" = "warning" ] && local t="warn"[ "$t" = "error" ] && local t="err"[ "$t" = "critical" ] && local t="crit"# Check priority, if givencase $t in'info'|'debug'|'notice'|'warn'|'err'|'crit')local priority="$t"local fn=$(($fn + 1));;*)local priority="notice";;esaclocal fnawk="print \$$fn"local t="$(echo $level | awk -F. "{ $fnawk }")"if [ -n "$t" ]; thenecho $"ERROR: [ipv6_log] Loglevel isn't valid '$level' (arg 2)" >/dev/stderrreturn 1fi# Generate function textif [ -z "$name" ]; thenlocal txt_name=""elselocal txt_name="[$name]"fi# Log messagecase $channel in'stdout'|'stderr')# Generate level textcase $priority in'debug')local txt_level=$"DEBUG ";;'err')local txt_level=$"ERROR ";;'warn')local txt_level=$"WARN ";;'crit')local txt_level=$"CRITICAL ";;'info')local txt_level=$"INFO ";;'notice')local txt_level=$"NOTICE ";;esac[ -n "$txt_name" ] && local txt_name="$txt_name "if [ "$channel" = "stderr" ]; thenecho "$txt_level: ${txt_name}${message}" >/dev/stderrelif [ "$channel" = "stdout" ]; thenecho "$txt_level: ${txt_name}${message}"fi;;'syslog')# note: logger resides in /usr/bin, but not used by defaultif ! [ -x /usr/bin/logger ]; thenecho $"ERROR: [ipv6_log] Syslog is chosen, but binary 'logger' doesn't exist or isn't executable" >/dev/stderrreturn 3fiif [ -z "$txt_name" ]; then/usr/bin/logger -p $facility.$priority $messageelse/usr/bin/logger -p $facility.$priority -t "$txt_name" "$message"fi;;*)echo $"ERROR: [ipv6_log] Cannot log to channel '$channel'" >/dev/stderrreturn 3;;esacreturn 0}###### Beginning of main code here, always executed on "source|. network-functions-ipv6"###### End of main code here##### Test for IPv6 capabilites# $1: (optional) testflag: currently supported: "testonly" (do not load a module)# return code: 0=ok 2=IPv6 test failsipv6_test() {local fn="ipv6_test"local testflag=$1if ! [ -f /proc/net/if_inet6 ]; thenif [ "$testflag" = "testonly" ]; thenreturn 2elsemodprobe ipv6if ! [ -f /proc/net/if_inet6 ]; then# ipv6_log $"Kernel is not compiled with IPv6 support" crit $fnreturn 2fififiif ! [ -d /proc/sys/net/ipv6/conf/ ]; thenreturn 2fireturn 0}##### Static IPv6 route configuration# Set static IPv6 route# $1: <IPv6 network> : to route# $2: <IPv6 gateway> : over which $1 should be routed (if "::", gw will be skipped)# $3: [<Interface>] : (optional)# return code: 0=ok 1=argument error 2=IPv6 test fails 3=major problem adding routeipv6_add_route() {local fn="ipv6_add_route"local networkipv6=$1local gatewayipv6=$2local device=$3 # maybe emptyif [ -z "$networkipv6" ]; thenipv6_log $"Missing parameter 'IPv6-network' (arg 1)" err $fnreturn 1fiif [ -z "$gatewayipv6" ]; thenipv6_log $"Missing parameter 'IPv6-gateway' (arg 2)" err $fnreturn 1fiipv6_test || return 2ipv6_test_ipv6_addr_valid $networkipv6 || return 2ipv6_test_ipv6_addr_valid $gatewayipv6 || return 2if [ -z "$device" ]; thenlocal returntxt="$(/sbin/ip -6 route add $networkipv6 via $gatewayipv6 metric 1 2>&1)"elseif [ "$gatewayipv6" = "::" ]; thenlocal returntxt="$(/sbin/ip -6 route add $networkipv6 dev $device metric 1 2>&1)"elselocal returntxt="$(/sbin/ip -6 route add $networkipv6 via $gatewayipv6 dev $device metric 1 2>&1)"fifiif [ -n "$returntxt" ]; thenif echo $returntxt | LC_ALL=C grep -q "File exists"; then# Netlink: "File exists"trueelif echo $returntxt | LC_ALL=C grep -q "No route to host"; then# Netlink: "No route to host"ipv6_log $"'No route to host' adding route '$networkipv6' via gateway '$gatewayipv6' through device '$device'" warn $fnreturn 3elseipv6_log $"Unknown error" warn $fnreturn 3fifireturn 0}##### automatic tunneling configuration## Configure automatic tunneling up# return code: 0=ok 2=IPv6 test fails 3=major problemipv6_enable_autotunnel() {local fn="ipv6_enable_autotunnel"ipv6_test || return 2# enable IPv6-over-IPv4 tunnelsif ipv6_test_device_status sit0; thentrueelse# bring up basic tunnel device/sbin/ip link set sit0 upif ! ipv6_test_device_status sit0; thenipv6_log $"Tunnel device 'sit0' enabling didn't work" err $fnreturn 3fi# Set sysctls proper (regardless "default")/sbin/sysctl -e -w net.ipv6.conf.sit0.forwarding=1 >/dev/null 2>&1/sbin/sysctl -e -w net.ipv6.conf.sit0.accept_ra=0 >/dev/null 2>&1/sbin/sysctl -e -w net.ipv6.conf.sit0.accept_redirects=0 >/dev/null 2>&1fireturn 0}##### Interface configuration## Add an IPv6 address for given interface# $1: <Interface># $2: <IPv6 address[/prefix]># return code: 0=ok 1=argument error 2=IPv6 test fails 3=major problemipv6_add_addr_on_device() {local fn="ipv6_add_addr_on_device"local device=$1local address=$2if [ -z "$device" ]; thenipv6_log $"Missing parameter 'device' (arg 1)" err $fnreturn 1fiif [ -z "$address" ]; thenipv6_log $"Missing parameter 'IPv6-address' (arg 2)" err $fnreturn 1fiipv6_test || return 2ipv6_test_ipv6_addr_valid $address || return 1ipv6_test_device_status $devicelocal result=$?if [ "$result" = "0" ]; thentrueelif [ "$result" != "11" ]; thenipv6_log $"Device '$device' doesn't exist" err $fnreturn 3else/sbin/ip link set $device upif ! ipv6_test_device_status $device; thenipv6_log $"Device '$device' enabling didn't work" err $fnreturn 3fifi# Extract address partslocal prefixlength_implicit="$(echo $address | awk -F/ '{ print $2 }')"local address_implicit="$(echo $address | awk -F/ '{ print $1 }')"# Check prefix length and using '64' as defaultif [ -z "$prefixlength_implicit" ]; thenlocal prefixlength_implicit="64"local address="$address_implicit/$prefixlength_implicit"fi/sbin/ip -6 addr add $address dev $devicelocal result=$?if [ $result -eq 2 ]; thenreturn 0elif [ $result -ne 0 ]; thenipv6_log $"Cannot add IPv6 address '$address' on dev '$device'" err $fnreturn 3fireturn 0}## Remove all IPv6 routes and addresses on given interface (cleanup to prevent kernel crashes)# $1: <Interface># return code: 0=ok 1=argument error 2=IPv6 test fails 3=major problemipv6_cleanup_device() {local fn="ipv6_cleanup_device"local device=$1if [ -z "$device" ]; thenipv6_log $"Missing parameter 'device' (arg 1)" err $fnreturn 1fiipv6_test testonly || return 2# Remove all IPv6 routes through this device (but not "lo")if [ "$device" != "lo" ]; then/sbin/ip -6 route flush dev $device scope global >/dev/null 2>&1/sbin/ip -6 route flush dev $device scope site >/dev/null 2>&1fi# Remove all IPv6 addresses on this interface/sbin/ip -6 addr flush dev $device scope global >/dev/null 2>&1/sbin/ip -6 addr flush dev $device scope site >/dev/null 2>&1return 0}## Remove all IPv6 6to4 related routes and addresses on given interface# $1: <Interface># return code: 0=ok 1=argument error 2=IPv6 test fails 3=major problemipv6_cleanup_6to4_device() {local fn="ipv6_cleanup_6to4_device"local device=$1if [ -z "$device" ]; thenipv6_log $"Missing parameter 'device' (arg 1)" err $fnreturn 1fiipv6_test testonly || return 2# Cleanup 6to4 addresses on this device/sbin/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/sbin/ip -6 addr del ${addr} dev ${dev}done# Get all IPv6 routes through given interface related to 6to4 and remove them/sbin/ip -6 route show dev $device | LC_ALL=C grep "^2002:" | while read ipv6net dummy; do/sbin/ip -6 route del $ipv6net dev $devicedonereturn 0}##### Some address test functions## Test a given IPv6 address for validity# $1: <IPv6 address># return code: 0=ok 1=not validipv6_test_ipv6_addr_valid() {ipcalc -cs6 $1}## Test a given IPv4 address for validity# $1: <IPv4 address># return code: 0=ok 1=not validipv6_test_ipv4_addr_valid() {ipcalc -cs4 $1}## Test a given IPv4 address for not a private but unicast one# $1: <IPv4 address># return code: 0=ok 1=argument error 10=private or not unicastipv6_test_ipv4_addr_global_usable() {local fn="ipv6_test_ipv4_addr_global_usable"local testipv4addr_globalusable=$1if [ -z "$testipv4addr_globalusable" ]; thenreturn 1fi# Test for a globally usable IPv4 address now# test 0.0.0.0/8/bin/ipcalc --network $testipv4addr_globalusable 255.0.0.0 | LC_ALL=C grep -q "NETWORK=0\.0\.0\.0" && return 10# test 10.0.0.0/8 (RFC 1918 / private)/bin/ipcalc --network $testipv4addr_globalusable 255.0.0.0 | LC_ALL=C grep -q "NETWORK=10\.0\.0\.0" && return 10# test 127.0.0.0/8 (loopback)/bin/ipcalc --network $testipv4addr_globalusable 255.0.0.0 | LC_ALL=C grep -q "NETWORK=127\.0\.0\.0" && return 10# test 169.254.0.0/16 (APIPA / DHCP link local)/bin/ipcalc --network $testipv4addr_globalusable 255.255.0.0 | LC_ALL=C grep -q "NETWORK=169\.254\.0\.0" && return 10# test 172.16.0.0/12 (RFC 1918 / private)/bin/ipcalc --network $testipv4addr_globalusable 255.240.0.0 | LC_ALL=C grep -q "NETWORK=172\.16\.0\.0" && return 10# test 192.168.0.0/16 (RFC 1918 / private)/bin/ipcalc --network $testipv4addr_globalusable 255.255.0.0 | LC_ALL=C grep -q "NETWORK=192\.168\.0\.0" && return 10# test 224.0.0.0/3 (multicast and reserved, broadcast)/bin/ipcalc --network $testipv4addr_globalusable 224.0.0.0 | LC_ALL=C grep -q "NETWORK=224\.0\.0\.0" && return 10return 0}## Test a given device for status# $1: <Interface># return code: 0=ok 1=argument error 10=not exists 11=downipv6_test_device_status() {local fn="ipv6_test_device_status"local device=$1if [ -z "$device" ]; thenipv6_log $"Missing parameter 'device' (arg 1)" err $fnreturn 1fi# Test if device existsif [ ! -d "/sys/class/net/${device}" ]; then# not existsreturn 10fi# Test if device is upif /sbin/ip link show dev $device 2>/dev/null | LC_ALL=C grep -q "UP"; then# upreturn 0else# downreturn 11fi}## Create 6to4 prefix# $1: <IPv4 address># stdout: <6to4address># return code: 0=ok 1=argument erroripv6_create_6to4_prefix() {local fn="ipv6_create_6to4_prefix"local ipv4addr=$1if [ -z "$ipv4addr" ]; thenipv6_log $"Missing parameter 'IPv4 address' (arg 1)" stderr.err $fnfilocal major1="$(echo $ipv4addr | awk -F. '{ print $1 }')"local minor1="$(echo $ipv4addr | awk -F. '{ print $2 }')"local major2="$(echo $ipv4addr | awk -F. '{ print $3 }')"local minor2="$(echo $ipv4addr | awk -F. '{ print $4 }')"if [ -z "$major1" -o -z "$minor1" -o -z "$major2" -o -z "$minor2" ]; thenreturn 1fiif [ $major1 -eq 0 ]; thenlocal block1="$(printf "%x" $minor1)"elselocal block1="$(printf "%x%02x" $major1 $minor1)"fiif [ $major2 -eq 0 ]; thenlocal block2="$(printf "%x" $minor2)"elselocal block2="$(printf "%x%02x" $major2 $minor2)"filocal prefix6to4="2002:$block1:$block2"echo "$prefix6to4"return 0}## Check and create 6to4 tunnel relay address# $1: <IPv4 address|IPv6to4 address># stdout: <tunnel relay address># return code: 0=ok 1=argument erroripv6_create_6to4_relay_address() {local fn="ipv6_create_6to4_relay_address"local addr=$1if [ -z "$addr" ]; thenipv6_log $"Missing parameter 'address' (arg 1)" stderr.err $fnreturn 1fi# Checkif ipv6_test_ipv4_addr_valid $addr ; then# ok, a IPv4 oneif ipv6_test_ipv4_addr_global_usable $addr; then# IPv4 globally usablelocal ipv6to4_relay="::$addr"elseipv6_log $"Given address '$addr' is not a global IPv4 one (arg 1)" stderr.err $fnreturn 1fielseipv6_log $"Given address '$addr' is not a valid IPv4 one (arg 1)" stderr.err $fnreturn 1fiecho "$ipv6to4_relay"return 0}##### 6to4 tunneling setup## Configure 6to4 tunneling up# $1: <Interface> : only "tun6to4" is supported# $2: <IPv4 address> : global IPv4 address of interface (will be used to generate 6to4 prefix)# $3: [<IPv6 suffix>] : for 6to4 prefix (optional, default is "::1")# $4: [<MTU>] : MTU of tunnel device (optional, default is automatic)# $5: [<IPv4 address>] : local IPv4 address of tunnel interface (required in case of 6to4 behind NAT)# return code: 0=ok 1=argument error 2=IPv6 test fails 3=major problemipv6_add_6to4_tunnel() {local fn="ipv6_add_6to4_tunnel"local device=$1local globalipv4=$2local globalipv6to4suffix=$3local mtu=$4local localipv4=$5if [ -z "$device" ]; thenipv6_log $"Missing parameter 'device' (arg 1)" err $fnreturn 1fiif [ -z "$globalipv4" ]; thenipv6_log $"Missing parameter 'global IPv4 address' (arg 2)" err $fnreturn 1fi# Check deviceif [ "$device" != "tun6to4" ]; thenipv6_log $"Given device '$device' is not supported (arg 1)" err $fnreturn 1fi# Copy global IPv4 address to local if last one is not givenif [ -z "$localipv4" ]; thenlocalipv4="$globalipv4"fiipv6_test || return 2# Generate 6to4 addresslocal prefix6to4="$(ipv6_create_6to4_prefix $globalipv4)"if [ $? -ne 0 -o -z "$prefix6to4" ]; thenreturn 3fiif [ -z "$globalipv6to4suffix" ]; thenlocal address6to4="${prefix6to4}::1/16"elselocal address6to4="${prefix6to4}::${globalipv6to4suffix}/16"fiipv6_add_tunnel_device tun6to4 0.0.0.0 $address6to4 $localipv4if [ $? -ne 0 ]; thenlocal retval=3elselocal retval=0fi# Add unspecific unreachable route for local 6to4 address space/sbin/ip route add unreach ${prefix6to4}::/48# Set MTU, if givenif [ -n "$mtu" ]; thenipv6_set_mtu $device $mtufireturn $retval}## Configure all 6to4 tunneling down# $1: <Interface> : only "tun6to4" is supported# return code: 0=ok 1=argument error 2=IPv6 test fails 3=major problemipv6_cleanup_6to4_tunnels() {local fn="ipv6_cleanup_6to4_tunnels"local device=$1if [ -z "$device" ]; thenipv6_log $"Missing parameter 'device' (arg 1)" err $fnreturn 1fi# Check deviceif [ "$device" != "tun6to4" ]; thenipv6_log $"Given device '$device' is not supported (arg 1)" err $fnreturn 1fiipv6_test testonly || return 2ipv6_del_tunnel_device tun6to4# Remove all unspecific unreachable routes for local 6to4 address space/sbin/ip -6 route | LC_ALL=C grep "^unreachable 2002:" | LC_ALL=C grep "/48 dev lo" | while read token net rest; do/sbin/ip route del unreach $netdonereturn 0}## Configure 6to4 tunneling down# $1: <Interface> : only "tun6to4" is supported# $2: <IPv4 address> : global address of local interface# return code: 0=ok 1=argument error 2=IPv6 test fails 3=major problemipv6_del_6to4_tunnel() {local fn="ipv6_del_6to4_tunnel"local device=$1local localipv4=$2if [ -z "$device" ]; thenipv6_log $"Missing parameter 'device' (arg 1)" err $fnreturn 1fiif [ -z "$localipv4" ]; thenipv6_log $"Missing parameter 'local IPv4 address' (arg 2)" err $fnreturn 1fi# Check deviceif [ "$device" != "tun6to4" ]; thenipv6_log $"Given device '$device' is not supported (arg 1)" err $fnreturn 1fiipv6_test || return 2ipv6_del_tunnel_device tun6to4local retval=$?# Remove unspecific unreachable route for local 6to4 address space/sbin/ip route del unreach ${prefix6to4}::/48return $retval}## Configure a static tunnel device up# $1: <Interface># $2: <IPv4 address> : of foreign tunnel# $3: [<IPv6 address>] : local one of a P-t-P tunnel (optional)# $4: [<IPv4 address>] : local one of tunnel (optional)# return code: 0=ok 1=argument error 2=IPv6 test fails 3=major problemipv6_add_tunnel_device() {local fn="ipv6_add_tunnel_device"local device=$1local addressipv4tunnel=$2local addressipv6local=$3local addressipv4tunnellocal=$4if [ -z "$device" ]; thenipv6_log $"Missing parameter 'device' (arg 1)" err $fnreturn 1fiif [ -z "$addressipv4tunnel" ]; thenipv6_log $"Missing parameter 'IPv4-tunnel address' (arg 2)" err $fnreturn 1fiif [ -z "$addressipv4tunnellocal" ]; thenlocal addressipv4tunnellocal="any"fiipv6_test || return 2if ! ipv6_test_device_status $device; thenlocal ttldefault="$(/sbin/sysctl -e net.ipv4.ip_default_ttl | awk '{ print $3 }')"if [ -z "$ttldefault" ]; thenlocal ttldefault=64fi# Test whether remote IPv4 address was already applied to another tunnelif [ "$addressipv4tunnel" != "0.0.0.0" -a "$addressipv4tunnel" != "any" ]; then/sbin/ip tunnel show remote $addressipv4tunnel 2>/dev/null | LC_ALL=C grep -w "ipv6/ip" | while IFS=":" read devnew rest; doif [ "$devnew" != "$device" ]; thenipv6_log $"Given remote address '$addressipv4tunnel' on tunnel device '$device' is already configured on device '$devnew'" err $fnreturn 3fidonefi/sbin/ip tunnel add $device mode sit ttl $ttldefault remote $addressipv4tunnel local $addressipv4tunnellocalif [ $? -ne 0 ]; thenreturn 3fi# Test, whether "ip tunnel show" reports valid contentif ! /sbin/ip tunnel show $device 2>/dev/null | LC_ALL=C grep -q -w "remote"; thenipv6_log $"Tunnel device '$device' creation didn't work" err $fnreturn 3fi/sbin/ip link set $device upif ! ipv6_test_device_status $device; thenipv6_log $"Tunnel device '$device' bringing up didn't work" err $fnreturn 3fi# Set sysctls proper (regardless "default")/sbin/sysctl -e -w net.ipv6.conf.$SYSCTLDEVICE.forwarding=1 >/dev/null 2>&1/sbin/sysctl -e -w net.ipv6.conf.$SYSCTLDEVICE.accept_ra=0 >/dev/null 2>&1/sbin/sysctl -e -w net.ipv6.conf.$SYSCTLDEVICE.accept_redirects=0 >/dev/null 2>&1if [ -n "$addressipv6local" ]; then# Setup P-t-P addressipv6_add_addr_on_device $device $addressipv6localif [ $? -ne 0 ]; thenreturn 3fifielsefalsefireturn 0}## Configure a static tunnel device down# $1: <Interface># return code: 0=ok 1=argument error 2=IPv6 test fails 3=major problemipv6_del_tunnel_device() {local fn="ipv6_del_tunnel_device"local device=$1if [ -z "$device" ]; thenipv6_log $"Missing parameter 'device' (arg 1)" err $fnreturn 1fiipv6_test testonly || return 2if ipv6_test_device_status $device; thenipv6_cleanup_device $deviceelseif [ "$device" != "sit0" ]; thenfalsefifiif [ "$device" != "sit0" ]; thenif /sbin/ip tunnel show $device 2>/dev/null | LC_ALL=C grep -q -w "ipv6/ip"; then/sbin/ip tunnel del $deviceif ipv6_test_device_status $device; thenreturn 3fielsefalsefifireturn 0}## Cleanup all dedicated tunnel devicesipv6_cleanup_tunnel_devices() {local fn="ipv6_cleanup_tunnel_devices"ipv6_test testonly || return 2# Find still existing tunnel devices and shutdown and delete them/sbin/ip tunnel show | LC_ALL=C grep -w "ipv6/ip" | awk -F: '{ print $1 }' | while read device; doipv6_del_tunnel_device $devicedonereturn 0}## Get address of a dedicated tunnel# $1: <Interface># $2: local|remote : local or remote address# stdout: <IPv4 address> if available# return code: 0=ok 1=argument error 2=IPv6 test fails 3=major problemipv6_get_ipv4addr_of_tunnel() {local fn="ipv6_get_local_ipv4_of_tunnel"local device=$1local selection=$2if [ -z "$device" ]; thenipv6_log $"Missing parameter 'device' (arg 1)" stderr.err $fnreturn 1fiif [ -z "$selection" ]; thenipv6_log $"Missing parameter 'selection' (arg 2)" stderr.err $fnreturn 1fiif [ "$selection" != "local" -a "$selection" != "remote" ]; thenipv6_log $"Unsupported selection '$selection' specified (arg 2)" stderr.err $fnreturn 1fiipv6_test testonly || return 2ipv6_test_device_status $deviceif [ $? != 0 -a $? != 11 ]; then# Device doesn't existreturn 3fi# Device exists, retrieve addressif [ "$selection" = "local" ]; thenlocal tunnel_local_ipv4addr="$(/sbin/ip tunnel show $device | awk '{ print $6 }')"elif [ "$selection" = "remote" ]; thenlocal tunnel_local_ipv4addr="$(/sbin/ip tunnel show $device | awk '{ print $4 }')"fiif [ $? != 0 ]; thenreturn 3fiif [ "$tunnel_local_ipv4addr" = "any" ]; thenlocal tunnel_local_ipv4addr="0.0.0.0"fiecho "$tunnel_local_ipv4addr"return 0}## Get IPv4 address of a device# $1: <Interface># stdout: <IPv4 address> if available# return code: 0=ok 1=argument error 2=IPv6 test fails 3=major problem (more than one IPv4 address applied)ipv6_get_ipv4addr_of_device() {local fn="ipv6_get_ipv4addr_of_device"local device=$1if [ -z "$device" ]; thenipv6_log $"Missing parameter 'device' (arg 1)" stderr.err $fnreturn 1fiipv6_test_device_status $deviceif [ $? != 0 -a $? != 11 ]; then# Device doesn't existreturn 3fi# Device exists, retrieve the first address onlylocal ipv4addr="$(/sbin/ip -o -4 addr show dev $device | awk '{ print $4 }' | awk -F/ '{ print $1; exit }')"if [ $? != 0 ]; thenreturn 3fiif [ "$ipv4addr" = "any" ]; thenlocal ipv4addr="0.0.0.0"fiecho "$ipv4addr"return 0}## Set IPv6 MTU for a device# $1: <Interface># $2: <IPv6 MTU># return code: 0=ok 1=argument error 2=IPv6 test fails 3=major problemipv6_set_mtu() {local fn="ipv6_set_mtu"local device=$1local ipv6_mtu=$2if [ -z "$device" ]; thenipv6_log $"Missing parameter 'device' (arg 1)" err $fnreturn 1fiif [ -z "$ipv6_mtu" ]; thenipv6_log $"Missing parameter 'IPv6 MTU' (arg 2)" err $fnreturn 1fi# Check rangeif [ $ipv6_mtu -lt 1280 -o $ipv6_mtu -gt 65535 ]; thenipv6_log $"Given IPv6 MTU '$ipv6_mtu' is out of range" err $fnreturn 1fiipv6_test testonly || return 2# Set value/sbin/ip link set dev $device mtu $ipv6_mtureturn 0}## Set a default route# $1: <IPv6 address> : gateway, can also contain scope suffix (device name), cause a warning if not matching with $2 (but will have precedence)# $2: <gateway device>: gateway device (optional in case of $1 is a global address or $1 contains scope suffix)# $3: <check device>: (optional) device to check scope and gateway device against (setup is skipped, if not matching)# return code: 0=ok 1=argument error 2=IPv6 test fails 3=major problemipv6_set_default_route() {local fn="ipv6_set_default_route"local address=$1local device=$2local device_check=$3ipv6_test testonly || return 2# Map the unspecified address to nothingif [ "$address" = "::" ]; thenlocal address=""fiif [ -n "$address" ]; thenlocal addressgw=$(echo $address | awk -F% '{ print $1 }')local device_scope=$(echo $address | awk -F% '{ print $2 }')if [ -z "$addressgw" ]; thenipv6_log $"Given IPv6 default gateway '$address' is not in proper format" err $fnreturn 3fi# Scope device has precedenceif [ -n "$device_scope" -a -n "$device" -a "$device_scope" != "$device" ]; thenipv6_log $"Given IPv6 default gateway '$address' has scope '$device_scope' defined, given default gateway device '$device' will be not used" inf $fnlocal device=""fi# Link local addresses require a deviceif echo $addressgw | LC_ALL=C grep -qi "^fe80:"; thenif [ -z "$device_scope" ]; thenif [ -z "$device" ]; thenipv6_log $"Given IPv6 default gateway '$address' is link-local, but no scope or gateway device is specified" err $fnreturn 3fififi# Check whether the route belongs to the specific given interfaceif [ -n "$device_check" ]; then# Check whether scope device matches given check deviceif [ -n "$device_scope" -a "$device_check" != "$device_scope" ]; then# scope device != specific given -> skipreturn 0elif [ -n "$device" -a "$device_check" != "$device" ]; then# gateway device != specific given -> skipreturn 0fifi# Set device now, if not givenif [ -z "$device" ]; thenlocal device="$device_scope"fiif [ -z "$device" ]; then# Note: this can cause a warning and a not installed route, if given address is not reachable on the linkipv6_add_route ::/0 $addressgwelseipv6_add_route ::/0 $addressgw $devicefielif [ -n "$device" ]; then# Check whether the route belongs to the specific given interfaceif [ -n "$device_check" -a "$device_check" != "$device" ]; then# gateway device != specific given -> skipreturn 0fiipv6_test_route_requires_next_hop $devicelocal result=$?if [ $result = 0 ]; thenipv6_log $"Given IPv6 default device '$device' requires an explicit nexthop" err $fnreturn 3elif [ $result != 10 ]; thenipv6_log $"Given IPv6 default device '$device' doesn't exist or isn't up" err $fnreturn 3fiipv6_add_route ::/0 :: $deviceelseipv6_log $"No parameters given to setup a default route" err $fnreturn 3fireturn 0}## Resolve need of explicit next hop for an interface# $1: <Interface># return code: 0=ok 1=argument error 2=IPv6 test fails 3=major problem 10=needs no explicit hopipv6_test_route_requires_next_hop() {local fn="ipv6_test_route_requires_next_hop"local device=$1if [ -z "$device" ]; thenipv6_log $"Missing parameter 'device' (arg 1)" err $fnreturn 1fiipv6_test testonly || return 2ipv6_test_device_status $deviceif [ $? != 0 ]; thenreturn 3fiif [ "$device" = "sit0" ]; thenreturn 10fiif /sbin/ip -o link show $device 2>/dev/null | LC_ALL=C grep -q "POINTOPOINT"; thenreturn 10fireturn 0}## Trigger radvd# $1: up|down : device reason for triggering (coming up or going down)# $2: [startstop|restart|reload|SIGHUP] : triger mechanism (default is "SIGHUP")# "startstop" : reason=up -> start, reason=down -> stop# $3: [<filename>] : alternative pid file [optional]# return code: 0=ok 1=argument error 2=IPv6 test fails 3=major problemipv6_trigger_radvd() {local fn="ipv6_trigger_radvd"local reason=$1local mechanism=$2local pidfile=$3if [ -z "$reason" ]; thenipv6_log $"No reason given for sending trigger to radvd" err $fnreturn 1fiif [ "$reason" != "up" -a "$reason" != "down" ]; thenipv6_log $"Unsupported reason '$reason' for sending trigger to radvd" err $fnreturn 1fiif [ -z "$mechanism" ]; then# Take defaultlocal mechanism="SIGHUP"fiif [ -z "$pidfile" ]; thenlocal pidfile="/var/run/radvd/radvd.pid"fi# Print message and select actioncase $mechanism in'startstop')case $reason inup)local action="start";;down)local action="stop";;esac;;'reload'|'restart'|'SIGHUP')local action="$mechanism";;*)ipv6_log $"Unsupported mechanism '$mechanism' for sending trigger to radvd" err $fnreturn 3;;esac# PID file needed?if [ "$action" = "SIGHUP" ]; thenif ! [ -f "$pidfile" ]; thenif [ "$reason" = "down" ]; then# be quiet because triggering may have been disabledtrueelseipv6_log $"Given pidfile '$pidfile' doesn't exist, cannot send trigger to radvd" err $fnfireturn 3fi# Get PIDlocal pid="$(cat $pidfile)"if [ -z "$pid" ]; then# pidfile empty - strangeipv6_log $"Pidfile '$pidfile' is empty, cannot send trigger to radvd" err $fnreturn 3fifi# Do actioncase $action in'SIGHUP')kill -HUP $pid;;'reload'|'restart'|'stop'|'start')if ! /sbin/chkconfig --list radvd >/dev/null 2>&1; thenif [ "$reason" = "down" ]; then# be quiet because triggering may have been disabledtrueelseipv6_log $"radvd not (properly) installed, triggering failed" err $fnfireturn 3else/sbin/service radvd $action >/dev/null 2>&1fi;;*)# Normally not reached, "action" is set above to proper value;;esacreturn 0}