rokkonet

PC・Androidソフトウェア・アプリの開発・使い方に関するメモ

SoftEther VPN Gateサーバーへの接続シェルスクリプト

2020 May 17.
2020 Apr. 12.


接続スクリプト connectVpnGate.sh

#!/bin/bash
# 2020 May 17.
# 2020 May 16.
# Ryuichi Hashimoto

# connect to VPN-GATE-server

# You have to be a root user.
# Do not forget to disconnect VpnGateServer and resume network route after using vpn-gate-server.

# flow
# 1) get VPN Gate server address from arguement.
# 2) check host is communicating with outside of LAN
# 3) add packet-route to server to routing table.
# 4) start vpnclient.
# 5) change VPN-server's address of account.
# 6) connect account.
# 7) give ip-address to virtual NIC.
# 8) change default route to VPN-Gate in routing table.
# You can enjoy VPN-Gate-server


Command=`basename $0` 
DhclientPidFile=/var/run/dhclint-vpngate`date "+%y%m%d%H%M%S"`.pid

# usage
function usage() {
cat << EOP
usage:
    $ su -
    # ${Command} IpAddress Port

    Example: # ${Command} 111.222.333.444 443

flow:
1) get VPN Gate server address from arguement. 
2) check host is communicating with outside of LAN
3) add packet-route to server to routing table.
4) start vpnclient.
5) change VPN-server's address of account.
6) connect account.
7) give ip-address to virtual NIC.
8) change default route to VPN-Gate in routing table.
You can enjoy VPN-Gate-server
EOP
}


