1. A Full ppp-ssh VPN script
    1. Author
    2. Discussion
    3. Full Text of the Script

A Full ppp-ssh VPN script

Author

Discussion

In ../ppp-ssh VPN, toward the bottom, I note that the one liner featured there,

pppd nodetach 10.0.3.1:10.0.3.2 pty "ssh -l root remotehost pppd notty"

would typically be embedded in a much larger script.

This article presents my best shot at that much larger script.

Full Text of the Script

#!/bin/bash

# A scenario involving one server and three clients.
#
# Note that:
#   id_rsa1.pub is client1's root user's public ssh key
#   id_rsa2.pub is client2's root user's public ssh key
#   id_rsa3.pub is client3's root user's public ssh key
# on server 10.10.0.1:
#   vlan.sh install vlanuser vlangroup id_rsa1.pub vlan1 10.0.1.1 10.0.1.2
#   vlan.sh install vlanuser vlangroup id_rsa2.pub vlan2 10.0.2.1 10.0.2.2
#   vlan.sh install vlanuser vlangroup id_rsa3.pub vlan3 10.0.3.1 10.0.3.2
# to connect from client1 10.10.0.2:
#   vlan.sh client vlan1 vlanuser 10.10.0.1 10.0.1.1 10.0.1.2 10 10.0.0.0 255.255.0.0
# to connect from client2 10.10.0.3:
#   vlan.sh client vlan2 vlanuser 10.10.0.1 10.0.1.1 10.0.1.2 10 10.0.0.0 255.255.0.0
# to connect from client3 10.10.0.4:
#   vlan.sh client vlan3 vlanuser 10.10.0.1 10.0.1.1 10.0.1.2 10 10.0.0.0 255.255.0.0
#

PPPD=/usr/sbin/pppd
IFCONFIG=/sbin/ifconfig
VLAN=/usr/local/sbin/vlan.sh
config_file=/etc/vlan-server.conf
# time to sleep after starting pppd and before calling route
route_delay=10

function vlan_uninstall {
   local vlanuser=$1
   local vlangroup=$2
   if [ -z "$2" ] ; then
      echo "usage: <vlanuser> <vlangroup>"
      exit 1
   fi
   hdir=/home/${vlanuser}

   userdel $vlanuser
   groupdel $vlangroup
   if [ -d "$hdir" ] ; then
      rm -rf $hdir
   fi
   rm $config_file   
   
   echo "done"
   echo "you will have to remove the entry from sudoers yourself"
   echo "it should look like this:"
   echo "${vlanuser} ALL=NOPASSWD $VLAN server *"
}

function vlan_install {
   local vlanuser=$1
   local vlangroup=$2
   local rsa_pub=$3
   local name=$4
   local server_ip=$5
   local client_ip=$6
   if [ -z "$5" ] ; then
      echo "usage: <vlanuser> <vlangroup> <rsa public key file> <name> <server_ip> <client_ip>"
      exit 1
   fi

   groupadd $vlangroup
   
   mkdir /home/${vlanuser}
   useradd $vlanuser
   # you need to set the password string or the account is considered "locked"
   usermod -p "X" -s /bin/bash -g $vlangroup $vlanuser
   chown ${vlanuser}.${vlangroup} /home/${vlanuser}/
   
   echo "${vlanuser} ALL=NOPASSWD: $VLAN server *" >> /etc/sudoers
   mkdir /home/${vlanuser}/.ssh
   cat $rsa_pub >> /home/${vlanuser}/.ssh/authorized_keys
   chown ${vlanuser}.${vlangroup} /home/${vlanuser}/.ssh
   chown ${vlanuser}.${vlangroup} /home/${vlanuser}/.ssh/authorized_keys
   
   touch $config_file
   echo "$name $client_ip $server_ip" >> $config_file
}

function test_ppp_address {
   ipv4=$1
   if [ -z "$1" ] ; then
      echo "usgae: <ipv4 address>"
      return 1
   fi

   if ! grep "ppp" /proc/net/dev > /dev/null 2>&1 ; then
      echo "no ppp interfaces found"
      return 1
   fi

   ppp_ifaces=$(grep "ppp" /proc/net/dev | cut -d: -f1)
   for ppp_iface in $ppp_ifaces; do
      ppp_address=$($IFCONFIG $ppp_iface | grep "inet addr" | cut -d: -f2 | cut -d" " -f1)
      echo "$ppp_iface $ppp_address"
      if [ "$ipv4" = "$ppp_address" ] ; then
         return 0
      fi
   done
   return 1
}

