aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTrumeet <yuuta@yuuta.moe>2022-09-05 22:49:12 -0700
committerTrumeet <yuuta@yuuta.moe>2022-09-05 22:49:12 -0700
commit2f392bc9bcf935306e7a9c74957c815f68ba8ad0 (patch)
treef55d399c3c811db0229366120f81b41be0834572
downloadvpnswitch-2f392bc9bcf935306e7a9c74957c815f68ba8ad0.tar
vpnswitch-2f392bc9bcf935306e7a9c74957c815f68ba8ad0.tar.gz
vpnswitch-2f392bc9bcf935306e7a9c74957c815f68ba8ad0.tar.bz2
vpnswitch-2f392bc9bcf935306e7a9c74957c815f68ba8ad0.zip
First Commit
-rw-r--r--README.md11
-rw-r--r--profile61
-rwxr-xr-xvpnswitch139
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
diff --git a/profile b/profile
new file mode 100644
index 0000000..f2a5034
--- /dev/null
+++ b/profile
@@ -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