diff options
Diffstat (limited to 'net')
| -rw-r--r-- | net/ip6rd.sh | 168 | 
1 files changed, 168 insertions, 0 deletions
diff --git a/net/ip6rd.sh b/net/ip6rd.sh new file mode 100644 index 00000000..9da05768 --- /dev/null +++ b/net/ip6rd.sh @@ -0,0 +1,168 @@ +# Copyright (c) 2011 by Gentoo Foundation +# Released under the 2-clause BSD license. + +_config_vars="$_config_vars link prefix suffix ipv4mask relay" + +ip6rd_depend() +{ +	program ip +	after interface +} + +ip6rd_pre_start() +{ +	# ALL interfaces run pre_start blocks, not just those with something +	# assigned, so we must check if we need to run on this interface before we +	# do so. +	local config +	eval config=\$config_${IFVAR} +	[ "$config" = "ip6rd" ] || return 0 + +	case "${MODULES}" in +		*" ifconfig "*) +			eerror "ifconfig is not supported for 6rd" +			eerror "Please emerge sys-apps/iproute2" +			return 1 +			;; +	esac + +	local host= suffix= relay= addr= iface=${IFACE} config_ip6rd= localip= ipv4mask= +	eval host=\$link_${IFVAR} +	if [ -z "${host}" ]; then +		eerror "link_${IFVAR} not set" +		return 1 +	fi + +	eval host=\${link_${IFVAR}} +	eval ipv4mask=\${ipv4mask_${IFVAR}:-0} +	eval suffix=\${suffix_${IFVAR}:-1} +	eval relay=\${relay_${IFVAR}} +	eval prefix=\${prefix_${IFVAR}} + +	IFACE=${host} +	addrs=$(_get_inet_addresses) +	IFACE=${iface} +	if [ -z "${addrs}" ]; then +		eerror "${host} is not configured with an IPv4 address" +		return 1 +	fi +	# TODO: Get this settings from DHCP (Option 212)  +	if [ -z "${prefix}" ]; then +		eerror "prefix_${IFVAR} not set" +		return 1 +	fi +	if [ -z "${relay}" ]; then +		eerror "relay_${IFVAR} not set" +		return 1 +	fi +	for addr in ${addrs}; do +		# Strip the subnet +		local ip="${addr%/*}" subnet="${addr#*/}" +		# We don't work on private IPv4 addresses +		if _ip6rd_inet_is_private_network "${ip}" +		then +			continue +		fi + +		local ip6= ip6_prefix="${prefix%::/*}" ip6_subnet="${prefix#*/}" +		ip6_subnet=$((ip6_subnet + (32-ipv4mask))) +		eval ip6="$(printf "${ip6_prefix}:%s::%s" \ +		$(_ip6rd_prefix_shave_bits  ${ip} ${ipv4mask}) ${suffix})" +		veinfo "Derived IPv6 address: ${ip6}" + +		# Now apply our IPv6 address to our config +		config_ip6rd="${config_ip6rd}${config_ip6rd:+ }${ip6}/${ip6_subnet}" + +		if [ -n "${localip}" ]; then +			localip="any" +		else +			localip="${ip}" +		fi +	done + +	if [ -z "${config_ip6rd}" ]; then +		eerror "No global IPv4 addresses found on interface ${host}" +		return 1 +	fi + +	ebegin "Creating 6rd tunnel ${IFACE}" +	if [ "${IFACE}" != "sit0" ]; then +		_tunnel add "${IFACE}" mode sit ttl 255 remote any local "${localip}" +	fi +	_tunnel 6rd dev "${IFACE}" 6rd-prefix "${prefix}" +	eend $? || return 1 +	_up + +	routes_ip6rd="2003::/3 via ::${relay} metric 2147483647" +	service_set_value "config_ip6rd_$IFVAR" "$config_ip6rd" +	service_set_value "routes_ip6rd_$IFVAR" "$routes_ip6rd" +} + +ip6rd_start() +{ +	local config_ip6rd=$(service_get_value "config_ip6rd_$IFVAR") +	local routes_ip6rd=$(service_get_value "routes_ip6rd_$IFVAR") + +	# Now apply our config +	eval config_${config_index}=\'"${config_ip6rd}"\' +	: $(( config_index -= 1 )) + +	# Add a route for us, ensuring we don't delete anything else +	local routes="$(_get_array "routes_${IFVAR}") +$routes_ip6rd" +	eval routes_${IFVAR}=\$routes +} + +_ip6rd_inet_atoi() +{ +	local IFS="${IFS}." ipi=0 j=3 +	for i in $1 ; do +	       ipi=$(( ipi | i << 8*j-- )) +	done +	echo ${ipi} +} + +_ip6rd_inet_itoa() +{ +	local ipi=$1 +	for i in 0 1 2 3; do +		if [ $i != 3 ] ; then +			printf "%d." $(( (ipi & ~((1<<24)-1)) >> 24 )) +			ipi=$(( (ipi & ((1<<24)-1)) << 8)) +		else +			printf "%d\n" $(( (ipi & ~((1<<24)-1)) >> 24 )) +		fi +	done +} + +_ip6rd_inet_get_network() +{ +	echo $(_ip6rd_inet_itoa $(( ($(_ip6rd_inet_atoi $1) & ((1<<$2)-1) << (32-$2) ) )) ) +} + +_ip6rd_inet_is_private_network() +{ +	if [ "$(_ip6rd_inet_get_network $1 16)" = "192.168.0.0" ]\ +	  || [ "$(_ip6rd_inet_get_network $1 8)" = "10.0.0.0" ]\ +	  || [ "$(_ip6rd_inet_get_network $1 12)" = "172.16.0.0" ]\ +	  || [ "$(_ip6rd_inet_get_network $1 16)" = "169.254.0.0" ] +	then +		return 0; +	fi +	return 1; +} + +_ip6rd_prefix_shave_bits() +{ +	local ipi= +	ipi=$((  ($(_ip6rd_inet_atoi $1) & (1<<(32-$2))-1) << $2)) +	if [ $2 -le 16 ] +	then +		printf "%04x:%0$(( (16-$2>>2)+(($2%4)?1:0) ))x" \ +		$((ipi >> 16)) $((ipi & (1<<(16-$2))-1)) +	elif [ $2 -lt 32 ] +	then +		printf "%0$(( (32-$2>>2)+(($2%4)?1:0) ))x" \ +		$((ipi >> 16)) +	fi	 +}  | 
