#!/bin/sh #---------------------------------------------------------------------------- # /etc/rc.d/base-helper.ipv6 __FLI4LVER__ # basic helper functions for IPv6 # # Creation: 2007-10-21 kristov # Last Update: $Id$ #---------------------------------------------------------------------------- #---------------------------------------------------------------------------- # usage: lookup_name_ipv6 # parameter: either a FullQualifiedDomainName or an alias name # returns: nothing # errorcodes: 0 success - successfully resolved name to IPv6 address # 1 error - no matching host record found # # description: Tries to resolve either an FQDN or an alias to an IPv6 address. # Uses /etc/hosts and /etc/hosts.d/hosts* as source. # MAGIC done by this function: # The result will be stored in an global variable "res". #---------------------------------------------------------------------------- lookup_name_ipv6 () { local name="$1" if [ -f /etc/dnsmasq.d/cname.conf ] then local real=`grep "=${name}," /etc/dnsmasq.d/cname.conf | cut -d "=" -f2 | cut -d "," -f2` [ -z "$real" ] || name="$real" fi local ip=`sed -n -e "/[[:space:]]${name}\([[:space:]]\|$\)/s/^\([0-9a-fA-F:]\+\)[[:space:]].*/\1/p" /etc/hosts.d/hosts*` [ -z "$ip" ] && return 1 set $ip [ "$2" ] && log_error "lookup_name_ipv6: multiple IPv6 addresses for $name - $ip" res=$1 return 0 } #---------------------------------------------------------------------------- # Translates a net variable like IPV6_NET_1. Returns 0 on success and # non-zero on failure. Stores the translation result in the variable 'res'. # # If a tunnel is associated with the net and the tunnel is up, the address # returned combines the assigned net prefix with the configured suffix. # Otherwise only the suffix is returned. # # $1 = name of net variable #---------------------------------------------------------------------------- do_translate_ip6_net() { get_value $1 is_error && return 1 local net="$res" local prefix= eval local tunnel=\"\$$1_TUNNEL\" if [ -n "$tunnel" ] then potentially_dynamic=1 local config="/var/run/ipv6.tunnels/$tunnel.conf" [ -f "$config" ] && . "$config" else prefix="::/0" fi if [ -n "$prefix" ] then prefix=$(expandv6.sh $prefix) local prefixaddr=$(echo $prefix | cut -d '/' -f 1) local net=$(expandv6.sh $net) local netaddr=$(echo $net | cut -d '/' -f 1) local netlen=$(echo $net | cut -d '/' -f 2) res=$(netcalc canonicalize "$(addip6 $prefixaddr $netaddr)/$netlen") return 0 else set_error return 1 fi } #---------------------------------------------------------------------------- # Checks if a config value like IPV6_NET_1 can be translated. Returns 0 on # success and a non-zero value on failure. A translation may be impossible if # e.g. the source value is associated with a tunnel which has not started yet. # # $1 = value to translate #---------------------------------------------------------------------------- can_translate_ip6_net() { tin_param="$1" case $tin_param in none | default | pppoe | any | IPV6_TUNNEL_*_DEV | IPV6_NET_*_DEV | IPV6_ROUTE_*) return 0 ;; dynamic) [ -s /var/run/dynamic.ipv6 ] ;; IPV6_NET_*_IPADDR) can_translate_ip6_net ${tin_param%_IPADDR} ;; IPV6_NET_*) do_translate_ip6_net $tin_param res=$? clear_error return $res ;; @*) lookup_name_ipv6 ${tin_param#@} ;; *) echo $tin_param | grep -q '^[0-9a-zA-Z:]\+\(/[0-9]*\)\?$' ;; esac } #---------------------------------------------------------------------------- # Translates a config value like IPV6_NET_1. Returns 0 on success and a # non-zero value on failure; in the latter case, set_error is invoked. The # result is stored in the variable 'res'. # # $1 = value to translate # $2 = (optional) name of variable containing this value; used in error # message when value is invalid # $3 = (optional) name of variable receiving the translated value in addition # to 'res' #---------------------------------------------------------------------------- translate_ip6_net () { tin_param="$1" local var_name=$2 local var=$3 potentially_dynamic= case $tin_param in none | default | pppoe) res=$tin_param ;; dynamic) potentially_dynamic=1 if [ -s /var/run/dynamic.ipv6 ] then # TODO: only the first address is taken res=$(head -n 1 /var/run/dynamic.ipv6) else set_error "no dynamic IPv6 address available" fi ;; any) res=::/0 ;; IPV6_TUNNEL_*_DEV) get_value $tin_param ;; IPV6_NET_*_DEV) get_value $tin_param translate_ip_dev $res res ;; IPV6_NET_*_IPADDR) do_translate_ip6_net ${tin_param%_IPADDR} res=${res%/*} ;; IPV6_NET_*) do_translate_ip6_net $tin_param ;; IPV6_ROUTE_*) get_value $tin_param set $res res=$1 case $res in ::/0) set_error "you can't use a default route entry in a packet filter rule" ;; esac ;; @*) if ! lookup_name_ipv6 ${tin_param#@} then set_error "unable to lookup name $tin_param" fi ;; *) if echo $tin_param | grep '^[0-9a-zA-Z:]\+\(/[0-9]*\)\?$' >/dev/null 2>&1 then res="$tin_param" else set_error fi ;; esac if is_error then if [ "$var_name" ]; then log_error "Unable to translate value '$tin_param' contained in $var_name." else set_error "invalid value '$tin_param' in translate_ip6_net ()" fi clear_error return 1 else [ "$var" ] && eval $var="\"$res\"" return 0 fi } #---------------------------------------------------------------------------- # Translates a symbolic device name (e.g. pppoe) into the real interface (e.g. # ppp0). Invokes set_error when the symbolic name is unknown. # # $1 = symbolic network device to translate # $2 = name of variable receiving the translated value # $3 = if nonzero, nonexisting interfaces are ignored (this is e.g. used for # the firewall, as the firewall accepts interface _expressions_ (e.g. # ppp+) and may reference interfaces that will be created later (e.g. # ppp interfaces dynamically created by pppoe_server) #---------------------------------------------------------------------------- translate_ip6_dev () { local tid_tif=$1 local tid_var=$2 local tid_ignore=$3 local tid_real_if= if [ ! "$tid_var" ]; then log_error "translate_ip6_dev: missing variable name" return fi net_alias_lookup_dev $tid_tif $tid_var TID_ && return case $tid_tif in IPV6_NET_*_DEV) translate_ip6_net $tid_tif && tid_real_if=$res ;; IPV6_TUNNEL_*_DEV) translate_ip6_net $tid_tif && tid_real_if=$res ;; circuit-*) if [ -f /var/run/$tid_tif ]; then read tid_real_if < /var/run/$tid_tif else set_error " Error: unknown circuit $tid_tif" fi ;; pppoe) if [ -f /var/run/pppoe-device ]; then read tid_real_if < /var/run/pppoe-device else set_error " Error: unknown circuit pppoe" fi ;; *) tid_real_if=$tid_tif ;; esac if [ "$tid_real_if" ]; then case $tid_real_if in *+) ;; # ignore wildcard names *) if grep -q "^[[:space:]]*\<$tid_real_if\>" /proc/net/dev then net_alias_add $tid_tif $tid_real_if TID_ elif [ -z "$tid_ignore" ] then log_error "translate_ip6_dev '$tid_tif': device '$tid_real_if' not present" fi ;; esac [ "$tid_var" ] && eval $tid_var=$tid_real_if fi } #---------------------------------------------------------------------------- # Flips bit 2 in a hexadecimal digit, needed for computing valid EUI-64 # identifiers. # # $1 = hexadecimal digit # $result = passed digit with bit 2 flipped, returned in lowercase #---------------------------------------------------------------------------- fliplocalbit() { case $1 in 0) result=2;; 1) result=3;; 2) result=0;; 3) result=1;; 4) result=6;; 5) result=7;; 6) result=4;; 7) result=5;; 8) result=a;; 9) result=b;; a|A) result=8;; b|B) result=9;; c|C) result=e;; d|D) result=f;; e|E) result=c;; f|F) result=d;; *) result=$1;; esac }