ipv6-support: Remove site-border feature * was causing routing problems * will be...
[openwrt/staging/wigyori.git] / package / network / ipv6 / ipv6-support / files / support.sh
index 5525a3a56f00761926dfd63d0590586a42a4d2d9..01efb9ed7c492656bc8bcca6728f5e415d891edb 100644 (file)
@@ -5,13 +5,13 @@
 . /lib/functions/network.sh
 
 config_load network6
-
+local NAT="ip6tables -t nat"
 
 conf_get() {
        local __return="$1"
        local __device="$2"
        local __option="$3"
-       local __value=$(cat "/proc/sys/net/ipv6/conf/$device/$option")
+       local __value=$(cat "/proc/sys/net/ipv6/conf/$__device/$__option")
        eval "$__return=$__value"
 }
 
@@ -52,7 +52,6 @@ resolve_network_add() {
        local __section="$1"
        local __device="$2"
        local __return="$3"
-
        local __cdevice
        network_get_device __cdevice "$__section"
        [ "$__cdevice" != "$__device" ] && return
@@ -68,10 +67,52 @@ resolve_network() {
 }
 
 
+setup_masquerading() {
+       local cmd="$1"
+       local chain="network6_masquerade_$2"
+       local device="$3"
+
+       $NAT -D POSTROUTING -j "$chain" 2>/dev/null && {
+               $NAT -F "$chain" 2>/dev/null
+               $NAT -X "$chain" 2>/dev/null
+       }
+
+       [ "$cmd" != "stop" ] && {
+               $NAT -N "$chain"
+               $NAT -A "$chain" -o "$device" -j MASQUERADE
+               $NAT -A POSTROUTING -j "$chain"
+       }
+}
+
+
+setup_npt_chain() {
+       local cmd="$1"
+       local network="$2"
+       local chain="network6_npt_$network"
+
+       [ "$cmd" != "start" ] && {
+               $NAT -D POSTROUTING -j "$chain" 2>/dev/null && {
+                       $NAT -D PREROUTING -j "$chain" 2>/dev/null
+                       $NAT -F "$chain" 2>/dev/null
+                       $NAT -X "$chain" 2>/dev/null
+               }
+       }
+
+       [ "$cmd" != "stop" ] && {
+               $NAT -N "$chain" 2>/dev/null && {
+                       $NAT -A PREROUTING -j "$chain"
+                       $NAT -A POSTROUTING -j "$chain"
+               }
+       }
+}
+
+
 announce_prefix() {
        local prefix="$1"
        local network="$2"
-       local cmd="$3"
+       local device="$3"
+       local cmd="$4"
+       local type="$5"
 
        local addr=$(echo "$prefix" | cut -d/ -f1)
        local rem=$(echo "$prefix" | cut -d/ -f2)
@@ -85,101 +126,223 @@ announce_prefix() {
                valid=$(echo "$rem" | cut -d, -f3)
        }
 
-       local msg='{"network": "'"$network"'", "prefix": "'"$addr"'", "length": '"$length"
-       [ -n "$valid" ] && msg="$msg"', "valid": '"$valid"', "preferred": '"$prefer"
-       [ -z "$cmd" ] && cmd=newprefix
-       
-       ubus call 6distributed "$cmd" "$msg}"
+       # Get prefix configuration
+       local ula=""
+       local prefix_action=""
+       config_get ula global ula_prefix
+       config_get prefix_action "$network" prefix_action
+       [ -z "$prefix_action" ] && prefix_action="distribute"
+
+       # Always announce the ULA when doing NPT
+       [ "$prefix" == "$ula" -a "$prefix_action" == "npt" ] && prefix_action="distribute"
+
+       [ "$prefix_action" == "distribute" -o "$prefix_action" == "npt" ] && {
+               local msg='{"network": "'"$network"'", "prefix": "'"$addr"'", "length": '"$length"
+               [ -n "$valid" ] && msg="$msg"', "valid": '"$valid"', "preferred": '"$prefer"
+               [ -z "$cmd" ] && cmd=newprefix
+
+               [ "$prefix_action" == "npt" ] && msg="$msg"', "npt": 1'
+               [ "$type" == "secondary" ] && msg="$msg"', "secondary": 1'
+
+               # Detect MTU
+               local mtu
+               conf_get mtu "$device" mtu
+               msg="$msg"', "mtu": '"$mtu"
+
+               ubus call 6distributed "$cmd" "$msg}"
+       }
+
+       [ "$prefix_action" == "npt" ] && {
+               local chain="network6_npt_$network"
+               local ula_addr=$(echo "$ula" | cut -d/ -f1)
+               local ula_rem=$(echo "$ula" | cut -d/ -f2)
+               local ula_length=$(echo "$ula_rem" | cut -d, -f1)
+               local device=""
+
+               network_get_device device "$network"
+               [ "$length" -lt "$ula_length" ] && length="$ula_length"
+               [ "$cmd" == "delprefix" ] && cmd="-D $chain" || cmd="-A $chain"
+
+               local in="-i $device -d $addr/$length -j NETMAP --to $ula_addr/$ula_length"
+               local out="-o $device -s $ula_addr/$ula_length -j NETMAP --to $addr/$length"
+
+               setup_npt_chain start "$network"
+               $NAT $cmd $in
+               $NAT $cmd $out
+       }
 }
 
 
-disable_downstream() {
+disable_router() {
        local network="$1"
 
        # Notify the address distribution daemon
        ubus call 6distributed deliface '{"network": "'"$network"'"}'
 
-       # Disable advertisement daemon
-       stop_service /usr/sbin/6relayd "/var/run/ipv6-downstream-$network.pid"
+
+       # Start RD & DHCPv6 service
+       local router_service
+       config_get router_service global router_service
+
+       if [ "$router_service" == "dnsmasq" ]; then
+               rm -f "/var/etc/dnsmasq.d/ipv6-router-$network.conf"
+               /etc/init.d/dnsmasq restart
+       else
+               stop_service /usr/sbin/6relayd "/var/run/ipv6-router-$network.pid"
+       fi
+}
+
+
+restart_relay_slave() {
+       local __section="$1"
+       local __master="$2"
+
+       network_is_up "$__section" || return
+
+       local __device=""
+       network_get_device __device "$__section"
+
+       local __cmaster=""
+       config_get __cmaster "$__section" relay_master
+
+       [ "$__master" == "$__cmaster" ] && {
+               disable_interface "$__section"
+               enable_interface "$__section" "$__device"
+       }
 }
 
 
-restart_relay_add() {
+add_relay_slave() {
        local __section="$1"
        local __return="$2"
        local __master="$3"
-       local __disable="$4"
+       local __mode="$4"
 
        network_is_up "$__section" || return
 
+       # Get device
+       local __device=""
+       network_get_device __device "$__section"
+
        # Match master network
        local __cmaster=""
        config_get __cmaster "$__section" relay_master
-       [ "$__master" != "$__cmaster" ] && return
+       [ "$__master" == "$__cmaster" ] || return
        
+       # Test slave  mode
+       local __cmode=""
+       config_get __cmode "$__section" mode
+       [ "$__cmode" == "downstream" ] && __cmode="router"
+
+       # Don't start fallback interfaces if we are in forced-relay mode
+       [ "$__cmode" == "relay" -o "$__mode" == "fallback" ] || return
+
+       # Don't make non-relay or non-router interfaces slaves
+       [ "$__cmode" == "relay" -o "$__cmode" == "router" ] || return
+
        # Disable any active distribution
-       disable_downstream "$__section"
+       [ "$__cmode" == "router" ] && disable_router "$__section"
 
-       local __device=""
-       network_get_device __device "$__section"
-       
-       # Coming from stop relay, reenable distribution
-       [ "$__disable" == "disable" ] && {
-               enable_downstream "$__section" "$__device"
-               return
-       }
+       # Configure interface to accept RA and send RS
+       conf_set "$__device" accept_ra 2
+       conf_set "$__device" forwarding 2
 
-       
        eval "$__return"'="$'"$__return"' '"$__device"'"'
 }
 
 
 stop_relay() {
        local network="$1"
-       local pid="/var/run/ipv6-relay-$network.pid"
-       local was_running=""
+       local pid_fallback="/var/run/ipv6-relay-fallback-$network.pid"
+       local pid_forced="/var/run/ipv6-relay-forced-$network.pid"
+       local was_fallback=""
        
-       stop_service /usr/sbin/6relayd "$pid" was_running
+       stop_service /usr/sbin/6relayd "$pid_fallback" was_fallback
+       stop_service /usr/sbin/6relayd "$pid_forced"
 
        # Reenable normal distribution on slave interfaces      
-       [ -n "$was_running" ] && config_foreach restart_relay_add interface dummy "$network" disable
+       [ -n "$was_fallback" ] && config_foreach restart_relay_slave interface "$network"
+}
+
+
+detect_forced_relay_mode() {
+       local __section="$1"
+       local __mode="$2"
+
+       local __cmode
+       config_get __cmode "$__section" mode
+       [ "$__cmode" == "relay" ] && eval "$__mode=forced"
 }
 
 
 restart_relay() {
        local network="$1"
-       local force="$2"
-       local pid="/var/run/ipv6-relay-$network.pid"
+       local mode="$2"
 
-       local not_running=0
-       [ -f "$pid" ] || not_running=1
+       # Stop last active relay
+       stop_relay "$network"
 
-       # Don't start if not desired
-       [ "$force" != "1" ] && [ "$not_running" == "1" ] && return
+       # Detect if we have a forced-relay
+       [ -z "$mode" ] && config_foreach detect_forced_relay_mode interface mode
 
-       # Kill current relay and distribution daemon
-       stop_relay "$network"
+       # Don't start without a mode
+       [ -z "$mode" ] && return
 
        # Detect master device
        local device=""
-       network_get_device device $network
+       network_get_device device "$network"
 
        # Generate command string
-       local cmd="/usr/sbin/6relayd -A $device "
-       config_foreach restart_relay_add interface cmd "$network"
+       local cmd="/usr/sbin/6relayd -A $device"
+       local ifaces=""
+       config_foreach add_relay_slave interface ifaces "$network" "$mode"
 
        # Start relay
-       start_service "$cmd" "$pid"
+       local pid="/var/run/ipv6-relay-$mode-$network.pid"
+       [ -n "$ifaces" ] && start_service "$cmd $ifaces" "$pid"
+
+       # There are no slave interface, however indicate that we want to relay
+       [ -z "$ifaces" ] && touch "$pid"
+}
+
+
+setup_prefix_fallback() {
+       local cmd="$1"
+       local network="$2"
+       local device="$3"
+
+       stop_relay "$network"
+       restart_relay "$network"
+
+       setup_masquerading stop "$network"
+
+       [ "$cmd" != "stop" ] && {
+               local fallback=""
+               config_get fallback "$network" prefix_fallback
+
+               [ "$fallback" == "relay" ] && restart_relay "$network" fallback
+               [ "$fallback" == "masquerade" ] && setup_masquerading start "$network" "$device"
+       }
 }
 
 
 restart_master_relay() {
        local network="$1"
+       local mode="$2"
+       local pid_fallback="/var/run/ipv6-relay-fallback-$network.pid"
+       local pid_forced="/var/run/ipv6-relay-forced-$network.pid"
 
        # Disable active relaying to this interface
-       local relay_master
        config_get relay_master "$network" relay_master
-       [ -n "$relay_master" ] && restart_relay "$relay_master"
+       [ -z "$relay_master" ] && return
+       network_is_up "$relay_master" || return
+
+       # Detect running mode
+       [ -z "$mode" && -f "$pid_fallback" ] && mode="fallback"
+       [ -z "$mode" && -f "$pid_forced" ] && mode="forced"
+
+       # Restart relay if running or start requested
+       [ -n "$mode" ] && restart_relay "$relay_master" "$mode"
 }
 
 
@@ -193,32 +356,27 @@ disable_interface() {
        restart_master_relay "$network"
 
        # Disable distribution
-       disable_downstream "$network"
+       disable_router "$network"
 
-       # Disable relay
+       # Disable any active relays, masquerading rules and NPT rules
        stop_relay "$network"
+       setup_masquerading stop "$network"
+       setup_npt_chain stop "$network"
 
        # Disable DHCPv6 client if enabled, state script will take care
-       stop_service /usr/sbin/odhcp6c "/var/run/ipv6-upstream-$network.pid"
+       stop_service /usr/sbin/odhcp6c "/var/run/ipv6-dhcpv6-$network.pid"
 }
 
 
-enable_static() {
+enable_ula_prefix() {
        local network="$1"
-       local device="$2"
-
-       # Enable global forwarding
-       local global_forward
-       conf_get global_forward all forwarding
-       [ "$global_forward" != "1" ] && conf_set all forwarding 1
-
-       # Configure device
-       conf_set "$device" accept_ra 1
-       conf_set "$device" forwarding 1
+       local ula="$2"
+       local device="$3"
+       [ -z "$ula" ] && ula="global"
 
        # ULA-integration
        local ula_prefix=""
-       config_get ula_prefix "$network" ula_prefix
+       config_get ula_prefix "$ula" ula_prefix
 
        # ULA auto configuration (first init)
        [ "$ula_prefix" == "auto" ] && {
@@ -236,19 +394,43 @@ enable_static() {
                ula_prefix="fd$r1:$r2:$r3::/48"
 
                # Save prefix so it will be preserved across reboots
-               uci set network6.$network.ula_prefix=$ula_prefix
-               uci commit network6
+               config_set "$ula" ula_prefix "$ula_prefix"
+               uci_set network6 "$ula" ula_prefix "$ula_prefix"
+               uci_commit network6
        }
 
        # Announce ULA
-       [ -n "$ula_prefix" ] && announce_prefix $ula_prefix $network
+       [ -n "$ula_prefix" ] && announce_prefix "$ula_prefix" "$network" "$device" newprefix secondary
+}
+
+
+enable_static() {
+       local network="$1"
+       local device="$2"
+
+       # Enable global forwarding
+       local global_forward
+       conf_get global_forward all forwarding
+       [ "$global_forward" != "1" ] && conf_set all forwarding 1
+
+       # Configure device
+       conf_set "$device" accept_ra 1
+       conf_set "$device" forwarding 1
+
+       # Enable ULA
+       enable_ula_prefix "$network" global "$device"
+       # Compatibility (deprecated)
+       enable_ula_prefix "$network" "$network" "$device"
 
        # Announce all static prefixes
-       config_list_foreach "$network" static_prefix announce_prefix $network
+       config_list_foreach "$network" static_prefix announce_prefix "$network" "$device"
+
+       # start relay if there are forced relay members
+       restart_relay "$network"
 }
 
 
-enable_downstream() {
+enable_router() {
        local network="$1"
        local device="$2"
 
@@ -259,15 +441,30 @@ enable_downstream() {
        [ "$length" -ne "0" ] && ubus call 6distributed newiface '{"network": "'"$network"'", "iface": "'"$device"'", "length": '"$length"'}'
 
        # Start RD & DHCPv6 service
-       local pid="/var/run/ipv6-downstream-$network.pid"
-       start_service "/usr/sbin/6relayd -Rserver -Dserver . $device" "$pid"
+       local router_service
+       config_get router_service global router_service
+
+       if [ "$router_service" == "dnsmasq" ]; then
+               local dnsmasq_opts
+               config_get dnsmasq_opts "$network" dnsmasq_opts
+               [ -z "$dnsmasq_opts" ] && dnsmasq_opts="ra-names,24h"
+
+               local conf="/var/etc/dnsmasq.d/ipv6-router-$network.conf"
+               mkdir -p $(dirname $conf)
+               echo "dhcp-range=::00ff,::ffff,constructor:$device,$dnsmasq_opts" > $conf
+               echo "enable-ra" >> $conf
+               /etc/init.d/dnsmasq restart
+       else
+               local pid="/var/run/ipv6-router-$network.pid"
+               start_service "/usr/sbin/6relayd -S . $device" "$pid"
+       fi
 
        # Try relaying if necessary
        restart_master_relay "$network"
 }
 
 
-enable_upstream() {
+enable_dhcpv6() {
        local network="$1"
        local device="$2"
        
@@ -292,13 +489,52 @@ enable_upstream() {
        }
        
        # Start DHCPv6 client
-       local pid="/var/run/ipv6-upstream-$network.pid"
+       local pid="/var/run/ipv6-dhcpv6-$network.pid"
        start_service "/usr/sbin/odhcp6c -s/lib/ipv6/dhcpv6.sh $dhcp6_opts" "$pid"
 
        # Refresh RA on all interfaces
-       for pid in /var/run/ipv6-downstream-*.pid; do
+       for pid in /var/run/ipv6-router-*.pid; do
                kill -SIGUSR1 $(cat "$pid")
        done
 }
 
 
+enable_6to4() {
+       local network="$1"
+       local device="$2"
+       local mode="$3"
+
+       local prefixlen="48"
+       [ "$mode" == "6rd" ] && {
+               local ip4prefix=$(uci_get network "$network" ip4prefixlen 0)
+               local ip6prefix=$(uci_get network "$network" ip6prefixlen 32)
+               prefixlen=$(($ip6prefix + 32 - $ip4prefix))
+       }
+
+       local prefix=""
+       network_get_ipaddr6 prefix "$network"
+
+       announce_prefix "$prefix/$prefixlen" "$network" "$device"
+}
+
+
+enable_interface()
+{
+       local network="$1"
+       local device="$2"
+       local mode=""
+
+       config_get mode "$network" mode
+       [ -n "$mode" -a "$mode" != "none" ] || return
+
+       # Compatibility with old mode names
+       [ "$mode" == "downstream" ] && mode=router
+       [ "$mode" == "upstream" ] && mode=dhcpv6
+
+       # Run mode startup code
+       enable_static "$network" "$device"
+       [ "$mode" == "dhcpv6" ] && enable_dhcpv6 "$network" "$device"
+       [ "$mode" == "router" ] && enable_router "$network" "$device"
+       [ "$mode" == "6to4" -o "$mode" == "6rd" ] && enable_6to4 "$network" "$device" "$mode"
+       [ "$mode" == "relay" ] && restart_master_relay "$network" forced
+}