#! /bin/sh
#
# Shell script to automatically maintain a 6to4 tunnel on Linux using iproute
# Copyright (C) 2007 Rémi Denis-Courmont. All rights reserved.

#############################################################################
# Redistribution and use in source and binary forms, with or without        #
# modification, are permitted provided that the following conditions        #
# are met:                                                                  #
# 1. Redistributions of source code must retain the above copyright notice, #
#    this list of conditions and the following disclaimer.                  #
# 2. Redistribution in binary form must reproduce the above copyright       #
#    notice, this list of conditions and the following disclaimer in the    #
#    documentation and/or other materials provided with the distribution.   #
#                                                                           #
# The situation as regards scientific and technical know-how at the time    #
# when this software was distributed did not enable all possible uses to be #
# tested and verified, nor for the presence of any or all faults to be      #
# detected. In this respect, people's attention is drawn to the risks       #
# associated with loading, using, modifying and/or developing and           #
# reproducing this software.                                                #
# The user shall be responsible for verifying, by any or all means, the     #
# software's suitability for its requirements, its due and proper           #
# functioning, and for ensuring that it shall not cause damage to either    #
# persons or property.                                                      #
#                                                                           #
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR      #
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES #
# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.   #
# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,          #
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT  #
# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, #
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY     #
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT       #
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF  #
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.         #
#############################################################################

# BUGS:
# - if there are multiple public addresses,
#   we might not pick the same one as radvd

RELAY=192.88.99.1
TUNNEL=stf

ip addr >/dev/null 2>&1 || {
	echo "$0: cannot find iproute. Please install it." >&2
	exit 1
}

ADDRS=""
OLDGW=""

{
	LANG=C ip -4 address show | sed -n -e 's/^    inet/0: KLUDGE inet/p'
	LANG=C ip -4 monitor address
} | while read l; do
	# Which address has been added/removed?
	ADDR="$(echo "$l" | sed -n -e 's/^\(Deleted \)\?[0-9]*: [^ ]\+ \+inet \([0-9.]\+\)[ /].*$/\2/p')"
	test -z "$ADDR" && {
		echo "Skipping $l"
		continue
	}

	# Discard non-global addresses
	case "$ADDR" in
		10.*|127.*|169.254.*|172.16.*|172.17.*|172.18.*|172.19.*|172.2?.*|172.30.*|172.31.*|192.168.*|24?.*|25?.*)
			continue
			;;
	esac

	case "$l" in
		Deleted*)
			# Remove address from list
			NEWADDRS=""
			for a in $ADDRS; do
				test "$ADDR" = "$a" || NEWADDRS="$NEWADDRS $a"
			done
			ADDRS="$NEWADDRS"
			;;
		*)
			# Add address to list
			ADDRS="$ADDRS $ADDR"
			;;
	esac
	echo "list: $ADDRS"
	# Extract the first word from variable, could probably be better...
	NEWGW="$(for a in $ADDRS; do echo $a; break; done)"

	test "$OLDGW" = "$NEWGW" && continue

	# Remove old prefix
	ip link set dev "$TUNNEL" down 2>/dev/null
	ip tunnel del "$TUNNEL" 2>/dev/null

	# Add new prefix
	if test "$NEWGW"; then
		PREFIX48="$(printf "2002:%02x%02x:%02x%02x" $(echo $NEWGW | tr "." " "))"

		ip tunnel add "$TUNNEL" mode sit remote any local "$NEWGW" ttl 64
		ip link set dev "$TUNNEL" up
		ip -6 address add "${PREFIX48}::1/16" dev "$TUNNEL"
		ip -6 route add "2000::/3" via "::$RELAY" dev "$TUNNEL" metric 1024
	fi

	OLDGW=$NEWGW
	killall -HUP radvd 2>/dev/null || true
done

