#!/bin/sh
#  ================================================== DATEIUEBERSICHT ===  
#
#  THEMA	      : secvpn - Secure Virtual Private Network
#
#  WARNUNGEN!	      :
#  
#  ANWENDUNGSBEISPIEL :
#
#  ABHAENGIGKEITEN    :	
#
#  DATEIEN	      : 
#
#  SIEHE AUCH         : 
#
#  AUTOR              :	
#  Bernd Schumacher, HP Consulting, HEWLETT-PACKARD GmbH, Bad Homburg, 2000
#
#  GESCHICHTE         :
#  06.10.2005 UM - Checked for reentrant code - keep it this way
#  03.08.2000 BS - Added this Header
#
#  =====================================================================
 
# --------------------------------------------------------- SYNOPSIS ---
#  KURZBESCHREIBUNG      : secvpn - Control the secure virtual private network
#
#  AUFRUF                :
#
#  secvpn [-v][-n][-s][-r] "start|stop|routedel|routeadd|test|status [Host]"
#         -v = Verbose
#         -n = Do nothing
#         -s = Be silent
#         -r = Recursive
#  
#  RUECKGABEWERT         : 
#  
#  GLOBALE VARIABLE	 :
#
# --------------------------------------------------------- REFERENZ ---
#  FUNKTIONSBESCHREIBUNG : 
#    secvpn builds a virtual private network as defined 
#    in /etc/network/secvpn.conf
#  
#  ABLAUFBESCHREIBUNG    : 
#  			
#  BEMERKUNGEN           : 
#
# ---------------------------------------------------------------------
#
#set -x
#set -x

CONF=/etc/network/secvpn.conf
LIB=/usr/share/secvpn/secvpn.lib

#
# if the new route would delete the route to O_BAD_IP save O_BAD_IP
# as hostroute before.
#
# USAGE1: <testip> -net <dest> netmask <mask>
# USAGE2: <testip> -host <dest>
#
save_ssh_route()
{
  if [ "$2" = "-net" ]; then
    _testip=$1; _dest=$3; _netmask=$5

    # Test if route could influence ssh_route
    if [ "`is_useful_route $_dest $_netmask $_testip`" = "1" ]; then

      # Ignore if hostroute
      if [ "`get_route_entry mask $_testip`" != "255.255.255.255" ]; then

        # Get actual Gateway
        gw=`get_route_entry gw $_testip`

	# Translate Gateway 0.0.0.0 to be accepted by route command
	if [ "$gw" = "0.0.0.0" ]; then
	  gw="$_testip"
        fi

        # Add ssh hostroute with actual Gateway
        [ "$VERBOSE" ] && 
          echo "saving ssh route: route add -host $_testip gw $gw"
        [ "$NOTHING" ] || /sbin/route add -host $_testip gw $gw
      fi

    fi
  elif [ "$2" != "-host" ]; then
    # -host routes will be ignored
    echo "ERROR: save_ssh_route: bad format: <$*>" >&2
    exit 1
  fi
}

start()
{
  if [ "$ROLE" = "ACTIVE" ]; then
    [ "$SILENT" ] || echo "Starting Secure VPN $THIS_IS -> $OTHER_IS"
    logger "secvpn: starting vpn $THIS_IS to $OTHER_IS"

    # Test if SSH Connection works
    [ "$VERBOSE" ] && echo "ssh ... $O_BAD_IP"
    [ "$NOTHING" ] || ssh $SSH_OPTS -o 'BatchMode yes' $O_BAD_IP exit 0
    if [ $? -ne 0 ]; then
      echo "ERROR: ssh $O_BAD_IP failed" >&2
      exit 1
    else
      [ "$VERBOSE" ] && echo "pppd ... $T_CRYPT_IP:$O_CRYPT_IP ... "
      [ "$NOTHING" ] || /usr/sbin/pppd $T_CRYPT_IP:$O_CRYPT_IP $PPP_OPTS \
         netmask $CRYPT_MASK pty \
        "ssh $SSH_OPTS -t -o 'BatchMode yes' $O_BAD_IP \
        $ROOTCMD /usr/sbin/pppd $O_CRYPT_IP:$T_CRYPT_IP $PPP_OPTS passive"
      if [ "$RECURSIVE" ]; then
        [ "$VERBOSE" ] && echo "Starting recursive on $OTHER_IS"
        [ "$NOTHING" ] || ssh $SSH_OPTS -o 'BatchMode yes' $O_BAD_IP \
	  $ROOTCMD /usr/sbin/secvpn $RECURSIVE $VERBOSE start
      fi
    fi

  else
    [ "$SILENT" ] || echo "start: Nothing to do for $OTHER_IS -> $THIS_IS"
  fi
}

