#!/usr/local/bin/bash

# 
# -------------------------------------------------------------------
#                                   X-BONE
#
#                          http://www.isi.edu/xbone
#                USC Information Sciences Institute (USC/ISI)
#                   Marina del Rey, California 90292, USA
#                          Copyright (c) 1998-2005
# 
# -------------------------------------------------------------------
#
# Copyright (c) 1998-2005 by the University of Southern California.
# All rights reserved.
#
# Permission to use, copy, modify, and distribute this software and
# its documentation in source and binary forms for non-commercial
# purposes and without fee is hereby granted, provided that the above
# copyright notice appear in all copies and that both the copyright
# notice and this permission notice appear in supporting
# documentation, and that any documentation, advertising materials,
# and other materials related to such distribution and use acknowledge
# that the software was developed by the University of Southern
# California, Information Sciences Institute.  The name of the
# University may not be used to endorse or promote products derived
# from this software without specific prior written permission.
# 
# THE UNIVERSITY OF SOUTHERN CALIFORNIA MAKES NO REPRESENTATIONS ABOUT
# THE SUITABILITY OF THIS SOFTWARE FOR ANY PURPOSE.  THIS SOFTWARE IS
# PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
# INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
#
# Other copyrights might apply to parts of this software and are so
# noted when applicable.
#
# -------------------------------------------------------------------
#
# Effort partly sponsored by the Defense Advanced Research Projects
# Agency (DARPA) and Air Force Research Laboratory, Air Force Materiel
# Command, USAF, under agreement numbers F30602-98-1-0200 (X-Bone) and
# F30602-01-2-0529 (DynaBone). The views and conclusions contained
# herein are those of the authors and should not be interpreted as
# necessarily representing the official policies or endorsements,
# either expressed or implied, of the Defense Advanced Research
# Projects Agency (DARPA), the Air Force Research Laboratory, or the
# U.S. Government.
#
# This work was partly supported by the NSF STI-XTEND (ANI-0230789)
# and NETFS (ANI-0129689) projects. Any opinions, findings, and
# conclusions or recommendations expressed in this material are those
# of the authors and do not necessarily reflect the views of the
# National Science Foundation.
#
# -------------------------------------------------------------------

# Run as root, of course

# Physical(Public)IP address of the 4 testing nodes
PHYSICAL_ADDR=()

#check whether a command can be executed successfully. if not, stop.
check_error() { # arg1: given_command; arg2: error_message
  #echo "COMMAND=$1"
  $1 >& /dev/null
  if [ "$?" -ne "0" ]; then
    echo -n $2 
    exit 1
  fi 
}