function get_ppp_pid {
   ipv4=$1
   if [ -z "$1" ] ; then
      echo "usgae: <ipv4 address>" 1>&2
      return 1
   fi

   if ! grep "ppp" /proc/net/dev > /dev/null 2>&1 ; then
      echo "no ppp interfaces found" 1>&2
      return 1
   fi

   ppp_ifaces=$(grep "ppp" /proc/net/dev | cut -d: -f1)
   for ppp_iface in $ppp_ifaces; do
      ppp_address=$($IFCONFIG $ppp_iface | grep "inet addr" | cut -d: -f2 | cut -d" " -f1)
      if [ "$ipv4" = "$ppp_address" ] ; then
         cat /var/run/${ppp_iface}.pid
         return 0
      fi
   done
   return 1
}

function get_ppp_pid2 {
   while ! get_ppp_pid "$@" 2>/dev/null ; do
      sleep 1
   done
}

# why does killall pppd kill the vlan.sh processes that spawned the pppd?
# because nodetach keeps the pppd as part of the same threadgroup as vlan.sh which called it
# and when pppd exits it calls exit_group(), which kills the whole threadgroup.
# I need to get rid of the nodetach argument and figure out another way to capture the pid
# of the particular pppd spawned.
#
# one way might be to use /var/run/ppp<iface name>.pid file that pppd creates.
#
function vlan_client {
   NAME=$1
   REMOTE_USER=$2
   REMOTE_HOST=$3
   REMOTE_IP=$4
   LOCAL_IP=$5
   DELAY=$6
   NETWORK=$7
   NETMASK=$8

   if [ -z "$8" ]; then
      echo "usage: <name> <remote_user> <remote_host> <remote_virtual_ip> <local_virtual_ip> <delay> <network> <netmask>"
      exit 1
   fi

   pppd_pid=""

   $PPPD pty "ssh -o StrictHostKeyChecking\ no -l $REMOTE_USER ${REMOTE_HOST} \"sudo $VLAN server ${NAME}\""
   pppd_pid=$(get_ppp_pid2 $LOCAL_IP)

   sleep $route_delay
   route add -net $NETWORK netmask $NETMASK gw $REMOTE_IP
   sleep $DELAY

   while true; do
      if ! test_ppp_address $LOCAL_IP >/dev/null 2>&1 ; then
         echo "$(date) ppp address failed. setting up ssh-ppp tunnel"
         if ! [ -z "$pppd_pid" ] ; then
             kill $pppd_pid
         fi
         $PPPD pty "ssh -o StrictHostKeyChecking\ no -l $REMOTE_USER ${REMOTE_HOST} \"sudo $VLAN server ${NAME}\""
         pppd_pid=$(get_ppp_pid2 $LOCAL_IP)
         sleep $route_delay
         route add -net $NETWORK netmask $NETMASK gw $REMOTE_IP
         sleep $DELAY
      else
         true
   #      echo "remote host is already up"
      fi

      sleep $DELAY
   done
}

function vlan_sclient {
   NAME=$1
   REMOTE_USER=$2
   REMOTE_HOST=$3
   REMOTE_IP=$4
   LOCAL_IP=$5
   DELAY=$6
   NETWORK=$7
   NETMASK=$8

   if [ -z "$8" ]; then
      echo "usage: <name> <remote_user> <remote_host> <remote_virtual_ip> <local_virtual_ip> <delay> <network> <netmask>"
      exit 1
   fi

   if ! test_ppp_address $LOCAL_IP >/dev/null 2>&1 ; then
      $PPPD pty "ssh -o StrictHostKeyChecking\ no -l $REMOTE_USER ${REMOTE_HOST} \"sudo $VLAN server ${NAME}\""
      sleep $route_delay
      route add -net $NETWORK netmask $NETMASK gw $REMOTE_IP
   else
      echo "connection already up"
   fi
}

function vlan_server {
   vlan_name="$1"
   if [ -z "$1" ] ; then
      echo "vlan-client <vlan_name>"
      exit 1
   fi

   if ! grep $vlan_name $config_file > /dev/null 2>&1 ; then
      echo "name not recognized"
      exit 1
   fi

   # gather ip addresses from config file
   tfile=$(mktemp)
   grep $vlan_name $config_file > $tfile
   read name ip_client ip_server < $tfile
   rm $tfile

   $PPPD notty nodetach ${ip_server}:${ip_client}
}

command=$1
if [ -z "$1" ] ; then
   echo "usage: <command>"
   echo "   install"
   echo "   uninstall"
   echo "   sclient"
   echo "   client"
   echo "   server"
   exit 1
fi

shift
if [ "$command" == "install" ] ; then
   vlan_install "$@"
elif [ "$command" == "uninstall" ] ; then
   vlan_uninstall "$@"
elif [ "$command" == "sclient" ] ; then
   vlan_sclient "$@"
elif [ "$command" == "client" ] ; then
   vlan_client "$@"
elif [ "$command" == "server" ] ; then
   vlan_server "$@"
elif [ "$command" == "getpid" ] ; then
   get_ppp_pid "$@"
fi

hopeless_linux: ppp/A Full ppp-ssh VPN script (last modified 2007-07-01 16:01:00)