#!/bin/bash
# openconn.bash, ver. 1.0.0.9
# setup OpenConnect VPN to UC Berkeley
# tested using a sudo runports shell on PC-BSD 7.1.1
# Karl R. Grose, UC Berkeley, IST-IS-IA, 2009-07-20
# Modified for Debian by Fahrzin Hemmate, UC Berkeley 3rd year CSE
#
DEBUG="0"
GRP1="1-Campus_VPN"
GRP2="2-Campus_VPN_Full_Tunnel"
GRP3="3-Library_VPN"
GRP4="4-Campus_VPN_Split_Tunnel_v4_v6"
GRP5="5-Campus_VPN_Full_Tunnel_v4_v6"
GWFILE="/tmp/openconn.gw"
HOST="ucbvpn.berkeley.edu"
NET1="128.32.0.0"
NET2="169.229.0.0"
NET3="136.152.0.0"
NET4="172.16.0.0"
NET5="192.101.42.0"
NET6="10.16.0.0"
NET7="10.32.0.0"
NET8="10.64.0.0"
NET9="10.128.0.0"
NM1="255.255.255.255" #0xffffffff
NM2="255.255.255.0"   #0xffffff00
NM3="255.255.0.0"     #0xffff0000
NM4="255.240.0.0"     #0xfff00000
NM5="255.224.0.0"     #0xffe00000
NM6="255.192.0.0"     #0xffc00000
NM7="255.128.0.0"     #0xff800000
NS1="128.32.136.12"
NS2="128.32.206.9"
PIDFILE="/tmp/openconn.pid"
PIDFILE2="/tmp/openconn.output"
PROFILE="/tmp/openconn.profile"
RESOLV="/etc/resolv.conf"
RESOLVBAK="/tmp/openconn.resolv"
TUN="tun0"
CALNET="$1"
VNM1="255.255.254.0" #0xfffffe00
VNM2="255.255.252.0" #0xfffffc00
VPN1="169.229.205.229" # ucbvpn-1-external
VPN2="169.229.205.230" # ucbvpn-2-external

# Make sure we are root
if [ `id | sed -e 's/(.*//'` != "uid=0" ]; then
  echo "Sorry, you need super user privileges to run this script."
  exit 1
fi

if [ "$#" = "0" ]; then
  read -p "Enter Calnet ID: " CALNET
fi

if [ "${CALNET}" = "--debug" ]; then
  DEBUG="1"

  if [ "$2" = "" ]; then
    read -p "Enter Calnet ID: " CALNET
  else
    CALNET="$2"
  fi
fi

if [ "$2" = "--debug" ]; then
  DEBUG="1"
fi
echo "Using Calnet ID: [${CALNET}]"

function add-vpnserv-routes()
{
  if [ -f ${GWFILE} ]; then
    echo -n "Error, a ${GWFILE} file is found. Is OpenConnect "
    echo "already running?"
    echo -n "Try using the option to shutdown the VPN or delete "
    echo "the ${GWFILE} file manually. Exiting..."
    exit 1
  fi
  # GW is the gateway for the local network
  #GW=$(netstat -rn -f inet | grep -i default | tr -s '  ' ' ' | cut -d' ' -f2)
  GW=$(netstat -rn inet | grep -i UG | tr -s '  ' ' ' | cut -d' ' -f2)

  if [ -z "${GW}" ]; then
    echo "No gateway route found...exiting."
    exit 1
  fi
  echo ${GW} > ${GWFILE}
  netstat -rn inet | grep -iq ${VPN1}
  RC=$?

  if [ "$RC" = "0" ]; then
    if [ "${DEBUG}" = "1" ]; then
      echo "route to ${VPN1} found"
    fi
  else
    if [ "${DEBUG}" = "1" ]; then
      echo "making route to ${VPN1} with netmask ${NM1} and gateway ${GW}"
    fi
    route add -net ${VPN1} netmask "${NM1}" gw "${GW}"
  fi
  netstat -rn inet | grep -iq ${VPN2}
  RC=$?

  if [ "$RC" = "0" ]; then
    if [ "${DEBUG}" = "1" ]; then
      echo "route to ${VPN2} found"
    fi
  else
    route add -net ${VPN2} netmask "${NM1}" gw "${GW}"
  fi
}

