Help with auto switching VPN servers

Status
Not open for further replies.

toyebox

Explorer
Joined
Aug 20, 2016
Messages
87
Hey all! You have never let me down here ! Before I go through the trouble of trying to write a bash script, I thought I would ask here first. I have about 10 different openVPN Servers I connect to. Sometimes one will go down and I want to set up an auto switching between the servers. I have it setup so when not connected to a VPN, there is no internet access for that jail. I'm trying to minimize down time. Any thoughts appreciated!
 

toyebox

Explorer
Joined
Aug 20, 2016
Messages
87
well, i decided to just write up a bash script. i run it with a cron job. here it is for anyone who wants it. i know its not perfect btw, but it does work well.

Code:
#!/usr/local/bin/bash

#__________ Don't edit below this!!!__________

# Edit these var's by using command line arguments -r, -w and -c
timeBetweenResets=60
timeToWaitForTun=45
userSetConfig=null
vpns=(US.conf Canada.conf Russia.conf);

initiateNewTun () {
	totalLength=${#vpns[@]}
	oldPos=null

	# Read the file of the last used server
	mapfile -t < /home/admin/last_used_server lines
	oldValue="${lines[0]}"
	oldTime="${lines[1]}"
	newTime=`date +%s`
	
	# Check to make sure that the info file contains a time in seconds and a last used server, if not, create it
	rc='^[0-9]+$'
	if [[ ! $oldTime =~ $rc ]] || [[ ${oldValue} != *".conf"* ]]; then
		echo "error: corrupt last_used_server file.. resetting it"
		cat > /home/admin/last_used_server <<- EOF
		${vpns[0]}
		$newTime
		EOF
		
		# Set oldTime to 0 so the script will continue and ignore the timeBetweenResets var
		oldTime=0
		lastConf=$(($totalLength -1))
		oldValue=${vpns[$lastConf]}
		echo "Set oldValue and oldTime so the script will continue.."
	fi

	# Specific script for setting a user set config (must match one of the ones in the array)
	if [[ $userSetConfig != null ]]; then
		for i in "${!vpns[@]}"; do
			if [[ "${vpns[$i]}" = "${userSetConfig}" ]]; then
				userInputIsGood=true	
			fi
		done
	
		if [[ $userInputIsGood == true ]]; then
			echo "the user input config name is available, we will set it now."
			newValue=$userSetConfig
		fi

	# Specific script if NOT setting a user specific script
	else
		difference=$(($newTime - $oldTime))
	
		if [[ $difference -lt $timeBetweenResets ]]; then
			echo "too soon between resets, exiting.."
			exit
		fi

			for i in "${!vpns[@]}"; do
			  if [[ "${vpns[$i]}" = "${oldValue}" ]]; then
					oldPos="${i}";
			fi
			done

		if [[ $oldPos == null ]]; then
			echo "Current config was not found in array.. resetting to the first config.."
			newPos=0
		else
			nextPos=$(($oldPos + 1)) 
		
			if [[ $nextPos -eq $totalLength ]]; then
				echo "there is no next config, need to circle back to the beginning"
				nextPos=0
			fi
		fi
		
		# set the new config value		
		newValue=${vpns[$nextPos]}
	fi

	# Update last_server_used file info
	echo "Next config to use is: $newValue , Updating last_used_server file"
	cat > /home/admin/last_used_server <<- EOF
	$newValue
	$newTime
	EOF
	
	/usr/local/sbin/openvpn --daemon openvpn --config /usr/local/etc/openvpn/$newValue --writepid /var/run/openvpn.pid
	return 0
}

killAllTuns () {
	# First kill all openvpn services so we don't lock up when trying to remove tunnels
	for pid in $(ps -xj | grep "openvpn" | grep -v "grep" | awk '{print $2}'); do 
		kill -9 $pid
		echo "killed pid: $pid" 
	done
	
	# Check to see if all openvpn instances were closed out (the tunnel will not show UP in the description)
	if ifconfig | grep "tun" | grep "UP" > /dev/null; then
		echo "failed to kill all openvpn instances, exiting.."
		exit
	fi

	# Destroy all empty tunnel interfaces
	for tuns in $(/sbin/ifconfig -l | tr " " "\n" | grep "tun"); do ifconfig $tuns destroy; done
	
	# Verify all tunnels were removed
		if ifconfig | grep "tun" > /dev/null; then
				echo "failed to kill all tunnels, exiting.."
				exit	
		fi

	echo "Successfully reset all interfaces"
}

checkInternet () 
{
	wget -q --tries=5 --timeout=30 --spider http://google.com
	if [[ $? -eq 0 ]]; then
		return 0
	else
		return 1
	fi
}

# ________________________________________________________________Main Run Starts Here ____________________________________________
# Check for options that were run
while getopts ":c:r:w:" opt; do
	case $opt in
		c ) userSetConfig=$OPTARG ;;
		r ) timeBetweenResets=$OPTARG ;;
		w ) timeToWaitForTun=$OPTARG ;;
		* ) echo "incorrect argument, exiting.."
			exit 1
	esac
done

# When setting a specific user config, don't check for internet connection, just do it
if [[ $userSetConfig == null ]]; then
	# Check if everything is working properly
	checkInternet

	# return 0 means all is healthy and we are connected; exit the script
	if [[ $? -eq 0 ]]; then
			exit
	fi

	echo "Internet is not up and running.. Starting reset procedures"
fi

# Kill all active tunnels and instances of OpenVPN
killAllTuns

# Initiate a new tunnel using the next config				
initiateNewTun

if [[ $? -eq 0 ]]; then
	echo "Waiting for tunnel device to appear.."
	
	tunAvail=null
		end=$((SECONDS+$timeToWaitForTun))

		while [ $SECONDS -lt $end -a $tunAvail == null ]; do
				tunAvail=$(/sbin/ifconfig -l | tr " " "\n" | /usr/bin/grep 'tun')

				if [[ $tunAvail != *"tun"* ]]; then
						tunAvail=null
				fi

				sleep 1
		done

	if ! ifconfig | grep "tun" | grep "UP" > /dev/null; then
				echo "No tunnel found.. Failed to initiate a new tunnel.. Exiting.."
		exit
		fi

	echo "tunnel created successfully, setting firewall and checking internet connection.."
	service ipfw restart
	checkInternet
	
	if [[ $? -eq 0 ]]; then
		echo "Internet restoration complete, exiting"
	else
		echo "internet restoration was unsuccessful, exiting"
	fi
	
	exit
fi

echo "initiateNewTun failed with an unknown reason"
exit

 
Status
Not open for further replies.
Top