#!/bin/sh /etc/rc.common
-# Copyright (C) 2006 OpenWrt.org
+# Copyright (C) 2008 Alina Friedrichsen <x-alina@gmx.net>
START=50
+RADVD_INTERFACE_STRING_OPTIONS='MaxRtrAdvInterval MinRtrAdvInterval MinDelayBetweenRAs AdvLinkMTU AdvReachableTime AdvRetransTimer AdvCurHopLimit AdvDefaultLifetime AdvDefaultPreference HomeAgentLifetime HomeAgentPreference'
+RADVD_INTERFACE_BOOLEAN_OPTIONS='IgnoreIfMissing AdvSendAdvert UnicastOnly AdvManagedFlag AdvOtherConfigFlag AdvSourceLLAddress AdvHomeAgentFlag AdvHomeAgentInfo AdvMobRtrSupportFlag AdvIntervalOpt'
+
+RADVD_PREFIX_STRING_OPTIONS='AdvValidLifetime AdvPreferredLifetime'
+RADVD_PREFIX_BOOLEAN_OPTIONS='AdvOnLink AdvAutonomous AdvRouterAddr'
+
+RADVD_ROUTE_STRING_OPTIONS='AdvRouteLifetime AdvRoutePreference'
+RADVD_ROUTE_BOOLEAN_OPTIONS=''
+
+RADVD_RDNSS_STRING_OPTIONS='AdvRDNSSPreference AdvRDNSSLifetime'
+RADVD_RDNSS_BOOLEAN_OPTIONS='AdvRDNSSOpen'
+
+validate_varname() {
+ local varname=$1
+ [ -z "$varname" -o "$varname" != "${varname%%[!A-Za-z0-9_]*}" ] && return 1
+ return 0
+}
+
+validate_ifname() {
+ local ifname=$1
+ [ -z "$ifname" -o "$ifname" != "${ifname%%[!A-Za-z0-9.:_-]*}" ] && return 1
+ return 0
+}
+
+validate_ip6addr() {
+ local ip6addr=$1
+ [ -z "$ip6addr" -o "$ip6addr" != "${ip6addr%%[!A-Fa-f0-9.:]*}" ] && return 1
+ return 0
+}
+
+validate_ip6prefix() {
+ local ip6prefix=$1
+ [ -z "$ip6prefix" -o "$ip6prefix" != "${ip6prefix%%[!A-Fa-f0-9./:]*}" ] && return 1
+ return 0
+}
+
+validate_radvd_string() {
+ local radvd_string=$1
+ [ -z "$radvd_string" -o "$radvd_string" != "${radvd_string%%[!a-z0-9.:_-]*}" ] && return 1
+ return 0
+}
+
+get_ifname() {
+ local interface=$1
+ validate_varname "$interface" || return 1
+ local cfgt
+ local ifname
+
+ scan_interfaces
+ config_get cfgt "$interface" TYPE
+ [ "$cfgt" != "interface" ] && return 1
+ config_get ifname "$interface" ifname
+ validate_ifname "$ifname" || return 1
+ printf '%s\n' "$ifname"
+
+ return 0
+}
+
+get_ip6addr() {
+ local ifname=$1
+ local scope=$2
+ local iproute2_scope
+ local ifconfig_scope
+ local ip6addr
+
+ case "$scope" in
+ host) iproute2_scope=host ifconfig_scope=Host;;
+ link) iproute2_scope=link ifconfig_scope=Link;;
+ site) iproute2_scope=site ifconfig_scope=Site;;
+ global) iproute2_scope=global ifconfig_scope=Global;;
+ "") get_ip6addr "$ifname" global || get_ip6addr "$ifname" site; return;;
+ *) return 1;;
+ esac
+
+ ip6addr=$(LANG=C ip -f inet6 -- addr show dev "$ifname" 2> /dev/null | sed -n -e 's/^ *inet6 \([A-Fa-f0-9.:]*[/][0-9]*\) scope '"$iproute2_scope"' $/\1/p' | head -n 1)
+ if [ -z "$ip6addr" ]; then
+ ip6addr=$(LANG=C ifconfig "$ifname" 2> /dev/null | sed -n -e 's/^ *inet6 addr: \([A-Fa-f0-9.:]*[/][0-9]*\) Scope:'"$ifconfig_scope"'$/\1/p' | tail -n 1)
+ [ -z "$ip6addr" ] && return 1
+ fi
+
+ printf '%s\n' "$ip6addr"
+
+ return 0
+}
+
+radvd_find_config_file() {
+ local cfg=$1
+ validate_varname "$cfg" || return 0
+
+ config_get_bool ignore "$cfg" ignore 0
+ [ "$ignore" -ne 0 ] && return 0
+ config_get RADVD_CONFIG_FILE "$cfg" config_file
+
+ return 0
+}
+
+radvd_add_interface() {
+ local cfg=$1
+ validate_varname "$cfg" || return 0
+ local ignore
+ local interfaces
+ local interface
+ local list_interface
+ local exist
+
+ config_get ignore "$cfg" ignore
+ [ "$ignore" -ne 0 ] && return 0
+
+ config_get interfaces "$cfg" interface
+ for interface in $interfaces; do
+ validate_varname "$interface" || continue
+ exist=0
+ for list_interface in $RADVD_INTERFACES; do
+ [ "$interface" = "$list_interface" ] && exist=1
+ done
+ [ "$exist" -eq 0 ] && RADVD_INTERFACES="$RADVD_INTERFACES $interface"
+ done
+
+ return 0
+}
+
+radvd_write_interface() {
+ local cfg=$1
+ validate_varname "$cfg" || return 0
+ local ignore
+ local interfaces
+ local interface
+ local name
+ local value
+
+ config_get_bool ignore "$cfg" ignore 0
+ [ "$ignore" -ne 0 ] && return 0
+
+ config_get interfaces "$cfg" interface
+ exist=0
+ for interface in $interfaces; do
+ [ "$INTERFACE" = "$interface" ] && exist=1
+ done
+ [ "$exist" -eq 0 ] && return 0
+
+ for name in $RADVD_INTERFACE_STRING_OPTIONS; do
+ config_get value "$cfg" "$name"
+ validate_radvd_string "$value" || continue
+ printf '\t%s %s;\n' "$name" "$value"
+ done
+
+ for name in $RADVD_INTERFACE_BOOLEAN_OPTIONS; do
+ config_get value "$cfg" "$name"
+ [ -z "$value" ] && continue
+ config_get_bool value "$cfg" "$name" 0
+ if [ "$value" -ne 0 ]; then
+ printf '\t%s on;\n' "$name"
+ else
+ printf '\t%s off;\n' "$name"
+ fi
+ done
+
+ return 0
+}
+
+radvd_write_prefix() {
+ local cfg=$1
+ validate_varname "$cfg" || return 0
+ local ignore
+ local interfaces
+ local interface
+ local prefixes
+ local prefix
+ local name
+ local value
+ local cfgt
+
+ config_get_bool ignore "$cfg" ignore 0
+ [ "$ignore" -ne 0 ] && return 0
+
+ config_get interfaces "$cfg" interface
+ exist=0
+ for interface in $interfaces; do
+ [ "$INTERFACE" = "$interface" ] && exist=1
+ done
+ [ "$exist" -eq 0 ] && return 0
+
+ config_get prefixes "$cfg" prefix
+ if [ -z "$prefixes" ]; then
+ prefixes=$(get_ip6addr "$IFNAME") || return 0
+ fi
+
+ for prefix in $prefixes; do
+ validate_ip6prefix "$prefix" || continue
+ printf '\n\tprefix %s\n\t{\n' "$prefix"
+
+ for name in $RADVD_PREFIX_STRING_OPTIONS; do
+ config_get value "$cfg" "$name"
+ validate_radvd_string "$value" || continue
+ printf '\t\t%s %s;\n' "$name" "$value"
+ done
+
+ for name in $RADVD_PREFIX_BOOLEAN_OPTIONS; do
+ config_get value "$cfg" "$name"
+ [ -z "$value" ] && continue
+ config_get_bool value "$cfg" "$name" 0
+ if [ "$value" -ne 0 ]; then
+ printf '\t\t%s on;\n' "$name"
+ else
+ printf '\t\t%s off;\n' "$name"
+ fi
+ done
+
+ config_get value "$cfg" Base6to4Interface
+ if [ -n "$value" ]; then
+ if ifname=$(get_ifname "$value"); then
+ printf '\t\t%s %s;\n' "Base6to4Interface" "$ifname"
+ fi
+ fi
+
+ printf '\t};\n'
+ done
+
+ return 0
+}
+
+radvd_write_route() {
+ local cfg=$1
+ validate_varname "$cfg" || return 0
+ local ignore
+ local interfaces
+ local interface
+ local prefixes
+ local prefix
+ local name
+ local value
+
+ config_get_bool ignore "$cfg" ignore 0
+ [ "$ignore" -ne 0 ] && return 0
+
+ config_get interfaces "$cfg" interface
+ exist=0
+ for interface in $interfaces; do
+ [ "$INTERFACE" = "$interface" ] && exist=1
+ done
+ [ "$exist" -eq 0 ] && return 0
+
+ config_get prefixes "$cfg" prefix
+ for prefix in $prefixes; do
+ validate_ip6prefix "$prefix" || continue
+ printf '\n\troute %s\n\t{\n' "$prefix"
+
+ for name in $RADVD_ROUTE_STRING_OPTIONS; do
+ config_get value "$cfg" "$name"
+ validate_radvd_string "$value" || continue
+ printf '\t\t%s %s;\n' "$name" "$value"
+ done
+
+ for name in $RADVD_ROUTE_BOOLEAN_OPTIONS; do
+ config_get value "$cfg" "$name"
+ [ -z "$value" ] && continue
+ config_get_bool value "$cfg" "$name" 0
+ if [ "$value" -ne 0 ]; then
+ printf '\t\t%s on;\n' "$name"
+ else
+ printf '\t\t%s off;\n' "$name"
+ fi
+ done
+
+ printf '\t};\n'
+ done
+
+ return 0
+}
+
+radvd_write_rdnss() {
+ local cfg=$1
+ validate_varname "$cfg" || return 0
+ local ignore
+ local interfaces
+ local interface
+ local addrs
+ local addr
+ local addr_list
+ local name
+ local value
+ local i
+
+ config_get_bool ignore "$cfg" ignore 0
+ [ "$ignore" -ne 0 ] && return 0
+
+ config_get interfaces "$cfg" interface
+ exist=0
+ for interface in $interfaces; do
+ [ "$INTERFACE" = "$interface" ] && exist=1
+ done
+ [ "$exist" -eq 0 ] && return 0
+
+ config_get addrs "$cfg" addr
+ i=0
+ for addr in $addrs; do
+ [ "$i" -ge 3 ] && break
+ validate_ip6addr "$addr" || continue
+ addr_list="$addr_list $addr"
+ i=$(($i+1))
+ done
+
+ if [ -z "$addr_list" ]; then
+ addr=$(get_ip6addr "$IFNAME" link) || return 0
+ addr_list=" ${addr%%[/]*}"
+ fi
+
+ printf '\n\tRDNSS%s\n\t{\n' "$addr_list"
+
+ for name in $RADVD_RDNSS_STRING_OPTIONS; do
+ config_get value "$cfg" "$name"
+ validate_radvd_string "$value" || continue
+ printf '\t\t%s %s;\n' "$name" "$value"
+ done
+
+ for name in $RADVD_RDNSS_BOOLEAN_OPTIONS; do
+ config_get value "$cfg" "$name"
+ [ -z "$value" ] && continue
+ config_get_bool value "$cfg" "$name" 0
+ if [ "$value" -ne 0 ]; then
+ printf '\t\t%s on;\n' "$name"
+ else
+ printf '\t\t%s off;\n' "$name"
+ fi
+ done
+
+ printf '\t};\n'
+
+ return 0
+}
+
+radvd_write_config() {
+ include /lib/network
+
+ RADVD_INTERFACES=
+ config_foreach radvd_add_interface interface
+ config_foreach radvd_add_interface prefix
+ config_foreach radvd_add_interface route
+ config_foreach radvd_add_interface RDNSS
+
+ for INTERFACE in $RADVD_INTERFACES; do
+ IFNAME=$(get_ifname "$INTERFACE") || continue
+ printf 'interface %s\n{\n' "$IFNAME"
+ config_foreach radvd_write_interface interface
+ config_foreach radvd_write_prefix prefix
+ config_foreach radvd_write_route route
+ config_foreach radvd_write_rdnss rdnss
+ printf '};\n\n'
+ done
+
+ return 0
+}
+
start() {
- echo 1 > /proc/sys/net/ipv6/conf/all/forwarding
- mkdir -p /var/log
- mkdir -p /var/run
- /usr/sbin/radvd
+ config_load radvd
+
+ RADVD_CONFIG_FILE=
+ config_foreach radvd_find_config_file radvd
+
+ if [ -z "$RADVD_CONFIG_FILE" ]; then
+ mkdir -p -- /var/etc/
+ radvd_write_config > /var/etc/radvd.conf
+ if [ -s "/var/etc/radvd.conf" ]; then
+ RADVD_CONFIG_FILE=/var/etc/radvd.conf
+ fi
+ fi
+
+ [ -z "$RADVD_CONFIG_FILE" ] && return 1
+
+ if grep '^net.ipv6.conf.all.forwarding=1$' /etc/sysctl.conf > /dev/null 2> /dev/null; then
+ sysctl -w net.ipv6.conf.all.forwarding=1 > /dev/null 2> /dev/null
+ fi
+
+ radvd -C "$RADVD_CONFIG_FILE" -m stderr_syslog -p /var/run/radvd.pid
}
stop() {
killall radvd
- echo 0 > /proc/sys/net/ipv6/conf/all/forwarding
}