diff options
| -rw-r--r-- | package/network/ipv6/ipv6-support/Makefile | 46 | ||||
| -rwxr-xr-x | package/network/ipv6/ipv6-support/files/dhcpv6.sh | 52 | ||||
| -rw-r--r-- | package/network/ipv6/ipv6-support/files/ipv6.hotplug | 18 | ||||
| -rw-r--r-- | package/network/ipv6/ipv6-support/files/network6.config | 17 | ||||
| -rw-r--r-- | package/network/ipv6/ipv6-support/files/support.sh | 304 | 
5 files changed, 437 insertions, 0 deletions
diff --git a/package/network/ipv6/ipv6-support/Makefile b/package/network/ipv6/ipv6-support/Makefile new file mode 100644 index 000000000..8397bc462 --- /dev/null +++ b/package/network/ipv6/ipv6-support/Makefile @@ -0,0 +1,46 @@ +# +# Copyright (C) 2010-2012 OpenWrt.org +# +# This is free software, licensed under the GNU General Public License v2. +# See /LICENSE for more information. +# + +include $(TOPDIR)/rules.mk + +PKG_NAME:=ipv6-support +PKG_VERSION:=2012-11-29 +PKG_RELEASE:=1 + +include $(INCLUDE_DIR)/package.mk + +define Package/ipv6-support +  SECTION:=ipv6 +  CATEGORY:=IPv6 +  DEPENDS:=+kmod-ipv6 +6relayd +odhcp6c +6distributed +ip6tables +ubus +  TITLE:=Basic IPv6-support for Customer Edge Routers +  MAINTAINER:=Steven Barth <steven@midlink.org> +  PKGARCH:=all +endef + +define Package/ipv6-support/description +This package provides basic IPv6 support including Router Discovery, +DHCPv6 (client & server), prefix delegation and distribution. +endef + +define Build/Compile +endef + +define Build/Configure +endef + +define Package/ipv6-support/install +	$(INSTALL_DIR) $(1)/etc/hotplug.d/iface +	$(INSTALL_DATA) ./files/ipv6.hotplug $(1)/etc/hotplug.d/iface/20-ipv6 +	$(INSTALL_DIR) $(1)/lib/ipv6 +	$(INSTALL_DATA) ./files/support.sh $(1)/lib/ipv6/support.sh +	$(INSTALL_BIN) ./files/dhcpv6.sh $(1)/lib/ipv6/dhcpv6.sh +	$(INSTALL_DIR) $(1)/etc/config +	$(INSTALL_DATA) ./files/network6.config $(1)/etc/config/network6 +endef + +$(eval $(call BuildPackage,ipv6-support)) diff --git a/package/network/ipv6/ipv6-support/files/dhcpv6.sh b/package/network/ipv6/ipv6-support/files/dhcpv6.sh new file mode 100755 index 000000000..67fa174d1 --- /dev/null +++ b/package/network/ipv6/ipv6-support/files/dhcpv6.sh @@ -0,0 +1,52 @@ +#!/bin/sh +# Copyright (c) 2012 OpenWrt.org +. /lib/ipv6/support.sh +. /lib/netifd/netifd-proto.sh + +local device="$1" +local state="$2" +local network="" + +resolve_network network "$device" + +# Unknown network +[ -z "$network" ] && exit 0 + + +# Announce prefixes +for prefix in $PREFIXES; do +	announce_prefix "$prefix" "$network" +done + +for prefix in $PREFIXES_LOST; do +	announce_prefix "$prefix" "$network" delprefix +done + + +# Enable relaying if requested +local prefix_fallback +config_get prefix_fallback "$network" prefix_fallback +[ "$prefix_fallback" == "relay" -a -z "$PREFIXES" -a "$state" != "unbound" ] && +	restart_relay "$network" 1 + +# Disable relay if requested +[ "$prefix_fallback" != "relay" -o -n "$PREFIXES" -o "$state" == "unbound" ] && +	stop_relay "$network" + + +# Operations in case of success +[ "$state" == "timeout" || "$state" == "unbound" ] && exit 0 + +local peerdns +config_get_bool peerdns "$network" peerdns 0 +[ "peerdns" -eq "1" ] && { +	proto_init_update "*" 1 +	for server in $RDNSS; do +		proto_add_dns_server "$server" +	done +	for domain in $DOMAINS; do +		proto_add_dns_search "$domain" +	done +	proto_send_update "$network" +} + diff --git a/package/network/ipv6/ipv6-support/files/ipv6.hotplug b/package/network/ipv6/ipv6-support/files/ipv6.hotplug new file mode 100644 index 000000000..e3379b6b2 --- /dev/null +++ b/package/network/ipv6/ipv6-support/files/ipv6.hotplug @@ -0,0 +1,18 @@ +#!/bin/sh +# Copyright (c) 2012 OpenWrt.org +[ "$DEVICE" == "lo" ] && exit 0 +. /lib/ipv6/support.sh + +local mode +config_get mode "$INTERFACE" mode + +case "$ACTION" in +	ifup) +		[ "$mode" != "downstream" ] && enable_static $INTERFACE $DEVICE +		[ "$mode" == "upstream" ] && enable_upstream $INTERFACE $DEVICE +		[ "$mode" == "downstream" ] && enable_downstream $INTERFACE $DEVICE +	;; +	ifdown) +		disable_interface $INTERFACE $DEVICE +	;; +esac diff --git a/package/network/ipv6/ipv6-support/files/network6.config b/package/network/ipv6/ipv6-support/files/network6.config new file mode 100644 index 000000000..4632bba0b --- /dev/null +++ b/package/network/ipv6/ipv6-support/files/network6.config @@ -0,0 +1,17 @@ +config interface wan +	option mode		upstream +	option ula_prefix	auto +	option request_prefix	auto +	option prefix_fallback	relay +	option peerdns		1	 + + +config interface lan +	option mode		downstream +	option advertise_prefix	64 +	option relay_master	wan + + +config interface 6in4 +	option mode		static +	list static_prefix	2001:DB8::/48 diff --git a/package/network/ipv6/ipv6-support/files/support.sh b/package/network/ipv6/ipv6-support/files/support.sh new file mode 100644 index 000000000..5525a3a56 --- /dev/null +++ b/package/network/ipv6/ipv6-support/files/support.sh @@ -0,0 +1,304 @@ +#!/bin/sh +# Copyright (c) 2012 OpenWrt.org +. /lib/functions.sh +. /lib/functions/service.sh +. /lib/functions/network.sh + +config_load network6 + + +conf_get() { +	local __return="$1" +	local __device="$2" +	local __option="$3" +	local __value=$(cat "/proc/sys/net/ipv6/conf/$device/$option") +	eval "$__return=$__value" +} + + +conf_set() { +	local device="$1" +	local option="$2" +	local value="$3" +	echo "$value" > "/proc/sys/net/ipv6/conf/$device/$option" +} + + +stop_service() { +	local __exe="$1" +	SERVICE_PID_FILE="$2" +	local __return="$3" + +	service_check "$__exe" && { +		service_stop "$__exe" +		[ -n "$__return" ] && eval "$__return=1" +	} +	rm -f "$SERVICE_PID_FILE" +} + + +start_service() { +	local cmd="$1" +	local pidfile="$2" + +	SERVICE_DAEMONIZE=1 +	SERVICE_WRITE_PID=1 +	SERVICE_PID_FILE="$pidfile" +	service_start $cmd +} + + +resolve_network_add() { +	local __section="$1" +	local __device="$2" +	local __return="$3" + +	local __cdevice +	network_get_device __cdevice "$__section" +	[ "$__cdevice" != "$__device" ] && return +	 +	eval "$__return"'="'"$__section"'"' +} + + +resolve_network() { +	local __return="$1" +	local __device="$2" +	config_foreach resolve_network_add interface "$__device" "$__return" +} + + +announce_prefix() { +	local prefix="$1" +	local network="$2" +	local cmd="$3" + +	local addr=$(echo "$prefix" | cut -d/ -f1) +	local rem=$(echo "$prefix" | cut -d/ -f2) +	local length=$(echo "$rem" | cut -d, -f1) +	local prefer="" +	local valid="" + +	# If preferred / valid provided +	[ "$rem" != "$length" ] && { +		prefer=$(echo "$rem" | 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}" +} + + +disable_downstream() { +	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" +} + + +restart_relay_add() { +	local __section="$1" +	local __return="$2" +	local __master="$3" +	local __disable="$4" + +	network_is_up "$__section" || return + +	# Match master network +	local __cmaster="" +	config_get __cmaster "$__section" relay_master +	[ "$__master" != "$__cmaster" ] && return +	 +	# Disable any active distribution +	disable_downstream "$__section" + +	local __device="" +	network_get_device __device "$__section" +	 +	# Coming from stop relay, reenable distribution +	[ "$__disable" == "disable" ] && { +		enable_downstream "$__section" "$__device" +		return +	} + +	 +	eval "$__return"'="$'"$__return"' '"$__device"'"' +} + + +stop_relay() { +	local network="$1" +	local pid="/var/run/ipv6-relay-$network.pid" +	local was_running="" +	 +	stop_service /usr/sbin/6relayd "$pid" was_running + +	# Reenable normal distribution on slave interfaces	 +	[ -n "$was_running" ] && config_foreach restart_relay_add interface dummy "$network" disable +} + + +restart_relay() { +	local network="$1" +	local force="$2" +	local pid="/var/run/ipv6-relay-$network.pid" + +	local not_running=0 +	[ -f "$pid" ] || not_running=1 + +	# Don't start if not desired +	[ "$force" != "1" ] && [ "$not_running" == "1" ] && return + +	# Kill current relay and distribution daemon +	stop_relay "$network" + +	# Detect master device +	local device="" +	network_get_device device $network + +	# Generate command string +	local cmd="/usr/sbin/6relayd -A $device " +	config_foreach restart_relay_add interface cmd "$network" + +	# Start relay +	start_service "$cmd" "$pid" +} + + +restart_master_relay() { +	local network="$1" + +	# Disable active relaying to this interface +	local relay_master +	config_get relay_master "$network" relay_master +	[ -n "$relay_master" ] && restart_relay "$relay_master" +} + + +disable_interface() { +	local network="$1" + +	# Delete all prefixes routed to this interface +	ubus call 6distributed delprefix '{"network": "'"$network"'"}' + +	# Restart Relay +	restart_master_relay "$network" + +	# Disable distribution +	disable_downstream "$network" + +	# Disable relay +	stop_relay "$network" + +	# Disable DHCPv6 client if enabled, state script will take care +	stop_service /usr/sbin/odhcp6c "/var/run/ipv6-upstream-$network.pid" +} + + +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 + +	# ULA-integration +	local ula_prefix="" +	config_get ula_prefix "$network" ula_prefix + +	# ULA auto configuration (first init) +	[ "$ula_prefix" == "auto" ] && { +		local r1="" +		local r2="" +		local r3="" + +		# Sometimes results are empty, therefore try until it works...		 +		while [ -z "$r1" -o -z "$r2" -o -z "$r3" ]; do +			r1=$(printf "%02x" $(($(</dev/urandom tr -dc 0-9 | dd bs=9 count=1) % 256))) +			r2=$(printf "%01x" $(($(</dev/urandom tr -dc 0-9 | dd bs=9 count=1) % 65536))) +			r3=$(printf "%01x" $(($(</dev/urandom tr -dc 0-9 | dd bs=9 count=1) % 65536))) +		done +		 +		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 +	} + +	# Announce ULA +	[ -n "$ula_prefix" ] && announce_prefix $ula_prefix $network + +	# Announce all static prefixes +	config_list_foreach "$network" static_prefix announce_prefix $network +} + + +enable_downstream() { +	local network="$1" +	local device="$2" + +	# Get IPv6 prefixes +	local length +	config_get length "$network" advertise_prefix +	[ -z "$length" ] && length=64 +	[ "$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" + +	# Try relaying if necessary +	restart_master_relay "$network" +} + + +enable_upstream() { +	local network="$1" +	local device="$2" +	 +	# Configure device +	conf_set "$device" accept_ra 2 +	conf_set "$device" forwarding 2 +	 +	# Trigger RS +	conf_set "$device" disable_ipv6 1 +	conf_set "$device" disable_ipv6 0 + +	# Configure DHCPv6-client +	local dhcp6_opts="$device" + +	# Configure DHCPv6-client (e.g. requested prefix) +	local request_prefix +	config_get request_prefix "$network" request_prefix +	[ -z "$request_prefix" ] && request_prefix="auto" +	[ "$request_prefix" != "no" ] && { +		[ "$request_prefix" == "auto" ] && request_prefix=0 +		dhcp6_opts="-P$request_prefix $dhcp6_opts" +	} +	 +	# Start DHCPv6 client +	local pid="/var/run/ipv6-upstream-$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 +		kill -SIGUSR1 $(cat "$pid") +	done +} + +  | 