# routeadd [CONNECTED]
routeadd()
{
  CONNECTED="$1"
  [ "$SILENT" ] || echo "routeadd $THIS_IS -> $OTHER_IS"
  logger "secvpn: adding routes from $THIS_IS to $OTHER_IS"

  for i in $O_GOOD_ONES
  do
    if [ "$CONNECTED" ]; then
      save_ssh_route $CONNECTED `route_area $i`
    else
      save_ssh_route $O_BAD_IP `route_area $i`
    fi

    [ "$VERBOSE" ] && echo "route add `route_area $i` gw $O_CRYPT_IP"
    [ "$NOTHING" ] || /sbin/route add `route_area $i` gw $O_CRYPT_IP || exit $?
  done

  if [ "$ROLE" = "ACTIVE" ]; then
    CONNECTED=`local_ip_connected_to $O_BAD_IP`
    if [ "$VERBOSE" ]; then
      if [ "$CONNECTED" ]; then
        echo "ask remote $OTHER_IS to add back route to $CONNECTED"
      else
        echo "ask remote $OTHER_IS to add back route"
      fi
    fi
    [ "$NOTHING" ] || ssh $SSH_OPTS -o 'BatchMode yes' $O_BAD_IP \
      $ROOTCMD /usr/sbin/secvpn $VERBOSE routeadd \
      $THIS_IS $CONNECTED || exit $?

    if [ "$RECURSIVE" ]; then
      [ "$VERBOSE" ] && echo "Routeadd recursive on $OTHER_IS"
      [ "$NOTHING" ] || ssh $SSH_OPTS -o 'BatchMode yes' $O_BAD_IP \
        $ROOTCMD /usr/sbin/secvpn $RECURSIVE $VERBOSE routeadd
    fi
  fi
}

testvpn()
{
  # test if ppp interface will be used to reach O_CRYPT_IP
  _iface=`getpppif $T_CRYPT_IP $O_CRYPT_IP`
  if [ "`echo $_iface | cut -c1-3`" != "ppp" ]; then
    [ "$SILENT" ] || echo -n "ERROR "
    [ "$VERBOSE" ] && echo -n "(no ppp from $T_CRYPT_IP to $O_CRYPT_IP) "
    echo "$OTHER_IS"
    return
  fi

  if [ "$VERBOSE" ]; then
    if [ "$ROLE" = "ACTIVE" ]; then
      INFO="$THIS_IS -> $OTHER_IS"
    else
      INFO="$THIS_IS <- $OTHER_IS"
    fi
  else
    INFO="$OTHER_IS"
  fi

  [ "$NOTHING" ] || ping -c 3 $O_CRYPT_IP >/dev/null 2>&1
  if [ $? -eq 0 ]; then
    [ "$SILENT" ] || [ "$NOTHING" ] || echo -n "OK "
    [ "$SILENT" ] || echo "$INFO"
  else
    [ "$SILENT" ] || echo -n "ERROR "
    echo "$INFO"
    logger "secvpn: testvpn $THIS_IS -> $OTHER_IS returns ERROR"
  fi

  if [ "$ROLE" = "ACTIVE" ]; then
    if [ "$RECURSIVE" ]; then
      [ "$VERBOSE" ] && echo "Testing recursive on $OTHER_IS"
      [ "$NOTHING" ] || ssh $SSH_OPTS -o 'BatchMode yes' $O_BAD_IP \
        $ROOTCMD /usr/sbin/secvpn $RECURSIVE $VERBOSE status
    fi
  fi
}

wait_for_ppp()
{
  wt=0
  while [ $wt -le 60 ]; do
    [ "$NOTHING" ] || ping -c 3 $O_CRYPT_IP >/dev/null 2>&1
    if [ $? -eq 0 ]; then
      [ "$SILENT" ] || echo "[$wt] wait_for_ppp($O_CRYPT_IP) UP"
      return
    fi
    [ "$SILENT" ] || echo "[$wt] wait_for_ppp($O_CRYPT_IP) DOWN"
    sleep 5
    wt=`echo "$wt + 5" | bc`
  done
  exit 1
}