# setup IP tunnels among the 4 testing nodes
# setup IPsec in transport mode per link if required
create_tunnels() {
  # arg1: tunnel_layer_index; arg2: node_index; arg3: ipsec 

  local lid=$1    
  local nid=$2
  local ipsec=$3

  PUB_IP=( `echo ${PHYSICAL_ADDR[@]}` )
  NETMASK="255.255.255.192"
  NET=( "$lid.0.0.0/30" "$lid.0.1.0/30" "$lid.0.2.0/30" )
  IP_1=( "$lid.0.0.1" "$lid.0.1.1" "$lid.0.2.1" x.x.x.x )
  IP_2=(     x.x.x.x  "$lid.0.0.2" "$lid.0.1.2" "$lid.0.2.2" )
  let u=$lid-1
  IP_UNDER_1=( "$u.0.0.1" "$u.0.1.1" "$u.0.2.1" x.x.x.1      )
  IP_UNDER_2=(  x.x.x.2  "$u.0.0.2" "$u.0.1.2" "$u.0.2.2" )
 
  local i=$(($lid*2-2))
  local j=$(($lid*2-1))
  GIFS=( "gif$i" "gif$j" )

  # clear gifs
  echo -n "Clear gifs on node $nid ... "
  for i in 0 1
  do 
    if [[ $i -eq "0"  &&  $nid -lt "3" ]] || [[ $i -eq "1"  &&  $nid -gt "0" ]]  
    then 
      $IFCONFIG ${GIFS[$i]} down  >& /dev/null
      $IFCONFIG ${GIFS[$i]} destroy >& /dev/null 
    fi
  done
  echo "done" 

  # create gifs on node 
  echo -n "Create tunnels on node $nid ... "
  for i in 0 1 
  do 
    if [ $i -eq "0" ] && [ $nid -lt "3" ] ; then 
      let j=$nid+1
      check_error "$IFCONFIG ${GIFS[$i]} create" "Can not create ${GIFS[$i]} on node $nid"
      if [ $lid -eq "1" ]; then
          cmd="$IFCONFIG ${GIFS[$i]} tunnel ${PUB_IP[$nid]} ${PUB_IP[$j]}"
          msg="Cannot configure physical address on ${GIFS[$i]} from ${PUB_IP[$nid]} to ${PUB_IP[$j]}!"
      fi
      if [ $lid -gt "1" ]; then
	  cmd="$IFCONFIG ${GIFS[$i]} tunnel ${IP_UNDER_1[$nid]} ${IP_UNDER_2[$j]}"
	  msg="Cannot configure physical address on ${GIFS[$i]} from ${IP_UNDER_1[$nid]} to ${IP_UNDER_2[$j]}!"
      fi
      check_error "$cmd" "$msg"
      cmd="$IFCONFIG ${GIFS[$i]} ${IP_1[$nid]} ${IP_2[$j]} netmask $NETMASK" 
      msg="Cannot configure tunnel address on ${GIFS[$i]} from ${IP_1[$nid]} to ${IP_2[$j]} !"
      check_error "$cmd" "$msg"
    fi

    if [ $i -eq "1" ] && [ $nid -gt "0" ]; then 
      let j=$nid-1
      check_error "$IFCONFIG ${GIFS[$i]} create" "Can not create ${GIFS[$i]} on node $nid"
      if [ "$lid" -eq "1" ]; then
        cmd="$IFCONFIG ${GIFS[$i]} tunnel ${PUB_IP[$nid]} ${PUB_IP[$j]}" 
      	msg="Cannot configure physical address on ${GIFS[$i]} from ${PUB_IP[$nid]} to ${PUB_IP[$j]}!"
      fi
      if [ "$lid" -gt "1" ]; then
	cmd="$IFCONFIG ${GIFS[$i]} tunnel ${IP_UNDER_2[$nid]} ${IP_UNDER_1[$j]}"
	msg="Cannot configure physical address on ${GIFS[$i]} from ${IP_UNDER_2[$nid]} ${IP_UNDER_1[$j]}!"
      fi
      check_error "$cmd" "$msg"
      cmd="$IFCONFIG ${GIFS[$i]} ${IP_2[$nid]} ${IP_1[$j]} netmask $NETMASK" 
      msg="Can not configure tunnel address on ${GIFS[$i]} from ${IP_2[$nid]} to ${IP_1[$j]} !"
      check_error "$cmd" "$msg"
    fi
  done
  echo "done" 

  # clear existing routes 
  echo -n "Clear existing routes on node $nid ... "
  for i in 0 1 2 
  do
    $ROUTE delete -net ${NET[$i]} >& /dev/null
  done
  echo "done"

  # create route on nodes
  echo -n "Configure route on node $nid ... "
  for i in 0 1 2
  do 
    let j=$nid+1
    if [ $i -gt $nid ]; then 
      cmd="$ROUTE add -net ${NET[$i]} -gateway ${IP_2[$j]}" 
      msg="Can not add route to net ${NET[$i]} through ${IP_2[$j]} !"
      check_error "$cmd" "$msg"
    fi

    let j=$nid-1
    if [ $i -lt $j ]; then 
      cmd="$ROUTE add -net ${NET[$i]} -gateway ${IP_1[$j]}" 
      msg="Can not add route to net ${NET[$i]} through ${IP_[$j]} !"
      check_error "$cmd" "$msg"
    fi
  done
  echo "done"

  # set up the IPSEC per link if required
  if [ $ipsec -eq "1" ]; then
     echo -n "Set up the IPSEC on node $nid ... "
     if [ $lid -gt "1" ]; then 
       check_error "setkey -F" "Can not flush the SAD entries !"
       check_error "setkey -FP" "Can not flush the SPD entries !"

       if [ $nid -lt "3" ]; then
         let j=$nid+1
         echo "add ${IP_UNDER_1[$nid]} ${IP_UNDER_2[$j]} esp 1000 "\
         " -m transport -E des-cbc \"12345678\" ;" | setkey -c
         echo "add ${IP_UNDER_2[$j]} ${IP_UNDER_1[$nid]} esp 2000 "\
         " -m transport -E des-cbc \"87654321\" ;"| setkey -c
         echo "add ${IP_UNDER_1[$nid]} ${IP_UNDER_2[$j]} ah  3000 "\
         " -m transport -A hmac-sha1 \"12341234123412341234\" ;" | setkey -c
         echo "add ${IP_UNDER_2[$j]} ${IP_UNDER_1[$nid]} ah 4000 "\
         " -m transport -A hmac-sha1 \"43214321432143214321\" ;" | setkey -c
         echo "spdadd ${IP_UNDER_1[$nid]} ${IP_UNDER_2[$j]} any -P out ipsec "\
         "esp/transport/${IP_UNDER_1[$nid]}-${IP_UNDER_2[$j]}/require "\
         "ah/transport/${IP_UNDER_1[$nid]}-${IP_UNDER_2[$j]}/require;" | setkey -c
         echo "spdadd ${IP_UNDER_2[$j]} ${IP_UNDER_1[$nid]} any -P in  ipsec "\
         "esp/transport/${IP_UNDER_2[$j]}-${IP_UNDER_1[$nid]}/require "\
         "ah/transport/${IP_UNDER_2[$j]}-${IP_UNDER_1[$nid]}/require;" | setkey -c
       fi

       if [ $nid -gt "0" ]; then 
         let j=$nid-1 
         echo "add ${IP_UNDER_1[$j]} ${IP_UNDER_2[$nid]} esp 1000 "\
         " -m transport -E des-cbc \"12345678\" ;" | setkey -c
         echo "add ${IP_UNDER_2[$nid]} ${IP_UNDER_1[$j]} esp 2000 "\
         " -m transport -E des-cbc \"87654321\" ;" | setkey -c
         echo "add ${IP_UNDER_1[$j]} ${IP_UNDER_2[$nid]} ah  3000 "\
         " -m transport -A hmac-sha1 \"12341234123412341234\" ;" | setkey -c
         echo "add ${IP_UNDER_2[$nid]} ${IP_UNDER_1[$j]} ah 4000 "\
         " -m transport -A hmac-sha1 \"43214321432143214321\" ;" | setkey -c
         echo "spdadd ${IP_UNDER_2[$nid]} ${IP_UNDER_1[$j]} any -P out ipsec "\
         "esp/transport/${IP_UNDER_2[$nid]}-${IP_UNDER_1[$j]}/require "\
         "ah/transport/${IP_UNDER_2[$nid]}-${IP_UNDER_1[$j]}/require;" | setkey -c
       	
         echo "spdadd ${IP_UNDER_1[$j]} ${IP_UNDER_2[$nid]} any -P in ipsec "\
         "esp/transport/${IP_UNDER_1[$j]}-${IP_UNDER_2[$nid]}/require "\
         "ah/transport/${IP_UNDER_1[$j]}-${IP_UNDER_2[$nid]}/require;" | setkey -c
       fi
    fi
    echo "done"
  fi
}

