diff options
author | Trumeet <yuuta@yuuta.moe> | 2022-09-05 22:49:12 -0700 |
---|---|---|
committer | Trumeet <yuuta@yuuta.moe> | 2022-09-05 22:49:12 -0700 |
commit | 2f392bc9bcf935306e7a9c74957c815f68ba8ad0 (patch) | |
tree | f55d399c3c811db0229366120f81b41be0834572 | |
download | vpnswitch-2f392bc9bcf935306e7a9c74957c815f68ba8ad0.tar vpnswitch-2f392bc9bcf935306e7a9c74957c815f68ba8ad0.tar.gz vpnswitch-2f392bc9bcf935306e7a9c74957c815f68ba8ad0.tar.bz2 vpnswitch-2f392bc9bcf935306e7a9c74957c815f68ba8ad0.zip |
First Commit
-rw-r--r-- | README.md | 11 | ||||
-rw-r--r-- | profile | 61 | ||||
-rwxr-xr-x | vpnswitch | 139 |
3 files changed, 211 insertions, 0 deletions
diff --git a/README.md b/README.md new file mode 100644 index 0000000..79485ae --- /dev/null +++ b/README.md @@ -0,0 +1,11 @@ +# `vpnswitch(1)` + +Automatically switch VPN based on internal network connectivity, similar to DirectAccess. + +## Configuration + +Refer to `profile` for more details. + +## License + +WTFPL @@ -0,0 +1,61 @@ +# The command to check if this computer is connected to the internal network. +# Return codes: +# - 0: This computer is in the internal network. +# vpnswitch(1) will then execute CHECK_VPN_CMD, and stop the VPN if needed. +# - 1: This computer is NOT in the internal network. +# vpnswitch(1) will then execute CHECK_VPN_CMD, and start the VPN if needed. +# - [2, 255]: An error occured. Abort the whole execution. +# vpnswitch(1) will exit with the same return code. +# This command is usually ping(1) or curl(1). +# Mandatory value. +CHECK_NETWORK_CMD="ping -c 3 10.0.1.200" + +# The command to check if this computer is connected to the internal network, with VPN already on. +# This command is only ran if CHECK_VPN_CMD returns 0. +# Refer to CHECK_NETWORK_CMD for documentation. +# Mandatory value. It can be simply $CHECK_NETWORK_CMD. +CHECK_NETWORK_CMD_VPN="ping -c 2 10.0.3.1" + +# Specifies the timeout CHECK_NETWORK_CMD runs in seconds. +# After the specified seconds: +# - CHECK_NETWORK_CMD will be killed using SIGTERM +# - The computer will be considered NOT in the internal network, thus starting the VPN. +# Specifing 0 or not specifing this value will not set a timeout for CHECK_NETWORK_CMD. +# However, it is the administrator's responsibility to not let vpnswitch(1) stucking. +# Optional value. +CHECK_NETWORK_TIMEOUT=5 + +# The command to check if the VPN is already running. +# Return codes: +# - 0: VPN is running. +# If CHECK_NETWORK_CMD returns 0 (in the internal network), VPN_DOWN_CMD will be executed. +# - 1: VPN is NOT running. +# If CHECK_NETWORK_CMD returns 1 (NOT in the internal network), VPN_UP_CMD will be executed. +# - [2, 255]: An error occured. Abort the whole execution. +# vpnswitch(1) will exit with the same return code. +# Mandatory value. +CHECK_VPN_CMD="ip a s dev sea1us" + +# The command to start the VPN and anything else depending on the VPN. +# Return codes: +# - 0: The VPN is successfully started or requested to start. +# It is the administrator's responsibility to make sure the VPN started. +# - [1, 255]: An error occured. Abort the whole execution. +# vpnswitch(1) will exit with the same return code. +# This command is executed when: +# - CHECK_NETWORK_CMD returns 1 (NOT in the ineternal network), AND +# - CHECK_VPN_CMD returns 1 (VPN is NOT running). +# Mandatory value. +VPN_UP_CMD="echo Up" + +# The command to stop the VPN and anything else depending on the VPN. +# Return codes: +# - 0: The VPN is successfully stopped or requested to stopped. +# It is the administrator's responsibility to make sure the VPN stopped. +# - [1, 255]: An error occured. Abort the whole execution. +# vpnswitch(1) will exit with the same return code. +# This command is executed when: +# - CHECK_NETWORK_CMD returns 0 (in the ineternal network), AND +# - CHECK_VPN_CMD returns 0 (VPN is running). +# Mandatory value. +VPN_DOWN_CMD="echo Down" diff --git a/vpnswitch b/vpnswitch new file mode 100755 index 0000000..aeb2ecc --- /dev/null +++ b/vpnswitch @@ -0,0 +1,139 @@ +#!/bin/sh +set -e + +alias echoe=">&2 echo" + +## Debug setup + +# To be overrided by DEBUG +function dbg() { + : +} + +if ! test -z ${DEBUG+x}; then + set -x + function dbg() { + echoe $1 + } +fi + +## End debug setup + +## Util functions + +# Check if a variable named $1 is set. If not, apply the default value at $2. +# If no default value is supplied, prompt an error and exit with 64. +function check_var() { + local _var=$1 + local _t=$(eval "\${$_var+echo ' '}") + if test -z "$_t"; then + if test "$#" -eq 2; then + eval "$_var=$2" + dbg "Setting variable '$_var' to default value '$1'" + else + echoe "Required variable: '$_var' is missing in the profile." + exit 64 + fi + fi +} + +function run_test() { + local _cmd=$@ + dbg "Running '$_cmd' ..." + if _out=$($_cmd); then + echo "$_out" + return 0 + else + local _exit=$? + echo "$_out" + if test $_exit -eq 124; then + case $_cmd in + "timeout"*) + echoe "Command '$_cmd' timed out." + return 1 + ;; + *) + ;; + esac + fi + case $_exit in + 1) + return 1 + ;; + *) + echo "Command '$_cmd' exited with abnormal code: $_exit." + exit $_exit + ;; + esac + fi +} + +## End util functions + +## Main + +if test "$#" -ne 1; then + echoe "Usage: $0 [Profile]" + exit 64 +fi +PROFILE=$1 +if test -e "$PROFILE"; then + dbg "Using profile from path $PROFILE" + . $PROFILE +else + . /etc/vpnswitch/$PROFILE.conf +fi + +check_var CHECK_NETWORK_CMD +check_var CHECK_NETWORK_CMD_VPN +check_var CHECK_NETWORK_TIMEOUT 0 +if test $CHECK_NETWORK_TIMEOUT -lt 0; then + echoe "\$CHECK_NETWORK_TIMEOUT must be greater or equals than 0, but it is currently set to $CHECK_NETWORK_TIMEOUT." + exit 64 +fi +check_var CHECK_VPN_CMD +check_var VPN_UP_CMD +check_var VPN_DOWN_CMD + +## Gather information +if _out=$(run_test $CHECK_VPN_CMD); then + echo "$_out" + echo "VPN running: yes" + IN_VPN=0 + dbg "Using CHECK_NETWORK_CMD_VPN when VPN is running." + CHECK_NETWORK_CMD=$CHECK_NETWORK_CMD_VPN +else + echo "$_out" + echo "VPN running: no" + IN_VPN=1 +fi + +if test $CHECK_NETWORK_TIMEOUT -gt 0; then + CHECK_NETWORK_CMD="timeout -s SIGTERM ${CHECK_NETWORK_TIMEOUT}s $CHECK_NETWORK_CMD" +fi +if _out=$(run_test $CHECK_NETWORK_CMD); then + echo "$_out" + echo "Internal network: yes" + IN_NET=0 +else + echo "$_out" + echo "Internal network: no" + IN_NET=1 +fi + +## Start / stop VPN +if test $IN_NET -eq 1; then # Not in internal network + if test $IN_VPN -eq 1; then # VPN not running + dbg "Starting VPN by running '$VPN_UP_CMD'" + exec $VPN_UP_CMD + else # VPN is running + exit 0 + fi +else # In internal network + if test $IN_VPN -eq 1; then # VPN not running + exit 0 + else # VPN is running + dbg "Stopping VPN by running '$VPN_UP_CMD'" + exec $VPN_DOWN_CMD + fi +fi |