#!/bin/sh /etc/rc.common # Copyright (C) 2008 Alina Friedrichsen 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_RDNSS_STRING_OPTIONS='AdvRDNSSLifetime' RADVD_DNSSL_STRING_OPTIONS='AdvDNSSLLifetime' 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_bool ignore "$cfg" ignore 0 [ "$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 config_get clients "$cfg" client if [ -n "$clients" ]; then printf '\n\tclients\n\t{\n' for client in $clients; do validate_ip6addr "$client" || continue printf '\t\t%s;\n' "$client" done printf '\t};\n' fi 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 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 printf '\t};\n' return 0 } radvd_write_dnssl() { local cfg=$1 validate_varname "$cfg" || return 0 local ignore local interfaces local interface local suffixes local suffix local suffix_list 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 suffixes "$cfg" suffix for suffix in $suffixes; do validate_radvd_string "$suffix" || continue suffix_list="$suffix_list $suffix" done printf '\n\tDNSSL%s\n\t{\n' "$suffix_list" for name in $RADVD_DNSSL_STRING_OPTIONS; do config_get value "$cfg" "$name" validate_radvd_string "$value" || continue printf '\t\t%s %s;\n' "$name" "$value" 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 config_foreach radvd_add_interface DNSSL 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 config_foreach radvd_write_dnssl dnssl printf '};\n\n' done return 0 } start() { 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 sysctl -w net.ipv6.conf.all.forwarding=1 > /dev/null 2> /dev/null radvd -C "$RADVD_CONFIG_FILE" -m stderr_syslog -p /var/run/radvd.pid } stop() { killall radvd }