#!/bin/sh
#
# $NetBSD: hf6to4,v 1.5 2006/01/19 01:46:56 joerg Exp $
#
# Copyright (c) 2000-2005 Hubert Feyrer <hubert@feyrer.de>
# 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. Redistributions 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.
# 3. All advertising materials mentioning features or use of this software
#    must display the following acknowledgement:
#	This product includes software developed by Hubert Feyrer
#	for the NetBSD Project.
# 4. The name of the author may not be used to endorse or promote products
#    derived from this software without specific prior written permission.
#
# 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.
#

#
# hf6to4 - Setup 6to4 IPv6, for NetBSD (and others)
#

etcdir="/usr/pkg/etc";

not=false
verbose=false

f=$etcdir/hf6to4.conf
if [ -f "$f" ]
then
    . $f
else
    echo "$0: config file $f missing."
    exit 1
fi

###########################################################################
run()
{
    if $not
    then
    	echo "$@"
    else
	if $verbose
	then
	    echo "$@"
	fi
	"$@"
    fi
}

###########################################################################
usage()
{
    echo "Usage: $0 [-n] [-v] {stf-start | stf-stop | rtadvd-start | rtadvd-stop}";
}

###########################################################################
### M A I N
###########################################################################
#
# Process options
#
args=`getopt nvh $*`
if [ $? != 0 ]
then
    usage
    exit 1
fi

set -- $args
while [ $# -gt 0 ]
do
  case "$1" in
  -n)
	not=true
	;;
  -v)
        verbose=true
	;;
  --)
        shift
	break
	;;
  -h)
        usage
	exit 0
	;;
  *)
        usage
	exit 1
	;;
  esac
  shift
done


# maybe ifconfig stf0 create?


#
# Some sanity checks
#
if  [ `ifconfig -a | grep fe80: | wc -l` -le 0 -o \
      `ifconfig -a | grep stf | wc -l` -le 0 ]; then
    echo "$0: It seems your kernel does not support IPv6 or 6to4 (stf)."
    echo "Add 'options INET6' and 'pseudo-device stf 1' to your kernel and retry!";
    exit 1
fi


#
# Figure out IP#s etc. - ignore RFC 1918 and 3927 IPs
#
localadr4=`ifconfig $out_if inet \
           | grep inet \
	   | sed 's/^.*inet *//' \
	   | sed 's/ .*$//' \
	   | grep -v '^192\.168\.' \
	   | grep -v '^10\.' \
	   | grep -v '^172\.1[6-9]\.' \
	   | grep -v '^172\.2[0-9]\.' \
	   | grep -v '^172\.3[01]\.' \
	   | grep -v '^169\.254\.' \
	   | head -1`

l4c=`echo $localadr4 | sed 's,\., ,g'`
prefix=`printf "2002:%02x%02x:%02x%02x" $l4c`

localadr6=`printf "$prefix:%04x" $v6_net`


if [ "$peer" = "6to4-anycast" ]
then
    # magic values from rfc 3068
    remoteadr4="192.88.99.1"
    remoteadr6="2002:c058:6301::"
else
    if [ `expr "$remoteadr4" : "^[0-9.]*$"` -gt 0 ]
    then
	$verbose && \
	    echo "IPv4 address of peer given numerically, no resolving needed"
    else
	# Hostname, needs resolving
	
	remoteadr4=`host $peer | sed 's/^.*address //'`

	$verbose && \
	    echo "resolving IPv4 address of peer $peer as $remoteadr4"
    fi

    if [ `expr "$remoteadr6" : "^[0-9a-fA-Z:]*$"` -gt 0 ]
    then
	$verbose && \
	echo "IPv6 address of peer given numerically, no resolving needed"
    else
	remoteadr6=`host -t AAAA $peer | sed 's/^.*address //'`

	$verbose && \
	echo "resolving IPv6 address of peer $peer as $remoteadr6"
    fi
fi


if $verbose
then
    echo "remote v4 address: $remoteadr4"
    echo "local  v4 address: $localadr4"
    echo "remote v6 address: $remoteadr6"
    echo "local  v6 address: $localadr6:$hostbits6"
    echo ""
fi


#
# Handle commands
#

# stop:
if [ "$1" = "stf-stop" -o "$1" = "stop" ]
then
	run ifconfig stf0 down
	
	# remove all v6 addresses from stf interface:
	adrs=`ifconfig stf0 inet6 \
	      | grep inet6 \
	      | sed -e 's/inet6//' \
	 	    -e 's/prefix.*//g' \
	 	    -e 's/^[ 	]*//' \
		    -e 's/[ 	]*\$//'`
	for adr in $adrs
	do
		run ifconfig stf0 inet6 -alias $adr
	done

	# remove v6 addresses from internal interface
	if [ "$in_if" != "" ]
	then
		adrs=`ifconfig $in_if inet6 \
		      | grep inet6 \
		      | grep "2002:.*:$v6_innernet:$hostbits6" \
		      | sed -e 's/inet6//' \
			    -e 's/prefix.*//g' \
			    -e 's/^[ 	]*//' \
			    -e 's/[ 	]*\$//'`
		for adr in $adrs
		do
			run ifconfig $in_if inet6 -alias $adr
		done
	fi

	# remove default route:
	run route delete -inet6 default
fi


# start:
if [ "$1" = "stf-start" -o "$1" = "start" ]
then
	run ifconfig stf0 inet6 $localadr6:$hostbits6 prefixlen $v6_prefixlen alias
	run route add -inet6 default $remoteadr6 >/dev/null
	if [ "$in_if" != "" ]
	then
	    run ifconfig $in_if inet6 $prefix:$v6_innernet:$hostbits6
	fi
fi

# rtadvd-stop:
#
# XXX maybe better do this via rc.conf & rc.d/rtadvd?
if [ "$1" = "rtadvd-stop" -o "$1" = "stop-rtadvd" ]
then
    if [ -f "/var/run/rtadvd.pid" ]
    then
	pid=`cat /var/run/rtadvd.pid`
	run kill -TERM $pid
	run rm -f /var/run/rtadvd.pid
    else
	echo $0: no rtadvd running!
    fi
fi

# rtadvd-start:
#
# XXX maybe better do this via rc.conf & rc.d/rtadvd?
if [ "$1" = "rtadvd-start" -o "$1" = "start-rtadvd" ]
then
    if [ -f "/var/run/rtadvd.pid" ]
    then
	echo $0: rtadvd already running!
    else
	run sysctl -w net.inet6.ip6.forwarding=1
	run sysctl -w net.inet6.ip6.accept_rtadv=0
	run rtadvd $in_if
    fi
fi