function connect()
{
  if [ -f ${PIDFILE} ]; then
    echo -n "Error, a ${PIDFILE} file is found. Is OpenConnect "
    echo "already running?"
    echo -n "Try using the option to shutdown the VPN or delete "
    echo "the ${PIDFILE} file manually. Exiting..."
    exit 1
  fi
  echo "openconnect -b -i ${TUN} --authgroup=$1 -u ${CALNET} --no-dtls ${HOST} >${PIDFILE} 2>&1"
  openconnect -b -i ${TUN} --authgroup=$1 -u ${CALNET} --no-dtls ${HOST} >${PIDFILE2} 2>&1
  PID=$(cat ${PIDFILE2}  | grep -i pid | cut -d' ' -f5)

  if [ "${DEBUG}" = "1" ]; then
    echo "PID = [${PID}]"
    ifconfig ${TUN}
  fi
  echo ${PID} > ${PIDFILE}
}

function add-routes()
{
  VPN0=$(ifconfig ${TUN} | grep -o $1.[0-9]*\.[0-9]* | head -n 1)
#echo ${VPN0}

  if [ -n "${VPN0}" ]; then
    ifconfig ${TUN} ${VPN0} ${VPN0} netmask $2

    if [[ ("${ans}" = "2") || ("${ans}" = "3") ]]; then
      route del default
      route add default gw ${VPN0}
    elif [ "${ans}" = "1" ]; then
      route add -net ${NET1} gw ${VPN0} netmask ${NM3}
      route add -net ${NET2} gw ${VPN0} netmask ${NM3}
      route add -net ${NET3} gw ${VPN0} netmask ${NM3}
      route add -net ${NET4} gw ${VPN0} netmask ${NM4}
      route add -net ${NET5} gw ${VPN0} netmask ${NM2}
      route add -net ${NET6} gw ${VPN0} netmask ${NM4}
      route add -net ${NET7} gw ${VPN0} netmask ${NM5}
      route add -net ${NET8} gw ${VPN0} netmask ${NM6}
      route add -net ${NET9} gw ${VPN0} netmask ${NM7}
    else
      echo "Unknown option; exiting..."
      exit 1
    fi

    if [ "${DEBUG}" = "1" ]; then
      ifconfig ${TUN}
      netstat -rn inet
    fi

    if [ -f ${RESOLVBAK} ]; then
      echo -n "Error, a ${RESOLVBAK} file is detected. Is OpenConnect "
      echo "already running?"
      echo -n "Try using the option to shutdown the VPN or delete "
      echo "the ${RESOLVBAK} file manually. Exiting..."
      exit 1
    fi
    cat ${RESOLV} > ${RESOLVBAK}
    echo "nameserver ${NS1}" > ${RESOLV}
    echo "nameserver ${NS2}" >> ${RESOLV}

    if [ "${DEBUG}" = "1" ]; then
      cat ${RESOLV}
    fi
  else
    echo "Error, no tun IP address found; exiting..."
    exit 1
  fi
}