stop()
{
  [ "$SILENT" ] || echo "stop $THIS_IS -> $OTHER_IS"
  logger "secvpn: stopping vpn from $THIS_IS to $OTHER_IS"

  # Shutting down ppp interfaces
  PL=`getpppif $O_CRYPT_IP $T_CRYPT_IP`
  if [ "$PL" ]; then
    [ "$VERBOSE" ] && echo "shutting down $PL"
    [ "$NOTHING" ] || /sbin/ifconfig $PL down
  fi

  PL=`getpppif $T_CRYPT_IP $O_CRYPT_IP`
  if [ "$PL" ]; then
    [ "$VERBOSE" ] && echo "shutting down $PL"
    [ "$NOTHING" ] || /sbin/ifconfig $PL down
  fi

  # Killing ppp deamons
  PL=`ps ax| grep ssh| grep $O_CRYPT_IP:$T_CRYPT_IP| grep -v grep`
  if [ "$PL" ]; then
    [ "$VERBOSE" ] && ( echo "killing:"; echo "$PL" )
    [ "$NOTHING" ] || echo "$PL" | awk '{print $1}'| xargs -r kill
    sleep 5
  fi

  PL=`ps ax| grep ssh| grep $O_CRYPT_IP:$T_CRYPT_IP| grep -v grep`
  if [ "$PL" ]; then
    [ "$VERBOSE" ] && ( echo "killing -9"; echo "$PL" )
    [ "$NOTHING" ] || echo "$PL" | awk '{print $1}'| xargs -r kill -9
    sleep 5
  fi

  if [ "$ROLE" = "ACTIVE" ]; then
    [ "$VERBOSE" ] && echo "ask remote $OTHER_IS ($O_BAD_IP) to stop"
    [ "$NOTHING" ] || ssh $SSH_OPTS -o 'BatchMode yes' $O_BAD_IP \
      $ROOTCMD /usr/sbin/secvpn $VERBOSE stop $THIS_IS

    if [ "$RECURSIVE" ]; then
      [ "$VERBOSE" ] && echo "Stopping recursive on $OTHER_IS"
      [ "$NOTHING" ] || ssh $SSH_OPTS -o 'BatchMode yes' $O_BAD_IP \
        $ROOTCMD /usr/sbin/secvpn $RECURSIVE $VERBOSE stop
    fi
  fi
}

routedel()
{
  [ "$SILENT" ] || echo "routedel $THIS_IS -> $OTHER_IS"
  logger "secvpn: deleting routes from $THIS_IS to $OTHER_IS"

  for i in $O_GOOD_ONES
  do
    [ "$VERBOSE" ] && echo "route del `route_area $i` gw $O_CRYPT_IP"
    [ "$NOTHING" ] || /sbin/route del `route_area $i` gw $O_CRYPT_IP
  done

  if [ "$ROLE" = "ACTIVE" ]; then
    [ "$VERBOSE" ] && echo "ask remote $OTHER_IS to delete back route"
    [ "$NOTHING" ] || ssh $SSH_OPTS -o 'BatchMode yes' $O_BAD_IP \
      $ROOTCMD /usr/sbin/secvpn $VERBOSE routedel $THIS_IS

    if [ "$RECURSIVE" ]; then
      [ "$VERBOSE" ] && echo "Routedel recursive on $OTHER_IS"
      [ "$NOTHING" ] || ssh $SSH_OPTS -o 'BatchMode yes' $O_BAD_IP \
        $ROOTCMD /usr/sbin/secvpn $RECURSIVE $VERBOSE routedel
    fi
  fi
}

i="go on"
NOTHING=""
VERBOSE=""
SILENT=""
RECURSIVE=""
while [ "$i" ]; do
  if [ "$1" = "-v" ]; then
    VERBOSE="-v"
    shift
  elif [ "$1" = "-n" ]; then
    NOTHING="-n"
    shift
  elif [ "$1" = "-s" ]; then
    SILENT="-s"
    shift
  elif [ "$1" = "-r" ]; then
    RECURSIVE="-r"
    shift
  else
    i=""
  fi
done

# The next 2 lines could be overwritten in Conffile.
PPP_OPTS="noaccomp nobsdcomp noccp nopcomp novj nodeflate novjccomp"
SSH_OPTS="-c blowfish -l secvpn"
ROOTCMD="/usr/bin/sudo"

. $CONF
. $LIB

PPP_OPTS="$PPP_OPTS noauth connect-delay 10000 noipdefault ipcp-accept-local \
ipcp-accept-remote local nocrtscts proxyarp lock nodefaultroute"
SSH_OPTS="$SSH_OPTS -e none"

case "$1" in
  start)
    if [ "$2" != "" ]; then
      use_vpn $2 start
      use_vpn $2 wait_for_ppp
    else
      for_all_active_vpns start
      for_all_active_vpns wait_for_ppp
    fi
    ;;
  routeadd)
    if [ "$2" != "" ]; then
      use_vpn $2 routeadd $3
    else
      for_all_active_vpns routeadd
    fi
    ;;
  test)
    if [ "$2" != "" ]; then
      use_vpn $2 testvpn
    else
      for_all_active_vpns testvpn
    fi
    ;;
  stop)
    if [ "$2" != "" ]; then
      use_vpn $2 stop
    else
      for_all_active_vpns stop
    fi
    ;;
  routedel)
    if [ "$2" != "" ]; then
      use_vpn $2 routedel
    else
      for_all_active_vpns routedel
    fi
    ;;
  status)
    if [ "$2" != "" ]; then
      use_vpn $2 testvpn
    else
      for_all_vpns testvpn
    fi
    ;;
  *)
    echo "Usage: secvpn [-v][-n][-s] "
    echo "  start    [Host]"
    echo "  stop     [Host]"
    echo "  routeadd [Host [ConnectedIP]]"
    echo "  routedel [Host]"
    echo "  test     [Host]"
    echo "  status   [Host]"
    echo ""
    echo "       -v = Verbose"
    echo "       -n = Do nothing"
    echo "       -s = Be silent"
    echo "       -r = Recursive"
    exit 1
    ;;
esac
