#!/bin/bash

#
# manipulate IPSec SA database on behalf of the racoon daemon
# Gabriel Somlo <somlo at cmu edu>, 08/27/2007
#

#FIXME: read this from, e.g., /etc/sysconfig/racoon
NAT_T="yes"


shopt -s nocasematch
umask 0022

PATH=/bin:/sbin:/usr/bin:/usr/sbin

case "${NAT_T}" in
  yes|true|on|enable*|1)
    LOCAL="${LOCAL_ADDR}[${LOCAL_PORT}]"
    REMOTE="${REMOTE_ADDR}[${REMOTE_PORT}]"
    ;;
  *)
    LOCAL="${LOCAL_ADDR}"
    REMOTE="${REMOTE_ADDR}"
    ;;
esac

DFLT_RT=$(ip route list | awk '($1 == "default"){print $3 ";" $5}')
DFLT_IF=${DFLT_RT#*;}
DFLT_GW=${DFLT_RT%;*}


# convert something like '192.168.123.0/255.255.255.0' into '192.168.123.0/24'
# FIXME: convince racoon folks to return SPLIT_INCLUDE in the latter form ?
to_cidr() {
  local IP_ADDR=${1%/*}
  local NETMASK=${1#*/}
  local PREFIX_STR=$(ipcalc -p ${IP_ADDR} ${NETMASK})
  local PREFIX=${PREFIX_STR#*=}
  echo ${IP_ADDR}/${PREFIX}
}


phase1_up() {
  [ -f /etc/resolv.conf.prevpn ] || cp /etc/resolv.conf /etc/resolv.conf.prevpn
  {
    echo "# Generated by racoon on $(date)"
    echo "search ${DEFAULT_DOMAIN}"
    for NS in ${INTERNAL_DNS4_LIST}; do
      echo "nameserver ${NS}"
    done
  } > /etc/resolv.conf

  ip addr add dev ${DFLT_IF} ${INTERNAL_ADDR4}/32
  ip route add ${REMOTE_ADDR} via ${DFLT_GW} dev ${DFLT_IF}

  if [ -n "${SPLIT_INCLUDE}" ]; then
    for N in ${SPLIT_INCLUDE}; do
      ip route add $(to_cidr ${N}) via ${DFLT_GW} dev ${DFLT_IF} \
                                   src ${INTERNAL_ADDR4}
    done
  else
    for N in ${SPLIT_LOCAL}; do
      ip route add $(to_cidr ${N}) via ${DFLT_GW} dev ${DFLT_IF}
    done
    ip route del default
    ip route add default via ${DFLT_GW} dev ${DFLT_IF} src ${INTERNAL_ADDR4}
  fi

  setkey -c << EOT
spdadd ${INTERNAL_ADDR4}/32[any] 0.0.0.0/0[any] any -P out ipsec
       esp/tunnel/${LOCAL}-${REMOTE}/require;
spdadd 0.0.0.0/0[any] ${INTERNAL_ADDR4}[any] any -P in ipsec
       esp/tunnel/${REMOTE}-${LOCAL}/require;
EOT
}


phase1_down() {
  [ -f /etc/resolv.conf.prevpn ] && mv /etc/resolv.conf.prevpn /etc/resolv.conf

  if [ -n "${SPLIT_INCLUDE}" ]; then
    for N in ${SPLIT_INCLUDE}; do
      ip route del $(to_cidr ${N})
    done
  else
    for N in ${SPLIT_LOCAL}; do
      ip route del $(to_cidr ${N})
    done
    ip route del default
    ip route add default via ${DFLT_GW} dev ${DFLT_IF}
  fi

  ip route del ${REMOTE_ADDR}
  ip addr del dev ${DFLT_IF} ${INTERNAL_ADDR4}/32

  setkey -c << EOT
spddelete ${INTERNAL_ADDR4}/32[any] 0.0.0.0/0[any] any -P out ipsec
          esp/tunnel/${LOCAL}-${REMOTE}/require;
spddelete 0.0.0.0/0[any] ${INTERNAL_ADDR4}[any] any -P in ipsec
          esp/tunnel/${REMOTE}-${LOCAL}/require;
deleteall ${REMOTE_ADDR} ${LOCAL_ADDR} esp;
deleteall ${LOCAL_ADDR} ${REMOTE_ADDR} esp; 
# linux won't honor a 'deleteall', so we use flush (bad, but necessary for now)
flush;
EOT
}



echo "p1_up_down: $1 starting..."
echo "p1_up_down: LOCAL_ADDR = ${LOCAL_ADDR}"
echo "p1_up_down: LOCAL_PORT = ${LOCAL_PORT}"
echo "p1_up_down: REMOTE_ADDR = ${REMOTE_ADDR}"
echo "p1_up_down: REMOTE_PORT = ${REMOTE_PORT}"
echo "p1_up_down: DFLT_GW = ${DFLT_GW}"
echo "p1_up_down: DFLT_IF = ${DFLT_IF}"
echo "p1_up_down: INTERNAL_ADDR4 = ${INTERNAL_ADDR4}"
echo "p1_up_down: INTERNAL_DNS4 = ${INTERNAL_DNS4}"
echo "p1_up_down: DEFAULT_DOMAIN = ${DEFAULT_DOMAIN}"
echo "p1_up_down: SPLIT_INCLUDE = ${SPLIT_INCLUDE}"
echo "p1_up_down: SPLIT_LOCAL = ${SPLIT_LOCAL}"

echo ${INTERNAL_ADDR4} | grep -q '[0-9]' || {
  echo "p1_up_down: error: invalid INTERNAL_ADDR4."
  exit 1
}

echo ${DFLT_GW} | grep -q '[0-9]' || {
  echo "p1_up_down: error: invalid DFLT_GW."
  exit 2
}

case "$1" in
  phase1_up)
    phase1_up
    ;;
  phase1_down)
    phase1_down
    ;;
  *)
    echo "p1_up_down: error: must be called by racoon w. arg=phase1_[up|down]"
    exit 3
    ;;
esac

echo "p1_up_down: $1 completed successfully."
exit 0
