#!@LOCALBASE@/bin/perl
#
#  Setup 6to4 IPv6, for NetBSD (and maybe others)
#
# (c) Copyright 2000-2002 Hubert Feyrer <hubert@feyrer.de>
#

$etcdir="@PREFIX@/etc";
#$etcdir="/usr/pkg/etc";		# debug

require "$etcdir/6to4.conf";

use Getopt::Std;

###########################################################################
sub run
{
	local($str) = @_;

	if ($not) {
	    print "$str\n";
	} else {
	    if ($verbose) {
		print "$str\n";
	    } 
	    system($str);
	}
}

###########################################################################

#
# Process options
#
getopts('nvh');

$not = 1	if $opt_n;
$verbose = 1	if $opt_v;

if ($opt_h) {
    print "Usage: $0 [-n] [-v] {start | stop | rtadvd-start | rtadvd-stop}\n";
    exit 0;
}

# Make sure the interface exists
system("ifconfig stf0 create >/dev/null 2>&1");

#
# Some sanity checks
#
if (`ifconfig -a | grep fe80: | wc -l` <= 0 or
    `ifconfig -a | grep stf | wc -l` <= 0) {
    die "$0: It seems your kernel does not support IPv6 or 6to4 (stf).\n".
	"Add 'options INET6' and 'pseudo-device stf 1' to your kernel and retry!\n";
}

#
# Figure out IP#s etc.
#
$localadr4 = `ifconfig $out_if inet | grep inet`;
$localadr4 =~ s/^.*inet\s*//;
$localadr4 =~ s/\s.*$//;
chomp($localadr4);

@l4c = split('\.', $localadr4);
$prefix = sprintf("2002:%02x%02x:%02x%02x", @l4c[0..3]);
	
$localadr6 = sprintf("$prefix:%04x", $v6_net);

if ($peer eq "6to4-anycast") {
    # magic values from rfc 3068
    $remoteadr4 =  "192.88.99.1";
    $remoteadr6 =  "2002:c058:6301::";
} else {
    if ($remoteadr4 !~ /^[0-9.]+$/ ) {
	chomp($remoteadr4 = `host $peer`);
	$remoteadr4 =~ s/^.*address //;
	
	print "resolving IPv4 address of peer $peer\n"
	    if $verbose;
    } else {
	print "IPv4 address of peer given numerically, no resolving needed\n"
	    if $verbose;
    }

    if ($remoteadr6 !~ /^[0-9a-fA-Z:]+$/ ) {
	chomp($remoteadr6 = `host -t AAAA $peer`);
	$remoteadr6 =~ s/^.*address //;
	
	print "resolving IPv6 address of peer $peer\n"
	    if $verbose;
    } else {
	print "IPv6 address of peer given numerically, no resolving needed\n"
	    if $verbose;
    }
}


if ($verbose) {
    print "remote v4 address: $remoteadr4\n";
    print "local  v4 address: $localadr4\n";
    print "remote v6 address: $remoteadr6\n";
    print "local  v6 address: $localadr6:$hostbits6\n";
    print "\n";
}


#
# Handle commands
#

# stop:
if ( $ARGV[0] eq "stop" ) {
	run("ifconfig stf0 down");
	$cmd="ifconfig stf0 inet6 " .
	     "| grep inet6 " .
	     "| sed -e 's/inet6//' " .
		   "-e 's/prefix.*//g' " .
		   "-e 's/^[ 	]*//' " .
		   "-e 's/[ 	]*\$//'";
	foreach $ip ( split('\s+', `$cmd`)) {
		run("ifconfig stf0 inet6 -alias $ip");
	}
	run("route delete -inet6 default");
}

# start:
if ( $ARGV[0] eq "start" ) {
	run("ifconfig stf0 inet6 $localadr6:$hostbits6 prefixlen $v6_prefixlen alias");
	run("route add -inet6 default $remoteadr6");
	if ($in_if ne "") {
	    run("ifconfig $in_if inet6 $prefix:$v6_innernet:$hostbits6");
	}
}

# rtadvd-stop:
if ($ARGV[0] eq "rtadvd-stop" or $ARGV[0] eq "stop-rtadvd") {
    if ( -f "/var/run/rtadvd.pid" ) {
	$pid = `cat /var/run/rtadvd.pid`;
	run ("kill -TERM $pid");
	run ("rm -f /var/run/rtadvd.pid");
	run ("rm -f /var/run/6to4-rtadvd.conf.$pid");
    } else {
	print "no rtadvd running!\n";
    }
}

# rtadvd-start:
if ($ARGV[0] eq "rtadvd-start" or $ARGV[0] eq "start-rtadvd" ) {
    if ( -f "/var/run/rtadvd.pid" ) {
	print "rtadvd already running!\n";
    } else {
	run("sysctl -w net.inet6.ip6.forwarding=1");
	run("sysctl -w net.inet6.ip6.accept_rtadv=0");
	run("rtadvd $in_if");
    }
}
