#!/bin/bash # This is a script for StrongSWAN's ipsec command. It is used on the Astaro routers but is not limited to Astaro. # This script can be put into /root/bin folder on the device which is in the path. # # To create the file (and paste the contents through terminal session) # # cd <-- puts you in the home directory. (need to be logged in as 'root') # cd bin <-- goes to 'bin' subfolder. By default it is in the path. # rm vpn <-- Remove (delete) file 'vpn' if it exists. # or you can rename it using: mv vpn vpn.old # vim vpn <-- creates the file and opens editor. (Don't need .sh extension. Up to you.) # Press the 'i' key which causes vim to go into INSERT mode for editing. # Paste the contents of this file. Need to include these comments with the /bin/bash at the top. # Press the 'Escape' key to get out of INSERT mode. # Type ':x' to save and exit. ':w' saves without exit ':q' quits without saving # # chmod u+x vpn <-- sets user permission to executable for this file. # # In command shells like DOS or UNIX, a command returning error level of 0 means it is successful. TRUE=0 FALSE=1 DEBUG=$FALSE function main() { if [[ $1 == "--debug" ]]; then DEBUG=$TRUE; shift; fi local COMMAND=$1 shift if [[ $COMMAND == '' ]]; then # This next comment just visualizes where col 80 is as default for most terminals # is 80 chars to not mess up the instructions. Also make sure to replace any # tabstops with 4 spaces here or it could really throw the output out of wack. #............................................................................80 echo " Commands for this script: list Lists the VPN connection names to use for other commands. status Shows if it detects the named connections listed as parameters as UP or DOWN. Shows status for all connections if none listed. reset Resets named connections listed as parameters. log Tails the encrypted TCP dump of the named connection. monitor Watches the status of a named connection and automatically resets if it goes down. Also has ability to use ping or an IP:Port to check while monitoring. If any of the pings or tests or an IP:Port fail, the VPN will be reset. This is in result of sometimes having the VPN indicate it's up while traffic stops working. Examples: (assuming you name this script just 'vpn') vpn monitor S_REF_IpsSitVpnXXX_0 ping 192.168.0.1 ping 192.168.0.2 This will check the VPN tunnel and also ping those IP's. vpn monitor S_REF_IpsSitVpnXXX_0 ping 192.168.0.1 ipport 192.168.0.2:80 This will ping 192.168.0.1 and check port 80 on 192.168.0.2 in the very possible case the ICMP ping is not allowed on a firewall. If you specify --debug as the first parameter, more verbose output will be created. " #............................................................................80 elif [[ $COMMAND == 'reset' ]]; then loop reset $* elif [[ $COMMAND == 'status' ]]; then loop status $* elif [[ $COMMAND == 'monitor' ]]; then monitor $* elif [[ $COMMAND == 'list' ]]; then list $* elif [[ $COMMAND == 'log' ]]; then log $* fi } # Use this function as a wrapper for other functions where the list of parameters indicates running it for each one. function loop() { local COMMAND=$1 shift # if we have no parameters, call the command so it can run without the parameters. if [[ $1 == '' ]]; then $COMMAND; fi # call the command for each parameter in the list. for PARAM in $* do $COMMAND $PARAM done } function list() { ipsec status | grep === | awk '{print $2}' | sed 's/://' | sed 's/"//g' | sort | uniq | paste - - } function reset() { local CONN=$1 if [[ $CONN == '' ]]; then echo "VPN Connection name needed."; return; fi ipsec down $CONN; ipsec up $CONN } # returns TRUE (0) if the connection is UP, FALSE (1) if DOWN. function is_vpn_up() { if [[ $DEBUG == $TRUE ]]; then echo "Checking VPN tunnel $CONN..."; fi # WARNING: If you use just a variable on the next line it will not result correctly. local RESULT=`ipsec status $CONN | grep 'IPsec SA established'` if [[ $DEBUG == $TRUE ]]; then echo "RESULT:\n$RESULT"; fi if [[ $RESULT == '' ]]; then return $FALSE else return $TRUE; fi } function status_specific() { local CONN=$1 if [[ $CONN == '' ]]; then echo "VPN Connection name needed."; return; fi is_vpn_up $CONN local RESULT=$? if [[ $RESULT == $TRUE ]]; then echo " UP $CONN"; else echo " DOWN $CONN"; fi } function status_all() { local CONN_LIST=`list` loop status_specific $CONN_LIST } function status() { local CONN=$1 if [[ $CONN == '' ]]; then status_all else status_specific $CONN fi } function log() { local CONN=$1 if [[ $CONN == '' ]]; then echo "VPN Connection name needed."; return; fi local COMMAND="espdump -c 1000 -n --conn $CONN" echo $COMMAND $COMMAND # -c option causes it to exit after the number of messages logged. In case # it runs away with a really busy connection. } function monitor() { local CONN=$1 if [[ $CONN == '' ]]; then echo "VPN Connection name needed."; return; fi shift #cycle through parameters to find other methods of monitoring local PING_IPS="" local IP_PORTS_TO_TEST="" while [[ "$1" != "" ]]; do if [[ "$1" == "ping" ]]; then PING_IPS="$PING_IPS $2" shift elif [[ "$1" == "ipport" ]]; then # they should be : delimited to make life easier. # example: 127.0.0.1:80 IP_PORTS_TO_TEST="$IP_PORTS_TO_TEST $2" shift fi shift done while [[ $TRUE ]]; do local UP=0 is_vpn_up $CONN let "UP = UP + $?" if [[ $UP > 0 ]]; then echo "VPN tunnel $CONN detected as DOWN."; fi # $? is the return value of the last command executed. # If using 'let' command, use quotes to let you use spaces for readability. local TEMP="" # so that the var stays within this function scope in 'for' commands. # ping IPs if any specified. for TEMP in $PING_IPS; do is_ping_up $TEMP let "UP = UP + $?" done # test ip:ports if specified. for TEMP in $IP_PORTS_TO_TEST; do is_port_up $TEMP let "UP = UP + $?" done if [[ $UP > 0 ]]; then echo "`date` - Detected VPN down. Resetting..." reset $CONN echo "`date` - reset action completed." fi sleep 60 done } # This function uses 'ping' command to test an IP. # Input should be just 1 IP address or host name. # returns 0 if it worked, returns 1 if it failed. function is_ping_up() { local COMMAND="ping -c 1" # -c x means to ping x times. local IP=$1 if [[ $IP == '' ]]; then echo "IP address needed to ping."; return; fi if [[ $DEBUG == $TRUE ]]; then $COMMAND $IP else $COMMAND $IP > /dev/nul; fi # send standard out to null to not see it. local RESULT=$? if [[ $RESULT == $TRUE ]]; then return $TRUE else echo "$COMMAND $IP returned failure." return $FALSE fi # ping already returns 0 if it works and 1 if ping failed. But can return 2 for other reasons. } # This function uses the 'nc' command to test for an IP/port. # Input should be an IP:Port parameter. Example: 127.0.0.1:80 or localhost:80 # returns 0 if it worked, returns 1 if it failed. function is_port_up() { local COMMAND="nc -w 5 -z" # -w x indicates wait time in seconds, -z means to only test for the port. local IP_PORT=$1 IP_PORT=`echo $IP_PORT | sed 's/:/ /'` # replace the : with a space. if [[ $IP_PORT == "" ]]; then echo "IP address and port needed to ping delimited with colon." echo "Example: 127.0.0.1:80" return fi $COMMAND $IP_PORT local RESULT=$? if [[ $RESULT == $TRUE ]]; then if [[ $DEBUG == $TRUE ]]; then echo "$COMMAND $IP_PORT returned success."; fi return $TRUE else echo "$COMMAND $IP_PORT returned failure." return $FALSE fi } # now start running the script by calling main() with all parameters. main $*