. /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"
}
local __section="$1"
local __device="$2"
local __return="$3"
-
local __cdevice
network_get_device __cdevice "$__section"
[ "$__cdevice" != "$__device" ] && return
}
+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)
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"
}
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" ] && {
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"
[ "$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"
}
# 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
+}