#!/bin/sh # # network-functions-ipv6 # # Taken from: # (P) & (C) 1997-2001 by Peter Bieringer # # Version: 2001-03-03b # # Extended address detection is enabled, if 'ipv6calc' is installed # Available here: http://www.bieringer.de/linux/IPv6/tools/index.html#ipv6calc # # Known bugs: # sit0 will not be shutdowned, if an additional IPv6 address was manually added to this device # # Filter tags (for stripping, empty lines following here if all is stripped) # Return values # 0 = ok # 1 = error occurs # 2 = not enabled, i.e. no IPv6 kernel support or switched off by configuration ##### Test for "ipv6calc" (can be used for better duplicate address detection) EXISTS_ipv6calc=no if which ipv6calc >/dev/null 2>&1; then EXISTS_ipv6calc=yes else true fi ##### Test for IPv6 capabilites function test_ipv6() { # Test for IPv6 enabled kernel if ! [ -f /proc/net/if_inet6 ]; then modprobe ipv6 if ! [ -f /proc/net/if_inet6 ]; then echo $"Kernel is not compiled with IPv6 support" return 2 fi fi return 0 } ##### Control IPv6 forwarding # Display usage function forwarding_ipv6_usage() { echo $"Usage: $0 yes|no [device]" } # Control IPv6 forwarding # $1: control [yes|no|on|off] # $2: network device (if not given, global IPv6 forwarding is set) function forwarding_ipv6() { fw_control=$1 fw_device=$2 # maybe empty if [ -z "$fw_control" ]; then echo $"Missing parameter 'forwarding control'" forwarding_ipv6_usage return 1 fi if ! [ "$fw_control" = "yes" -o "$fw_control" = "no" -o "$fw_control" = "on" -o "$fw_control" = "off" ]; then echo $"Don't understand forwarding control parameter '$fw_control'" forwarding_ipv6_usage return 1 fi # Device "lo" need no IPv6 configuration if [ "$fw_device" = "lo" ]; then return 0; fi # Run IPv6 test test_ipv6 || return if [ "$fw_control" = "yes" -o "$fw_control" = "on" ]; then status=1 else status=0 fi # Global control? (if no device is given) if [ -z "$fw_device" ]; then sysctl -w net.ipv6.conf.all.forwarding=$status >/dev/null 2>&1 fi # Per device control if [ ! -z "$fw_device" ]; then sysctl -w net.ipv6.conf.$fw_device.forwarding=$status >/dev/null 2>&1 fi } ##### Static IPv6 route configuration # Display usage function ifupdown_ipv6_route_usage() { echo $"Usage: $0 IPv6-network IPv6-gateway [device]" } # Set static IPv6 route # $1: IPv6 network to route # $2: IPv6 gateway over which $1 should be routed # $3: Interface (optional) function ifup_ipv6_route() { networkipv6=$1 gatewayipv6=$2 device=$3 # maybe empty if [ -z "$networkipv6" ]; then echo $"Missing parameter 'IPv6-network'" ifupdown_ipv6_route_usage return 1 fi if [ -z "$gatewayipv6" ]; then echo $"Missing parameter 'IPv6-gateway'" ifupdown_ipv6_route_usage return 1 fi # Device "lo" need no IPv6 configuration if [ "$device" = "lo" ]; then return 0; fi # Run IPv6 test test_ipv6 || return if [ -z "$device" ]; then output="`LC_ALL=C route -A inet6 add $networkipv6 gw $gatewayipv6 2>&1`" if [ $? -ne 0 ]; then if echo $output | grep -i -q 'SIOCADDRT: File exists'; then true else echo $output fi fi else output="`LC_ALL=C route -A inet6 add $networkipv6 gw $gatewayipv6 dev $device 2>&1`" if [ $? -ne 0 ]; then if echo $output | grep -i -q 'SIOCADDRT: File exists'; then true else echo $output fi fi fi } # Delete static IPv6 route # $1: IPv6 network to route # $2: IPv6 gateway over which $1 should be routed # $3: Interface (optional) function ifdown_ipv6_route() { networkipv6=$1 gatewayipv6=$2 device=$3 # maybe empty if [ -z "$networkipv6" ]; then echo $"Missing parameter 'IPv6-network'" ifup_ipv6_route_usage return 1 fi if [ -z "$gatewayipv6" ]; then echo $"Missing parameter 'IPv6-gateway'" ifup_ipv6_route_usage return 1 fi # Device "lo" need no IPv6 configuration if [ "$device" = "lo" ]; then return 0; fi # Run IPv6 test test_ipv6 || return if [ -z "$device" ]; then output="`LC_ALL=C route -A inet6 del $networkipv6 gw $gatewayipv6 2>&1`" if [ $? -ne 0 ]; then if echo $output | grep -i -q 'SIOCDELRT: No such process'; then true else echo $output fi fi else output="`LC_ALL=C route -A inet6 del $networkipv6 gw $gatewayipv6 dev $device 2>&1`" if [ $? -ne 0 ]; then if echo $output | grep -i -q 'SIOCDELRT: No such process'; then true else echo $output fi fi fi } ##### automatic tunneling configuration ## Configure automatic tunneling up function ifup_ipv6_autotunnel() { # Run IPv6 test test_ipv6 || return # enable IPv6-over-IPv4 tunnels if LC_ALL=C ifconfig sit0 | grep -q "UP "; then # already up, do nothing true else # basic tunnel device to up ifconfig sit0 up # Switch on forwarding forwarding_ipv6 on sit0 fi } ## Configure automatic tunneling down function ifdown_ipv6_autotunnel() { # Run IPv6 test test_ipv6 || return if LC_ALL=C ifconfig sit0 | grep -q "UP "; then # still up? # disable IPv6-over-IPv4 tunnels (if a tunnel is no longer up) if LC_ALL=C route -n -A inet6 -n | grep sit0 | awk '{ print $2 }' | grep -v -q "^::$"; then # still existing routes, skip shutdown of sit0 true elif LC_ALL=C ifconfig sit0 | grep 'inet6 addr:' | awk '{ print $3 }' | grep -v -q '^::'; then # still existing IPv6 addresses, skip shutdown of sit0 true else # basic tunnel device to down # Switch off forwarding forwarding_ipv6 off sit0 ifconfig sit0 down fi fi } ##### static tunneling configuration function ifupdown_ipv6_tunnel_usage() { echo $"Usage: $0 interfacename IPv4-tunneladdress IPv6-route" } ## Configure static tunnels up # $1: Interface (not needed - dummy) # $2: IPv4 address of foreign tunnel # $3: IPv6 route through this tunnel function ifup_ipv6_tunnel() { device=$1 addressipv4tunnel=$2 routeipv6=$3 if [ -z "$device" ]; then echo $"Missing parameter 'device'" ifupdown_ipv6_tunnel_usage return 1 fi if [ -z "$addressipv4tunnel" ]; then echo $"Missing parameter 'IPv4-tunneladdress'" ifupdown_ipv6_tunnel_usage return 1 fi if [ -z "$routeipv6" ]; then echo $"Missing parameter 'IPv6-route'" ifupdown_ipv6_tunnel_usage return 1 fi # Run IPv6 test test_ipv6 || return # enable general IPv6-over-IPv4 tunneling ifup_ipv6_autotunnel # Set up a tunnel output="`LC_ALL=C route -A inet6 add $routeipv6 gw ::$addressipv4tunnel dev sit0 2>&1`" if [ $? -ne 0 ]; then if echo $output | grep -i -q 'SIOCADDRT: File exists'; then true else echo $output fi fi } ## Configure static tunnels down # $1: Interface (not used - dummy) # $2: IPv4 address of foreign tunnel # $3: IPv6 route through this tunnel function ifdown_ipv6_tunnel() { device=$1 addressipv4tunnel=$2 routeipv6=$3 if [ -z "$device" ]; then echo $"Missing parameter 'device'" ifupdown_ipv6_tunnel_usage return 1 fi if [ -z "$addressipv4tunnel" ]; then echo $"Missing parameter 'IPv4-tunneladdress'" ifupdown_ipv6_tunnel_usage return 1 fi if [ -z "$routeipv6" ]; then echo $"Missing parameter 'IPv6-route'" ifupdown_ipv6_tunnel_usage return 1 fi # Run IPv6 test test_ipv6 || return # Set up a tunnel output="`route -A inet6 del $routeipv6 gw ::$addressipv4tunnel dev sit0 2>&1`" if [ $? -ne 0 ]; then if echo $output | grep -i -q 'SIOCDELRT: No such process'; then true else echo $output fi fi # disable IPv6-over-IPv4 tunneling (if no longer a tunnel is up) ifdown_ipv6_autotunnel } ## Remove all IPv6 tunnels for a given tunnel endpoint # $1: Interface (not used - dummy) # $2: IPv4-tunneladdress function ifdown_ipv6_tunnel_all() { idtuall_device=$1 idtuall_tunnel=$2 if [ -z "$idtuall_device" ]; then echo $"Missing parameter 'device'" echo $"Usage: ifdown_ipv6_tunnel_all interfacename IPv4-tunneladdress" return 1 fi if [ -z "$idtuall_tunnel" ]; then echo $"Missing parameter 'IPv4-tunneladdress'" echo $"Usage: ifdown_ipv6_tunnel_all interfacename IPv4-tunneladdress" return 1 fi # Get all IPv6 routes through given interface and remove them LC_ALL=C route -n -A inet6 | grep "::$idtuall_tunnel" | while read ipv6net nexthop flags metric ref use iface args; do if [ "::$idtuall_tunnel" = "$nexthop" ]; then if echo $flags | grep -v -q "A"; then # Only non addrconf (automatic installed) routes should be removed ifdown_ipv6_tunnel $idtuall_device $idtuall_tunnel $ipv6net fi fi done } ##### Test, whether an IPv6 address exists on an interface # $1: Device for testing # $2: Address to test (without prefix) # $3: Prefix of address $1 # return values: 1:problem, 10:not exists, 11:exits function test_ipv6_addrs_exists () { testdevice=$1 testaddr=$2 testprefix=$3 if [ -z "$testaddr" ]; then echo $"Missing parameter 'IPv6AddrToTest'" return 1 fi if [ "$EXISTS_ipv6calc" = "yes" ]; then # Using ipv6calc and compare against /proc/net/if_inet6 convertresult="`ipv6calc --addr2if_inet6 $testaddr/$testprefix`" # Split in address, scope and prefix length test_addr="`echo $convertresult | awk '{ print $1 }'`" test_scope="`echo $convertresult | awk '{ print $2 }'`" test_prefixlength="`echo $convertresult | awk '{ print $3 }'`" if [ -z "$test_prefixlength" ]; then testresult="`grep "$test_addr .. .. $test_scope .." /proc/net/if_inet6 | grep $testdevice$`" else testresult="`grep "$test_addr .. $test_prefixlength $test_scope .." /proc/net/if_inet6 | grep $testdevice$`" fi if [ ! -z "$testresult" ]; then return 11 else return 10 fi else # low budget version, only works if given address is in equal form like ifconfig displays testresult="`LC_ALL=C ifconfig $testdevice | grep "inet6 addr:" | grep -i ": $testaddr/$testprefix" | awk '{ print $3 }'`" if [ ! -z "$testresult" ]; then return 11 else return 10 fi fi } ##### Interface configuration function ifupdown_ipv6_usage() { echo $"Usage: $0 interfacename IPv6-address/IPv6-prefixlength" } ## Add an IPv6 address for given interface # $1: Interface # $2: IPv6 address function ifup_ipv6_real() { device=$1 address=$2 if [ -z "$device" ]; then echo $"Missing parameter 'device'" ifupdown_ipv6_usage return 1 fi # Device "lo" need no IPv6 configuration if [ "$device" = "lo" ]; then return 0; fi if [ -z "$address" ]; then echo $"Missing parameter 'IPv6-address'" ifupdown_ipv6_usage return 1 fi # Test status of interface if LC_ALL=C ifconfig $device | grep -q "UP "; then # Interface is up true else # no IPv4 for this interface, interface is still down, do up ... ifconfig $device up fi # Extract address parts prefixlength_implicit="`echo $address | awk -F/ '{ print $2 }'`" address_implicit="`echo $address | awk -F/ '{ print $1 }'`" # Test for prefix length if [ -z "$prefixlength_implicit" ]; then echo $"Missing 'prefix length' for given address" ifupdown_ipv6_usage return 1 elif [ $prefixlength_implicit -lt 0 -o $prefixlength_implicit -gt 128 ]; then echo $"'prefix length' on given address is out of range (0-128)" ifupdown_ipv6_usage return 1 fi # Run IPv6 test test_ipv6 || return # Only add, if address do not already exist test_ipv6_addrs_exists $device $address_implicit $prefixlength_implicit retval=$? if [ $retval -lt 10 ]; then return 2 fi if [ $retval -eq 11 ]; then true else ifconfig $device add $address || return 2 fi } ## Remove all IPv6 routes and addresses for given interface # cleanup to prevent kernel crashes # $1: Interface function ifdown_ipv6_real_all() { idall_device=$1 if [ -z "$idall_device" ]; then echo $"Missing parameter 'device'" echo $"Usage: ifdown_ipv6_real_all interfacename" return 1 fi # Get all IPv6 routes through given interface and remove them LC_ALL=C route -n -A inet6 | grep $idall_device | while read ipv6net nexthop flags metric ref use iface args; do if [ "$idall_device" = "$iface" ]; then if echo $flags | grep -v -q "A"; then # Only non addrconf (automatic installed) routes should be removed ifdown_ipv6_route $ipv6net $nexthop $iface fi fi done # Get all IPv6 addresses assigned to given interface and remove them if [ "$EXISTS_ipv6calc" = "yes" ]; then grep $idall_device$ /proc/net/if_inet6 | while read hexaddr dummy1 hexprefixlenth hexscope device args; do if [ "$hexscope" != "20" ]; then ipv6addr="`ipv6calc --if_inet62addr $hexaddr $hexprefixlenth`" ifdown_ipv6_real $idall_device $ipv6addr fi done else LC_ALL=C ifconfig $idall_device | grep "inet6 addr:" | while read dummy1 dummy2 ipv6addr scope args; do if [ "$scope" != "Scope:Link" ]; then ifdown_ipv6_real $idall_device $ipv6addr fi done fi } ## Remove an IPv6 address on given interface # $1: Interface # $2: IPv6 address function ifdown_ipv6_real() { device=$1 address=$2 if [ -z "$device" ]; then echo $"Missing parameter 'device'" ifupdown_ipv6_usage return 1 fi # Device "lo" need no IPv6 configuration if [ "$device" = "lo" ]; then return 0; fi if [ -z "$address" ]; then echo $"Missing parameter 'IPv6-address'" ifupdown_ipv6_usage return 1 fi # Extract address parts prefixlength_implicit="`echo $address | awk -F/ '{ print $2 }'`" address_implicit="`echo $address | awk -F/ '{ print $1 }'`" # Test for prefix length if [ -z "$prefixlength_implicit" ]; then echo $"Missing 'prefix length' for given address" ifupdown_ipv6_usage return 1 elif [ $prefixlength_implicit -lt 0 -o $prefixlength_implicit -gt 128 ]; then echo $"'prefix length' on given address is out of range (0-128)" ifupdown_ipv6_usage return 1 fi # Run IPv6 test test_ipv6 || return # Only remove, if address exists and is not link-local (prevents from kernel crashing) test_ipv6_addrs_exists $device $address_implicit $prefixlength_implicit retval=$? if [ $retval -lt 10 ]; then return 2 fi if [ $retval -eq 11 ]; then ifconfig $device del $address || return 2 else true fi }