# only root can run this script
ROOT_UID=0  # Only users with $UID 0 have root privileges
E_NOROOT=67 # Non-root exit error

if [ "$UID" -ne "$ROOT_UID" ]
then
  echo "Must be root to run this script."
  exit $E_NOTROOT
fi

LOCAL_ADDR=""
N_TUNNEL_LAYERS="0"
CONFIG_FILE="xbone-test.conf"
IPSEC="no"

while getopts "a:n:f:s:" Option
do 
  #echo "Option=$Option, Args=$OPTARG"
  case $Option in 
    f ) CONFIG_FILE="$OPTARG" ;;
    a ) LOCAL_ADDR="$OPTARG" ;;
    n ) N_TUNNEL_LAYERS="$OPTARG" ;;
    s ) IPSEC="$OPTARG" ;;
    * ) ;;
  esac
done
shift $(($OPTIND - 1))

#echo "$LOCAL_ADDR, $N_TUNNEL_LAYERS, $CONFIG_FILE, $IPSEC"

if [ "$LOCAL_ADDR" == "" ] || [ "$N_TUNNEL_LAYERS" -lt "1" ] 
then 
  echo "Usage: `basename $0` -f configure_file  -a local_IP_address  -n n_tunnel_layers  -s 1/0"
  exit 1
fi

LINE=`cat $CONFIG_FILE`
if [ "$?" -ne "0" ]; then
  echo "Cannot open config file \"$CONFIG_FILE\"!"
  exit 1
fi
PHYSICAL_ADDR=( `echo $LINE` )

if [ ${#PHYSICAL_ADDR[@]} -ne "4" ]; then
  echo "Invalid config file format, please list four IP addresses in one line!"
  exit 1
fi

NID="-1"
for ((i=0; i < "${#PHYSICAL_ADDR[@]}" ; i++)) 
do    
  if [ "${PHYSICAL_ADDR[$i]}" == "$LOCAL_ADDR" ]; then
    NID="$i"; break
  fi
done
if [ "$NID" -eq "-1" ]; then
  echo "Cannot find the local address $LOCAL_ADDR in the given address set: " 
  echo "    { ${PHYSICAL_ADDR[@]} }"
  exit 1
fi

IFCONFIG="ifconfig"
ROUTE="route"
SYSCTL="sysctl"

# check whether the commands we will use are available in the system
echo -n "check the commands \"ifconfig\", \"route\" and \"sysctl\" ... "
check_error "which $IFCONFIG" "system can not find $IFCONFIG by searching $PATH"
check_error "which $ROUTE" "system can not find $ROUTE by searching $PATH"
check_error "which $SYSCTL" "system can not find $SYSCTL by searching $PATH" 
echo "done"

#set forwarding=1 on node2 and node3
if [[ $NID -eq "1" ]]|| [[ $NID -eq "2" ]]; then
  echo -n "Enable packet forwarding on node $NID ... "
  $SYSCTL -w net.inet.ip.forwarding=1 >& /dev/null
  echo "done"
fi

for ((k=1; k <= "$N_TUNNEL_LAYERS" ; k++))
do 
  create_tunnels $k $NID $IPSEC
done



syntax highlighted by Code2HTML, v. 0.9.1