function remove-routes()
{
  if [ -f ${PIDFILE} ]; then
    PID=$(cat ${PIDFILE})
    rm ${PIDFILE}
  else
    echo "Error, no PID file found, exiting..."
    echo "Try to manually kill OpenConnect before running again."
    echo "Create a blank file at ${PIDFILE} to continue."
    exit 1
  fi

  if [ -n "$PID" ]; then
    kill $PID
    echo "killed OpenConnect, PID=[${PID}]"
  fi
  netstat -rn inet | grep -iq ${VPN1}
  RC=$?

  if [ "$RC" = "0" ]; then
    route del ${VPN1}
  fi
  netstat -rn inet  | grep -iq ${VPN2}
  RC=$?

  if [ "$RC" = "0" ]; then
    route del ${VPN2}
  fi

  if [ -f ${PROFILE} ]; then
    ans=$(cat ${PROFILE})
    rm ${PROFILE}
  else
    echo "Error, no VPN profile file found; exiting..."
    exit 1
  fi

  if [[ ("${ans}" = "2") || ("${ans}" = "3") ]]; then
    if [ -f ${GWFILE} ]; then
      GW=$(cat ${GWFILE})
      rm ${GWFILE}

      netstat -rn inet | grep -iq default
      RC=$?

      if [ "$RC" = "0" ]; then
        route del default
      fi
    else
      echo "Error, no backup gateway file found, exiting..."
      echo "Manually inspect the default route for correctness."
      exit 1
    fi
    route add default gw ${GW}
  elif [ "${ans}" = "1" ]; then
    if [ -f ${GWFILE} ]; then
      rm ${GWFILE}
    else
      echo "Error, no backup gateway file found, exiting..."
      echo "Manually inspect the default route for correctness."
      exit 1
    fi

    for net in ${NET1} ${NET2} ${NET3} ${NET4} ${NET5} \
               ${NET6} ${NET7} ${NET8} ${NET9}
    do
      netstat -rn inet | grep -iq $net
      RC=$?

      if [ "${RC}" = "0" ]; then
        route del $net
      fi
    done
  else
    echo "Error, unknown option; exiting..."
    exit 1
  fi

  if [ -f ${RESOLVBAK} ]; then
    cat ${RESOLVBAK} > ${RESOLV}
    rm ${RESOLVBAK}
  else
    echo "Error, no backup resolv.conf file found, exiting..."
    echo "Manually inspect the /etc/resolv.conf file for correctness."
    exit 1
  fi

  if [ "${DEBUG}" = "1" ]; then
    cat ${RESOLV}
    netstat -rn inet
  fi
}

echo -e "\n    VPN Options Menu\n"
echo "  1. Campus_VPN"
echo "  2. Campus_VPN_Full_Tunnel"
echo "  3. Library_VPN"
echo "  4. Campus_VPN_Split_Tunnel_v4_v6"
echo "  5. Campus_VPN_Full_Tunnel_v4_v6"
echo "  6. Shutdown VPN and restore normal routing."
echo -e "  7. Quit\n"
echo -n "Enter 1, 2, 3, 4, 5, 6, or 7: "
read ans
echo
case "$ans" in
  1)
    echo "Split tunnel..."
    echo "${ans}" >> ${PROFILE}
    add-vpnserv-routes
    connect "${GRP1}"
    VPN0="10.136." # partial IP for split-tunnel
    add-routes ${VPN0} ${VNM2}
    ;;
  2)
    echo "Full tunnel..."
    echo "${ans}" >> ${PROFILE}
    add-vpnserv-routes
    connect "${GRP2}"
    VPN0="136.152." # partial IP for full-tunnel
    add-routes ${VPN0} ${VNM1}
    ;;
  3)
    echo "Library (Full tunnel)..."
    echo "${ans}" >> ${PROFILE}
    add-vpnserv-routes
    connect "${GRP3}"
    VPN0="136.152." # partial IP for full-tunnel
    add-routes ${VPN0} ${VNM1}
    ;;
  4)
    echo "Split tunnel with IPv6 (not yet supported); exiting..."
    echo "${ans}" >> ${PROFILE}
    exit
    ;;
  5)
    echo "Full tunnel with IPv6 (not yet supported); exiting..."
    echo "${ans}" >> ${PROFILE}
    exit
    ;;
  6)
    echo "Restoring..."
    remove-routes
    exit
    ;;
  7)
    echo "Quitting..."
    exit
    ;;
  *)
    echo "Unrecognized choice: ${ans}"
    exit 1
    ;;
esac