function checkIPstr() {
  local IP=$1
  local NumDot=`echo -n $IP | sed -e 's@[^.]@@g' | wc -c`
  local TmpIP=${IP}
  local LengthTmpIP=${#TmpIP}
  local StrIPpart=""
  local HeadLetter=""

  ## check IP
  # count dots
  if [ ${NumDot} -ne 3 ]; then
    echo "Number of dot in IP-address ${IP} is not 3."
    return 1
  fi

  if [ $LengthTmpIP -lt 8 ]
  then
    echo "Too few address-letters."
    return 1
  fi

  # check number and digit of number
  while [ ${LengthTmpIP} -gt 0 ]
  do
    # get top strings before 1st dot
    StrIPpart=`echo ${TmpIP} | grep -oP '^[0-9]*'`
    if [ ${#StrIPpart} -lt 1 ]
    then
      echo "No number in some area in IP-address."
      return 1
    fi

    # store IPtmp for next loop
    TmpIP=`echo ${TmpIP} | sed -e "s/^${StrIPpart}//"`

    # if head of TmpIP is ".", remove "."
    HeadLetter=`echo ${TmpIP:0:1}`
    if [[ $HeadLetter = "." ]]
    then
      TmpIP=${TmpIP#.}

      # if TmpIP has no letter, then finish loop
      if [ ${#TmpIP} -lt 1 ]
      then
        break
      fi
    fi

    # check StrIPpart is number
    expr $StrIPpart + 1 >/dev/null 2>&1
    if [ $? -gt 1 ]
    then
      echo "Non-number-letters are included in IP-address."
      return 1
    fi

    # check StarIPpart is 0-255
    if [[ $StrIPpart -lt 0 || $StrIPpart -gt 255 ]]
    then
      echo "Number of IP-address is out of range[0-255]."
      return 1
    fi
    LengthTmpIP=${#TmpIP}
  done

  return 0
}


##############
#### main ####
##############

# check number of arguements
if [ $# -ne 2 ]
then
  echo "False: Num of arguements" 1>&2
  usage
  exit 1
fi

# get VPN Gate server address 
ServerIP=$1

# get port number
Port=$2

# check ServerIP-address-string
RetCheckIPstr=`checkIPstr ${ServerIP}`
if [ $? -gt 0 ]
then
  echo $RetCheckIPstr 1>&2
  exit 1
fi

# check $Port is number
expr "$Port" + 1 > /dev/null 2>&1
if [ $? -gt 1 ]
then
  echo "${Port} is not number." 1>&2
  exit 1
fi

# check host is not communicating with outside of LAN
which isCommunicatingOutLan.sh > /dev/null 2>&1
if [ $? -ne 0 ]
then
  echo "isCommunicatingOutLan.sh does not exist in command-PATH." 1>&2
  echo "Abort." 1>&2
  exit 1
fi
isCommunicatingOutLan.sh > /dev/null 2>&1
if [ $? -ne 1 ]
then
  echo "Host is communicating with outside through LAN." 1>&2
  echo "Changing packet-route stops existing communication through LAN." 1>&2
  echo "Abort." 1>&2
  exit 1
fi

# add packet-route to server to routing table.
RealNIC=`route | grep -m 1 default | sed 's/[\t ]\+/\t/g' | cut -f 8`
RealGWayAddress=`route -n | grep ${RealNIC} | sed 's/[\t ]\+/\t/g' | cut -f 2 | sort -r | sed -n '1,1p'`
route add ${ServerIP} gw ${RealGWayAddress} dev ${RealNIC}

# start vpnclient.
PathVpnClientCom=`find /usr/ -type f -name vpnclient`
DirVpnClient=`dirname ${PathVpnClientCom}`
cd $DirVpnClient
./vpnclient start

sleep 1

AccountName=`./vpncmd localhost /CLIENT /CMD AccountList | grep 接続設定名 | sed -e "s/^.*|//"`
if [ ${#AccountName} -lt 1 ]
then
  echo "No VPN-account found."
  echo "Abort."
  ./vpnclient stop
  route del ${ServerIP}
  exit 1
fi

AccountHub=`./vpncmd localhost /CLIENT /CMD AccountList | grep HUB | sed -e "s/^.*|//"`
if [ ${#AccountHub} -lt 1 ]
then
  echo "No VPN-account-hub found."
  echo "Abort."
  ./vpnclient stop
  route del ${ServerIP}
  exit 1
fi

# set server-address:port to account
./vpncmd localhost /CLIENT /CMD AccountSet ${AccountName} /SERVER:${ServerIP}:${Port} /HUB:${AccountHub}

# connect to VPN Gate server
./vpncmd localhost /CLIENT /CMD AccountConnect ${AccountName}

# set an address on virtual NIC on linux
VpnNIC=`./vpncmd localhost /CLIENT /CMD AccountList | grep LAN | sed -e "s/^.*|//"`
LinuxVirNIC=`ip l | grep -Po "\S+${VpnNIC}"`
echo "Getting IP-Address on virtual-NIC by dhclient..." 1>&2
dhclient -v -pf $DhclientPidFile $LinuxVirNIC
echo "Got IP-Address on virtual-NIC." 1>&2

# change default route of routing table to flow to VPN Gate server
VirNicAddress=` ip -4 a show ${LinuxVirNIC} | grep -Po "inet\s+[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+" | grep -Po "[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+"`
VirGWayAddress=`echo ${VirNicAddress} | grep -Po "[0-9]+\.[0-9]+\."`
VirGWayAddress="${VirGWayAddress}254.254"
# delete default route
while :
do
  NumDefaultRoute=`route -n | awk -v awkRealGWayAddress="${RealGWayAddress}" '{if ($1 == "0.0.0.0" && ($2 == awkRealGWayAddress)){print}}' | wc -l`
  if [ ${NumDefaultRoute} -lt 1 ]
  then
    break
  fi
  route del default
done
# add vpngate-route as default-gateway
route add default gw ${VirGWayAddress} dev ${LinuxVirNIC}

exit 0


切断スクリプト disconnectVpnGate.sh

#!/bin/bash
# 2020 May  17.
# 2020 Apr. 11.
# ryuichi Hashimoto

# Disconnect VPN Gate server connection

# You have to be a root user.


Cmd=`basename $0`

# usage
function usage() {
  cat << EOP
usage:
    $ su -
    ${Cmd}
EOP
}

# check host is communicating with outside of LAN
which isCommunicatingOutLan.sh > /dev/null 2>&1
if [ $? -ne 0 ]
then
  echo "isCommunicatingOutLan.sh does not exist in command-PATH."
  echo "Abort."
  exit 1
fi

UsingInternet="yes"
while [ "yes" = ${UsingInternet} ]
do
  isCommunicatingOutLan.sh > /dev/null 2>&1
  if [ $? -ne 1 ]
  then
    # Host is communicating with outside through LAN.
    # Changing packet-route stops existing communication through LAN.
    sleep 1m
  else
    UsingInternet="no"
  fi
done

# check vpnclient is running
ps ax -f | grep vpnclient | grep -v grep > /dev/null 2>&1
if [ $? -ne 0 ]
then
  echo "vpnclient is not running."
  echo "Abort."
  exit 1
fi

# move to VpnClient-command-dir
PathVpnClientCom=`find /usr/ -type f -name vpnclient`
DirVpnClient=`dirname ${PathVpnClientCom}`
cd $DirVpnClient

# check packet-route-setting
VpnNIC=`./vpncmd localhost /CLIENT /CMD AccountList | grep LAN | sed -e "s/^.*|//"`
LinuxVirNIC=`ip l | grep -Po -m 1 "\S+${VpnNIC}"`
if [ $? -ne 0 ]
then
  echo "Virtual NIC on linux does not exist."
  echo "Abort."
  exit 1
fi
route | grep default | grep ${LinuxVirNIC}
if [ $? -ne 0 ]
then
  echo "Default packet-route does not pass through virtual NIC."
  echo "Abort."
  exit 1
fi

# resume packet-route
RealNIC=`route -n | grep -m 1 '192.168.' | sed 's/[\t ]\+/\t/g' | cut -f 8`
RealGWayAddress=`route -n | grep ${RealNIC} | sed 's/[\t ]\+/\t/g' | cut -f 2 | grep -m 1 -Po '192.168.[0-9]+.[0-9]+'`
ServerIP=`route -n | grep ${RealNIC} | sed 's/[\t ]\+/ /g' | awk -v adrs=${RealGWayAddress} '{if ($2 == adrs){print $1}}'`
route del default
route add default gw ${RealGWayAddress} dev ${RealNIC}
route del ${ServerIP} 

# disconnect VPN Gate
AccountName=`./vpncmd localhost /CLIENT /CMD AccountList | grep 接続設定名 | sed -e "s/^.*|//"`
./vpncmd localhost /CLIENT /CMD AccountDisconnect ${AccountName}
./vpnclient stop

# kill dhclient
while :
do
  NumPsLines=`ps ax -f | grep "dhclient .*${LinuxVirNIC}" | grep -v grep | wc -l`
  if [ $NumPsLines -lt 1 ]
  then
    break
  fi
  PidDhclient=`ps ax -f | grep -v grep | grep -m1 "dhclient .*${LinuxVirNIC}" | sed -n '1,1p' | sed 's/[\t ]\+/\t/g' | cut -f 2`
  kill -9 ${PidDhclient}
done

exit 0


isCommunicatingOutLan.sh (上記2スクリプトから呼び出される)

#!/bin/bash
#
# 2020 Apr. 12.
# Ryuichi Hashimoto.
#
# Check if host is communicating with outside of LAN.
#   retrun code
#     0: host is using internet
#     1: host is not using internet


# List up programs which access to internet and with which you fear to break internet-communications.
# Connecting to VPN-gate-server breaks existing internet access.
#   CMDS='INETPROGRAM1|INETPROGRAM2|INETPROGRAM3'
CMDS='INETPROGRAM1|INETPROGRAM2|INETPROGRAM3'


function isCommunicate() {
  ps ax -f | grep -E $CMDS | grep -v grep 
  if [ $? -ne 0 ];then
     # nothing uses internet
     return 1
  fi
  # something uses internet
  return 0
}


############
### main ###
############

# set loop-count
NumLoop=5

# set default-retrun-code.
Result=1

while [ $NumLoop -gt 0 ]; do
  isCommunicate
    # return code of isCommunicate
    #   0: host is using internet
    #   1: host is not using internet

  if [ 0 -eq $? ]; then
    # when some commands are running
    Result=0
  fi
  sleep 1
  NumLoop=$(($NumLoop - 1))
done
exit $Result