#!/bin/sh

# Copyright (C) 2004 PeterG. This program is free software: you
# can redistribute it and/or modify it under the terms of the
# GNU General Public License as published by the Free Software
# Foundation, either version 2 of the License, or (at your
# option) any later version. This program is distributed in the
# hope that it will be useful, but WITHOUT ANY WARRANTY; without
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
# PARTICULAR PURPOSE.

# This script automagically sets up or closes down an IPv4 tunnel
# for IPv6 from a local machine to a proper IPv6 gateway, according
# to RFC3056 <http://WWW.IETF.org/rfc/rfc3056.txt>

TUN6RC='/etc/sabitun6rc'

IP6CONF="$1"; shift
IP6COMM="$1"; shift

SCOPELINK='fe80'
SCOPEMULT='ff00'
SCOPEGLOB='2001'
SCOPEV6V4='2002'

if test -x /sbin/ip
then iproute2 () { true; }
else iproute2 () { false; }
  echo 1>&2 "Should have '/sbin/ip' instaled for IPv6-to-IPv4 tunneling"
  exit 1
fi

if [ \! -f /proc/net/if_inet6 ]
then
  echo 1>&2 "'/proc/net/if_inet6' missing, IPv6 is not installed!"
  exit 1
fi

ifaceDescr() \
{
  case "$1" in ?*)
    expr "`ip addr show dev \"$1\"`" \
      : '.*\(\<inet [0-9./]* [a-z]* [0-9.]*\).*';;
  esac
}

ifaceDescrToIP() \
{
  case "$1" in ?*)
    expr "$1" : '\<inet \([0-9.]*\).*';;
  esac
}

case "$IP6CONF" in
''|-|auto|nearest|[rR][fF]cC]3068)
  # <http://WWW.IETF.org/rfc/rfc3068.txt>
  : ${IP6TYPE='subnet'}
  : ${IP6SITN='sit1'}
  : ${IP6EXDV='ppp0'}
  IP4DESC="`ifaceDescr \"$IP6EXDV\"`"
  IP4ADDRB="`ifaceDescrToIP \"$IP4DESC\" | sed 's/\./ /g'`"
  : ${IP6ADDR="2002:`printf '%02x%02x:%02x%02x' $IP4ADDRB`::/64"}
  : ${IP6NAME='[auto]'}
  : ${IP6GWV4='192.88.99.1'}
  : ${IP6GWV6='2002:c058:6301::1'}
  ;;

*)
  if ! test -r "$TUN6RC"
  then
    echo 1>&2 "$0: configuration '$IP6CONF' not 'auto', and "$TUN6RC" missing."
    exit 1
  elif ! . "TUN6RC" "$IP6CONF"
  then
    echo 1>&2 "$0: configuration '$IP6CONF' unknown to '$TUN6RC'."
    exit 1
  else : 'All fine we hope'
  fi

  IP4DESC="`ifaceDescr \"$IP6EXDV\"`"
  IP4ADDR="`ifaceDescrToIP \"$IP4DESC\"`"
  ;;
esac
: ${IP6NAME="`ip2name \"$IP6GWV4\"`"}

tunnelUp () {
  if iproute2
  then
    ip -6 tunnel add "$IP6SITN" mode sit \
	ttl 64 remote "$IP6GWV4" local 0 \
      && ip -6 link set dev "$IP6SITN" up \
      && ip -6 addr add dev "$IP6SITN" "$IP6ADDR" \
      && ip -6 route add default dev "$IP6SITN" # via "$IP6GWV6"
  else 
    ifconfig sit0 up \
      && ifconfig sit0 inet6 tunnel ::"$IP6GWV4" \
      && ifconfig "$IP6SITN" inet6 add "$IP6ADDR" \
      && route -A inet6 add ::/0 gw "$IP6GWV6" dev "$IP6SITN"
  fi
}

tunnelDown() {
  if iproute2
  then
    : ip -6 route del default dev "$IP6SITN"
    : ip -6 link set "$IP6SITN" down
    # deleting the tunnel with 'ip' deletes the route and closes the interface
    ip -6 tunnel del "$IP6SITN"
  else
    route -A inet6 del ::/0
    ifconfig "$IP6SITN" del "$IP6ADDR"
    ifconfig "$IP6SITN" down
  fi
}

case "$IP6TYPE" in
host|subnet)
  case "$IP6COMM" in
  up)
    if tunnelUp
    then
      echo 1>&2 "IPv6-to-IPv4 tunnel '$IP6SITN' to '$IP6NAME' is up"
    else
      echo 1>&2 "IPv6-to-IPv4 tunnel '$IP6SITN' to '$IP6NAME' error going up"
      tunnelDown > /dev/null 2>&1
      exit 1
    fi
    ;;

  down)
    if tunnelDown
    then echo 1>&2 "IPv6-to-IPv4 tunnel '$IP6SITN' to '$IP6NAME' is down"
    else echo 1>&2 "IPv6-to-IPv4 tunnel '$IP6SITN' to '$IP6NAME' error going down"; exit 1
    fi
    ;;
  esac
  ;;
esac
