#!/bin/sh # VPNMON-R3 v1.8.2 (VPNMON-R3.SH) is an all-in-one script that is optimized to maintain multiple VPN connections and is # able to provide for the capabilities to randomly reconnect using a specified server list containing the servers of your # choice. Special care has been taken to ensure that only the VPN connections you want to have monitored are tended to. # This script will check the health of up to 5 VPN connections on a regular interval to see if monitored VPN conenctions # are connected, and sends a ping to a host of your choice through each active connection. If it finds that a connection # has been lost, it will execute a series of commands that will kill that single VPN client, and randomly picks one of # your specified servers to reconnect to for each VPN client. # Last Modified: 2025-Nov-16 ########################################################################################## #Preferred standard router binaries path export PATH="/sbin:/bin:/usr/sbin:/usr/bin:$PATH" #Static Variables - please do not change version="1.8.2" # Version tracker beta=0 # Beta switch screenshotmode=0 # Switch to present bogus info for screenshots apppath="/jffs/scripts/vpnmon-r3.sh" # Static path to the app logfile="/jffs/addons/vpnmon-r3.d/vpnmon-r3.log" # Static path to the log dlverpath="/jffs/addons/vpnmon-r3.d/version.txt" # Static path to the version file config="/jffs/addons/vpnmon-r3.d/vpnmon-r3.cfg" # Static path to the config file lockfile="/jffs/addons/vpnmon-r3.d/resetlock.txt" # Static path to the reset lock file vr3emails="/jffs/addons/vpnmon-r3.d/vr3emails.txt" # Static path to email rate limit file availableslots="1 2 3 4 5" # Available slots tracker logsize=2000 # Log file size in rows timerloop=60 # Timer loop in sec recover=3 # Number of loops to allow for connection recovery schedule=0 # Scheduler enable y/n schedulehrs=1 # Scheduler hours schedulemin=0 # Scheduler mins autostart=0 # Auto start on router reboot y/n unboundclient=0 # Unbound bound to VPN client slot# unboundwgclient=0 # Unbound bound to WG client slot# unboundshowip=0 # Show expanded Unbound VPN IP on UI ResolverTimer=1 # Timer to give DNS resolver time to settle vpnping=0 # Tracking VPN Tunnel Pings refreshserverlists=0 # Tracking Automated Custom VPN Server List Reset monitorwan=0 # Tracking WAN/Dual WAN Monitoring useovpn=1 # Tracking OVPN Display/Monitoring usewg=1 # Tracking WG Display/Monitoring lockactive=0 # Check for active locks bypassscreentimer=0 # Check to see if screen timer can be bypassed pingreset=500 # Maximum ping in ms before reset updateskynet=0 # Check for VPN IP whitelisting in Skynet amtmemailsuccess=0 # AMTM Email Success Message Option amtmemailfailure=0 # AMTM Email Failure Message Option rstspdmerlin=0 # Reset spdMerlin Interfaces Option timeoutcmd="" # For "timeout" cmd for "nvram" calls timeoutsec="" # For "timeout" cmd for "nvram" calls timeoutlng="" # For "timeout" cmd for "nvram" calls hideoptions=1 # Hide/Show menu options flag ratelimit=0 # Rate limiting number of emails/houre vrcnt=0 # Counter for VPN connection recovery wrcnt=0 # Counter for WG connection recovery problemvpnslot=0 # Temporary holder for problem VPN slot problemwgslot=0 # Temporary holder for problem WG slot selectionmethod=0 # 0=Random vs 1=sequential slot selection lowutilspd=100 # Upper limit of Low / Lower Limit of Med RX Utilization Range medutilspd=250 # Upper Limit of Med / Lower Limit of High RX Utilization Range lowutilspdup=15 # Upper limit of Low / Lower Limit of Med TX Utilization Range medutilspdup=25 # Upper Limit of Med / Lower Limit of High TX Utilization Range bwdisp=1 # Display value for bandwidth/throughput - 1=Average, 2=Total ##-------------------------------------## ## Added by Martinski W. [2024-Oct-05] ## ##-------------------------------------## readonly PING_HOST_Deflt="8.8.8.8" readonly IPv4octet_RegEx="([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])" readonly IPv4addrs_RegEx="(${IPv4octet_RegEx}\.){3}${IPv4octet_RegEx}" LAN_HostName="" prevHideOpts=X # Avoid redisplaying the menu options unnecessarily too often # PINGHOST="$PING_HOST_Deflt" # Ping host ## Custom Email Library Notification Variables ## readonly scriptFileName="${0##*/}" readonly scriptFileNTag="${scriptFileName%.*}" readonly CEM_LIB_TAG="master" readonly CEM_LIB_URL="https://raw.githubusercontent.com/Martinski4GitHub/CustomMiscUtils/${CEM_LIB_TAG}/EMail" readonly CUSTOM_EMAIL_LIBDir="/jffs/addons/shared-libs" readonly CUSTOM_EMAIL_LIBName="CustomEMailFunctions.lib.sh" readonly CUSTOM_EMAIL_LIBFile="${CUSTOM_EMAIL_LIBDir}/$CUSTOM_EMAIL_LIBName" # Color variables CBlack="\e[1;30m" InvBlack="\e[1;40m" CRed="\e[1;31m" InvRed="\e[1;41m" CGreen="\e[1;32m" InvGreen="\e[1;42m" CDkGray="\e[1;90m" InvDkGray="\e[1;100m" InvLtGray="\e[1;47m" CYellow="\e[1;33m" InvYellow="\e[1;43m" CBlue="\e[1;34m" InvBlue="\e[1;44m" CMagenta="\e[1;35m" CCyan="\e[1;36m" InvCyan="\e[1;46m" CWhite="\e[1;37m" InvWhite="\e[1;107m" CClear="\e[0m" # ------------------------------------------------------------------------------------------------------------------------- # blackwhite is a simple function that removes all color attributes blackwhite() { CBlack="" InvBlack="" CRed="" InvRed="" CGreen="" InvGreen="" CDkGray="" InvDkGray="" InvLtGray="" CYellow="" InvYellow="" CBlue="" InvBlue="" CMagenta="" CCyan="" InvCyan="" CWhite="" InvWhite="" CClear="" } # ------------------------------------------------------------------------------------------------------------------------- # LogoNM is a function that displays the VPNMON-R3 script name in a cool ASCII font without menu options logoNM () { clear echo "" echo "" echo "" echo -e "${CDkGray} _ ______ _ ____ _______ _ __ ____ _____" echo -e " | | / / __ \/ | / / |/ / __ \/ | / / / __ \__ /" echo -e " | | / / /_/ / |/ / /|_/ / / / / |/ /_____/ /_/ //_ < " echo -e " | |/ / ____/ /| / / / / /_/ / /| /_____/ _, _/__/ / " echo -e " |___/_/ /_/ |_/_/ /_/\____/_/ |_/ /_/ |_/____/ v$version" echo "" echo "" printf "\r ${CGreen} [ INITIALIZING ] ${CClear}" sleep 2 clear echo "" echo "" echo "" echo -e "${CYellow} _ ______ _ ____ _______ _ __ ____ _____" echo -e " | | / / __ \/ | / / |/ / __ \/ | / / / __ \__ /" echo -e " | | / / /_/ / |/ / /|_/ / / / / |/ /_____/ /_/ //_ < " echo -e " | |/ / ____/ /| / / / / /_/ / /| /_____/ _, _/__/ / " echo -e " |___/_/ /_/ |_/_/ /_/\____/_/ |_/ /_/ |_/____/ v$version" echo "" echo "" printf "\r ${CGreen}[ INITIALIZING ... DONE ]${CClear}" sleep 1 printf "\r ${CGreen} [ LOADING... ] ${CClear}" sleep 2 } logoNMexit () { clear echo "" echo "" echo "" echo -e "${CYellow} _ ______ _ ____ _______ _ __ ____ _____" echo -e " | | / / __ \/ | / / |/ / __ \/ | / / / __ \__ /" echo -e " | | / / /_/ / |/ / /|_/ / / / / |/ /_____/ /_/ //_ < " echo -e " | |/ / ____/ /| / / / / /_/ / /| /_____/ _, _/__/ / " echo -e " |___/_/ /_/ |_/_/ /_/\____/_/ |_/ /_/ |_/____/ v$version" echo "" echo "" printf "\r ${CGreen} [ SHUTTING DOWN ] ${CClear}" sleep 2 clear echo "" echo "" echo "" echo -e "${CDkGray} _ ______ _ ____ _______ _ __ ____ _____" echo -e " | | / / __ \/ | / / |/ / __ \/ | / / / __ \__ /" echo -e " | | / / /_/ / |/ / /|_/ / / / / |/ /_____/ /_/ //_ < " echo -e " | |/ / ____/ /| / / / / /_/ / /| /_____/ _, _/__/ / " echo -e " |___/_/ /_/ |_/_/ /_/\____/_/ |_/ /_/ |_/____/ v$version" echo "" echo "" printf "\r ${CGreen} [ SHUTTING DOWN ] ${CClear}" sleep 1 printf "\r ${CDkGray} [ GOODBYE... ] ${CClear}\n\n" sleep 2 } # ------------------------------------------------------------------------------------------------------------------------- # Promptyn is a simple function that accepts y/n input promptyn () { # No defaults, just y or n while true; do read -p '[y/n]? ' YESNO case "$YESNO" in [Yy]* ) return 0 ;; [Nn]* ) return 1 ;; * ) echo -e "\nPlease answer y or n.";; esac done } # ------------------------------------------------------------------------------------------------------------------------- # Spinner is a script that provides a small indicator on the screen to show script activity spinner() { spins=$1 spin=0 charspin=0 totalspins=$((spins / 4)) while [ $spin -le $totalspins ]; do for spinchar in / - \\ \|; do printf "\r$spinchar ${CGreen}[${CWhite}$charspin${CGreen}]" charspin=$((charspin + 1)) sleep 1 done spin=$((spin+1)) done printf "\r" } # ------------------------------------------------------------------------------------------------------------------------- # Preparebar and Progressbar is a script that provides a nice progressbar to show script activity ##----------------------------------------## ## Modified by Martinski W. [2024-Nov-01] ## ##----------------------------------------## preparebar() { barlen="$1" barspaces="$(printf "%*s" "$1" ' ')" barchars="$(printf "%*s" "$1" ' ' | tr ' ' "$2")" } ##----------------------------------------## ## Modified by Martinski W. [2024-Nov-02] ## ##----------------------------------------## progressbaroverride() { insertspc=" " bypasswancheck=0 _GetPercent_() { printf "%.1f" "$(echo "$1" | awk "{print $1}")" ; } if [ "$1" -eq -1 ] then printf "\r $barspaces\r" else if [ $# -gt 6 ] && [ -n "$7" ] && [ "$1" -ge "$7" ] then barch="$(($7*barlen/$2))" barsp="$((barlen-barch))" percnt="$(_GetPercent_ "(100*$1/$2)")" else barch="$(($1*barlen/$2))" barsp="$((barlen-barch))" percnt="$(_GetPercent_ "(100*$1/$2)")" fi if [ $# -gt 5 ] && [ -n "$6" ]; then AltNum="$6" ; else AltNum="$1" ; fi if [ "$5" = "Standard" ] then printf " ${CWhite}${InvDkGray}%3d${4} /%5.1f%%${CClear} [${CGreen}e${CClear}=Exit] [Selection? ${InvGreen} ${CClear}${CGreen}]\r${CClear}" "$AltNum" "$percnt" fi fi # Borrowed this wonderful keypress capturing mechanism from @Eibgrad... thank you! :) key_press=''; read -rsn1 -t 1 key_press < "$(tty 0>&2)" if [ "$key_press" ] then case "$key_press" in [1]) echo ""; restartvpn 1; sendmessage 0 "VPN Reset" 1; restartrouting; resetspdmerlin; exec sh /jffs/scripts/vpnmon-r3.sh -noswitch;; [2]) echo ""; restartvpn 2; sendmessage 0 "VPN Reset" 2; restartrouting; resetspdmerlin; exec sh /jffs/scripts/vpnmon-r3.sh -noswitch;; [3]) echo ""; restartvpn 3; sendmessage 0 "VPN Reset" 3; restartrouting; resetspdmerlin; exec sh /jffs/scripts/vpnmon-r3.sh -noswitch;; [4]) echo ""; restartvpn 4; sendmessage 0 "VPN Reset" 4; restartrouting; resetspdmerlin; exec sh /jffs/scripts/vpnmon-r3.sh -noswitch;; [5]) echo ""; restartvpn 5; sendmessage 0 "VPN Reset" 5; restartrouting; resetspdmerlin; exec sh /jffs/scripts/vpnmon-r3.sh -noswitch;; [6]) echo ""; restartwg 1; sendmessage 0 "WG Reset" 1; restartrouting; resetspdmerlin; exec sh /jffs/scripts/vpnmon-r3.sh -noswitch;; [7]) echo ""; restartwg 2; sendmessage 0 "WG Reset" 2; restartrouting; resetspdmerlin; exec sh /jffs/scripts/vpnmon-r3.sh -noswitch;; [8]) echo ""; restartwg 3; sendmessage 0 "WG Reset" 3; restartrouting; resetspdmerlin; exec sh /jffs/scripts/vpnmon-r3.sh -noswitch;; [9]) echo ""; restartwg 4; sendmessage 0 "WG Reset" 4; restartrouting; resetspdmerlin; exec sh /jffs/scripts/vpnmon-r3.sh -noswitch;; [0]) echo ""; restartwg 5; sendmessage 0 "WG Reset" 5; restartrouting; resetspdmerlin; exec sh /jffs/scripts/vpnmon-r3.sh -noswitch;; [\!]) echo ""; killunmonvpn 1; sendmessage 0 "VPN Killed" 1; exec sh /jffs/scripts/vpnmon-r3.sh -noswitch;; [\@]) echo ""; killunmonvpn 2; sendmessage 0 "VPN Killed" 2; exec sh /jffs/scripts/vpnmon-r3.sh -noswitch;; [\#]) echo ""; killunmonvpn 3; sendmessage 0 "VPN Killed" 3; exec sh /jffs/scripts/vpnmon-r3.sh -noswitch;; [\$]) echo ""; killunmonvpn 4; sendmessage 0 "VPN Killed" 4; exec sh /jffs/scripts/vpnmon-r3.sh -noswitch;; [\%]) echo ""; killunmonvpn 5; sendmessage 0 "VPN Killed" 5; exec sh /jffs/scripts/vpnmon-r3.sh -noswitch;; [\^]) echo ""; killunmonwg 1; sendmessage 0 "WG Killed" 1; exec sh /jffs/scripts/vpnmon-r3.sh -noswitch;; [\&]) echo ""; killunmonwg 2; sendmessage 0 "WG Killed" 2; exec sh /jffs/scripts/vpnmon-r3.sh -noswitch;; [\-]) echo ""; killunmonwg 3; sendmessage 0 "WG Killed" 3; exec sh /jffs/scripts/vpnmon-r3.sh -noswitch;; [\+]) echo ""; killunmonwg 4; sendmessage 0 "WG Killed" 4; exec sh /jffs/scripts/vpnmon-r3.sh -noswitch;; [\=]) echo ""; killunmonwg 5; sendmessage 0 "WG Killed" 5; exec sh /jffs/scripts/vpnmon-r3.sh -noswitch;; [Aa]) autostart; resetifacestats;; [Cc]) vsetup; resetifacestats;; [Dd]) wgserverlistautomation; resetifacestats;; [Ee]) logoNMexit; echo -e "${CClear}\n"; exit 0;; [Hh]) hideoptions=1 ; [ "$hideoptions" != "$prevHideOpts" ] && timerreset=1 ;; [Ii]) amtmevents; resetifacestats;; [Ll]) vlogs; resetifacestats;; [Mm]) vpnslots; resetifacestats;; [Pp]) maxping; resetifacestats;; [Rr]) schedulevpnreset; resetifacestats;; [Ss]) hideoptions=0 ; [ "$hideoptions" != "$prevHideOpts" ] && timerreset=1 ;; [Tt]) timerloopconfig; resetifacestats;; [Uu]) vpnserverlistautomation; resetifacestats;; [Vv]) vpnserverlistmaint; resetifacestats;; [Ww]) wgserverlistmaint; resetifacestats;; [Xx]) uninstallr2; resetifacestats;; *) ;; ##IGNORE INVALID key presses ## esac bypasswancheck=1 fi } progressbarpause() { insertspc=" " bypasswancheck=0 if [ "$1" -eq -1 ] then printf "\r $barspaces\r" else if [ $# -gt 6 ] && [ -n "$7" ] && [ "$1" -ge "$7" ] then barch="$(($7*barlen/$2))" barsp="$((barlen-barch))" progr="$((100*$1/$2))" else barch="$(($1*barlen/$2))" barsp="$((barlen-barch))" progr="$((100*$1/$2))" fi if [ $# -gt 5 ] && [ -n "$6" ]; then AltNum="$6" ; else AltNum="$1" ; fi if [ "$5" = "Standard" ] then printf " ${CWhite}${InvDkGray}Continuing Reset in $AltNum/5...${CClear} [${CGreen}p${CClear}=Pause] [${CGreen}e${CClear}=Exit] [Selection? ${InvGreen} ${CClear}${CGreen}]\r${CClear}" "$barchars" "$barspaces" fi fi # Borrowed this wonderful keypress capturing mechanism from @Eibgrad... thank you! :) key_press=''; read -rsn1 -t 1 key_press < "$(tty 0>&2)" if [ $key_press ] then case $key_press in [Pp]) vpause;; [Ee]) logoNMexit; echo -e "${CClear}\n"; exit 0;; esac bypasswancheck=1 fi } # ------------------------------------------------------------------------------------------------------------------------- # This function optionally uninstalls VPNMON-R2 if still found present on local router uninstallr2() { if [ -f /jffs/scripts/vpnmon-r2.sh ] then clear echo -e "${InvGreen} ${InvDkGray}${CWhite} VPNMON-R2 Uninstall Utility ${CClear}" echo -e "${InvGreen} ${CClear}" echo -e "${InvGreen} ${CClear} This utility allows you to uninstall VPNMON-R2. NOTE: Please know that VPNMON-R2" echo -e "${InvGreen} ${CClear} development is ceasing, and product support will be sunset in the very near future." echo -e "${InvGreen} ${CClear}" echo -e "${InvGreen} ${CClear} VPNMON-R2 was still found installed on your router. This menu gives you the option" echo -e "${InvGreen} ${CClear} to launch (if needed) or uninstall the old legacy VPNMON-R2. Thank you!" echo -e "${InvGreen} ${CClear}" echo -e "${InvGreen} ${CClear}${CDkGray}---------------------------------------------------------------------------------------${CClear}" echo "" printf "${CClear}Please select? (${CGreen}u${CClear}=UNinstall R2, ${CGreen}r${CClear}=Run R2, ${CGreen}e${CClear}=Exit)" read -p ": " SelectR2 case $SelectR2 in [Uu]) echo -e "\n${CClear}Please type 'Y' to validate you wish to proceed with the uninstall of VPNMON-R2.${CClear}" if promptyn "(y/n): " then echo -e "\n${CClear}Uninstalling VPNMON-R2 components...${CClear}" if [ "$(cat /jffs/addons/vpnmon-r2.d/vpnmon-r2.cfg | grep "UpdateUnbound" | cut -d '=' -f 2-)" = "1" ] then # Delete all additions made to files to enable Unbound over VPN functionality echo "" echo -e "\n${CClear}Unbinding Unbound from VPN..." # Disable vpn functionality with Unbound sh /jffs/addons/unbound/unbound_manager.sh vpn=disable >/dev/null 2>&1 # Remove Unbound failsafe in post-mount if [ -f /jffs/scripts/post-mount ]; then sed -i -e '/vpn=disable/d' /jffs/scripts/post-mount >/dev/null 2>&1 fi # Remove Unbound VPN helper script in openvpn-event if [ -f /jffs/scripts/openvpn-event ]; then sed -i -e '/unbound_DNS_via_OVPN.sh/d' /jffs/scripts/openvpn-event >/dev/null 2>&1 fi # Remove RPDB Rules added to nat-start if [ -f /jffs/scripts/nat-start ]; then sed -i -e '/Added by vpnmon-r2/d' /jffs/scripts/nat-start >/dev/null 2>&1 fi # Remove the unbound_DNS_via_OVPN.sh file if [ -f /jffs/addons/unbound/unbound_DNS_via_OVPN.sh ]; then rm /jffs/addons/unbound/unbound_DNS_via_OVPN.sh fi echo -e "\n${CClear}If Unbound-over-VPN is enabled on VPNMON-R3, you may need to disable/re-enable" echo -e "this feature under the setup/configuration menu again. Conflicts may have" echo -e "arisen with both products having this feature enabled." fi echo -e "\n${CClear}Removing VPNMON-R2 Files..." # Remove R2 Files rm -f -r /jffs/addons/vpnmon-r2.d rm -f /jffs/scripts/vpnmon-r2.sh if [ -f /jffs/scripts/post-mount ]; then sed -i -e '/vpnmon-r2.sh/d' /jffs/scripts/post-mount >/dev/null 2>&1 fi echo -e "\n${CClear}VPNMON-R2 has been uninstalled...${CClear}" echo "" read -rsp $'Press any key to continue...\n' -n1 key timer="$timerloop" echo -e "${CClear}\n" return else timer="$timerloop" echo -e "${CClear}\n" return fi ;; [Rr]) exec sh /jffs/scripts/vpnmon-r2.sh -setup; exit 0;; [Ee]) timer="$timerloop" ; echo -e "${CClear}\n"; return;; esac fi } # ------------------------------------------------------------------------------------------------------------------------- # This function presents an Operational Menu in a Pause state, usually during VPN slot errors which give you a 5 second # opportunity to pause in order to make any particular changes that might help your situation vpause() { while true do if [ "$availableslots" = "1 2" ] then clear displayopsmenu printf "${CClear}Please select? (${CGreen}n${CClear}=UNpause, ${CGreen}e${CClear}=Exit)" read -p ": " SelectSlot case $SelectSlot in [1]) echo ""; restartvpn 1; sendmessage 0 "VPN Reset" 1; restartrouting; resetspdmerlin; exec sh /jffs/scripts/vpnmon-r3.sh -noswitch;; [2]) echo ""; restartvpn 2; sendmessage 0 "VPN Reset" 2; restartrouting; resetspdmerlin; exec sh /jffs/scripts/vpnmon-r3.sh -noswitch;; [\!]) echo ""; killunmonvpn 1; sendmessage 0 "VPN Killed" 1; exec sh /jffs/scripts/vpnmon-r3.sh -noswitch;; [\@]) echo ""; killunmonvpn 2; sendmessage 0 "VPN Killed" 2; exec sh /jffs/scripts/vpnmon-r3.sh -noswitch;; [Aa]) autostart; resetifacestats;; [Cc]) vsetup; resetifacestats;; [Ee]) echo -e "${CClear}\n"; exit 0;; [Ii]) amtmevents; resetifacestats;; [Ll]) vlogs; resetifacestats;; [Mm]) vpnslots; resetifacestats;; [Pp]) maxping; resetifacestats;; [Rr]) schedulevpnreset; resetifacestats;; [Tt]) timerloopconfig; resetifacestats;; [Uu]) vpnserverlistautomation; resetifacestats;; [Vv]) vpnserverlistmaint; resetifacestats;; [Nn]) exec sh /jffs/scripts/vpnmon-r3.sh -noswitch;; *) exec sh /jffs/scripts/vpnmon-r3.sh -noswitch;; esac elif [ "$availableslots" = "1 2 3 4 5" ] then clear displayopsmenu printf "${CClear}Please select? (${CGreen}n${CClear}=UNpause, ${CGreen}e${CClear}=Exit)" read -p ": " SelectSlot case $SelectSlot in [1]) echo ""; restartvpn 1; sendmessage 0 "VPN Reset" 1; restartrouting; resetspdmerlin; exec sh /jffs/scripts/vpnmon-r3.sh -noswitch;; [2]) echo ""; restartvpn 2; sendmessage 0 "VPN Reset" 2; restartrouting; resetspdmerlin; exec sh /jffs/scripts/vpnmon-r3.sh -noswitch;; [3]) echo ""; restartvpn 3; sendmessage 0 "VPN Reset" 3; restartrouting; resetspdmerlin; exec sh /jffs/scripts/vpnmon-r3.sh -noswitch;; [4]) echo ""; restartvpn 4; sendmessage 0 "VPN Reset" 4; restartrouting; resetspdmerlin; exec sh /jffs/scripts/vpnmon-r3.sh -noswitch;; [5]) echo ""; restartvpn 5; sendmessage 0 "VPN Reset" 5; restartrouting; resetspdmerlin; exec sh /jffs/scripts/vpnmon-r3.sh -noswitch;; [6]) echo ""; restartwg 1; sendmessage 0 "WG Reset" 1; restartrouting; resetspdmerlin; exec sh /jffs/scripts/vpnmon-r3.sh -noswitch;; [7]) echo ""; restartwg 2; sendmessage 0 "WG Reset" 2; restartrouting; resetspdmerlin; exec sh /jffs/scripts/vpnmon-r3.sh -noswitch;; [8]) echo ""; restartwg 3; sendmessage 0 "WG Reset" 3; restartrouting; resetspdmerlin; exec sh /jffs/scripts/vpnmon-r3.sh -noswitch;; [9]) echo ""; restartwg 4; sendmessage 0 "WG Reset" 4; restartrouting; resetspdmerlin; exec sh /jffs/scripts/vpnmon-r3.sh -noswitch;; [0]) echo ""; restartwg 5; sendmessage 0 "WG Reset" 5; restartrouting; resetspdmerlin; exec sh /jffs/scripts/vpnmon-r3.sh -noswitch;; [\!]) echo ""; killunmonvpn 1; sendmessage 0 "VPN Killed" 1; exec sh /jffs/scripts/vpnmon-r3.sh -noswitch;; [\@]) echo ""; killunmonvpn 2; sendmessage 0 "VPN Killed" 2; exec sh /jffs/scripts/vpnmon-r3.sh -noswitch;; [\#]) echo ""; killunmonvpn 3; sendmessage 0 "VPN Killed" 3; exec sh /jffs/scripts/vpnmon-r3.sh -noswitch;; [\$]) echo ""; killunmonvpn 4; sendmessage 0 "VPN Killed" 4; exec sh /jffs/scripts/vpnmon-r3.sh -noswitch;; [\%]) echo ""; killunmonvpn 5; sendmessage 0 "VPN Killed" 5; exec sh /jffs/scripts/vpnmon-r3.sh -noswitch;; [\^]) echo ""; killunmonwg 1; sendmessage 0 "WG Killed" 1; exec sh /jffs/scripts/vpnmon-r3.sh -noswitch;; [\&]) echo ""; killunmonwg 2; sendmessage 0 "WG Killed" 2; exec sh /jffs/scripts/vpnmon-r3.sh -noswitch;; [\-]) echo ""; killunmonwg 3; sendmessage 0 "WG Killed" 3; exec sh /jffs/scripts/vpnmon-r3.sh -noswitch;; [\+]) echo ""; killunmonwg 4; sendmessage 0 "WG Killed" 4; exec sh /jffs/scripts/vpnmon-r3.sh -noswitch;; [\=]) echo ""; killunmonwg 5; sendmessage 0 "WG Killed" 5; exec sh /jffs/scripts/vpnmon-r3.sh -noswitch;; [Aa]) autostart; resetifacestats;; [Cc]) vsetup; resetifacestats;; [Ee]) echo -e "${CClear}\n"; exit 0;; [Ii]) amtmevents; resetifacestats;; [Ll]) vlogs; resetifacestats;; [Mm]) vpnslots; resetifacestats;; [Pp]) maxping; resetifacestats;; [Rr]) schedulevpnreset; resetifacestats;; [Tt]) timerloopconfig; resetifacestats;; [Uu]) vpnserverlistautomation; resetifacestats;; [Vv]) vpnserverlistmaint; resetifacestats;; [Ww]) wgserverlistmaint; resetifacestats;; [Nn]) exec sh /jffs/scripts/vpnmon-r3.sh -noswitch;; *) exec sh /jffs/scripts/vpnmon-r3.sh -noswitch;; esac fi done } # ------------------------------------------------------------------------------------------------------------------------- # creates needed config files if they don't exist createconfigs() { # Fix older versions using incorrect client slots if [ "$availableslots" = "1 2 3" ] then availableslots="1 2" rm -f /jffs/addons/vpnmon-r3.d/vr3clients.txt rm -f /jffs/addons/vpnmon-r3.d/vr3timers.txt saveconfig fi # Create initial vr3clients.txt & vr3timers.txt file if [ ! -f /jffs/addons/vpnmon-r3.d/vr3clients.txt ] then if [ "$availableslots" = "1 2" ] then { echo 'VPN1=0' echo 'VPN2=0' } > /jffs/addons/vpnmon-r3.d/vr3clients.txt elif [ "$availableslots" = "1 2 3 4 5" ] then { echo 'VPN1=0' echo 'VPN2=0' echo 'VPN3=0' echo 'VPN4=0' echo 'VPN5=0' echo 'WG1=0' echo 'WG2=0' echo 'WG3=0' echo 'WG4=0' echo 'WG5=0' } > /jffs/addons/vpnmon-r3.d/vr3clients.txt fi fi if [ ! -f /jffs/addons/vpnmon-r3.d/vr3timers.txt ] then if [ "$availableslots" = "1 2" ] then { echo 'VPNTIMER1=0' echo 'VPNTIMER2=0' } > /jffs/addons/vpnmon-r3.d/vr3timers.txt elif [ "$availableslots" = "1 2 3 4 5" ] then { echo 'VPNTIMER1=0' echo 'VPNTIMER2=0' echo 'VPNTIMER3=0' echo 'VPNTIMER4=0' echo 'VPNTIMER5=0' echo 'WGTIMER1=0' echo 'WGTIMER2=0' echo 'WGTIMER3=0' echo 'WGTIMER4=0' echo 'WGTIMER5=0' } > /jffs/addons/vpnmon-r3.d/vr3timers.txt fi fi if [ "$availableslots" = "1 2 3 4 5" ] then # Determine if the new Wireguard client values are present, if not, add them if ! grep -q "WG" "/jffs/addons/vpnmon-r3.d/vr3clients.txt" then # Check for and remove empty lines after the last entry before the EOF awk 'NF > 0 {for (i=1; i<=b; i++) print ""; b=0; print} NF==0 {b++}' "/jffs/addons/vpnmon-r3.d/vr3clients.txt" > "/jffs/addons/vpnmon-r3.d/vr3clients.tmp" # Overwrite the original file with the cleaned-up version. mv "/jffs/addons/vpnmon-r3.d/vr3clients.tmp" "/jffs/addons/vpnmon-r3.d/vr3clients.txt" # Write the new Wireguard timer values cat << EOF >> "/jffs/addons/vpnmon-r3.d/vr3clients.txt" WG1=0 WG2=0 WG3=0 WG4=0 WG5=0 EOF fi # Determine if the new Wireguard timer values are present, if not, add them if ! grep -q "WGTIMER" "/jffs/addons/vpnmon-r3.d/vr3timers.txt" then # Check for and remove empty lines after the last entry before the EOF awk 'NF > 0 {for (i=1; i<=b; i++) print ""; b=0; print} NF==0 {b++}' "/jffs/addons/vpnmon-r3.d/vr3timers.txt" > "/jffs/addons/vpnmon-r3.d/vr3timers.tmp" # Overwrite the original file with the cleaned-up version. mv "/jffs/addons/vpnmon-r3.d/vr3timers.tmp" "/jffs/addons/vpnmon-r3.d/vr3timers.txt" # Write the new Wireguard timer values cat << EOF >> "/jffs/addons/vpnmon-r3.d/vr3timers.txt" WGTIMER1=0 WGTIMER2=0 WGTIMER3=0 WGTIMER4=0 WGTIMER5=0 EOF fi fi } ##-------------------------------------## ## Added by Martinski W. [2024-Oct-05] ## ##-------------------------------------## _SetUpTimeoutCmdVars_() { # If the timeout utility is available then use it # if [ -z "${timeoutcmd:+xSETx}" ] && [ -f "/opt/bin/timeout" ] then timeoutcmd="timeout " timeoutsec="10" timeoutlng="60" fi } ##-------------------------------------## ## Added by Martinski W. [2024-Oct-05] ## ##-------------------------------------## _SetLAN_HostName_() { [ -z "${LAN_HostName:+xSETx}" ] && \ LAN_HostName="$($timeoutcmd$timeoutsec nvram get lan_hostname)" } _GetLAN_HostName_() { _SetLAN_HostName_ ; echo "$LAN_HostName" ; } # ------------------------------------------------------------------------------------------------------------------------- # vsetup provide a menu interface to allow for initial component installs, uninstall, etc. ##----------------------------------------## ## Modified by Martinski W. [2024-Oct-05] ## ##----------------------------------------## vsetup() { _SetUpTimeoutCmdVars_ while true do clear # Initial Setup if [ ! -f "$config" ]; then # Write /jffs/addons/vpnmon-r3.d/vpnmon-r3.cfg saveconfig fi createconfigs echo -e "${InvGreen} ${InvDkGray}${CWhite} VPNMON-R3 Main Setup and Configuration Menu ${CClear}" echo -e "${InvGreen} ${CClear}" echo -e "${InvGreen} ${CClear} Please choose from the various options below, which allow you to perform high level${CClear}" echo -e "${InvGreen} ${CClear} actions in the management of the VPNMON-R3 script.${CClear}" echo -e "${InvGreen} ${CClear}${CDkGray}---------------------------------------------------------------------------------------${CClear}" echo -e "${InvGreen} ${CClear}" echo -e "${InvGreen} ${CClear} ${InvDkGray}${CWhite}(1)${CClear} : Custom configuration options for VPNMON-R3${CClear}" echo -e "${InvGreen} ${CClear} ${InvDkGray}${CWhite}(2)${CClear} : Force reinstall Entware dependencies${CClear}" echo -e "${InvGreen} ${CClear} ${InvDkGray}${CWhite}(3)${CClear} : Check for latest updates${CClear}" echo -e "${InvGreen} ${CClear} ${InvDkGray}${CWhite}(4)${CClear} : Uninstall VPNMON-R3${CClear}" echo -e "${InvGreen} ${CClear} ${InvDkGray}${CWhite} | ${CClear}" echo -e "${InvGreen} ${CClear} ${InvDkGray}${CWhite}(e)${CClear} : Exit${CClear}" echo -e "${InvGreen} ${CClear}" echo -e "${InvGreen} ${CClear}${CDkGray}---------------------------------------------------------------------------------------${CClear}" echo "" read -p "Please select? (1-4, e=Exit): " SelectSlot case $SelectSlot in 1) # Check for existence of entware, and if so proceed and install the timeout package, then run vpnmon-r3 -config clear if [ -f "/opt/bin/timeout" ] && [ -f "/opt/sbin/screen" ] && [ -f "/opt/bin/jq" ] then vconfig else clear echo -e "${InvGreen} ${InvDkGray}${CWhite} Install Dependencies ${CClear}" echo -e "${InvGreen} ${CClear}" echo -e "${InvGreen} ${CClear} Missing dependencies required by VPNMON-R3 will be installed during this process." echo -e "${InvGreen} ${CClear}${CDkGray}---------------------------------------------------------------------------------------${CClear}" echo "" echo -e "VPNMON-R3 has some dependencies in order to function correctly, namely, CoreUtils-Timeout" echo -e "JQ, and the Screen utility. These utilities require you to have Entware already installed" echo -e "using the AMTM tool. If Entware is present, the Timeout, JQ and Screen utilities will" echo -e "automatically be downloaded and installed during this process." echo "" echo -e "${CGreen}CoreUtils-Timeout${CClear} is a utility that provides more stability for certain routers (like" echo -e "the RT-AC86U) which has a tendency to randomly hang scripts running on this router model." echo "" echo -e "${CGreen}JQuery${CClear} is a utility for querying data across the internet through the the means of" echo -e "APIs for the purposes of interacting with the various VPN providers to get a list" echo -e "of available VPN hosts in the selected location(s)." echo "" echo -e "${CGreen}Screen${CClear} is a utility that allows you to run SSH scripts in a standalone environment" echo -e "directly on the router itself, instead of running your commands or a script from a network-" echo -e "attached SSH client. This can provide greater stability due to it running on the router" echo -e "itself." echo "" echo -e "Your router model is: ${CGreen}$ROUTERMODEL${CClear}" echo "" echo -e "Ready to install?" if promptyn " (y/n): " then if [ -d "/opt" ]; then # Does entware exist? If yes proceed, if no error out. echo "" echo -e "\n${CClear}Updating Entware Packages..." echo "" opkg update echo "" echo -e "Installing Entware ${CGreen}CoreUtils-Timeout${CClear} Package...${CClear}" echo "" opkg install coreutils-timeout echo "" echo -e "Installing Entware ${CGreen}JQuery${CClear} Package...${CClear}" echo "" opkg install jq echo "" echo -e "Installing Entware ${CGreen}Screen${CClear} Package...${CClear}" echo "" opkg install screen echo "" echo -e "Install completed..." echo "" read -rsp $'Press any key to continue...\n' -n1 key echo "" echo -e "Executing Configuration Utility..." sleep 2 vconfig else clear echo -e "${CRed}ERROR: Entware was not found on this router...${CClear}" echo -e "Please install Entware using the AMTM utility before proceeding..." echo "" read -rsp $'Press any key to continue...\n' -n1 key fi else echo "" echo -e "\nExecuting Configuration Utility..." sleep 2 vconfig fi fi ;; 2) # Force re-install the CoreUtils timeout/screen package clear echo -e "${InvGreen} ${InvDkGray}${CWhite} Re-install Dependencies ${CClear}" echo -e "${InvGreen} ${CClear}" echo -e "${InvGreen} ${CClear} Missing dependencies required by VPNMON-R3 will be re-installed during this process." echo -e "${InvGreen} ${CClear}${CDkGray}---------------------------------------------------------------------------------------${CClear}" echo "" echo -e "Would you like to re-install the CoreUtils-Timeout, JQ and the Screen utility? These" echo -e "utilities require you to have Entware already installed using the AMTM tool. If Entware" echo -e "is present, the Timeout and Screen utilities will be uninstalled, downloaded and re-" echo -e "installed during this setup process..." echo "" echo -e "${CGreen}CoreUtils-Timeout${CClear} is a utility that provides more stability for certain routers (like" echo -e "the RT-AC86U) which has a tendency to randomly hang scripts running on this router" echo -e "model." echo "" echo -e "${CGreen}JQuery${CClear} is a utility for querying data across the internet through the the means of" echo -e "APIs for the purposes of interacting with the various VPN providers to get a list" echo -e "of available VPN hosts in the selected location(s)." echo "" echo -e "${CGreen}Screen${CClear} is a utility that allows you to run SSH scripts in a standalone environment" echo -e "directly on the router itself, instead of running your commands or a script from a" echo -e "network-attached SSH client. This can provide greater stability due to it running on" echo -e "the router itself." echo "" echo -e "Your router model is: ${CGreen}$ROUTERMODEL${CClear}" echo "" echo -e "Force Re-install?" if promptyn "[y/n]: " then if [ -d "/opt" ]; then # Does entware exist? If yes proceed, if no error out. echo "" echo -e "\nUpdating Entware Packages..." echo "" opkg update echo "" echo -e "Force Re-installing Entware ${CGreen}CoreUtils-Timeout${CClear} Package..." echo "" opkg install --force-reinstall coreutils-timeout echo "" echo -e "Force Re-installing Entware ${CGreen}JQuery${CClear} Package..." echo "" opkg install --force-reinstall . jq echo "" echo -e "Force Re-installing Entware ${CGreen}Screen${CClear} Package..." echo "" opkg install --force-reinstall screen echo "" echo -e "Re-install completed..." echo "" read -rsp $'Press any key to continue...\n' -n1 key else clear echo -e "${CRed}ERROR: Entware was not found on this router...${CClear}" echo -e "Please install Entware using the AMTM utility before proceeding..." echo "" read -rsp $'Press any key to continue...\n' -n1 key fi fi ;; 3) vupdate;; 4) vuninstall;; [Ee]) echo "" timer="$timerloop" break;; esac done } # ------------------------------------------------------------------------------------------------------------------------- # vconfig is a function that provides a UI to choose various options for vpnmon-r3 ##----------------------------------------## ## Modified by Martinski W. [2024-Oct-05] ## ##----------------------------------------## vconfig() { _SetUpTimeoutCmdVars_ # Grab the VPNMON-R3 config file and read it in if [ -f "$config" ] then source "$config" else clear echo -e "${CRed}ERROR: VPNMON-R3 is not configured. Please run 'vpnmon-r3.sh -setup' first." echo "" echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - ERROR: VPNMON-R3 config file not found. Please run the setup/configuration utility" >> $logfile echo -e "${CClear}" exit 1 fi while true do if [ "$availableslots" = "1 2" ]; then availableslotsdisp="2 x OVPN" elif [ "$availableslots" = "1 2 3 4 5" ]; then availableslotsdisp="5 x OVPN | 5 x WG" fi if [ "$unboundclient" -eq 0 ]; then unboundclientexp="${CDkGray}Disabled" else unboundclientexp="Enabled, VPN$unboundclient" fi if [ "$unboundwgclient" -eq 0 ]; then unboundwgclientexp="${CDkGray}Disabled" else unboundwgclientexp="Enabled, WGC$unboundwgclient" fi if [ "$unboundclient" -eq 0 ] && [ "$unboundwgclient" -eq 0 ]; then unboundshowip=0 saveconfig fi if [ "$unboundshowip" -eq 0 ]; then unboundshowipdisp="${CDkGray}Disabled" else unboundshowipdisp="Enabled" fi if [ "$refreshserverlists" -eq 0 ]; then refreshserverlistsdisp="${CDkGray}Disabled" else refreshserverlistsdisp="Enabled" fi if [ "$monitorwan" -eq 0 ]; then monitorwandisp="${CDkGray}Disabled" else monitorwandisp="Enabled" fi if [ "$useovpn" -eq 0 ] && [ "$usewg" -eq 0 ]; then useovpnwgDisp="${CDkGray}OVPN/WG Disabled" elif [ "$useovpn" -eq 1 ] && [ "$usewg" -eq 0 ]; then useovpnwgDisp="${CGreen}OVPN Only" elif [ "$useovpn" -eq 0 ] && [ "$usewg" -eq 1 ]; then useovpnwgDisp="${CGreen}WG Only" elif [ "$useovpn" -eq 1 ] && [ "$usewg" -eq 1 ]; then useovpnwgDisp="${CGreen}OVPN/WG Enabled" fi if [ "$updateskynet" -eq 0 ]; then updateskynetdisp="${CDkGray}Disabled" else updateskynetdisp="Enabled" fi if [ "$amtmemailsuccess" = "0" ] && [ "$amtmemailfailure" = "0" ]; then amtmemailsuccfaildisp="${CDkGray}Disabled" elif [ "$amtmemailsuccess" = "1" ] && [ "$amtmemailfailure" = "0" ]; then amtmemailsuccfaildisp="Success" elif [ "$amtmemailsuccess" = "0" ] && [ "$amtmemailfailure" = "1" ]; then amtmemailsuccfaildisp="Failure" elif [ "$amtmemailsuccess" = "1" ] && [ "$amtmemailfailure" = "1" ]; then amtmemailsuccfaildisp="Success, Failure" else amtmemailsuccfaildisp="Disabled" fi rldisp="" if [ "$amtmemailsuccess" = "1" ] || [ "$amtmemailfailure" = "1" ] then if [ "$ratelimit" = "0" ]; then rldisp="| ${CDkGray}RL" else rldisp="| ${CGreen}RL:$ratelimit/h" fi fi if [ "$rstspdmerlin" -eq 0 ]; then rstspdmerlindisp="${CDkGray}Disabled" else rstspdmerlindisp="Enabled" fi if [ "$selectionmethod" -eq 0 ]; then selectionmethoddisp="Random" elif [ "$selectionmethod" -eq 1 ]; then selectionmethoddisp="Sequential" fi if [ "$bwdisp" -eq 1 ]; then throughputmethoddisp="Average Throughput (in Mbps)" elif [ "$bwdisp" -eq 2 ]; then throughputmethoddisp="Total Throughput (in MB)" fi utilspddisp="${CGreen}RX: 0-->$lowutilspd${CGreen}|${CYellow}$lowutilspd-->$medutilspd${CGreen}|${CRed}$medutilspd-->Max${CClear}" utilspdupdisp="${CGreen}TX: 0-->$lowutilspdup${CGreen}|${CYellow}$lowutilspdup-->$medutilspdup${CGreen}|${CRed}$medutilspdup-->Max${CClear}" clear echo -e "${InvGreen} ${InvDkGray}${CWhite} VPNMON-R3 Configuration Options ${CClear}" echo -e "${InvGreen} ${CClear}" echo -e "${InvGreen} ${CClear} Please choose from the various options below, which allow you to modify certain${CClear}" echo -e "${InvGreen} ${CClear} customizable parameters that affect the operation of this script.${CClear}" echo -e "${InvGreen} ${CClear}${CDkGray}---------------------------------------------------------------------------------------${CClear}" echo -e "${InvGreen} ${CClear}" echo -e "${InvGreen} ${CClear} ${InvDkGray}${CWhite}( 1)${CClear} : Number of VPN/WG Client Slots available : ${CGreen}$availableslotsdisp" echo -e "${InvGreen} ${CClear} ${InvDkGray}${CWhite}( 2)${CClear} : Custom PING host to determine VPN health : ${CGreen}$PINGHOST" echo -e "${InvGreen} ${CClear} ${InvDkGray}${CWhite}( 3)${CClear} : Custom Event Log size (rows) : ${CGreen}$logsize" echo -e "${InvGreen} ${CClear} ${InvDkGray}${CWhite}( 4)${CClear} : Unbound DNS Lookups over VPN Integration : ${CGreen}$unboundclientexp" echo -e "${InvGreen} ${CClear} ${InvDkGray}${CWhite}( 5)${CClear} : Unbound DNS Lookups over WG Integration : ${CGreen}$unboundwgclientexp" if [ "$unboundclient" -ge 1 ] || [ "$unboundwgclient" -ge 1 ]; then echo -e "${InvGreen} ${CClear} ${InvDkGray}${CWhite}( 6)${CClear} -- Show Expanded Unbound IP Info? : ${CGreen}$unboundshowipdisp" else echo -e "${InvGreen} ${CClear} ${InvDkGray}${CWhite}( 6)${CClear} -- ${CDkGray}Show Expanded Unbound IP Info? : $unboundshowipdisp" fi echo -e "${InvGreen} ${CClear} ${InvDkGray}${CWhite}( 7)${CClear} : Refresh Custom Server Lists on -RESET Switch : ${CGreen}$refreshserverlistsdisp" echo -e "${InvGreen} ${CClear} ${InvDkGray}${CWhite}( 8)${CClear} : Provide additional WAN/Dual WAN monitoring : ${CGreen}$monitorwandisp" echo -e "${InvGreen} ${CClear} ${InvDkGray}${CWhite}( 9)${CClear} : Enable/Disable VPN/WG Slot Monitoring : $useovpnwgDisp" echo -e "${InvGreen} ${CClear} ${InvDkGray}${CWhite}(10)${CClear} : Whitelist VPN Server IP Lists in Skynet : ${CGreen}$updateskynetdisp" echo -e "${InvGreen} ${CClear} ${InvDkGray}${CWhite}(11)${CClear} : AMTM Email Notifications / Rate Limiting : ${CGreen}$amtmemailsuccfaildisp $rldisp" echo -e "${InvGreen} ${CClear} ${InvDkGray}${CWhite}(12)${CClear} : Reset spdMerlin Interfaces on VPN Reset : ${CGreen}$rstspdmerlindisp" echo -e "${InvGreen} ${CClear} ${InvDkGray}${CWhite}(13)${CClear} : Server List Item Selection Method : ${CGreen}$selectionmethoddisp" echo -e "${InvGreen} ${CClear} ${InvDkGray}${CWhite}(14)${CClear} : Connection Throughput Threshold Selections : $utilspddisp" echo -e "${InvGreen} ${CClear} ${InvDkGray}${CWhite} |-${CClear}--- : $utilspdupdisp" echo -e "${InvGreen} ${CClear} ${InvDkGray}${CWhite}(15)${CClear} : Connection Throughput Display Method : ${CGreen}$throughputmethoddisp" echo -e "${InvGreen} ${CClear} ${InvDkGray}${CWhite} | ${CClear}" echo -e "${InvGreen} ${CClear} ${InvDkGray}${CWhite}( e)${CClear} : Exit${CClear}" echo -e "${InvGreen} ${CClear}" echo -e "${InvGreen} ${CClear}${CDkGray}---------------------------------------------------------------------------------------${CClear}" echo "" read -p "Please select? (1-15, e=Exit): " SelectSlot case $SelectSlot in 1) clear echo -e "${InvGreen} ${InvDkGray}${CWhite} Number of VPN/WG Client Slots Available on Router ${CClear}" echo -e "${InvGreen} ${CClear}" echo -e "${InvGreen} ${CClear} Please indicate how many VPN/WG client slots your router is configured with. Certain${CClear}" echo -e "${InvGreen} ${CClear} older model routers (RT-AC68U) can only handle a maximum of 2 VPN client slots, and${CClear}" echo -e "${InvGreen} ${CClear} natively can't handle WG without some effort using 3rd party scripts, while the vast${CClear}" echo -e "${InvGreen} ${CClear} majority of newer models can handle 5 VPN and 5 WG slots. Easiest way to tell is by${CClear}" echo -e "${InvGreen} ${CClear} looking at your VPN settings within the Merlin Web UI. Please choose below:" echo -e "${InvGreen} ${CClear}" echo -e "${InvGreen} ${CClear} ${CGreen}(2)${CClear} = 2 x VPN slots (Older router models)" echo -e "${InvGreen} ${CClear}" echo -e "${InvGreen} ${CClear} ${CGreen}(5)${CClear} = 5 x VPN | 5 x WG slots (Newer router models)" echo -e "${InvGreen} ${CClear}" echo -e "${InvGreen} ${CClear} (Default = 5 VPN/WG client slots)${CClear}" echo -e "${InvGreen} ${CClear}${CDkGray}---------------------------------------------------------------------------------------${CClear}" echo echo -e "${CClear}Current: ${CGreen}$availableslotsdisp${CClear}" ; echo read -p "Please enter value (2 or 5)? (e=Exit): " newAvailableSlots if [ "$newAvailableSlots" = "2" ] then availableslots="1 2" availableslotsdisp="2 x VPN" echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - INFO: New Available VPN Client Slot Configuration saved as: $availableslotsdisp" >> $logfile rm -f /jffs/addons/vpnmon-r3.d/vr3clients.txt rm -f /jffs/addons/vpnmon-r3.d/vr3timers.txt saveconfig createconfigs elif [ "$newAvailableSlots" = "5" ] then availableslots="1 2 3 4 5" availableslotsdisp="5 x VPN | 5 x WG" echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - INFO: New Available VPN Client Slot Configuration saved as: $availableslotsdisp" >> $logfile rm -f /jffs/addons/vpnmon-r3.d/vr3clients.txt rm -f /jffs/addons/vpnmon-r3.d/vr3timers.txt saveconfig createconfigs elif [ "$newAvailableSlots" = "e" ] then echo -e "\n[Exiting]"; sleep 2 else previousValue="$availableslots" availableslots="${availableslots:=1 2 3 4 5}" availableslotsdisp="5 x VPN | 5 x WG" [ "$availableslots" != "$previousValue" ] && \ echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - INFO: New Available VPN Client Slot Configuration saved as: $availableslotsdisp" >> $logfile rm -f /jffs/addons/vpnmon-r3.d/vr3clients.txt rm -f /jffs/addons/vpnmon-r3.d/vr3timers.txt saveconfig createconfigs fi ;; 2) clear echo -e "${InvGreen} ${InvDkGray}${CWhite} Custom PING Host (to determine VPN health) ${CClear}" echo -e "${InvGreen} ${CClear}" echo -e "${InvGreen} ${CClear} Please indicate which host you want to PING in order to determine VPN Client health.${CClear}" echo -e "${InvGreen} ${CClear} By default, the script will ping $PING_HOST_Deflt (Google DNS) as it's reliable, fairly${CClear}" echo -e "${InvGreen} ${CClear} standard, and typically available globally. You can change this depending on your" echo -e "${InvGreen} ${CClear} local access and connectivity situation." echo -e "${InvGreen} ${CClear}" echo -e "${InvGreen} ${CClear} (Default = ${PING_HOST_Deflt})${CClear}" echo -e "${InvGreen} ${CClear}${CDkGray}---------------------------------------------------------------------------------------${CClear}" echo echo -e "${CClear}Current: ${CGreen}${PINGHOST}${CClear}" ; echo read -p "Please enter valid IPv4 address? (e=Exit): " newPingHost if [ "$newPingHost" = "e" ] then echo -e "\n[Exiting]"; sleep 2 elif [ -n "$newPingHost" ] && echo "$newPingHost" | grep -qE "^${IPv4addrs_RegEx}$" then PINGHOST="$newPingHost" echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - INFO: New custom PING host entered: $PINGHOST" >> $logfile saveconfig else previousValue="$PINGHOST" PINGHOST="${PINGHOST:=$PING_HOST_Deflt}" [ "$PINGHOST" != "$previousValue" ] && \ echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - INFO: New custom PING host entered: $PINGHOST" >> $logfile saveconfig fi ;; 3) clear echo -e "${InvGreen} ${InvDkGray}${CWhite} Custom Event Log Size ${CClear}" echo -e "${InvGreen} ${CClear}" echo -e "${InvGreen} ${CClear} Please indicate below how large you would like your Event Log to grow. I'm a poet${CClear}" echo -e "${InvGreen} ${CClear} and didn't even know it. By default, with 2000 rows, you will have many months of${CClear}" echo -e "${InvGreen} ${CClear} Event Log data." echo -e "${InvGreen} ${CClear}" echo -e "${InvGreen} ${CClear} Use 0 to Disable, max number of rows is 9999. (Default = 2000)" echo -e "${InvGreen} ${CClear}${CDkGray}---------------------------------------------------------------------------------------${CClear}" echo echo -e "${CClear}Current: ${CGreen}$logsize${CClear}" ; echo read -p "Please enter Log Size (in rows)? (0-9999, e=Exit): " newLogSize if [ "$newLogSize" = "e" ] then echo -e "\n[Exiting]"; sleep 2 elif echo "$newLogSize" | grep -qE "^(0|[1-9][0-9]{0,3})$" && \ [ "$newLogSize" -ge 0 ] && [ "$newLogSize" -le 9999 ] then logsize="$newLogSize" echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - INFO: New custom Event Log Size entered (in rows): $logsize" >> $logfile saveconfig else previousValue="$logsize" logsize="${logsize:=2000}" [ "$logsize" != "$previousValue" ] && \ echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - INFO: New custom Event Log Size entered (in rows): $logsize" >> $logfile saveconfig fi ;; 4) if [ "$unboundwgclient" -ge 1 ]; then echo "" echo -e "${CRed}Unbound-over-WG is currently enabled. If you want to enable Unbound-over-VPN, please proceed to 'Disable'" echo -e "the Unbound-over-WG option first, then choose to enable Unbound-over-VPN.${CClear}" echo "" sleep 3 read -rsp $'Press any key to continue...\n' -n1 key continue fi while true; do clear echo -e "${InvGreen} ${InvDkGray}${CWhite} Unbound DNS Lookups over VPN Integration ${CClear}" echo -e "${InvGreen} ${CClear}" echo -e "${InvGreen} ${CClear} Please indicate if you would like to enable an integration with Unbound which allows${CClear}" echo -e "${InvGreen} ${CClear} you to force any DNS lookups that Unbound would normally handle, but over your VPN${CClear}" echo -e "${InvGreen} ${CClear} connection, essentially allowing you to appear as your own DNS resolver. DNS resolver${CClear}" echo -e "${InvGreen} ${CClear} traffic generated by Unbound is unencrypted as it queries DNS Root Servers by default.${CClear}" echo -e "${InvGreen} ${CClear} This integration encrypts your DNS Resolver traffic up to your Public VPN IP address,${CClear}" echo -e "${InvGreen} ${CClear} after which it goes unencrypted to the DNS Root Servers, preventing any ISP or other${CClear}" echo -e "${InvGreen} ${CClear} traffic inspection snooping when sending this across your WAN connection.${CClear}" echo -e "${InvGreen} ${CClear}" echo -e "${InvGreen} ${CClear} IMPORTANT: This integration will only work with 1 primary VPN connection that is${CClear}" echo -e "${InvGreen} ${CClear} designated as the connection that will carry DNS resolution traffic. This integration${CClear}" echo -e "${InvGreen} ${CClear} will work when multiple VPN connections are running, but the other VPN connections may${CClear}" echo -e "${InvGreen} ${CClear} not be able to utilize the Unbound functionality, and considered standalone. You will${CClear}" echo -e "${InvGreen} ${CClear} need to identify one VPN Client Slot that will remain on at all times. This integration${CClear}" echo -e "${InvGreen} ${CClear} requires additional scripts and configurations to get it working correctly. Please know${CClear}" echo -e "${InvGreen} ${CClear} that multiple files will either be downloaded or modified, and may increase the${CClear}" echo -e "${InvGreen} ${CClear} complexity in troubleshooting DNS lookup issues.${CClear}" echo -e "${InvGreen} ${CClear}" echo -e "${InvGreen} ${CClear} ${CRed}WARNING: As of around March 1 2024, the Unbound integration no longer works with the${CClear}" echo -e "${InvGreen} ${CClear} ${CRed}NordVPN Service due to possible blocking on their end. This service continues to work${CClear}" echo -e "${InvGreen} ${CClear} ${CRed}as advertised with other VPN Providers, like AirVPN. Use at your own risk.${CClear}" echo -e "${InvGreen} ${CClear}" echo -e "${InvGreen} ${CClear} ${CGreen}Requirements:" echo -e "${InvGreen} ${CClear} ${CGreen}1. Unbound must already be installed and functioning (AMTM)" echo -e "${InvGreen} ${CClear} ${CGreen}2. One static VPN Slot must be designated for Unbound-over-VPN use" echo -e "${InvGreen} ${CClear}" echo -e "${InvGreen} ${CClear} ${CGreen}These files will be downloaded or modified:" echo -e "${InvGreen} ${CClear} ${CGreen}1. /jffs/scripts/nat-start (modified)" echo -e "${InvGreen} ${CClear} ${CGreen}2. /jffs/scripts/openvpn-event (modified)" echo -e "${InvGreen} ${CClear} ${CGreen}3. /jffs/scripts/post-mount (modified)" echo -e "${InvGreen} ${CClear} ${CGreen}4. /jffs/addons/unbound/unbound_DNS_via_OVPN.sh (downloaded)" echo -e "${InvGreen} ${CClear} ${CGreen}5. Required router reboot - please don't forget to do so!${CClear}" echo -e "${InvGreen} ${CClear}" echo -e "${InvGreen} ${CClear} (Default = 0 / Disabled)${CClear}" echo -e "${InvGreen} ${CClear}${CDkGray}---------------------------------------------------------------------------------------${CClear}" echo "" if [ $unboundclient -eq 0 ]; then unboundclientexp="Disabled" else unboundclientexp="Enabled, VPN$unboundclient" fi echo -e "${CClear}Current: ${CGreen}$unboundclientexp${CClear}" echo "" read -p "Please enter value (Disabled=0, VPN Client=1-5)? (e=Exit): " unboundovervpn if [ ! -d "/jffs/addons/unbound" ]; then echo "" echo -e "${CRed}[Unbound was not detected on this system. Exiting...]${CClear}" echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - WARNING: Unbound was not detected on this system." >> $logfile unboundclient=0 saveconfig sleep 3 continue fi if [ "$unboundovervpn" = "0" ] || [ "$unboundovervpn" = "1" ] || [ "$unboundovervpn" = "2" ] || [ "$unboundovervpn" = "3" ] || [ "$unboundovervpn" = "4" ] || [ "$unboundovervpn" = "5" ] || [ "$unboundovervpn" = "e" ]; then if [ "$unboundovervpn" = "0" ]; then # Delete all additions made to files to enable Unbound over VPN functionality echo "" echo -e "${CGreen}[Disabling Unbound over VPN]...${CClear}" # Disable vpn functionality with Unbound sh /jffs/addons/unbound/unbound_manager.sh vpn=disable >/dev/null 2>&1 # Remove Unbound failsafe in post-mount if [ -f /jffs/scripts/post-mount ]; then sed -i -e '/vpn=disable/d' /jffs/scripts/post-mount fi # Remove Unbound VPN helper script in openvpn-event if [ -f /jffs/scripts/openvpn-event ]; then sed -i -e '/unbound_DNS_via_OVPN.sh/d' /jffs/scripts/openvpn-event fi # Remove RPDB Rules added to nat-start if [ -f /jffs/scripts/nat-start ]; then sed -i -e '/Added by vpnmon/d' /jffs/scripts/nat-start fi # Remove the unbound_DNS_via_OVPN.sh file if [ -f /jffs/addons/unbound/unbound_DNS_via_OVPN.sh ]; then rm -f /jffs/addons/unbound/unbound_DNS_via_OVPN.sh fi echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - INFO: Unbound-over-VPN was removed from VPNMON-R3" >> $logfile unboundclient=0 saveconfig sleep 3 continue elif [ "$unboundovervpn" = "1" ] || [ "$unboundovervpn" = "2" ] || [ "$unboundovervpn" = "3" ] || [ "$unboundovervpn" = "4" ] || [ "$unboundovervpn" = "5" ]; then if [ "$unboundovervpn" = "$unboundclient" ]; then echo -e "${CClear}\n[Unbound over VPN$unboundovervpn Already Active]"; sleep 2; break fi if [ "$unboundovervpn" = "1" ] || [ "$unboundovervpn" = "2" ] || [ "$unboundovervpn" = "3" ] || [ "$unboundovervpn" = "4" ] || [ "$unboundovervpn" = "5" ] && [ $unboundclient -ge 1 ]; then echo "" echo -e "${CRed}When changing a VPN Client Slot (from Slot #$unboundclient to Slot #$unboundovervpn), please proceed to 'Disable'" echo -e "first (option 0), then choose a new VPN Slot." sleep 5; continue fi # Modify or create post-mount if [ -f /jffs/scripts/post-mount ]; then if ! grep -q -F "[ -n "'"$(which unbound_manager)"'" ] && { sh /jffs/addons/unbound/unbound_manager.sh vpn=disable; }" /jffs/scripts/post-mount; then echo "[ -n "'"$(which unbound_manager)"'" ] && { sh /jffs/addons/unbound/unbound_manager.sh vpn=disable; } # Added by vpnmon-r3" >> /jffs/scripts/post-mount fi else echo "#!/bin/sh" > /jffs/scripts/post-mount echo "" >> /jffs/scripts/post-mount echo "[ -n "'"$(which unbound_manager)"'" ] && { sh /jffs/addons/unbound/unbound_manager.sh vpn=disable; } # Added by vpnmon-r3" >> /jffs/scripts/post-mount chmod 755 /jffs/scripts/post-mount fi # Modify or create nat-start if [ -f /jffs/scripts/nat-start ]; then if ! grep -q -F "sleep 10 # During the boot process nat-start may run multiple times so this is required" /jffs/scripts/nat-start; then echo "" >> /jffs/scripts/nat-start echo "sleep 10 # During the boot process nat-start may run multiple times so this is required - Added by vpnmon-r3" >> /jffs/scripts/nat-start echo "" >> /jffs/scripts/nat-start echo "# Ensure duplicate rules are not created - Added by vpnmon-r3" >> /jffs/scripts/nat-start echo "for VPN_ID in 0 1 2 3 4 5 # Added by vpnmon-r3" >> /jffs/scripts/nat-start echo " do # Added by vpnmon-r3" >> /jffs/scripts/nat-start echo " ip rule del prio 999$VPN_ID 2>/dev/null # Added by vpnmon-r3" >> /jffs/scripts/nat-start echo " done # Added by vpnmon-r3" >> /jffs/scripts/nat-start echo "" >> /jffs/scripts/nat-start echo "# Create the RPDB rules - Added by vpnmon-r3" >> /jffs/scripts/nat-start echo "ip rule add from 0/0 fwmark \"0x8000/0x8000\" table main prio 9990 # WAN fwmark - Added by vpnmon-r3" >> /jffs/scripts/nat-start echo "ip rule add from 0/0 fwmark \"0x7000/0x7000\" table ovpnc4 prio 9991 # VPN 4 fwmark - Added by vpnmon-r3" >> /jffs/scripts/nat-start echo "ip rule add from 0/0 fwmark \"0x3000/0x3000\" table ovpnc5 prio 9992 # VPN 5 fwmark - Added by vpnmon-r3" >> /jffs/scripts/nat-start echo "ip rule add from 0/0 fwmark \"0x1000/0x1000\" table ovpnc1 prio 9993 # VPN 1 fwmark - Added by vpnmon-r3" >> /jffs/scripts/nat-start echo "ip rule add from 0/0 fwmark \"0x2000/0x2000\" table ovpnc2 prio 9994 # VPN 2 fwmark - Added by vpnmon-r3" >> /jffs/scripts/nat-start echo "ip rule add from 0/0 fwmark \"0x4000/0x4000\" table ovpnc3 prio 9995 # VPN 3 fwmark - Added by vpnmon-r3" >> /jffs/scripts/nat-start fi else curl --silent --retry 3 --connect-timeout 3 --max-time 6 --retry-delay 2 --retry-all-errors "https://raw.githubusercontent.com/ViktorJp/VPNMON-R2/main/Unbound/nat-start" -o "/jffs/scripts/nat-start" && chmod 755 "/jffs/scripts/nat-start" fi # Modify or create openvpn-event if [ -f /jffs/scripts/openvpn-event ]; then if ! grep -q -F "[ "'"${dev:0:4}"'" = 'tun1' ] && vpn_id" /jffs/scripts/openvpn-event; then echo "[ "'"${dev:0:4}"'" = 'tun1' ] && vpn_id=$unboundovervpn && [ "'"$script_type"'" = 'route-up' ] && /jffs/addons/unbound/unbound_DNS_via_OVPN.sh \$vpn_id start &" >> /jffs/scripts/openvpn-event echo "[ "'"${dev:0:4}"'" = 'tun1' ] && vpn_id=$unboundovervpn && [ "'"$script_type"'" = 'route-pre-down' ] && /jffs/addons/unbound/unbound_DNS_via_OVPN.sh \$vpn_id stop &" >> /jffs/scripts/openvpn-event fi else echo "#!/bin/sh" > /jffs/scripts/openvpn-event echo "" >> /jffs/scripts/openvpn-event echo "[ "'"${dev:0:4}"'" = 'tun1' ] && vpn_id=$unboundovervpn && [ "'"$script_type"'" = 'route-up' ] && /jffs/addons/unbound/unbound_DNS_via_OVPN.sh \$vpn_id start &" >> /jffs/scripts/openvpn-event echo "[ "'"${dev:0:4}"'" = 'tun1' ] && vpn_id=$unboundovervpn && [ "'"$script_type"'" = 'route-pre-down' ] && /jffs/addons/unbound/unbound_DNS_via_OVPN.sh \$vpn_id stop &" >> /jffs/scripts/openvpn-event chmod 755 /jffs/scripts/openvpn-event # backup - curl --silent --retry 3 --connect-timeout 3 --max-time 6 --retry-delay 2 --retry-all-errors "https://raw.githubusercontent.com/ViktorJp/VPNMON-R2/main/Unbound/openvpn-event" -o "/jffs/scripts/openvpn-event" && chmod 755 "/jffs/scripts/openvpn-event" fi # Download and create the unbound_DNS_via_OVPN.sh file - many thanks to @Martineau and @Swinson if [ ! -f /jffs/addons/unbound/unbound_DNS_via_OVPN.sh ]; then curl --silent --retry 3 --connect-timeout 3 --max-time 6 --retry-delay 2 --retry-all-errors "https://raw.githubusercontent.com/MartineauUK/Unbound-Asuswrt-Merlin/dev/unbound_DNS_via_OVPN.sh" -o "/jffs/addons/unbound/unbound_DNS_via_OVPN.sh" && chmod 755 "/jffs/addons/unbound/unbound_DNS_via_OVPN.sh" # backup - curl --silent --retry 3 "https://raw.githubusercontent.com/ViktorJp/VPNMON-R2/main/Unbound/unbound_DNS_via_OVPN.sh" -o "/jffs/addons/unbound/unbound_DNS_via_OVPN.sh" && chmod 755 "/jffs/addons/unbound/unbound_DNS_via_OVPN.sh" fi echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - INFO: Unbound-over-VPN was enabled for VPNMON-R3" >> $logfile echo -e "${CClear}" unboundclient=$unboundovervpn saveconfig echo "Please reboot your router now if this is your first time or re-enabled Unbound over VPN" read -rsp $'Press any key to continue...\n' -n1 key continue elif [ "$unboundovervpn" = "e" ]; then echo -e "${CClear}\n[Exiting]"; sleep 2; break fi else echo -e "${CClear}\n[Exiting]"; sleep 2; break fi done ;; 5) if [ "$unboundclient" -ge 1 ]; then echo "" echo -e "${CRed}Unbound-over-VPN is currently enabled. If you want to enable Unbound-over-WG, please proceed to 'Disable'" echo -e "the Unbound-over-VPN option first, then choose to enable Unbound-over-WG.${CClear}" echo "" sleep 3 read -rsp $'Press any key to continue...\n' -n1 key continue fi while true; do clear echo -e "${InvGreen} ${InvDkGray}${CWhite} Unbound DNS Lookups over WG Integration ${CClear}" echo -e "${InvGreen} ${CClear}" echo -e "${InvGreen} ${CClear} Please indicate if you would like to enable an integration with Unbound which allows${CClear}" echo -e "${InvGreen} ${CClear} you to force any DNS lookups that Unbound would normally handle, but over your WG${CClear}" echo -e "${InvGreen} ${CClear} connection, essentially allowing you to appear as your own DNS resolver. DNS resolver${CClear}" echo -e "${InvGreen} ${CClear} traffic generated by Unbound is unencrypted as it queries DNS Root Servers by default.${CClear}" echo -e "${InvGreen} ${CClear} This integration encrypts your DNS Resolver traffic up to your Public WG IP address,${CClear}" echo -e "${InvGreen} ${CClear} after which it goes unencrypted to the DNS Root Servers, preventing any ISP or other${CClear}" echo -e "${InvGreen} ${CClear} traffic inspection snooping when sending this across your WAN connection.${CClear}" echo -e "${InvGreen} ${CClear}" echo -e "${InvGreen} ${CClear} IMPORTANT: This integration will only work with 1 primary WG connection that is${CClear}" echo -e "${InvGreen} ${CClear} designated as the connection that will carry DNS resolution traffic. This integration${CClear}" echo -e "${InvGreen} ${CClear} will work when multiple WG connections are running, but the other WG connections may${CClear}" echo -e "${InvGreen} ${CClear} not be able to utilize the Unbound functionality, and considered standalone. You will${CClear}" echo -e "${InvGreen} ${CClear} need to identify one WG Client Slot that will remain on at all times. This integration${CClear}" echo -e "${InvGreen} ${CClear} is much more elegant and simple when it compares to the Unbound over VPN integration.${CClear}" echo -e "${InvGreen} ${CClear} Should your WG connection go down, browsing/DNS resolution will continue to function${CClear}" echo -e "${InvGreen} ${CClear} by traversing directly out over the WAN.${CClear}" echo -e "${InvGreen} ${CClear}" echo -e "${InvGreen} ${CClear} ${CRed}WARNING: As of around March 1 2024, the Unbound integration no longer works with the${CClear}" echo -e "${InvGreen} ${CClear} ${CRed}NordVPN Service due to possible blocking on their end. This service continues to work${CClear}" echo -e "${InvGreen} ${CClear} ${CRed}as advertised with other VPN Providers, like AirVPN. Use at your own risk.${CClear}" echo -e "${InvGreen} ${CClear}" echo -e "${InvGreen} ${CClear} ${CGreen}Requirements:" echo -e "${InvGreen} ${CClear} ${CGreen}1. Unbound must already be installed and functioning (AMTM)" echo -e "${InvGreen} ${CClear} ${CGreen}2. One static WG Slot must be designated for Unbound-over-WG use" echo -e "${InvGreen} ${CClear}" echo -e "${InvGreen} ${CClear} ${CGreen}The following will be added/modified:" echo -e "${InvGreen} ${CClear} ${CGreen}1. A new virtual br0 interface will be created on 10.99.88.77 (added)" echo -e "${InvGreen} ${CClear} ${CGreen}2. A new ip rule will be added to point your WG Slot to this new br0 interface (added)" echo -e "${InvGreen} ${CClear} ${CGreen}3. The unbound.conf will have its outgoing-interface modified to 10.99.88.77 (modified)" echo -e "${InvGreen} ${CClear} ${CGreen}4. Unbound service will be restarted.${CClear}" echo -e "${InvGreen} ${CClear}" echo -e "${InvGreen} ${CClear} (Default = 0 / Disabled)${CClear}" echo -e "${InvGreen} ${CClear}${CDkGray}---------------------------------------------------------------------------------------${CClear}" echo "" if [ $unboundwgclient -eq 0 ]; then unboundwgclientexp="Disabled" else unboundwgclientexp="Enabled, WGC$unboundwgclient" fi echo -e "${CClear}Current: ${CGreen}$unboundwgclientexp${CClear}" echo "" read -p "Please enter value (Disabled=0, WG Client=1-5)? (e=Exit): " unboundoverwg if [ ! -d "/jffs/addons/unbound" ]; then echo "" echo -e "${CRed}[Unbound was not detected on this system. Exiting...]${CClear}" echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - WARNING: Unbound was not detected on this system." >> $logfile unboundwgclient=0 saveconfig sleep 3 continue fi if [ "$unboundoverwg" = "0" ] || [ "$unboundoverwg" = "1" ] || [ "$unboundoverwg" = "2" ] || [ "$unboundoverwg" = "3" ] || [ "$unboundoverwg" = "4" ] || [ "$unboundoverwg" = "5" ] || [ "$unboundoverwg" = "e" ]; then if [ "$unboundoverwg" = "0" ]; then # Delete all additions made to files to enable Unbound over VPN functionality echo "" echo -e "${CGreen}[Disabling Unbound over WG]...${CClear}" sleep 2 # =============================================== # === Disable Unbound-over-WG Integration === # === Methodology engineered by @ZebMcKayhan === # =============================================== # Modify unbound.conf file - set major variables UNBOUND_CONF="/opt/var/lib/unbound/unbound.conf" DISABLED_LINE="#outgoing-interface: 10.0.20.1 # v1.08 Martineau Use VPN tunnel to hide Root server queries from ISP (or force WAN ONLY)" # Check if the unbound.conf file exists and is readable. if [ ! -r "${UNBOUND_CONF}" ]; then echo "" echo -e "${CRed}Error: Unbound Configuration file not found or not readable at ${UNBOUND_CONF}${CClear}" echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - ERROR: Unbound Configuration file not found or not readable at ${UNBOUND_CONF}" >> $logfile sleep 3 continue fi # Create a temp file to move unbound.conf contents into TMP_FILE="${UNBOUND_CONF}.$$" # Remove outgoing-interface contents and replace with a dummy line sed "s/^[[:space:]]*#*[[:space:]]*outgoing-interface:.*/${DISABLED_LINE}/g" "${UNBOUND_CONF}" > "${TMP_FILE}" echo "" echo -e "${CGreen}[Disabled 'outgoing-interface' and set back to default]...${CClear}" sleep 1 # Ensure the temporary file was created and is not empty before overwriting the original if [ ! -s "${TMP_FILE}" ]; then echo -e "${CRed}Error: Failed to modify configuration. The temporary file is empty or was not created.${CClear}" echo -e "${CRed}No changes have been made to ${UNBOUND_CONF}.${CClear}" echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - ERROR: Failed to modify configuration. The temporary file is empty or was not created." >> $logfile sleep 3 continue fi # Move the temp file into the unbound.conf file mv "${TMP_FILE}" "${UNBOUND_CONF}" >/dev/null 2>&1 echo "" echo -e "${CGreen}[Modified unbound.conf file back to defaults]...${CClear}" sleep 1 # Restart unbound service if [ -f "/jffs/addons/unbound/unbound_manager.sh" ]; then unbound_manager restart >/dev/null 2>&1 RESTART_STATUS=$? if [ ${RESTART_STATUS} -eq 0 ]; then echo "" echo -e "${CGreen}[Unbound service restarted successfully]...${CClear}" echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - INFO: Unbound service restarted successfully" >> $logfile sleep 1 else echo "" echo -e "${CRed}[Warning: 'unbound_manager restart' command failed with status ${RESTART_STATUS}]...${CClear}" echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - WARNING: 'unbound_manager restart' command failed with status ${RESTART_STATUS}" >> $logfile sleep 3 fi else echo "" echo -e "${CRed}[Warning: 'unbound_manager.sh' script not found. Could not restart service]...${CClear}" echo -e "${CRed}[Please restart the unbound service manually]...${CClear}" echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - WARNING: 'unbound_manager.sh' script not found. Could not restart service" >> $logfile sleep 3 fi # Remove the IP rule from VPN Director ip rule del prio 11 >/dev/null 2>&1 echo "" echo -e "${CGreen}[Removed IP rule for virtual br0 interface at 10.99.88.77]...${CClear}" sleep 1 # Remove added virtual br0 interface ifconfig br0:UnboundWG down >/dev/null 2>&1 echo "" echo -e "${CGreen}[Removed virtual br0 interface at 10.99.88.77]...${CClear}" sleep 1 # Remove Unbound failsafe in init-start if [ -f /jffs/scripts/init-start ]; then sed -i -e '/vpnmon-r3/d' /jffs/scripts/init-start fi echo "" echo -e "${CGreen}[Unbound failsafe removed from init-start file]...${CClear}" sleep 1 # Remove Unbound failsafe in nat-start if [ -f /jffs/scripts/nat-start ]; then sed -i -e '/vpnmon-r3/d' /jffs/scripts/nat-start fi echo "" echo -e "${CGreen}[Unbound failsafe removed from nat-start file]...${CClear}" sleep 1 echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - INFO: Unbound-over-WG was removed from VPNMON-R3" >> $logfile unboundwgclient=0 saveconfig echo "" echo "Please consider rebooting your router now after major Unbound and system file changes." echo "" sleep 3 read -rsp $'Press any key to continue...\n' -n1 key continue elif [ "$unboundoverwg" = "1" ] || [ "$unboundoverwg" = "2" ] || [ "$unboundoverwg" = "3" ] || [ "$unboundoverwg" = "4" ] || [ "$unboundoverwg" = "5" ]; then if [ "$unboundoverwg" = "$unboundwgclient" ]; then echo -e "${CClear}\n[Unbound over WGC$unboundoverwg Already Active]"; sleep 3; break fi if [ "$unboundoverwg" = "1" ] || [ "$unboundoverwg" = "2" ] || [ "$unboundoverwg" = "3" ] || [ "$unboundoverwg" = "4" ] || [ "$unboundoverwg" = "5" ] && [ $unboundwgclient -ge 1 ]; then echo "" echo -e "${CRed}When changing a WG Client Slot (from WGC #$unboundwgclient to WGC #$unboundoverwg), please proceed to 'Disable'" echo -e "first (option 0), then choose a new WG Slot.${CClear}" echo "" sleep 3 read -rsp $'Press any key to continue...\n' -n1 key continue fi # =============================================== # === Create Unbound-over-WG Integration === # === Methodology engineered by @ZebMcKayhan === # =============================================== echo "" echo -e "${CGreen}[Enabling Unbound over WG]...${CClear}" sleep 2 # Create new virtual br0 interface ifconfig br0:UnboundWG 10.99.88.77 netmask 255.255.255.255 up >/dev/null 2>&1 echo "" echo -e "${CGreen}[Added virtual br0 interface at 10.99.88.77]...${CClear}" sleep 1 # Point WG slot to new br0 interface for VPN Director ip rule add from 10.99.88.77 lookup wgc$unboundoverwg prio 11 >/dev/null 2>&1 echo "" echo -e "${CGreen}[Pointed wgc$unboundoverwg to virtual br0 interface at 10.99.88.77]...${CClear}" sleep 1 # Modify unbound.conf file - set major variables UNBOUND_CONF="/opt/var/lib/unbound/unbound.conf" ENABLED_IP="10.99.88.77" COMMENT="# v1.08 Martineau Use VPN tunnel to hide Root server queries from ISP (or force WAN ONLY)" # Check if the unbound.conf file exists and is readable. if [ ! -r "${UNBOUND_CONF}" ]; then echo "" echo -e "${CRed}Error: Unbound Configuration file not found or not readable at ${UNBOUND_CONF}${CClear}" echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - ERROR: Unbound Configuration file not found or not readable at ${UNBOUND_CONF}" >> $logfile sleep 3 continue fi # Create a temp file to move unbound.conf contents into TMP_FILE="${UNBOUND_CONF}.$$" # Create new outgoing-interface contents ENABLED_LINE="outgoing-interface: ${ENABLED_IP} ${COMMENT}" sed "s/^[[:space:]]*#*[[:space:]]*outgoing-interface:.*/${ENABLED_LINE}/g" "${UNBOUND_CONF}" > "${TMP_FILE}" # Ensure the temporary file was created and is not empty before overwriting the original if [ ! -s "${TMP_FILE}" ]; then echo -e "${CRed}Error: Failed to modify configuration. The temporary file is empty or was not created.${CClear}" echo -e "${CRed}No changes have been made to ${UNBOUND_CONF}.${CClear}" echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - ERROR: Failed to modify configuration. The temporary file is empty or was not created." >> $logfile sleep 3 continue fi # Move the temp file into the unbound.conf file mv "${TMP_FILE}" "${UNBOUND_CONF}" >/dev/null 2>&1 echo "" echo -e "${CGreen}[Modified unbound.conf file 'outgoing-interface: 10.99.88.77']...${CClear}" sleep 1 # Restart unbound service if [ -f "/jffs/addons/unbound/unbound_manager.sh" ]; then unbound_manager restart >/dev/null 2>&1 RESTART_STATUS=$? if [ ${RESTART_STATUS} -eq 0 ]; then echo "" echo -e "${CGreen}[Unbound service restarted successfully]...${CClear}" echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - INFO: Unbound service restarted successfully" >> $logfile sleep 1 else echo "" echo -e "${CRed}[Warning: 'unbound_manager restart' command failed with status ${RESTART_STATUS}]...${CClear}" echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - WARNING: 'unbound_manager restart' command failed with status ${RESTART_STATUS}" >> $logfile sleep 3 fi else echo "" echo -e "${CRed}[Warning: 'unbound_manager.sh' script not found. Could not restart service]...${CClear}" echo -e "${CRed}[Please restart the unbound service manually]...${CClear}" echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - WARNING: 'unbound_manager.sh' script not found. Could not restart service" >> $logfile sleep 3 fi echo "" echo -e "${CGreen}[Adding Unbound Failsafe... Modifying init-start file]...${CClear}" sleep 1 # Modify or create init-start to ensure survivability after a router reboot if [ -f /jffs/scripts/init-start ]; then if ! grep -q -F "sh /jffs/scripts/vpnmon-r3.sh -uowginitstart" /jffs/scripts/init-start; then echo "sh /jffs/scripts/vpnmon-r3.sh -uowginitstart # Added by vpnmon-r3" >> /jffs/scripts/init-start fi else echo "#!/bin/sh" > /jffs/scripts/init-start echo "" >> /jffs/scripts/init-start echo "sh /jffs/scripts/vpnmon-r3.sh -uowginitstart # Added by vpnmon-r3" >> /jffs/scripts/init-start chmod 755 /jffs/scripts/init-start fi echo "" echo -e "${CGreen}[Adding Unbound Failsafe... Modifying nat-start file]...${CClear}" sleep 1 # Modify or create nat-start to ensure survivability after a router reboot if [ -f /jffs/scripts/nat-start ]; then if ! grep -q -F "sh /jffs/scripts/vpnmon-r3.sh -uowgnatstart" /jffs/scripts/nat-start; then echo "sh /jffs/scripts/vpnmon-r3.sh -uowgnatstart # Added by vpnmon-r3" >> /jffs/scripts/nat-start fi else echo "#!/bin/sh" > /jffs/scripts/nat-start echo "" >> /jffs/scripts/nat-start echo "sh /jffs/scripts/vpnmon-r3.sh -uowgnatstart # Added by vpnmon-r3" >> /jffs/scripts/nat-start chmod 755 /jffs/scripts/nat-start fi echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - INFO: Unbound-over-WG was enabled for VPNMON-R3" >> $logfile echo -e "${CClear}" unboundwgclient=$unboundoverwg saveconfig echo "" echo "Please consider rebooting your router now if this is your first time or have re-enabled Unbound-over-WG" echo "" sleep 3 read -rsp $'Press any key to continue...\n' -n1 key continue elif [ "$unboundoverwg" = "e" ]; then echo -e "${CClear}\n[Exiting]"; sleep 2; break fi else echo -e "${CClear}\n[Exiting]"; sleep 2; break fi done ;; 6) if [ "$unboundclient" != "0" ] || [ "$unboundwgclient" != "0" ]; then clear echo -e "${InvGreen} ${InvDkGray}${CWhite} Show Expanded Unbound IP Information ${CClear}" echo -e "${InvGreen} ${CClear}" echo -e "${InvGreen} ${CClear} Please indicate below if you would like to show your full Unbound DNS Resolver IP on-${CClear}" echo -e "${InvGreen} ${CClear} screen, or just an abbreviated color-coded indicator. Showing a full IP may in some${CClear}" echo -e "${InvGreen} ${CClear} cases help with troubleshooting.${CClear}" echo -e "${InvGreen} ${CClear}" echo -e "${InvGreen} ${CClear} Use 0 to Disable, 1 to Enable. (Default = 0)" echo -e "${InvGreen} ${CClear}${CDkGray}---------------------------------------------------------------------------------------${CClear}" echo echo -e "${CClear}Current: ${CGreen}$unboundshowipdisp${CClear}" ; echo read -p "Please Choose? (Disable = 0, Enable = 1, e=Exit): " newunboundshowip if [ "$newunboundshowip" = "0" ] then unboundshowip=0 unboundshowipdisp="Disabled" echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - INFO: Expanded Unbound IP Information Disabled" >> $logfile saveconfig elif [ "$newunboundshowip" = "1" ] then unboundshowip=1 unboundshowipdisp="Enabled" echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - INFO: Expanded Unbound IP Information Enabled" >> $logfile saveconfig elif [ "$newunboundshowip" = "e" ] then echo -e "\n[Exiting]"; sleep 2 else previousValue="$unboundshowip" unboundshowip="${unboundshowip:=0}" unboundshowipdisp="$([ "$unboundshowip" = "0" ] && echo "Disabled" || echo "Enabled")" [ "$unboundshowip" != "$previousValue" ] && \ echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - INFO: Expanded Unbound IP Information Disabled" >> $logfile saveconfig fi fi ;; 7) clear echo -e "${InvGreen} ${InvDkGray}${CWhite} Refresh Custom Server Lists on -RESET Switch ${CClear}" echo -e "${InvGreen} ${CClear}" echo -e "${InvGreen} ${CClear} Please indicate below if you would like to automatically refresh your custom Server${CClear}" echo -e "${InvGreen} ${CClear} Lists specified under the Edit/Run Server List Automation menu. This function will${CClear}" echo -e "${InvGreen} ${CClear} run any defined CURL+JQ statements you have configured and save them back to your${CClear}" echo -e "${InvGreen} ${CClear} Client Slot Server List files that will be used for VPN connections.${CClear}" echo -e "${InvGreen} ${CClear}" echo -e "${InvGreen} ${CClear} Use 0 to Disable, 1 to Enable. (Default = 0)" echo -e "${InvGreen} ${CClear}${CDkGray}---------------------------------------------------------------------------------------${CClear}" echo echo -e "${CClear}Current: ${CGreen}$refreshserverlistsdisp${CClear}" ; echo read -p "Please Choose? (Disable = 0, Enable = 1, e=Exit): " newRefreshServerList if [ "$newRefreshServerList" = "0" ] then refreshserverlists=0 refreshserverlistsdisp="Disabled" echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - INFO: Custom Server Lists Disabled on -RESET Switch" >> $logfile saveconfig elif [ "$newRefreshServerList" = "1" ] then refreshserverlists=1 refreshserverlistsdisp="Enabled" echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - INFO: Custom Server Lists Enabled on -RESET Switch" >> $logfile saveconfig elif [ "$newRefreshServerList" = "e" ] then echo -e "\n[Exiting]"; sleep 2 else previousValue="$refreshserverlists" refreshserverlists="${refreshserverlists:=0}" refreshserverlistsdisp="$([ "$refreshserverlists" = "0" ] && echo "Disabled" || echo "Enabled")" [ "$refreshserverlists" != "$previousValue" ] && \ echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - INFO: Custom Server Lists $refreshserverlistsdisp on -RESET Switch" >> $logfile saveconfig fi ;; 8) clear echo -e "${InvGreen} ${InvDkGray}${CWhite} Provide WAN/Dual WAN Monitoring Functionality ${CClear}" echo -e "${InvGreen} ${CClear}" echo -e "${InvGreen} ${CClear} Please indicate below if you would like to monitor your WAN/Dual WAN connection for${CClear}" echo -e "${InvGreen} ${CClear} connectivity issues that may impact your VPN connection. This functionality will${CClear}" echo -e "${InvGreen} ${CClear} determine if your WAN connection is viable, and upon determining that the WAN is${CClear}" echo -e "${InvGreen} ${CClear} down, VPNMON-R3 will kill all VPN connections and continue testing for a valid WAN${CClear}" echo -e "${InvGreen} ${CClear} connection until it can restore your VPN connections.${CClear}" echo -e "${InvGreen} ${CClear}" echo -e "${InvGreen} ${CClear} Use 0 to Disable, 1 to Enable. (Default = 0)" echo -e "${InvGreen} ${CClear}${CDkGray}---------------------------------------------------------------------------------------${CClear}" echo echo -e "${CClear}Current: ${CGreen}$monitorwandisp${CClear}" ; echo read -p "Please Choose? (Disable = 0, Enable = 1, e=Exit): " newMonitorWAN if [ "$newMonitorWAN" = "0" ] then monitorwan=0 monitorwandisp="Disabled" echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - INFO: WAN Monitoring Disabled" >> $logfile saveconfig elif [ "$newMonitorWAN" = "1" ] then monitorwan=1 monitorwandisp="Enabled" echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - INFO: WAN Monitoring Enabled" >> $logfile saveconfig elif [ "$newMonitorWAN" = "e" ] then echo -e "\n[Exiting]"; sleep 2 else previousValue="$monitorwan" monitorwan="${monitorwan:=0}" monitorwandisp="$([ "$monitorwan" = "0" ] && echo "Disabled" || echo "Enabled")" [ "$monitorwan" != "$previousValue" ] && \ echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - INFO: WAN Monitoring $monitorwandisp" >> $logfile saveconfig fi ;; 9) while true do clear echo -e "${InvGreen} ${InvDkGray}${CWhite} Enable/Disable VPN/WG Slot Monitoring and Display ${CClear}" echo -e "${InvGreen} ${CClear}" echo -e "${InvGreen} ${CClear} Please indicate whether you want to enable or disable VPN/WG Slots from being${CClear}" echo -e "${InvGreen} ${CClear} monitored and shown on the main VPNMON-R3 UI. This setting is meant for those${CClear}" echo -e "${InvGreen} ${CClear} who are only running VPN or only WG on their router, and do not want to display${CClear}" echo -e "${InvGreen} ${CClear} one or the other to only show relevant info.${CClear}" echo -e "${InvGreen} ${CClear}" echo -e "${InvGreen} ${CClear} Use the corresponding ${CGreen}()${CClear} key to enable/disable monitoring for each.${CClear}" echo -e "${InvGreen} ${CClear}${CDkGray}---------------------------------------------------------------------------------------${CClear}" if [ "$useovpn" = "1" ]; then useovpnDisp="${CGreen}Y${CCyan}"; else useovpn=0; useovpnDisp="${CRed}N${CCyan}"; fi if [ "$usewg" = "1" ]; then usewgDisp="${CGreen}Y${CCyan}"; else usewg=0; usewgDisp="${CRed}N${CCyan}"; fi echo -e "${InvGreen} ${CClear}" echo -e "${InvGreen} ${CClear} ${InvDkGray}${CWhite} OpenVPN${CClear} ${CGreen}(1) -${CClear} $useovpnDisp${CClear}" echo -e "${InvGreen} ${CClear} ${InvDkGray}${CWhite}Wireguard${CClear} ${CGreen}(2) -${CClear} $usewgDisp${CClear}" echo "" read -p "Please select? (1-2, e=Exit): " SelectSlot case $SelectSlot in 1) if [ "$unboundclient" = "0" ]; then if [ "$useovpn" = "0" ]; then useovpn=1 useovpnDisp="${CGreen}Y${CCyan}" elif [ "$useovpn" = "1" ]; then useovpn=0; useovpnDisp="${CRed}N${CCyan}" fi else echo -e "${CClear}\n[Unable to disable VPN. Unbound Active on Slot VPN$unboundclient]"; sleep 3 fi;; 2) if [ "$usewg" = "0" ]; then usewg=1 usewgDisp="${CGreen}Y${CCyan}" elif [ "$usewg" = "1" ]; then usewg=0 usewgDisp="${CRed}N${CCyan}" fi;; [Ee]) saveconfig echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - INFO: VPN/WG Client Slot Monitoring/Display configuration saved" >> $logfile timer="$timerloop" break;; esac done ;; 10) clear echo -e "${InvGreen} ${InvDkGray}${CWhite} Whitelist VPN Server IP Lists in Skynet ${CClear}" echo -e "${InvGreen} ${CClear}" echo -e "${InvGreen} ${CClear} Please indicate below if you would like to whitelist your VPN Server IP lists in${CClear}" echo -e "${InvGreen} ${CClear} the Skynet Firewall. This provides for better stability in connecting to your VPN${CClear}" echo -e "${InvGreen} ${CClear} provider, as there have been occasions where the Skynet blacklist will prevent${CClear}" echo -e "${InvGreen} ${CClear} connections to your VPN Servers. This could cause a disruption in being able to${CClear}" echo -e "${InvGreen} ${CClear} maintain a stable VPN connection. Note: Skynet must already be installed and${CClear}" echo -e "${InvGreen} ${CClear} operational for this functionality to work.${CClear}" echo -e "${InvGreen} ${CClear}" echo -e "${InvGreen} ${CClear} Use 0 to Disable, 1 to Enable. (Default = 0)" echo -e "${InvGreen} ${CClear}${CDkGray}---------------------------------------------------------------------------------------${CClear}" echo echo -e "${CClear}Current: ${CGreen}$updateskynetdisp${CClear}" ; echo read -p "Please Choose? (Disable = 0, Enable = 1, e=Exit): " newUpdateSkyNet if [ "$newUpdateSkyNet" = "1" ] then updateskynet=1 updateskynetdisp="Enabled" echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - INFO: VPN Server IP Skynet Whitelisting Enabled" >> $logfile saveconfig elif [ "$newUpdateSkyNet" = "0" ] then updateskynet=0 updateskynetdisp="Disabled" echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - INFO: VPN Server IP Skynet Whitelisting Disabled" >> $logfile saveconfig elif [ "$newUpdateSkyNet" = "e" ] then echo -e "\n[Exiting]"; sleep 2 else previousValue="$updateskynet" updateskynet="${updateskynet:=0}" updateskynetdisp="$([ "$updateskynet" = "0" ] && echo "Disabled" || echo "Enabled")" [ "$updateskynet" != "$previousValue" ] && \ echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - INFO: VPN Server IP Skynet Whitelisting $updateskynetdisp" >> $logfile saveconfig fi ;; [Ee]) echo -e "${CClear}\n[Exiting]"; sleep 2; break ;; 11) amtmevents source "$config" ;; 12) clear echo -e "${InvGreen} ${InvDkGray}${CWhite} Reset spdMerlin Interfaces on VPN Reset ${CClear}" echo -e "${InvGreen} ${CClear}" echo -e "${InvGreen} ${CClear} Please indicate below if you would like to reset your spdMerlin Interfaces each${CClear}" echo -e "${InvGreen} ${CClear} time VPNMON-R3 resets. This functionality will allow VPNMON-R3 to update spdMerlin${CClear}" echo -e "${InvGreen} ${CClear} whenever a VPN reset occurs. SpdMerlin will then know which interfaces are active${CClear}" echo -e "${InvGreen} ${CClear} in order to run manual or automated speedtests from.${CClear}" echo -e "${InvGreen} ${CClear}" echo -e "${InvGreen} ${CClear} Use 0 to Disable, 1 to Enable. (Default = 0)" echo -e "${InvGreen} ${CClear}${CDkGray}---------------------------------------------------------------------------------------${CClear}" echo echo -e "${CClear}Current: ${CGreen}$rstspdmerlindisp${CClear}" ; echo read -p "Please Choose? (Disable = 0, Enable = 1, e=Exit): " newrstspdmerlin if [ "$newrstspdmerlin" = "0" ] then rstspdmerlin=0 rstspdmerlindisp="Disabled" echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - INFO: spdMerlin Interface Reset Disabled" >> $logfile saveconfig elif [ "$newrstspdmerlin" = "1" ] then rstspdmerlin=1 rstspdmerlindisp="Enabled" echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - INFO: spdMerlin Interface Reset Enabled" >> $logfile saveconfig elif [ "$newrstspdmerlin" = "e" ] then echo -e "\n[Exiting]"; sleep 2 else previousValue="$rstspdmerlin" rstspdmerlin="${rstspdmerlin:=0}" rstspdmerlindisp="$([ "$rstspdmerlin" = "0" ] && echo "Disabled" || echo "Enabled")" [ "$rstspdmerlin" != "$previousValue" ] && \ echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - INFO: spdMerlin Interface Reset $monitorwandisp" >> $logfile saveconfig fi ;; 13) clear echo -e "${InvGreen} ${InvDkGray}${CWhite} Server List Item Selection Method ${CClear}" echo -e "${InvGreen} ${CClear}" echo -e "${InvGreen} ${CClear} Please indicate below if you would like to use a Random or Sequential method to pick${CClear}" echo -e "${InvGreen} ${CClear} your next available Server List item to populate your VPN/WG slots. When choosing${CClear}" echo -e "${InvGreen} ${CClear} 'Sequential', please know that this method will use a Round-Robin style method, and${CClear}" echo -e "${InvGreen} ${CClear} will start at the beginning of your list again after it has used the last entry in${CClear}" echo -e "${InvGreen} ${CClear} your list. The 'Sequential' method is a preferred method to use for those using${CClear}" echo -e "${InvGreen} ${CClear} shorter lists of servers, as the chances of selecting the same server is much greater${CClear}" echo -e "${InvGreen} ${CClear} when using a 'Random' method against these short lists.${CClear}" echo -e "${InvGreen} ${CClear}" echo -e "${InvGreen} ${CClear} (Default = 0 - Random)" echo -e "${InvGreen} ${CClear}${CDkGray}---------------------------------------------------------------------------------------${CClear}" echo echo -e "${CClear}Current: ${CGreen}$selectionmethoddisp${CClear}" ; echo read -p "Please Choose? (Random = 0, Sequential = 1, e=Exit): " newselectionmethod if [ "$newselectionmethod" = "0" ] then selectionmethod=0 newselectionmethoddisp="Random" echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - INFO: Server List Item Selection Method set to Random" >> $logfile saveconfig elif [ "$newselectionmethod" = "1" ] then selectionmethod=1 newselectionmethoddisp="Sequential" echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - INFO: Server List Item Selection Method set to Sequential" >> $logfile saveconfig elif [ "$newselectionmethod" = "e" ] then echo -e "\n[Exiting]"; sleep 2 else previousValue="$selectionmethod" selectionmethod="${selectionmethod:=0}" selectionmethoddisp="$([ "$selectionmethod" = "0" ] && echo "Random" || echo "Sequential")" [ "$selectionmethod" != "$previousValue" ] && \ echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - INFO: Server List Item Selection Method set to $selectionmethoddisp" >> $logfile saveconfig fi ;; 14) while true do if [ "$bwdisp" = "1" ]; then bwdispval="Mbps"; else bwdispval="MB"; fi clear echo -e "${InvGreen} ${InvDkGray}${CWhite} Connection Throughput Threshold Selections ${CClear}" echo -e "${InvGreen} ${CClear}" echo -e "${InvGreen} ${CClear} Please indicate below how you would like to configure the visual representation of${CClear}" echo -e "${InvGreen} ${CClear} the Connection Throughput that are displayed in the main UI for each active OVPN/WG${CClear}" echo -e "${InvGreen} ${CClear} Connection. This is very dependent on your own preferences and the total amount of${CClear}" echo -e "${InvGreen} ${CClear} bandwidth your have at your disposal. These ranges represent the different colors${CClear}" echo -e "${InvGreen} ${CClear} ${CGreen}Green${CClear} / ${CYellow}Yellow${CClear} / ${CRed}Red ${CClear} to provide visual indicators of the current speeds your${CClear}" echo -e "${InvGreen} ${CClear} connections are experiencing at that moment. You are able to choose different sets${CClear}" echo -e "${InvGreen} ${CClear} of RX/TX thresholds for those using asymmetric internet connections.${CClear}" echo -e "${InvGreen} ${CClear}" echo -e "${InvGreen} ${CClear} Use the corresponding ${CGreen}()${CClear} key to modify the different thresholds.${CClear}" echo -e "${InvGreen} ${CClear} RX Defaults: 0->100 / 100->250 / 250->Max -- TX Defaults: 0->15 / 15->25 / 25->Max${CClear}" echo -e "${InvGreen} ${CClear}${CDkGray}---------------------------------------------------------------------------------------${CClear}" echo -e "${InvGreen} ${CClear}" echo -e "${InvGreen} ${InvDkGray}${CWhite} RX (Receive) Thresholds ${CClear}" echo -e "${InvGreen} ${CClear}" echo -e "${InvGreen} ${CClear} ${InvDkGray}${CClear} ${InvGreen}${CWhite} Low Utilization ${CClear} - 0$bwdispval ---> ${CGreen}(1) ${lowutilspd}$bwdispval${CClear}" echo -e "${InvGreen} ${CClear} ${InvDkGray}${CClear} ${InvYellow}${CBlack} Med Utilization ${CClear} - ${lowutilspd}$bwdispval ---> ${CGreen}(2) ${medutilspd}$bwdispval${CClear}" echo -e "${InvGreen} ${CClear} ${InvDkGray}${CClear} ${InvRed}${CWhite} High Utilization ${CClear} - ${medutilspd}$bwdispval ---> Max Limit${CClear}" echo -e "${InvGreen} ${CClear}" echo -e "${InvGreen} ${InvDkGray}${CWhite} TX (Transmit) Thresholds ${CClear}" echo -e "${InvGreen} ${CClear}" echo -e "${InvGreen} ${CClear} ${InvDkGray}${CClear} ${InvGreen}${CWhite} Low Utilization ${CClear} - 0$bwdispval ---> ${CGreen}(3) ${lowutilspdup}$bwdispval${CClear}" echo -e "${InvGreen} ${CClear} ${InvDkGray}${CClear} ${InvYellow}${CBlack} Med Utilization ${CClear} - ${lowutilspdup}$bwdispval ---> ${CGreen}(4) ${medutilspdup}$bwdispval${CClear}" echo -e "${InvGreen} ${CClear} ${InvDkGray}${CClear} ${InvRed}${CWhite} High Utilization ${CClear} - ${medutilspdup}$bwdispval ---> Max Limit${CClear}" echo "" read -p "Please select? (1-4, e=Exit): " SelectSlot case $SelectSlot in 1) echo "" read -p "Please enter the upper 'Low RX Utilization' range (in $bwdispval)? (Default = 100): " lowutilspdchoice if [ "$lowutilspdchoice" -le 0 ] || [ "$lowutilspdchoice" -ge "$medutilspd" ] then echo ""; echo -e "${CRed}ERROR: Your upper 'Low RX Utilization' range must be greater than 0 and less than $medutilspd.${CClear}"; echo "" sleep 3 continue elif [ -z "$lowutilspdchoice" ] then lowutilspd=100 continue else lowutilspd=$lowutilspdchoice continue fi;; 2) echo "" read -p "Please enter the upper 'Med RX Utilization' range (in $bwdispval)? (Default = 250): " medutilspdchoice if [ "$medutilspdchoice" -le "$lowutilspd" ] then echo ""; echo -e "${CRed}ERROR: Your upper 'Med RX Utilization' range must be greater than $lowutilspd.${CClear}"; echo "" sleep 3 continue elif [ -z "$medutilspdchoice" ] then medutilspd=250 continue else medutilspd=$medutilspdchoice continue fi;; 3) echo "" read -p "Please enter the upper 'Low TX Utilization' range (in $bwdispval)? (Default = 15): " lowutilspdupchoice if [ "$lowutilspdupchoice" -le 0 ] || [ "$lowutilspdupchoice" -ge "$medutilspdup" ] then echo ""; echo -e "${CRed}ERROR: Your upper 'Low TX Utilization' range must be greater than 0 and less than $medutilspdup.${CClear}"; echo "" sleep 3 continue elif [ -z "$lowutilspdupchoice" ] then lowutilspdup=15 continue else lowutilspdup=$lowutilspdupchoice continue fi;; 4) echo "" read -p "Please enter the upper 'Med TX Utilization' range (in $bwdispval)? (Default = 25): " medutilspdupchoice if [ "$medutilspdupchoice" -le "$lowutilspdup" ] then echo ""; echo -e "${CRed}ERROR: Your upper 'Med TX Utilization' range must be greater than $lowutilspdup.${CClear}"; echo "" sleep 3 continue elif [ -z "$medutilspdupchoice" ] then medutilspdup=25 continue else medutilspdup=$medutilspdupchoice continue fi;; [Ee]) saveconfig echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - INFO: Connection Speed Threshold Selections Set -- RX: 0->$lowutilspd->$medutilspd->Max | TX: 0->$lowutilspdup->$medutilspdup->Max" >> $logfile timer="$timerloop" break;; esac done ;; 15) clear echo -e "${InvGreen} ${InvDkGray}${CWhite} Connection Throughput Display Method ${CClear}" echo -e "${InvGreen} ${CClear}" echo -e "${InvGreen} ${CClear} Please indicate below what kind of information you would like to display in the${CClear}" echo -e "${InvGreen} ${CClear} Connection Throughput field within the main VPNMON-R3 UI? You have the choice${CClear}" echo -e "${InvGreen} ${CClear} between displaying Average Throughput in Mbps (average speed across tunnels), ${CClear}" echo -e "${InvGreen} ${CClear} or Total Throughput in MB (total amount of data sent/received across tunnels),${CClear}" echo -e "${InvGreen} ${CClear} which is calculated each time your timer restarts.${CClear}" echo -e "${InvGreen} ${CClear}" echo -e "${InvGreen} ${CClear} Use 1 for Average Throughput (in Mbps), 2 for Total Throughput (in MB). (Default = 1)" echo -e "${InvGreen} ${CClear}${CDkGray}---------------------------------------------------------------------------------------${CClear}" echo echo -e "${CClear}Current: ${CGreen}$throughputmethoddisp${CClear}" ; echo read -p "Please Choose? (Avg in Mbps = 1, Ttl in MB = 2, e=Exit): " newthroughputmethod if [ "$newthroughputmethod" = "1" ] then bwdisp=1 throughputmethoddisp="Average Throughput (in Mbps)" echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - INFO: Connection Throughput Display Method set to: Average Throughput (in Mbps)" >> $logfile saveconfig elif [ "$newthroughputmethod" = "2" ] then bwdisp=2 throughputmethoddisp="Total Throughput (in MB)" echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - INFO: Connection Throughput Display Method set to: Total Throughput (in MB)" >> $logfile saveconfig elif [ "$newthroughputmethod" = "e" ] then echo -e "\n[Exiting]"; sleep 2 else bwdisp=1 throughputmethoddisp="Average Throughput (in Mbps)" echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - INFO: Connection Throughput Display Method set to: Average Throughput (in Mbps)" >> $logfile saveconfig fi ;; esac done } # ------------------------------------------------------------------------------------------------------------------------- # uowginitstart is a function that initializes the virtual br0 interface when called from init-start uowginitstart() { if [ -f "$config" ] then source "$config" # Remove added virtual br0 interface if it already exists ifconfig br0:UnboundWG down >/dev/null 2>&1 # Addvirtual br0 interface ifconfig br0:UnboundWG 10.99.88.77 netmask 255.255.255.255 up >/dev/null 2>&1 fi } # ------------------------------------------------------------------------------------------------------------------------- # uowgnatstart is a function that ties the virtual br0 interface to the assigned wgc slot uowgnatstart() { if [ -f "$config" ] then source "$config" # Remove ip rule if it already exists ip rule del prio 11 >/dev/null 2>&1 # Add ip rule to tie br0 interface with assigned wgc slot ip rule add from 10.99.88.77 lookup wgc$unboundwgclient prio 11 >/dev/null 2>&1 fi } # ------------------------------------------------------------------------------------------------------------------------- # vupdate is a function that provides a UI to check for script updates and allows you to install the latest version... vupdate() { updatecheck # Check for the latest version from source repository while true; do clear echo -e "${InvGreen} ${InvDkGray}${CWhite} VPNMON-R3 Update Utility ${CClear}" echo -e "${InvGreen} ${CClear}" echo -e "${InvGreen} ${CClear} This utility allows you to check, download and install updates" echo -e "${InvGreen} ${CClear}${CDkGray}---------------------------------------------------------------------------------------${CClear}" echo "" echo -e "Current Version: ${CGreen}$version${CClear}" echo -e "Updated Version: ${CGreen}$DLversion${CClear}" echo "" if [ "$version" = "$DLversion" ] then echo -e "You are on the latest version! Would you like to download anyways? This will overwrite${CClear}" echo -e "your local copy with the current build.${CClear}" if promptyn "[y/n]: "; then echo "" echo -e "\nDownloading VPNMON-R3 ${CGreen}v$DLversion${CClear}" curl --silent --retry 3 --connect-timeout 3 --max-time 5 --retry-delay 2 --retry-all-errors --fail "https://raw.githubusercontent.com/ViktorJp/VPNMON-R3/main/vpnmon-r3.sh" -o "/jffs/scripts/vpnmon-r3.sh" && chmod 755 "/jffs/scripts/vpnmon-r3.sh" echo "" echo -e "Download successful!${CClear}" echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - INFO: Successfully downloaded and installed VPNMON-R3 v$DLversion" >> $logfile echo "" read -rsp $'Press any key to restart VPNMON-R3...\n' -n1 key exec /jffs/scripts/vpnmon-r3.sh -setup else echo "" echo "" echo -e "Exiting Update Utility...${CClear}" sleep 1 return fi else echo -e "Score! There is a new version out there! Would you like to update?${CClear}" if promptyn "[y/n]: "; then echo "" echo -e "\nDownloading VPNMON-R3 ${CGreen}v$DLversion${CClear}" curl --silent --retry 3 --connect-timeout 3 --max-time 6 --retry-delay 2 --retry-all-errors --fail "https://raw.githubusercontent.com/ViktorJp/VPNMON-R3/main/vpnmon-r3.sh" -o "/jffs/scripts/vpnmon-r3.sh" && chmod 755 "/jffs/scripts/vpnmon-r3.sh" echo "" echo -e "Download successful!${CClear}" echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - INFO: Successfully downloaded and installed VPNMON-R3 v$DLversion" >> $logfile echo "" read -rsp $'Press any key to restart VPNMON-R3...\n' -n1 key exec /jffs/scripts/vpnmon-r3.sh -setup else echo "" echo "" echo -e "Exiting Update Utility...${CClear}" sleep 1 return fi fi done } # ------------------------------------------------------------------------------------------------------------------------- # updatecheck is a function that downloads the latest update version file, and compares it with what's currently installed updatecheck() { # Download the latest version file from the source repository curl --silent --retry 3 --connect-timeout 3 --max-time 6 --retry-delay 2 --retry-all-errors --fail "https://raw.githubusercontent.com/ViktorJp/VPNMON-R3/main/version.txt" -o "/jffs/addons/vpnmon-r3.d/version.txt" if [ -f $dlverpath ] then # Read in its contents for the current version file DLversion=$(cat $dlverpath) # Compare the new version with the old version and log it if [ "$beta" = "1" ]; then # Check if Dev/Beta Mode is enabled and disable notification message UpdateNotify=0 elif [ "$DLversion" != "$version" ]; then DLversionPF=$(printf "%-8s" $DLversion) versionPF=$(printf "%-8s" $version) UpdateNotify="${InvYellow} ${InvDkGray}${CWhite} Update available: v$versionPF -> v$DLversionPF ${CClear}" echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - INFO: A new update (v$DLversion) is available to download" >> $logfile else UpdateNotify=0 fi fi } # ------------------------------------------------------------------------------------------------------------------------- # vuninstall is a function that uninstalls and removes all traces of vpnmon-r3 from your router... vuninstall() { while true; do clear echo -e "${InvGreen} ${InvDkGray}${CWhite} Uninstall Utility ${CClear}" echo -e "${InvGreen} ${CClear}" echo -e "${InvGreen} ${CClear} You are about to uninstall VPNMON-R3! This action is irreversible." echo -e "${InvGreen} ${CClear}${CDkGray}---------------------------------------------------------------------------------------${CClear}" echo "" echo -e "Do you wish to proceed?${CClear}" if promptyn "(y/n): "; then echo "" echo -e "\nAre you sure? Please type 'y' to validate you wish to proceed.${CClear}" if promptyn "(y/n): "; then clear #Remove and uninstall files/directories rm -f -r /jffs/addons/vpnmon-r3.d rm -f /jffs/scripts/vpnmon-r3.sh sed -i -e '/vpnmon-r3.sh/d' /jffs/scripts/services-start cru d RunVPNMONR3reset echo "" echo -e "\nVPNMON-R3 has been uninstalled...${CClear}" echo "" exit 0 else echo "" echo -e "\nExiting Uninstall Utility...${CClear}" sleep 1 return fi else echo "" echo -e "\nExiting Uninstall Utility...${CClear}" sleep 1 return fi done } # ------------------------------------------------------------------------------------------------------------------------- # vlogs is a function that calls the nano text editor to view the BACKUPMON log file vlogs() { export TERM=linux nano +999999 --linenumbers $logfile timer="$timerloop" } # ------------------------------------------------------------------------------------------------------------------------- # vpnslots lets you pick which vpn slot numbers are being monitored by vpnmon-r3 vpnslots() { while true do clear echo -e "${InvGreen} ${InvDkGray}${CWhite} VPN/WG Client Slot Monitoring ${CClear}" echo -e "${InvGreen} ${CClear}" echo -e "${InvGreen} ${CClear} Please indicate which VPN/WG slots you would like VPNMON-R3 to monitor, or to${CClear}" echo -e "${InvGreen} ${CClear} alternatively reset the connected time on an active VPN/WG connection. Monitoring${CClear}" echo -e "${InvGreen} ${CClear} a VPN/WG connection ensures that VPNMON-R3 will actively keep a watch over it, and${CClear}" echo -e "${InvGreen} ${CClear} will reset it should the connection go down, or ping times go above set limits.${CClear}" echo -e "${InvGreen} ${CClear} A Connection Time reset may be necessary for WG connections at times, as a router${CClear}" echo -e "${InvGreen} ${CClear} reboot will start the WG tunnels up before VPNMON-R3 is able to start, and is not${CClear}" echo -e "${InvGreen} ${CClear} aware that they were restarted.${CClear}" echo -e "${InvGreen} ${CClear}" echo -e "${InvGreen} ${CClear} Use the corresponding ${CGreen}()${CClear} key to enable/disable monitoring or to reset the time${CClear}" echo -e "${InvGreen} ${CClear} for each connected slot:${CClear}" echo -e "${InvGreen} ${CClear}${CDkGray}---------------------------------------------------------------------------------------${CClear}" if [ "$availableslots" = "1 2" ] then if [ "$VPN1" = "1" ]; then VPN1Disp="${CGreen}Y${CCyan}"; else VPN1=0; VPN1Disp="${CRed}N${CCyan}"; fi if [ "$VPN2" = "1" ]; then VPN2Disp="${CGreen}Y${CCyan}"; else VPN2=0; VPN2Disp="${CRed}N${CCyan}"; fi currtime=$(date +%s) if [ "$VPNTIMER1" -gt 0 ]; then timediffvpn1=$((currtime-VPNTIMER1)); sincelastresetvpn1=$(printf '%dd %02dh:%02dm\n' $(($timediffvpn1/86400)) $(($timediffvpn1%86400/3600)) $(($timediffvpn1%3600/60))); else sincelastresetvpn1="${CDkGray}Disabled"; fi if [ "$VPNTIMER2" -gt 0 ]; then timediffvpn2=$((currtime-VPNTIMER2)); sincelastresetvpn2=$(printf '%dd %02dh:%02dm\n' $(($timediffvpn2/86400)) $(($timediffvpn2%86400/3600)) $(($timediffvpn2%3600/60))); else sincelastresetvpn2="${CDkGray}Disabled"; fi echo -e "${InvGreen} ${CClear}" echo -e "${InvGreen} ${CClear} ${CWhite} Monitored? Y/N ${CClear}|${CWhite} Time Connected / Reset? ${CClear}" echo -e "${InvGreen} ${CClear} |" echo -e "${InvGreen} ${CClear} ${InvDkGray}${CWhite}VPN1${CClear} ${CGreen}(1) -${CClear} $VPN1Disp | ${CGreen}(!) -${CClear} $sincelastresetvpn1 ${CClear}" echo -e "${InvGreen} ${CClear} ${InvDkGray}${CWhite}VPN2${CClear} ${CGreen}(2) -${CClear} $VPN2Disp | ${CGreen}(@) -${CClear} $sincelastresetvpn2 ${CClear}" echo -e "${InvGreen} ${CClear}" echo -e "${InvGreen} ${CClear}${CDkGray}---------------------------------------------------------------------------------------${CClear}" echo "" read -p "Please select? (1-2, !-@, e=Exit): " SelectSlot case $SelectSlot in 1) currvpn1state="$(_VPN_GetClientState_ "1")"; if [ "$VPN1" = "0" ] && [ "$currvpn1state" -eq 2 ]; then VPN1=1; VPNTIMER1=$(date +%s); VPN1Disp="${CGreen}Y${CCyan}"; elif [ "$VPN1" = "1" ]; then VPN1=0; VPNTIMER2=0; VPN1Disp="${CRed}N${CCyan}"; fi;; 2) currvpn2state="$(_VPN_GetClientState_ "2")"; if [ "$VPN2" = "0" ] && [ "$currvpn2state" -eq 2 ]; then VPN2=1; VPNTIMER2=$(date +%s); VPN2Disp="${CGreen}Y${CCyan}"; elif [ "$VPN2" = "1" ]; then VPN2=0; VPNTIMER2=0; VPN2Disp="${CRed}N${CCyan}"; fi;; [\!]) if [ "$VPN1" = "1" ]; then VPNTIMER1=$(date +%s); else VPNTIMER1=0; fi;; [\@]) if [ "$VPN2" = "1" ]; then VPNTIMER2=$(date +%s); else VPNTIMER2=0; fi;; [Ee]) { echo 'VPN1='$VPN1 echo 'VPN2='$VPN2 } > /jffs/addons/vpnmon-r3.d/vr3clients.txt { echo 'VPNTIMER1='$VPNTIMER1 echo 'VPNTIMER2='$VPNTIMER2 } > /jffs/addons/vpnmon-r3.d/vr3timers.txt echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - INFO: VPN/WG Client Slot Monitoring configuration / Connection Time Resets Saved" >> $logfile timer="$timerloop" break;; esac elif [ "$availableslots" = "1 2 3 4 5" ] then if [ "$VPN1" = "1" ]; then VPN1Disp="${CGreen}Y${CClear}"; else VPN1=0; VPN1Disp="${CRed}N${CClear}"; fi if [ "$VPN2" = "1" ]; then VPN2Disp="${CGreen}Y${CClear}"; else VPN2=0; VPN2Disp="${CRed}N${CClear}"; fi if [ "$VPN3" = "1" ]; then VPN3Disp="${CGreen}Y${CClear}"; else VPN3=0; VPN3Disp="${CRed}N${CClear}"; fi if [ "$VPN4" = "1" ]; then VPN4Disp="${CGreen}Y${CClear}"; else VPN4=0; VPN4Disp="${CRed}N${CClear}"; fi if [ "$VPN5" = "1" ]; then VPN5Disp="${CGreen}Y${CClear}"; else VPN5=0; VPN5Disp="${CRed}N${CClear}"; fi if [ "$WG1" = "1" ]; then WG1Disp="${CGreen}Y${CClear}"; else WG1=0; WG1Disp="${CRed}N${CClear}"; fi if [ "$WG2" = "1" ]; then WG2Disp="${CGreen}Y${CClear}"; else WG2=0; WG2Disp="${CRed}N${CClear}"; fi if [ "$WG3" = "1" ]; then WG3Disp="${CGreen}Y${CClear}"; else WG3=0; WG3Disp="${CRed}N${CClear}"; fi if [ "$WG4" = "1" ]; then WG4Disp="${CGreen}Y${CClear}"; else WG4=0; WG4Disp="${CRed}N${CClear}"; fi if [ "$WG5" = "1" ]; then WG5Disp="${CGreen}Y${CClear}"; else WG5=0; WG5Disp="${CRed}N${CClear}"; fi currtime=$(date +%s) if [ "$VPNTIMER1" -gt 0 ]; then timediffvpn1=$((currtime-VPNTIMER1)); sincelastresetvpn1=$(printf '%dd %02dh:%02dm\n' $(($timediffvpn1/86400)) $(($timediffvpn1%86400/3600)) $(($timediffvpn1%3600/60))); else sincelastresetvpn1="${CDkGray}Disabled"; fi if [ "$VPNTIMER2" -gt 0 ]; then timediffvpn2=$((currtime-VPNTIMER2)); sincelastresetvpn2=$(printf '%dd %02dh:%02dm\n' $(($timediffvpn2/86400)) $(($timediffvpn2%86400/3600)) $(($timediffvpn2%3600/60))); else sincelastresetvpn2="${CDkGray}Disabled"; fi if [ "$VPNTIMER3" -gt 0 ]; then timediffvpn3=$((currtime-VPNTIMER3)); sincelastresetvpn3=$(printf '%dd %02dh:%02dm\n' $(($timediffvpn3/86400)) $(($timediffvpn3%86400/3600)) $(($timediffvpn3%3600/60))); else sincelastresetvpn3="${CDkGray}Disabled"; fi if [ "$VPNTIMER4" -gt 0 ]; then timediffvpn4=$((currtime-VPNTIMER4)); sincelastresetvpn4=$(printf '%dd %02dh:%02dm\n' $(($timediffvpn4/86400)) $(($timediffvpn4%86400/3600)) $(($timediffvpn4%3600/60))); else sincelastresetvpn4="${CDkGray}Disabled"; fi if [ "$VPNTIMER5" -gt 0 ]; then timediffvpn5=$((currtime-VPNTIMER5)); sincelastresetvpn5=$(printf '%dd %02dh:%02dm\n' $(($timediffvpn5/86400)) $(($timediffvpn5%86400/3600)) $(($timediffvpn5%3600/60))); else sincelastresetvpn5="${CDkGray}Disabled"; fi if [ "$WGTIMER1" -gt 0 ]; then timediffwg1=$((currtime-WGTIMER1)); sincelastresetwg1=$(printf '%dd %02dh:%02dm\n' $(($timediffwg1/86400)) $(($timediffwg1%86400/3600)) $(($timediffwg1%3600/60))); else sincelastresetwg1="${CDkGray}Disabled"; fi if [ "$WGTIMER2" -gt 0 ]; then timediffwg2=$((currtime-WGTIMER2)); sincelastresetwg2=$(printf '%dd %02dh:%02dm\n' $(($timediffwg2/86400)) $(($timediffwg2%86400/3600)) $(($timediffwg2%3600/60))); else sincelastresetwg2="${CDkGray}Disabled"; fi if [ "$WGTIMER3" -gt 0 ]; then timediffwg3=$((currtime-WGTIMER3)); sincelastresetwg3=$(printf '%dd %02dh:%02dm\n' $(($timediffwg3/86400)) $(($timediffwg3%86400/3600)) $(($timediffwg3%3600/60))); else sincelastresetwg3="${CDkGray}Disabled"; fi if [ "$WGTIMER4" -gt 0 ]; then timediffwg4=$((currtime-WGTIMER4)); sincelastresetwg4=$(printf '%dd %02dh:%02dm\n' $(($timediffwg4/86400)) $(($timediffwg4%86400/3600)) $(($timediffwg4%3600/60))); else sincelastresetwg4="${CDkGray}Disabled"; fi if [ "$WGTIMER5" -gt 0 ]; then timediffwg5=$((currtime-WGTIMER5)); sincelastresetwg5=$(printf '%dd %02dh:%02dm\n' $(($timediffwg5/86400)) $(($timediffwg5%86400/3600)) $(($timediffwg5%3600/60))); else sincelastresetwg5="${CDkGray}Disabled"; fi echo -e "${InvGreen} ${CClear}" echo -e "${InvGreen} ${CClear} ${CWhite} Monitored? Y/N ${CClear}|${CWhite} Time Connected / Reset? ${CClear}" echo -e "${InvGreen} ${CClear} |" echo -e "${InvGreen} ${CClear} ${InvDkGray}${CWhite}VPN1${CClear} ${CGreen}(1) -${CClear} $VPN1Disp | ${CGreen}(!) -${CClear} $sincelastresetvpn1 ${CClear}" echo -e "${InvGreen} ${CClear} ${InvDkGray}${CWhite}VPN2${CClear} ${CGreen}(2) -${CClear} $VPN2Disp | ${CGreen}(@) -${CClear} $sincelastresetvpn2 ${CClear}" echo -e "${InvGreen} ${CClear} ${InvDkGray}${CWhite}VPN3${CClear} ${CGreen}(3) -${CClear} $VPN3Disp | ${CGreen}(#) -${CClear} $sincelastresetvpn3 ${CClear}" echo -e "${InvGreen} ${CClear} ${InvDkGray}${CWhite}VPN4${CClear} ${CGreen}(4) -${CClear} $VPN4Disp | ${CGreen}($) -${CClear} $sincelastresetvpn4 ${CClear}" echo -e "${InvGreen} ${CClear} ${InvDkGray}${CWhite}VPN5${CClear} ${CGreen}(5) -${CClear} $VPN5Disp | ${CGreen}(%) -${CClear} $sincelastresetvpn5 ${CClear}" echo -e "${InvGreen} ${CClear}" echo -e "${InvGreen} ${CClear}${CDkGray}---------------------------------------------------------------------------------------${CClear}" echo -e "${InvGreen} ${CClear}" echo -e "${InvGreen} ${CClear} ${InvDkGray}${CWhite} WG1${CClear} ${CGreen}(6) -${CClear} $WG1Disp | ${CGreen}(^) -${CClear} $sincelastresetwg1 ${CClear}" echo -e "${InvGreen} ${CClear} ${InvDkGray}${CWhite} WG2${CClear} ${CGreen}(7) -${CClear} $WG2Disp | ${CGreen}(&) -${CClear} $sincelastresetwg2 ${CClear}" echo -e "${InvGreen} ${CClear} ${InvDkGray}${CWhite} WG3${CClear} ${CGreen}(8) -${CClear} $WG3Disp | ${CGreen}(-) -${CClear} $sincelastresetwg3 ${CClear}" echo -e "${InvGreen} ${CClear} ${InvDkGray}${CWhite} WG4${CClear} ${CGreen}(9) -${CClear} $WG4Disp | ${CGreen}(+) -${CClear} $sincelastresetwg4 ${CClear}" echo -e "${InvGreen} ${CClear} ${InvDkGray}${CWhite} WG5${CClear} ${CGreen}(0) -${CClear} $WG5Disp | ${CGreen}(=) -${CClear} $sincelastresetwg5 ${CClear}" echo -e "${InvGreen} ${CClear}" echo -e "${InvGreen} ${CClear}${CDkGray}---------------------------------------------------------------------------------------${CClear}" echo "" read -p "Please select? (1-0, !-=, e=Exit): " SelectSlot case $SelectSlot in 1) currvpn1state="$(_VPN_GetClientState_ "1")"; if [ "$VPN1" = "0" ] && [ "$currvpn1state" -eq 2 ]; then VPN1=1; VPNTIMER1=$(date +%s); VPN1Disp="${CGreen}Y${CCyan}"; elif [ "$VPN1" = "1" ]; then VPN1=0; VPNTIMER2=0; VPN1Disp="${CRed}N${CCyan}"; fi;; 2) currvpn2state="$(_VPN_GetClientState_ "2")"; if [ "$VPN2" = "0" ] && [ "$currvpn2state" -eq 2 ]; then VPN2=1; VPNTIMER2=$(date +%s); VPN2Disp="${CGreen}Y${CCyan}"; elif [ "$VPN2" = "1" ]; then VPN2=0; VPNTIMER2=0; VPN2Disp="${CRed}N${CCyan}"; fi;; 3) currvpn3state="$(_VPN_GetClientState_ "3")"; if [ "$VPN3" = "0" ] && [ "$currvpn3state" -eq 2 ]; then VPN3=1; VPNTIMER3=$(date +%s); VPN3Disp="${CGreen}Y${CCyan}"; elif [ "$VPN3" = "1" ]; then VPN3=0; VPNTIMER3=0; VPN3Disp="${CRed}N${CCyan}"; fi;; 4) currvpn4state="$(_VPN_GetClientState_ "4")"; if [ "$VPN4" = "0" ] && [ "$currvpn4state" -eq 2 ]; then VPN4=1; VPNTIMER4=$(date +%s); VPN4Disp="${CGreen}Y${CCyan}"; elif [ "$VPN4" = "1" ]; then VPN4=0; VPNTIMER4=0; VPN4Disp="${CRed}N${CCyan}"; fi;; 5) currvpn5state="$(_VPN_GetClientState_ "5")"; if [ "$VPN5" = "0" ] && [ "$currvpn5state" -eq 2 ]; then VPN5=1; VPNTIMER5=$(date +%s); VPN5Disp="${CGreen}Y${CCyan}"; elif [ "$VPN5" = "1" ]; then VPN5=0; VPNTIMER5=0; VPN5Disp="${CRed}N${CCyan}"; fi;; 6) currwg1state="$(_WG_GetClientState_ "1")"; if [ "$WG1" = "0" ] && [ "$currwg1state" -eq 2 ]; then WG1=1; WGTIMER1=$(date +%s); WG1Disp="${CGreen}Y${CCyan}"; elif [ "$WG1" = "1" ]; then WG1=0; WGTIMER1=0; WG1Disp="${CRed}N${CCyan}"; fi;; 7) currwg2state="$(_WG_GetClientState_ "2")"; if [ "$WG2" = "0" ] && [ "$currwg2state" -eq 2 ]; then WG2=1; WGTIMER2=$(date +%s); WG2Disp="${CGreen}Y${CCyan}"; elif [ "$WG2" = "1" ]; then WG2=0; WGTIMER2=0; WG2Disp="${CRed}N${CCyan}"; fi;; 8) currwg3state="$(_WG_GetClientState_ "3")"; if [ "$WG3" = "0" ] && [ "$currwg3state" -eq 2 ]; then WG3=1; WGTIMER3=$(date +%s); WG3Disp="${CGreen}Y${CCyan}"; elif [ "$WG3" = "1" ]; then WG3=0; WGTIMER3=0; WG3Disp="${CRed}N${CCyan}"; fi;; 9) currwg4state="$(_WG_GetClientState_ "4")"; if [ "$WG4" = "0" ] && [ "$currwg4state" -eq 2 ]; then WG4=1; WGTIMER4=$(date +%s); WG4Disp="${CGreen}Y${CCyan}"; elif [ "$WG4" = "1" ]; then WG4=0; WGTIMER4=0; WG4Disp="${CRed}N${CCyan}"; fi;; 0) currwg5state="$(_WG_GetClientState_ "5")"; if [ "$WG5" = "0" ] && [ "$currwg5state" -eq 2 ]; then WG5=1; WGTIMER5=$(date +%s); WG5Disp="${CGreen}Y${CCyan}"; elif [ "$WG5" = "1" ]; then WG5=0; WGTIMER5=0; WG5Disp="${CRed}N${CCyan}"; fi;; [\!]) if [ "$VPN1" = "1" ]; then VPNTIMER1=$(date +%s); else VPNTIMER1=0; fi;; [\@]) if [ "$VPN2" = "1" ]; then VPNTIMER2=$(date +%s); else VPNTIMER2=0; fi;; [\#]) if [ "$VPN3" = "1" ]; then VPNTIMER3=$(date +%s); else VPNTIMER3=0; fi;; [\$]) if [ "$VPN4" = "1" ]; then VPNTIMER4=$(date +%s); else VPNTIMER4=0; fi;; [\%]) if [ "$VPN5" = "1" ]; then VPNTIMER5=$(date +%s); else VPNTIMER5=0; fi;; [\^]) if [ "$WG1" = "1" ]; then WGTIMER1=$(date +%s); else WGTIMER1=0; fi;; [\&]) if [ "$WG2" = "1" ]; then WGTIMER2=$(date +%s); else WGTIMER2=0; fi;; [\-]) if [ "$WG3" = "1" ]; then WGTIMER3=$(date +%s); else WGTIMER3=0; fi;; [\+]) if [ "$WG4" = "1" ]; then WGTIMER4=$(date +%s); else WGTIMER4=0; fi;; [\=]) if [ "$WG5" = "1" ]; then WGTIMER5=$(date +%s); else WGTIMER5=0; fi;; [Ee]) { echo 'VPN1='$VPN1 echo 'VPN2='$VPN2 echo 'VPN3='$VPN3 echo 'VPN4='$VPN4 echo 'VPN5='$VPN5 echo 'WG1='$WG1 echo 'WG2='$WG2 echo 'WG3='$WG3 echo 'WG4='$WG4 echo 'WG5='$WG5 } > /jffs/addons/vpnmon-r3.d/vr3clients.txt { echo 'VPNTIMER1='$VPNTIMER1 echo 'VPNTIMER2='$VPNTIMER2 echo 'VPNTIMER3='$VPNTIMER3 echo 'VPNTIMER4='$VPNTIMER4 echo 'VPNTIMER5='$VPNTIMER5 echo 'WGTIMER1='$WGTIMER1 echo 'WGTIMER2='$WGTIMER2 echo 'WGTIMER3='$WGTIMER3 echo 'WGTIMER4='$WGTIMER4 echo 'WGTIMER5='$WGTIMER5 } > /jffs/addons/vpnmon-r3.d/vr3timers.txt echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - INFO: VPN/WG Client Slot Monitoring configuration / Connection Time Resets Saved" >> $logfile timer="$timerloop" break;; esac fi done } # ------------------------------------------------------------------------------------------------------------------------- # amtmevents lets you pick success or failure amtm email notification selections amtmevents() { while true do clear echo -e "${InvGreen} ${InvDkGray}${CWhite} AMTM Email Notifications ${CClear}" echo -e "${InvGreen} ${CClear}" echo -e "${InvGreen} ${CClear} Please indicate if you would like VPNMON-R3 to send you email notifications for WAN${CClear}" echo -e "${InvGreen} ${CClear} or VPN slot failures, or successes on scheduled VPN resets, or both? PLEASE NOTE:${CClear}" echo -e "${InvGreen} ${CClear} This does require that AMTM email has been set up successfully under AMTM -> em${CClear}" echo -e "${InvGreen} ${CClear} (email settings). Once you are able to send and receive test emails from AMTM, you${CClear}" echo -e "${InvGreen} ${CClear} may use this functionality in VPNMON-R3. Additionally, this functionality will${CClear}" echo -e "${InvGreen} ${CClear} download an AMTM email interface library courtesy of @Martinsky, and will be${CClear}" echo -e "${InvGreen} ${CClear} located under a new common shared library folder called: /jffs/addons/shared-libs.${CClear}" echo -e "${InvGreen} ${CClear}" echo -e "${InvGreen} ${CClear} Secondarily, you can choose to rate limit the rate at which emails are sent to${CClear}" echo -e "${InvGreen} ${CClear} your email account per hour. (0=Disabled, 1-9999)${CClear}" echo -e "${InvGreen} ${CClear}" echo -e "${InvGreen} ${CClear} Use the corresponding ${CGreen}()${CClear} key to enable/disable email event notifications:${CClear}" echo -e "${InvGreen} ${CClear}${CDkGray}---------------------------------------------------------------------------------------${CClear}" if [ "$amtmemailsuccess" = "1" ]; then amtmemailsuccessdisp="${CGreen}Y${CCyan}"; else amtmemailsuccess=0; amtmemailsuccessdisp="${CRed}N${CCyan}"; saveconfig; fi if [ "$amtmemailfailure" = "1" ]; then amtmemailfailuredisp="${CGreen}Y${CCyan}"; else amtmemailfailure=0; amtmemailfailuredisp="${CRed}N${CCyan}"; saveconfig; fi if [ "$ratelimit" = "0" ]; then ratelimitdisp="Disabled"; else ratelimitdisp=$ratelimit; fi echo -e "${InvGreen} ${CClear}" echo -e "${InvGreen} ${CClear} ${InvDkGray}${CWhite}VPN Success Event Notifications${CClear} ${CGreen}(1) -${CClear} $amtmemailsuccessdisp${CClear}" echo -e "${InvGreen} ${CClear} ${InvDkGray}${CWhite}VPN Failure Event Notifications${CClear} ${CGreen}(2) -${CClear} $amtmemailfailuredisp${CClear}" echo -e "${InvGreen} ${CClear}" echo -e "${InvGreen} ${CClear} ${InvDkGray}${CWhite}Set Email Rate Limit (per hour)${CClear} ${CGreen}(r) - $ratelimitdisp${CClear}" echo "" read -p "Please select? (1-2, r=Set Email Rate Limit, t=Test Email, e=Exit): " SelectSlot case $SelectSlot in 1) if [ "$amtmemailsuccess" = "0" ]; then amtmemailsuccess=1; amtmemailsuccessdisp="${CGreen}Y${CCyan}"; elif [ "$amtmemailsuccess" = "1" ]; then amtmemailsuccess=0; amtmemailsuccessdisp="${CRed}N${CCyan}"; fi;; 2) if [ "$amtmemailfailure" = "0" ]; then amtmemailfailure=1; amtmemailfailuredisp="${CGreen}Y${CCyan}"; elif [ "$amtmemailfailure" = "1" ]; then amtmemailfailure=0; amtmemailfailuredisp="${CRed}N${CCyan}"; fi;; [Tt]) if [ -f "$CUSTOM_EMAIL_LIBFile" ] then . "$CUSTOM_EMAIL_LIBFile" if [ -z "${CEM_LIB_VERSION:+xSETx}" ] || \ _CheckLibraryUpdates_CEM_ "$CUSTOM_EMAIL_LIBDir" quiet then _DownloadCEMLibraryFile_ "update" fi else _DownloadCEMLibraryFile_ "install" fi cemIsFormatHTML=true cemIsVerboseMode=true ## true OR false ## emailBodyTitle="Testing Email Notification" emailSubject="TEST: VPNMON-R3 Email Notification" tmpEMailBodyFile="/tmp/var/tmp/tmpEMailBody_${scriptFileNTag}.$$.TXT" { printf "This is a TEST to check & verify if sending email notifications is working well from VPNMON-R3.\n" } > "$tmpEMailBodyFile" _SendEMailNotification_ "VPNMON-R3 v$version" "$emailSubject" "$tmpEMailBodyFile" "$emailBodyTitle" echo ; echo read -rsp $'Press any key to acknowledge...\n' -n1 key ;; [Rr]) echo "" read -p "Please enter new Email Rate Limit (per hour)? (0=disabled, 1-9999, e=Exit): " newratelimit if [ "$newratelimit" = "e" ] then echo -e "\n[Exiting]"; sleep 2 elif echo "$newratelimit" | grep -qE "^(0|[1-9][0-9]{0,3})$" && \ [ "$newratelimit" -ge 0 ] && [ "$newratelimit" -le 9999 ] then ratelimit="$newratelimit" echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - INFO: New Email Rate Limit entered (per hour): $ratelimit" >> $logfile saveconfig else previousValue="$ratelimit" ratelimit="${ratelimit:=0}" [ "$ratelimit" != "$previousValue" ] && \ echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - INFO: New Email Rate Limit entered (per hour): $ratelimit" >> $logfile saveconfig fi ;; [Ee]) saveconfig echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - INFO: AMTM Email notification configuration saved" >> $logfile timer="$timerloop" break;; esac done } # ------------------------------------------------------------------------------------------------------------------------- # vpnserverlistmaint lets you pick which vpn slot server list you want to edit/maintain vpnserverlistmaint() { while true do clear echo -e "${InvGreen} ${InvDkGray}${CWhite} VPN Client Slot Server List Maintenance ${CClear}" echo -e "${InvGreen} ${CClear}" echo -e "${InvGreen} ${CClear} Please indicate which VPN Slot Server List you would like to edit/maintain.${CClear}" echo -e "${InvGreen} ${CClear} Use the corresponding ${CGreen}()${CClear} key to launch and edit the list with the NANO text editor${CClear}" echo -e "${InvGreen} ${CClear}" echo -e "${InvGreen} ${CClear} VPN INSTRUCTIONS: Enter a single column of IP addresses or hostnames, as required by${CClear}" echo -e "${InvGreen} ${CClear} your VPN provider. ${CClear}" echo -e "${InvGreen} ${CClear}" echo -e "${InvGreen} ${CClear} NANO INSTRUCTIONS: CTRL-O + Enter (save), CTRL-X (exit)${CClear}" echo -e "${InvGreen} ${CClear}${CDkGray}---------------------------------------------------------------------------------------${CClear}" echo -e "${InvGreen} ${CClear}" echo -e "${InvGreen} ${CClear} ${InvDkGray}${CWhite}VPN1${CClear} ${CGreen}(1)${CClear}" if [ -f /jffs/addons/vpnmon-r3.d/vr3svr1.txt ]; then iplist=$(awk -vORS=, '{ print $1 }' /jffs/addons/vpnmon-r3.d/vr3svr1.txt | sed 's/,$/\n/') echo -en "${InvGreen} ${CClear} Contents: "; printf "%.75s>\n" $iplist else echo -e "${InvGreen} ${CClear} Contents: " fi echo -e "${InvGreen} ${CClear}" echo -e "${InvGreen} ${CClear} ${InvDkGray}${CWhite}VPN2${CClear} ${CGreen}(2)${CClear}" if [ -f /jffs/addons/vpnmon-r3.d/vr3svr2.txt ]; then iplist=$(awk -vORS=, '{ print $1 }' /jffs/addons/vpnmon-r3.d/vr3svr2.txt | sed 's/,$/\n/') echo -en "${InvGreen} ${CClear} Contents: "; printf "%.75s>\n" $iplist else echo -e "${InvGreen} ${CClear} Contents: " fi echo -e "${InvGreen} ${CClear}" if [ "$availableslots" = "1 2" ] then echo "" read -p "Please select? (1-2, e=Exit): " SelectSlot case $SelectSlot in 1) export TERM=linux; nano +999999 --linenumbers /jffs/addons/vpnmon-r3.d/vr3svr1.txt;; 2) export TERM=linux; nano +999999 --linenumbers /jffs/addons/vpnmon-r3.d/vr3svr2.txt;; [Ee]) timer="$timerloop" break;; esac fi if [ "$availableslots" = "1 2 3 4 5" ] then echo -e "${InvGreen} ${CClear} ${InvDkGray}${CWhite}VPN3${CClear} ${CGreen}(3)${CClear}" if [ -f /jffs/addons/vpnmon-r3.d/vr3svr3.txt ]; then iplist=$(awk -vORS=, '{ print $1 }' /jffs/addons/vpnmon-r3.d/vr3svr3.txt | sed 's/,$/\n/') echo -en "${InvGreen} ${CClear} Contents: "; printf "%.75s>\n" $iplist else echo -e "${InvGreen} ${CClear} Contents: " fi echo -e "${InvGreen} ${CClear}" echo -e "${InvGreen} ${CClear} ${InvDkGray}${CWhite}VPN4${CClear} ${CGreen}(4)${CClear}" if [ -f /jffs/addons/vpnmon-r3.d/vr3svr4.txt ]; then iplist=$(awk -vORS=, '{ print $1 }' /jffs/addons/vpnmon-r3.d/vr3svr4.txt | sed 's/,$/\n/') echo -en "${InvGreen} ${CClear} Contents: "; printf "%.75s>\n" $iplist else echo -e "${InvGreen} ${CClear} Contents: " fi echo -e "${InvGreen} ${CClear}" echo -e "${InvGreen} ${CClear} ${InvDkGray}${CWhite}VPN5${CClear} ${CGreen}(5)${CClear}" if [ -f /jffs/addons/vpnmon-r3.d/vr3svr5.txt ]; then iplist=$(awk -vORS=, '{ print $1 }' /jffs/addons/vpnmon-r3.d/vr3svr5.txt | sed 's/,$/\n/') echo -en "${InvGreen} ${CClear} Contents: "; printf "%.75s>\n" $iplist else echo -e "${InvGreen} ${CClear} Contents: " fi echo "" read -p "Please select? (1-5, e=Exit): " SelectSlot case $SelectSlot in 1) export TERM=linux; nano +999999 --linenumbers /jffs/addons/vpnmon-r3.d/vr3svr1.txt;; 2) export TERM=linux; nano +999999 --linenumbers /jffs/addons/vpnmon-r3.d/vr3svr2.txt;; 3) export TERM=linux; nano +999999 --linenumbers /jffs/addons/vpnmon-r3.d/vr3svr3.txt;; 4) export TERM=linux; nano +999999 --linenumbers /jffs/addons/vpnmon-r3.d/vr3svr4.txt;; 5) export TERM=linux; nano +999999 --linenumbers /jffs/addons/vpnmon-r3.d/vr3svr5.txt;; [Ee]) timer="$timerloop" break;; esac fi done } # ------------------------------------------------------------------------------------------------------------------------- # wgserverlistmaint lets you pick which wg slot server list you want to edit/maintain wgserverlistmaint() { if [ "$availableslots" = "1 2" ] then return fi while true do clear echo -e "${InvGreen} ${InvDkGray}${CWhite} WG Client Slot Server List Maintenance ${CClear}" echo -e "${InvGreen} ${CClear}" echo -e "${InvGreen} ${CClear} Please indicate which WG Slot Server List you would like to edit/maintain.${CClear}" echo -e "${InvGreen} ${CClear} Use the corresponding ${CGreen}()${CClear} key to launch and edit the list with the NANO text editor${CClear}" echo -e "${InvGreen} ${CClear}" echo -e "${InvGreen} ${CClear} WG INSTRUCTIONS: Enter a 7-field comma-delimited row of WG Connections${CClear}" echo -e "${InvGreen} ${CClear} Format: ${CWhite}ConnectionName,InterfaceIP/Sub,EndpointIP,EndpointPort,PrivateKey,PublicKey,PreSharedKey(Opt)${CClear}" echo -e "${InvGreen} ${CClear} Example: ${CGreen}City WG,10.50.0.2/32,143.32.55.23,34334,fasdkaffkasdjfj=,221t949as2323kf=,23fj39fffjdaf=${CClear}" echo -e "${InvGreen} ${CClear}" echo -e "${InvGreen} ${CClear} NANO INSTRUCTIONS: CTRL-O + Enter (save), CTRL-X (exit)${CClear}" echo -e "${InvGreen} ${CClear}${CDkGray}---------------------------------------------------------------------------------------${CClear}" echo -e "${InvGreen} ${CClear}" echo -e "${InvGreen} ${CClear} ${InvDkGray}${CWhite}WG1${CClear} ${CGreen}(6)${CClear}" if [ -f /jffs/addons/vpnmon-r3.d/vr3wgsvr1.txt ]; then wglist=$(awk -F, '{printf "%s%s", sep, $1; sep=","} END {print ""}' /jffs/addons/vpnmon-r3.d/vr3wgsvr1.txt | awk '{print substr($0, 1, 75) ">"}') echo -en "${InvGreen} ${CClear} Contents: "; echo $wglist else echo -e "${InvGreen} ${CClear} Contents: " fi echo -e "${InvGreen} ${CClear}" echo -e "${InvGreen} ${CClear} ${InvDkGray}${CWhite}WG2${CClear} ${CGreen}(7)${CClear}" if [ -f /jffs/addons/vpnmon-r3.d/vr3wgsvr2.txt ]; then wglist=$(awk -F, '{printf "%s%s", sep, $1; sep=","} END {print ""}' /jffs/addons/vpnmon-r3.d/vr3wgsvr2.txt | awk '{print substr($0, 1, 75) ">"}') echo -en "${InvGreen} ${CClear} Contents: "; echo $wglist else echo -e "${InvGreen} ${CClear} Contents: " fi echo -e "${InvGreen} ${CClear}" echo -e "${InvGreen} ${CClear} ${InvDkGray}${CWhite}WG3${CClear} ${CGreen}(8)${CClear}" if [ -f /jffs/addons/vpnmon-r3.d/vr3wgsvr3.txt ]; then wglist=$(awk -F, '{printf "%s%s", sep, $1; sep=","} END {print ""}' /jffs/addons/vpnmon-r3.d/vr3wgsvr3.txt | awk '{print substr($0, 1, 75) ">"}') echo -en "${InvGreen} ${CClear} Contents: "; echo $wglist else echo -e "${InvGreen} ${CClear} Contents: " fi echo -e "${InvGreen} ${CClear}" echo -e "${InvGreen} ${CClear} ${InvDkGray}${CWhite}WG4${CClear} ${CGreen}(9)${CClear}" if [ -f /jffs/addons/vpnmon-r3.d/vr3wgsvr4.txt ]; then wglist=$(awk -F, '{printf "%s%s", sep, $1; sep=","} END {print ""}' /jffs/addons/vpnmon-r3.d/vr3wgsvr4.txt | awk '{print substr($0, 1, 75) ">"}') echo -en "${InvGreen} ${CClear} Contents: "; echo $wglist else echo -e "${InvGreen} ${CClear} Contents: " fi echo -e "${InvGreen} ${CClear}" echo -e "${InvGreen} ${CClear} ${InvDkGray}${CWhite}WG5${CClear} ${CGreen}(0)${CClear}" if [ -f /jffs/addons/vpnmon-r3.d/vr3wgsvr5.txt ]; then wglist=$(awk -F, '{printf "%s%s", sep, $1; sep=","} END {print ""}' /jffs/addons/vpnmon-r3.d/vr3wgsvr5.txt | awk '{print substr($0, 1, 75) ">"}') echo -en "${InvGreen} ${CClear} Contents: "; echo $wglist else echo -e "${InvGreen} ${CClear} Contents: " fi echo "" read -p "Please select? (6-0, e=Exit): " SelectSlot case $SelectSlot in 6) export TERM=linux; nano +999999 --linenumbers /jffs/addons/vpnmon-r3.d/vr3wgsvr1.txt;; 7) export TERM=linux; nano +999999 --linenumbers /jffs/addons/vpnmon-r3.d/vr3wgsvr2.txt;; 8) export TERM=linux; nano +999999 --linenumbers /jffs/addons/vpnmon-r3.d/vr3wgsvr3.txt;; 9) export TERM=linux; nano +999999 --linenumbers /jffs/addons/vpnmon-r3.d/vr3wgsvr4.txt;; 0) export TERM=linux; nano +999999 --linenumbers /jffs/addons/vpnmon-r3.d/vr3wgsvr5.txt;; [Ee]) timer="$timerloop" break;; esac done } # ------------------------------------------------------------------------------------------------------------------------- # vpnserverlistautomation lets you pick which vpn slot server list automation you want to edit/execute vpnserverlistautomation() { while true do clear echo -e "${InvGreen} ${InvDkGray}${CWhite} WG/VPN Client Slot Server List Automation ${CClear}" echo -e "${InvGreen} ${CClear}" echo -e "${InvGreen} ${CClear} Please indicate which VPN Slot Automation Script you would like to edit/execute.${CClear}" echo -e "${InvGreen} ${CClear} Use the corresponding ${CGreen}()${CClear} key to edit or launch your update statements${CClear}" echo -e "${InvGreen} ${CClear}" echo -e "${InvGreen} ${CClear} VPN INSTRUCTIONS: Insert CURL statement that outputs a single-column Server IP list${CClear}" echo -e "${InvGreen} ${CClear}" echo -e "${InvGreen} ${CClear} WG INSTRUCTIONS: Insert CURL statement that outputs a 7-field comma-separated list${CClear}" echo -e "${InvGreen} ${CClear} Format: ${CWhite}ConnectionName,InterfaceIP/Sub,EndpointIP,EndpointPort,PrivateKey,PublicKey,PreSharedKey(Opt)${CClear}" echo -e "${InvGreen} ${CClear} Example: ${CGreen}City WG,10.50.0.2/32,143.32.55.23,34334,fasdkaffkasdjfj=,221t949as2323kf=,23fj39fffjdaf=${CClear}" echo -e "${InvGreen} ${CClear}${CDkGray}---------------------------------------------------------------------------------------${CClear}" echo -e "${InvGreen} ${CClear}" echo -e "${InvGreen} ${CClear} ${InvDkGray}${CWhite}VPN1${CClear} ${CGreen}(e1)${CClear} View/Edit | ${CGreen}(x1)${CClear} Execute | ${CGreen}(s1)${CClear} Skynet WL Import${CClear}" if [ -z "$automation1" ] || [ "$automation1" = "" ]; then echo -e "${InvGreen} ${CClear} Contents: " else automation1unenc=$(echo "$automation1" | openssl enc -d -base64 -A) echo -en "${InvGreen} ${CClear} Contents: ${InvDkGray}${CWhite}"; printf "%.75s>\n" "$automation1unenc" fi echo -e "${InvGreen} ${CClear}" echo -e "${InvGreen} ${CClear} ${InvDkGray}${CWhite}VPN2${CClear} ${CGreen}(e2)${CClear} View/Edit | ${CGreen}(x2)${CClear} Execute | ${CGreen}(s2)${CClear} Skynet WL Import${CClear}" if [ -z "$automation2" ] || [ "$automation2" = "" ]; then echo -e "${InvGreen} ${CClear} Contents: " else automation2unenc=$(echo "$automation2" | openssl enc -d -base64 -A) echo -en "${InvGreen} ${CClear} Contents: ${InvDkGray}${CWhite}"; printf "%.75s>\n" "$automation2unenc" fi echo -e "${InvGreen} ${CClear}" if [ "$availableslots" = "1 2" ]; then echo "" read -p "Please select? (e1-e2, x1-x2, s1-s2, e=Exit): " SelectSlot2 case $SelectSlot2 in e1) echo "" if [ "$automation1" = "" ] || [ -z "$automation1" ]; then echo -e "${CClear}Old Script: " echo "" else echo -en "${CClear}Old Script: "; echo "$automation1" | openssl enc -d -base64 -A echo "" fi read -rp 'Enter New Script (e=Exit): ' automation1new if [ "$automation1new" = "" ] || [ -z "$automation1new" ]; then automation1="" saveconfig elif [ "$automation1new" = "e" ]; then echo ""; echo -e "${CGreen}[Exiting]${CClear}"; sleep 1 else automation1=`echo $automation1new | openssl enc -base64 -A` echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - INFO: New Custom VPN Server List Command entered for VPN Slot 1" >> $logfile saveconfig fi ;; x1) echo "" echo -e "${CGreen}[Executing Script]${CClear}" automation1unenc=$(echo "$automation1" | openssl enc -d -base64 -A) echo -e "${CClear}Running: $automation1unenc" echo "" eval "$automation1unenc" > /jffs/addons/vpnmon-r3.d/vr3svrtmp.txt #Determine how many server entries are in each of the vpn slot alternate server files if [ -f /jffs/addons/vpnmon-r3.d/vr3svrtmp.txt ]; then dlcnt=$(cat /jffs/addons/vpnmon-r3.d/vr3svrtmp.txt | wc -l) >/dev/null 2>&1 if [ $dlcnt -lt 1 ]; then dlcnt=0 elif [ -z $dlcnt ]; then dlcnt=0 fi else dlcnt=0 fi if [ "$dlcnt" -gt 1 ] then cp "/jffs/addons/vpnmon-r3.d/vr3svrtmp.txt" "/jffs/addons/vpnmon-r3.d/vr3svr1.txt" >/dev/null 2>&1 rm -f "/jffs/addons/vpnmon-r3.d/vr3svrtmp.txt" >/dev/null 2>&1 echo "" echo -e "${CGreen}[$dlcnt Rows Retrieved From Source]${CClear}" echo "" echo -e "${CGreen}[Saved to VPN Client Slot 1 Server List]${CClear}" echo "" echo -e "${CGreen}[Execution Complete]${CClear}" echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - INFO: Custom VPN Server List Command executed for VPN Slot 1" >> $logfile echo "" skynetwhitelist 1 echo "" read -rsp $'Press any key to acknowledge...\n' -n1 key else rm -f "/jffs/addons/vpnmon-r3.d/vr3svrtmp.txt" >/dev/null 2>&1 echo "" echo -e "${CGreen}[$dlcnt Rows Retrieved From Source - Preserving Original Server List]${CClear}" echo "" echo -e "${CGreen}[Please check Query Language or VPN Service API may be down]${CClear}" echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - ERROR: Custom VPN Client Server List Query for VPN Slot 1 yielded 0 rows -- Query may be invalid or VPN API service may be down" >> $logfile echo "" read -rsp $'Press any key to acknowledge...\n' -n1 key fi ;; s1) echo "" echo -e "${CGreen}[Executing Skynet Whitelist Import]${CClear}" firewall import whitelist /jffs/addons/vpnmon-r3.d/vr3svr1.txt "VPNMON-R3 VPN Slot 1 Import" >/dev/null 2>&1 echo "" echo -e "${CGreen}[Contents of VPN Slot 1 Imported]${CClear}" echo "" echo -e "${CGreen}[Execution Complete]${CClear}" echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - INFO: Skynet Whitelist imported for VPN Slot 1" >> $logfile echo "" read -rsp $'Press any key to acknowledge...\n' -n1 key ;; e2) echo "" if [ "$automation2" = "" ] || [ -z "$automation2" ]; then echo -e "${CClear}Old Script: " echo "" else echo -en "${CClear}Old Script: "; echo "$automation2" | openssl enc -d -base64 -A echo "" fi read -rp 'Enter New Script (e=Exit): ' automation2new if [ "$automation2new" = "" ] || [ -z "$automation2new" ]; then automation2="" saveconfig elif [ "$automation2new" = "e" ]; then echo ""; echo -e "${CGreen}[Exiting]${CClear}"; sleep 1 else automation2=`echo $automation2new | openssl enc -base64 -A` echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - INFO: New Custom VPN Server List Command entered for VPN Slot 2" >> $logfile saveconfig fi ;; x2) echo "" echo -e "${CGreen}[Executing Script]${CClear}" automation2unenc=$(echo "$automation2" | openssl enc -d -base64 -A) echo -e "${CClear}Running: $automation2unenc" echo "" eval "$automation2unenc" > /jffs/addons/vpnmon-r3.d/vr3svrtmp.txt #Determine how many server entries are in each of the vpn slot alternate server files if [ -f /jffs/addons/vpnmon-r3.d/vr3svrtmp.txt ]; then dlcnt=$(cat /jffs/addons/vpnmon-r3.d/vr3svrtmp.txt | wc -l) >/dev/null 2>&1 if [ $dlcnt -lt 1 ]; then dlcnt=0 elif [ -z $dlcnt ]; then dlcnt=0 fi else dlcnt=0 fi if [ "$dlcnt" -gt 1 ] then cp "/jffs/addons/vpnmon-r3.d/vr3svrtmp.txt" "/jffs/addons/vpnmon-r3.d/vr3svr2.txt" >/dev/null 2>&1 rm -f "/jffs/addons/vpnmon-r3.d/vr3svrtmp.txt" >/dev/null 2>&1 echo "" echo -e "${CGreen}[$dlcnt Rows Retrieved From Source]${CClear}" echo "" echo -e "${CGreen}[Saved to VPN Client Slot 2 Server List]${CClear}" echo "" echo -e "${CGreen}[Execution Complete]${CClear}" echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - INFO: Custom VPN Server List Command executed for VPN Slot 2" >> $logfile echo "" skynetwhitelist 2 echo "" read -rsp $'Press any key to acknowledge...\n' -n1 key else rm -f "/jffs/addons/vpnmon-r3.d/vr3svrtmp.txt" >/dev/null 2>&1 echo "" echo -e "${CGreen}[$dlcnt Rows Retrieved From Source - Preserving Original Server List]${CClear}" echo "" echo -e "${CGreen}[Please check Query Language or VPN Service API may be down]${CClear}" echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - ERROR: Custom VPN Client Server List Query for VPN Slot 2 yielded 0 rows -- Query may be invalid or VPN API service may be down" >> $logfile echo "" read -rsp $'Press any key to acknowledge...\n' -n1 key fi ;; s2) echo "" echo -e "${CGreen}[Executing Skynet Whitelist Import]${CClear}" firewall import whitelist /jffs/addons/vpnmon-r3.d/vr3svr2.txt "VPNMON-R3 VPN Slot 2 Import" >/dev/null 2>&1 echo "" echo -e "${CGreen}[Contents of VPN Slot 2 Imported]${CClear}" echo "" echo -e "${CGreen}[Execution Complete]${CClear}" echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - INFO: Skynet Whitelist imported for VPN Slot 2" >> $logfile echo "" read -rsp $'Press any key to acknowledge...\n' -n1 key ;; [Ee]) timer="$timerloop" break;; esac fi if [ "$availableslots" = "1 2 3 4 5" ]; then echo -e "${InvGreen} ${CClear} ${InvDkGray}${CWhite}VPN3${CClear} ${CGreen}(e3)${CClear} View/Edit | ${CGreen}(x3)${CClear} Execute | ${CGreen}(s3)${CClear} Skynet WL Import${CClear}" if [ -z "$automation3" ] || [ "$automation3" = "" ]; then echo -e "${InvGreen} ${CClear} Contents: " else automation3unenc=$(echo "$automation3" | openssl enc -d -base64 -A) echo -en "${InvGreen} ${CClear} Contents: ${InvDkGray}${CWhite}"; printf "%.75s>\n" "$automation3unenc" fi echo -e "${InvGreen} ${CClear}" echo -e "${InvGreen} ${CClear} ${InvDkGray}${CWhite}VPN4${CClear} ${CGreen}(e4)${CClear} View/Edit | ${CGreen}(x4)${CClear} Execute | ${CGreen}(s4)${CClear} Skynet WL Import${CClear}" if [ -z "$automation4" ] || [ "$automation4" = "" ]; then echo -e "${InvGreen} ${CClear} Contents: " else automation4unenc=$(echo "$automation4" | openssl enc -d -base64 -A) echo -en "${InvGreen} ${CClear} Contents: ${InvDkGray}${CWhite}"; printf "%.75s>\n" "$automation4unenc" fi echo -e "${InvGreen} ${CClear}" echo -e "${InvGreen} ${CClear} ${InvDkGray}${CWhite}VPN5${CClear} ${CGreen}(e5)${CClear} View/Edit | ${CGreen}(x5)${CClear} Execute | ${CGreen}(s5)${CClear} Skynet WL Import${CClear}" if [ -z "$automation5" ] || [ "$automation5" = "" ]; then echo -e "${InvGreen} ${CClear} Contents: " else automation5unenc=$(echo "$automation5" | openssl enc -d -base64 -A) echo -en "${InvGreen} ${CClear} Contents: ${InvDkGray}${CWhite}"; printf "%.75s>\n" "$automation5unenc" fi echo -e "${InvGreen} ${CClear}" ##-------------------------------------## ## Added by Dan G. [2025-Jul-15] ## ##-------------------------------------## echo -e "${InvGreen} ${CClear} ${InvDkGray}${CWhite} WG1${CClear} ${CGreen}(e6)${CClear} View/Edit | ${CGreen}(x6)${CClear} Execute | ${CGreen}(s6)${CClear} Skynet WL Import${CClear}" if [ -z "$wgautomation1" ] || [ "$wgautomation1" = "" ]; then echo -e "${InvGreen} ${CClear} Contents: " else wgautomation1unenc=$(echo "$wgautomation1" | openssl enc -d -base64 -A) echo -en "${InvGreen} ${CClear} Contents: ${InvDkGray}${CWhite}"; printf "%.75s>\n" "$wgautomation1unenc" fi echo -e "${InvGreen} ${CClear}" echo -e "${InvGreen} ${CClear} ${InvDkGray}${CWhite} WG2${CClear} ${CGreen}(e7)${CClear} View/Edit | ${CGreen}(x7)${CClear} Execute | ${CGreen}(s7)${CClear} Skynet WL Import${CClear}" if [ -z "$wgautomation2" ] || [ "$wgautomation2" = "" ]; then echo -e "${InvGreen} ${CClear} Contents: " else wgautomation2unenc=$(echo "$wgautomation2" | openssl enc -d -base64 -A) echo -en "${InvGreen} ${CClear} Contents: ${InvDkGray}${CWhite}"; printf "%.75s>\n" "$wgautomation2unenc" fi echo -e "${InvGreen} ${CClear}" echo -e "${InvGreen} ${CClear} ${InvDkGray}${CWhite} WG3${CClear} ${CGreen}(e8)${CClear} View/Edit | ${CGreen}(x8)${CClear} Execute | ${CGreen}(s8)${CClear} Skynet WL Import${CClear}" if [ -z "$wgautomation3" ] || [ "$wgautomation3" = "" ]; then echo -e "${InvGreen} ${CClear} Contents: " else wgautomation3unenc=$(echo "$wgautomation3" | openssl enc -d -base64 -A) echo -en "${InvGreen} ${CClear} Contents: ${InvDkGray}${CWhite}"; printf "%.75s>\n" "$wgautomation3unenc" fi echo -e "${InvGreen} ${CClear}" echo -e "${InvGreen} ${CClear} ${InvDkGray}${CWhite} WG4${CClear} ${CGreen}(e9)${CClear} View/Edit | ${CGreen}(x9)${CClear} Execute | ${CGreen}(s9)${CClear} Skynet WL Import${CClear}" if [ -z "$wgautomation4" ] || [ "$wgautomation4" = "" ]; then echo -e "${InvGreen} ${CClear} Contents: " else wgautomation4unenc=$(echo "$wgautomation4" | openssl enc -d -base64 -A) echo -en "${InvGreen} ${CClear} Contents: ${InvDkGray}${CWhite}"; printf "%.75s>\n" "$wgautomation4unenc" fi echo -e "${InvGreen} ${CClear}" echo -e "${InvGreen} ${CClear} ${InvDkGray}${CWhite} WG5${CClear} ${CGreen}(e0)${CClear} View/Edit | ${CGreen}(x0)${CClear} Execute | ${CGreen}(s0)${CClear} Skynet WL Import${CClear}" if [ -z "$wgautomation5" ] || [ "$wgautomation5" = "" ]; then echo -e "${InvGreen} ${CClear} Contents: " else wgautomation5unenc=$(echo "$wgautomation5" | openssl enc -d -base64 -A) echo -en "${InvGreen} ${CClear} Contents: ${InvDkGray}${CWhite}"; printf "%.75s>\n" "$wgautomation5unenc" fi echo "" read -p "Please select? (e1-e0, x1-x0, s1-s0, e=Exit): " SelectSlot5 case $SelectSlot5 in e1) echo "" if [ "$automation1" = "" ] || [ -z "$automation1" ]; then echo -e "${CClear}Old Script: " echo "" else echo -en "${CClear}Old Script: "; echo "$automation1" | openssl enc -d -base64 -A echo "" fi read -rp 'Enter New Script (e=Exit): ' automation1new if [ "$automation1new" = "" ] || [ -z "$automation1new" ]; then automation1="" saveconfig elif [ "$automation1new" = "e" ]; then echo ""; echo -e "${CGreen}[Exiting]${CClear}"; sleep 1 else automation1=`echo $automation1new | openssl enc -base64 -A` echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - INFO: New Custom VPN Server List Command entered for VPN Slot 1" >> $logfile saveconfig fi ;; x1) echo "" echo -e "${CGreen}[Executing Script]${CClear}" automation1unenc=$(echo "$automation1" | openssl enc -d -base64 -A) echo -e "${CClear}Running: $automation1unenc" echo "" eval "$automation1unenc" > /jffs/addons/vpnmon-r3.d/vr3svrtmp.txt #Determine how many server entries are in each of the vpn slot alternate server files if [ -f /jffs/addons/vpnmon-r3.d/vr3svrtmp.txt ]; then dlcnt=$(cat /jffs/addons/vpnmon-r3.d/vr3svrtmp.txt | wc -l) >/dev/null 2>&1 if [ $dlcnt -lt 1 ]; then dlcnt=0 elif [ -z $dlcnt ]; then dlcnt=0 fi else dlcnt=0 fi if [ "$dlcnt" -gt 1 ] then cp "/jffs/addons/vpnmon-r3.d/vr3svrtmp.txt" "/jffs/addons/vpnmon-r3.d/vr3svr1.txt" >/dev/null 2>&1 rm -f "/jffs/addons/vpnmon-r3.d/vr3svrtmp.txt" >/dev/null 2>&1 echo "" echo -e "${CGreen}[$dlcnt Rows Retrieved From Source]${CClear}" echo "" echo -e "${CGreen}[Saved to VPN Client Slot 1 Server List]${CClear}" echo "" echo -e "${CGreen}[Execution Complete]${CClear}" echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - INFO: Custom VPN Server List Command executed for VPN Slot 1" >> $logfile echo "" skynetwhitelist 1 echo "" read -rsp $'Press any key to acknowledge...\n' -n1 key else rm -f "/jffs/addons/vpnmon-r3.d/vr3svrtmp.txt" >/dev/null 2>&1 echo "" echo -e "${CGreen}[$dlcnt Rows Retrieved From Source - Preserving Original Server List]${CClear}" echo "" echo -e "${CGreen}[Please check Query Language or VPN Service API may be down]${CClear}" echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - ERROR: Custom VPN Client Server List Query for VPN Slot 1 yielded 0 rows -- Query may be invalid or VPN API service may be down" >> $logfile echo "" read -rsp $'Press any key to acknowledge...\n' -n1 key fi ;; s1) echo "" echo -e "${CGreen}[Executing Skynet Whitelist Import]${CClear}" firewall import whitelist /jffs/addons/vpnmon-r3.d/vr3svr1.txt "VPNMON-R3 VPN Slot 1 Import" >/dev/null 2>&1 echo "" echo -e "${CGreen}[Contents of VPN Slot 1 Imported]${CClear}" echo "" echo -e "${CGreen}[Execution Complete]${CClear}" echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - INFO: Skynet Whitelist imported for VPN Slot 1" >> $logfile echo "" read -rsp $'Press any key to acknowledge...\n' -n1 key ;; e2) echo "" if [ "$automation2" = "" ] || [ -z "$automation2" ]; then echo -e "${CClear}Old Script: " echo "" else echo -en "${CClear}Old Script: "; echo "$automation2" | openssl enc -d -base64 -A echo "" fi read -rp 'Enter New Script (e=Exit): ' automation2new if [ "$automation2new" = "" ] || [ -z "$automation2new" ]; then automation2="" saveconfig elif [ "$automation2new" = "e" ]; then echo ""; echo -e "${CGreen}[Exiting]${CClear}"; sleep 1 else automation2=`echo $automation2new | openssl enc -base64 -A` echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - INFO: New Custom VPN Server List Command entered for VPN Slot 2" >> $logfile saveconfig fi ;; x2) echo "" echo -e "${CGreen}[Executing Script]${CClear}" automation2unenc=$(echo "$automation2" | openssl enc -d -base64 -A) echo -e "${CClear}Running: $automation2unenc" echo "" eval "$automation2unenc" > /jffs/addons/vpnmon-r3.d/vr3svrtmp.txt #Determine how many server entries are in each of the vpn slot alternate server files if [ -f /jffs/addons/vpnmon-r3.d/vr3svrtmp.txt ]; then dlcnt=$(cat /jffs/addons/vpnmon-r3.d/vr3svrtmp.txt | wc -l) >/dev/null 2>&1 if [ $dlcnt -lt 1 ]; then dlcnt=0 elif [ -z $dlcnt ]; then dlcnt=0 fi else dlcnt=0 fi if [ "$dlcnt" -gt 1 ] then cp "/jffs/addons/vpnmon-r3.d/vr3svrtmp.txt" "/jffs/addons/vpnmon-r3.d/vr3svr2.txt" >/dev/null 2>&1 rm -f "/jffs/addons/vpnmon-r3.d/vr3svrtmp.txt" >/dev/null 2>&1 echo "" echo -e "${CGreen}[$dlcnt Rows Retrieved From Source]${CClear}" echo "" echo -e "${CGreen}[Saved to VPN Client Slot 2 Server List]${CClear}" echo "" echo -e "${CGreen}[Execution Complete]${CClear}" echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - INFO: Custom VPN Server List Command executed for VPN Slot 2" >> $logfile echo "" skynetwhitelist 2 echo "" read -rsp $'Press any key to acknowledge...\n' -n1 key else rm -f "/jffs/addons/vpnmon-r3.d/vr3svrtmp.txt" >/dev/null 2>&1 echo "" echo -e "${CGreen}[$dlcnt Rows Retrieved From Source - Preserving Original Server List]${CClear}" echo "" echo -e "${CGreen}[Please check Query Language or VPN Service API may be down]${CClear}" echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - ERROR: Custom VPN Client Server List Query for VPN Slot 2 yielded 0 rows -- Query may be invalid or VPN API service may be down" >> $logfile echo "" read -rsp $'Press any key to acknowledge...\n' -n1 key fi ;; s2) echo "" echo -e "${CGreen}[Executing Skynet Whitelist Import]${CClear}" firewall import whitelist /jffs/addons/vpnmon-r3.d/vr3svr2.txt "VPNMON-R3 VPN Slot 2 Import" >/dev/null 2>&1 echo "" echo -e "${CGreen}[Contents of VPN Slot 2 Imported]${CClear}" echo "" echo -e "${CGreen}[Execution Complete]${CClear}" echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - INFO: Skynet Whitelist imported for VPN Slot 2" >> $logfile echo "" read -rsp $'Press any key to acknowledge...\n' -n1 key ;; e3) echo "" if [ "$automation3" = "" ] || [ -z "$automation3" ]; then echo -e "${CClear}Old Script: " echo "" else echo -en "${CClear}Old Script: "; echo "$automation3" | openssl enc -d -base64 -A echo "" fi read -rp 'Enter New Script (e=Exit): ' automation3new if [ "$automation3new" = "" ] || [ -z "$automation3new" ]; then automation3="" saveconfig elif [ "$automation3new" = "e" ]; then echo ""; echo -e "${CGreen}[Exiting]${CClear}"; sleep 1 else automation3=`echo $automation3new | openssl enc -base64 -A` echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - INFO: New Custom VPN Server List Command entered for VPN Slot 3" >> $logfile saveconfig fi ;; x3) echo "" echo -e "${CGreen}[Executing Script]${CClear}" automation3unenc=$(echo "$automation3" | openssl enc -d -base64 -A) echo -e "${CClear}Running: $automation3unenc" echo "" eval "$automation3unenc" > /jffs/addons/vpnmon-r3.d/vr3svrtmp.txt #Determine how many server entries are in each of the vpn slot alternate server files if [ -f /jffs/addons/vpnmon-r3.d/vr3svrtmp.txt ]; then dlcnt=$(cat /jffs/addons/vpnmon-r3.d/vr3svrtmp.txt | wc -l) >/dev/null 2>&1 if [ $dlcnt -lt 1 ]; then dlcnt=0 elif [ -z $dlcnt ]; then dlcnt=0 fi else dlcnt=0 fi if [ "$dlcnt" -gt 1 ] then cp "/jffs/addons/vpnmon-r3.d/vr3svrtmp.txt" "/jffs/addons/vpnmon-r3.d/vr3svr3.txt" >/dev/null 2>&1 rm -f "/jffs/addons/vpnmon-r3.d/vr3svrtmp.txt" >/dev/null 2>&1 echo "" echo -e "${CGreen}[$dlcnt Rows Retrieved From Source]${CClear}" echo "" echo -e "${CGreen}[Saved to VPN Client Slot 3 Server List]${CClear}" echo "" echo -e "${CGreen}[Execution Complete]${CClear}" echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - INFO: Custom VPN Server List Command executed for VPN Slot 3" >> $logfile echo "" skynetwhitelist 3 echo "" read -rsp $'Press any key to acknowledge...\n' -n1 key else rm -f "/jffs/addons/vpnmon-r3.d/vr3svrtmp.txt" >/dev/null 2>&1 echo "" echo -e "${CGreen}[$dlcnt Rows Retrieved From Source - Preserving Original Server List]${CClear}" echo "" echo -e "${CGreen}[Please check Query Language or VPN Service API may be down]${CClear}" echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - ERROR: Custom VPN Client Server List Query for VPN Slot 3 yielded 0 rows -- Query may be invalid or VPN API service may be down" >> $logfile echo "" read -rsp $'Press any key to acknowledge...\n' -n1 key fi ;; s3) echo "" echo -e "${CGreen}[Executing Skynet Whitelist Import]${CClear}" firewall import whitelist /jffs/addons/vpnmon-r3.d/vr3svr3.txt "VPNMON-R3 VPN Slot 3 Import" >/dev/null 2>&1 echo "" echo -e "${CGreen}[Contents of VPN Slot 3 Imported]${CClear}" echo "" echo -e "${CGreen}[Execution Complete]${CClear}" echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - INFO: Skynet Whitelist imported for VPN Slot 3" >> $logfile echo "" read -rsp $'Press any key to acknowledge...\n' -n1 key ;; e4) echo "" if [ "$automation4" ="" ] || [ -z "$automation4" ]; then echo -e "${CClear}Old Script: " echo "" else echo -en "${CClear}Old Script: "; echo "$automation4" | openssl enc -d -base64 -A echo "" fi read -rp 'Enter New Script (e=Exit): ' automation4new if [ "$automation4new" = "" ] || [ -z "$automation4new" ]; then automation4="" saveconfig elif [ "$automation4new" = "e" ]; then echo ""; echo -e "${CGreen}[Exiting]${CClear}"; sleep 1 else automation4=`echo $automation4new | openssl enc -base64 -A` echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - INFO: New Custom VPN Server List Command entered for VPN Slot 4" >> $logfile saveconfig fi ;; x4) echo "" echo -e "${CGreen}[Executing Script]${CClear}" automation4unenc=$(echo "$automation4" | openssl enc -d -base64 -A) echo -e "${CClear}Running: $automation4unenc" echo "" eval "$automation4unenc" > /jffs/addons/vpnmon-r3.d/vr3svrtmp.txt #Determine how many server entries are in each of the vpn slot alternate server files if [ -f /jffs/addons/vpnmon-r3.d/vr3svrtmp.txt ]; then dlcnt=$(cat /jffs/addons/vpnmon-r3.d/vr3svrtmp.txt | wc -l) >/dev/null 2>&1 if [ $dlcnt -lt 1 ]; then dlcnt=0 elif [ -z $dlcnt ]; then dlcnt=0 fi else dlcnt=0 fi if [ "$dlcnt" -gt 1 ] then cp "/jffs/addons/vpnmon-r3.d/vr3svrtmp.txt" "/jffs/addons/vpnmon-r3.d/vr3svr4.txt" >/dev/null 2>&1 rm -f "/jffs/addons/vpnmon-r3.d/vr3svrtmp.txt" >/dev/null 2>&1 echo "" echo -e "${CGreen}[$dlcnt Rows Retrieved From Source]${CClear}" echo "" echo -e "${CGreen}[Saved to VPN Client Slot 4 Server List]${CClear}" echo "" echo -e "${CGreen}[Execution Complete]${CClear}" echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - INFO: Custom VPN Server List Command executed for VPN Slot 4" >> $logfile echo "" skynetwhitelist 4 echo "" read -rsp $'Press any key to acknowledge...\n' -n1 key else rm -f "/jffs/addons/vpnmon-r3.d/vr3svrtmp.txt" >/dev/null 2>&1 echo "" echo -e "${CGreen}[$dlcnt Rows Retrieved From Source - Preserving Original Server List]${CClear}" echo "" echo -e "${CGreen}[Please check Query Language or VPN Service API may be down]${CClear}" echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - ERROR: Custom VPN Client Server List Query for VPN Slot 4 yielded 0 rows -- Query may be invalid or VPN API service may be down" >> $logfile echo "" read -rsp $'Press any key to acknowledge...\n' -n1 key fi ;; s4) echo "" echo -e "${CGreen}[Executing Skynet Whitelist Import]${CClear}" firewall import whitelist /jffs/addons/vpnmon-r3.d/vr3svr4.txt "VPNMON-R3 VPN Slot 4 Import" >/dev/null 2>&1 echo "" echo -e "${CGreen}[Contents of VPN Slot 4 Imported]${CClear}" echo "" echo -e "${CGreen}[Execution Complete]${CClear}" echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - INFO: Skynet Whitelist imported for VPN Slot 4" >> $logfile echo "" read -rsp $'Press any key to acknowledge...\n' -n1 key ;; e5) echo "" if [ "$automation5" = "" ] || [ -z "$automation5" ]; then echo -e "${CClear}Old Script: " echo "" else echo -en "${CClear}Old Script: "; echo "$automation5" | openssl enc -d -base64 -A echo "" fi read -rp 'Enter New Script (e=Exit): ' automation5new if [ "$automation5new" = "" ] || [ -z "$automation5new" ]; then automation5="" saveconfig elif [ "$automation5new" = "e" ]; then echo ""; echo -e "${CGreen}[Exiting]${CClear}"; sleep 1 else automation5=`echo $automation5new | openssl enc -base64 -A` echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - INFO: New Custom VPN Server List Command entered for VPN Slot 5" >> $logfile saveconfig fi ;; x5) echo "" echo -e "${CGreen}[Executing Script]${CClear}" automation5unenc=$(echo "$automation5" | openssl enc -d -base64 -A) echo -e "${CClear}Running: $automation5unenc" echo "" eval "$automation5unenc" > /jffs/addons/vpnmon-r3.d/vr3svrtmp.txt #Determine how many server entries are in each of the vpn slot alternate server files if [ -f /jffs/addons/vpnmon-r3.d/vr3svrtmp.txt ]; then dlcnt=$(cat /jffs/addons/vpnmon-r3.d/vr3svrtmp.txt | wc -l) >/dev/null 2>&1 if [ $dlcnt -lt 1 ]; then dlcnt=0 elif [ -z $dlcnt ]; then dlcnt=0 fi else dlcnt=0 fi if [ "$dlcnt" -gt 1 ] then cp "/jffs/addons/vpnmon-r3.d/vr3svrtmp.txt" "/jffs/addons/vpnmon-r3.d/vr3svr5.txt" >/dev/null 2>&1 rm -f "/jffs/addons/vpnmon-r3.d/vr3svrtmp.txt" >/dev/null 2>&1 echo "" echo -e "${CGreen}[$dlcnt Rows Retrieved From Source]${CClear}" echo "" echo -e "${CGreen}[Saved to VPN Client Slot 5 Server List]${CClear}" echo "" echo -e "${CGreen}[Execution Complete]${CClear}" echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - INFO: Custom VPN Server List Command executed for VPN Slot 5" >> $logfile echo "" skynetwhitelist 5 echo "" read -rsp $'Press any key to acknowledge...\n' -n1 key else rm -f "/jffs/addons/vpnmon-r3.d/vr3svrtmp.txt" >/dev/null 2>&1 echo "" echo -e "${CGreen}[$dlcnt Rows Retrieved From Source - Preserving Original Server List]${CClear}" echo "" echo -e "${CGreen}[Please check Query Language or VPN Service API may be down]${CClear}" echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - ERROR: Custom VPN Client Server List Query for VPN Slot 5 yielded 0 rows -- Query may be invalid or VPN API service may be down" >> $logfile echo "" read -rsp $'Press any key to acknowledge...\n' -n1 key fi ;; s5) echo "" echo -e "${CGreen}[Executing Skynet Whitelist Import]${CClear}" firewall import whitelist /jffs/addons/vpnmon-r3.d/vr3svr5.txt "VPNMON-R3 VPN Slot 5 Import" >/dev/null 2>&1 echo "" echo -e "${CGreen}[Contents of VPN Slot 5 Imported]${CClear}" echo "" echo -e "${CGreen}[Execution Complete]${CClear}" echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - INFO: Skynet Whitelist imported for VPN Slot 5" >> $logfile echo "" read -rsp $'Press any key to acknowledge...\n' -n1 key ;; e6) echo "" if [ "$wgautomation1" = "" ] || [ -z "$wgautomation1" ]; then echo -e "${CClear}Old Script: " echo "" else echo -en "${CClear}Old Script: "; echo "$wgautomation1" | openssl enc -d -base64 -A echo "" fi read -rp 'Enter New Script (e=Exit): ' wgautomation1new if [ "$wgautomation1new" = "" ] || [ -z "$wgautomation1new" ]; then wgautomation1="" saveconfig elif [ "$wgautomation1new" = "e" ]; then echo ""; echo -e "${CGreen}[Exiting]${CClear}"; sleep 1 else wgautomation1=`echo $wgautomation1new | openssl enc -base64 -A` echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - INFO: New Custom WG Server List Command entered for WG Slot 1" >> $logfile saveconfig fi ;; x6) echo "" echo -e "${CGreen}[Executing Script]${CClear}" wgautomation1unenc=$(echo "$wgautomation1" | openssl enc -d -base64 -A) echo -e "${CClear}Running: $wgautomation1unenc" echo "" eval "$wgautomation1unenc" > /jffs/addons/vpnmon-r3.d/vr3svrtmp.txt #Determine how many server entries are in each of the vpn slot alternate server files if [ -f /jffs/addons/vpnmon-r3.d/vr3svrtmp.txt ]; then dlcnt=$(cat /jffs/addons/vpnmon-r3.d/vr3svrtmp.txt | wc -l) >/dev/null 2>&1 if [ $dlcnt -lt 1 ]; then dlcnt=0 elif [ -z $dlcnt ]; then dlcnt=0 fi else dlcnt=0 fi if [ "$dlcnt" -gt 1 ] then cp "/jffs/addons/vpnmon-r3.d/vr3svrtmp.txt" "/jffs/addons/vpnmon-r3.d/vr3wgsvr1.txt" >/dev/null 2>&1 rm -f "/jffs/addons/vpnmon-r3.d/vr3svrtmp.txt" >/dev/null 2>&1 echo "" echo -e "${CGreen}[$dlcnt Rows Retrieved From Source]${CClear}" echo "" echo -e "${CGreen}[Saved to WG Client Slot 1 Server List]${CClear}" echo "" echo -e "${CGreen}[Execution Complete]${CClear}" echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - INFO: Custom WG Server List Command executed for WG Slot 1" >> $logfile echo "" skynetwhitelist wg1 echo "" read -rsp $'Press any key to acknowledge...\n' -n1 key else rm -f "/jffs/addons/vpnmon-r3.d/vr3svrtmp.txt" >/dev/null 2>&1 echo "" echo -e "${CGreen}[$dlcnt Rows Retrieved From Source - Preserving Original Server List]${CClear}" echo "" echo -e "${CGreen}[Please check Query Language or WG Service API may be down]${CClear}" echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - ERROR: Custom WG Client Server List Query for WG Slot 1 yielded 0 rows -- Query may be invalid or WG API service may be down" >> $logfile echo "" read -rsp $'Press any key to acknowledge...\n' -n1 key fi ;; s6) echo "" echo -e "${CGreen}[Executing Skynet Whitelist Import]${CClear}" awk -F',' '{print $2}' /jffs/addons/vpnmon-r3.d/vr3wgsvr1.txt > /jffs/addons/vpnmon-r3.d/vr3svrtmp.txt firewall import whitelist /jffs/addons/vpnmon-r3.d/vr3svrtmp.txt "VPNMON-R3 WG Slot 1 Import" >/dev/null 2>&1 rm -f "/jffs/addons/vpnmon-r3.d/vr3svrtmp.txt" >/dev/null 2>&1 echo "" echo -e "${CGreen}[Contents of WG Slot 1 Imported]${CClear}" echo "" echo -e "${CGreen}[Execution Complete]${CClear}" echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - INFO: Skynet Whitelist imported for WG Slot 1" >> $logfile echo "" read -rsp $'Press any key to acknowledge...\n' -n1 key ;; e7) echo "" if [ "$wgautomation2" = "" ] || [ -z "$wgautomation2" ]; then echo -e "${CClear}Old Script: " echo "" else echo -en "${CClear}Old Script: "; echo "$wgautomation2" | openssl enc -d -base64 -A echo "" fi read -rp 'Enter New Script (e=Exit): ' wgautomation2new if [ "$wgautomation2new" = "" ] || [ -z "$wgautomation2new" ]; then wgautomation2="" saveconfig elif [ "$wgautomation2new" = "e" ]; then echo ""; echo -e "${CGreen}[Exiting]${CClear}"; sleep 1 else wgautomation2=`echo $wgautomation2new | openssl enc -base64 -A` echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - INFO: New Custom WG Server List Command entered for WG Slot 2" >> $logfile saveconfig fi ;; x7) echo "" echo -e "${CGreen}[Executing Script]${CClear}" wgautomation2unenc=$(echo "$wgautomation2" | openssl enc -d -base64 -A) echo -e "${CClear}Running: $wgautomation2unenc" echo "" eval "$wgautomation2unenc" > /jffs/addons/vpnmon-r3.d/vr3svrtmp.txt #Determine how many server entries are in each of the vpn slot alternate server files if [ -f /jffs/addons/vpnmon-r3.d/vr3svrtmp.txt ]; then dlcnt=$(cat /jffs/addons/vpnmon-r3.d/vr3svrtmp.txt | wc -l) >/dev/null 2>&1 if [ $dlcnt -lt 1 ]; then dlcnt=0 elif [ -z $dlcnt ]; then dlcnt=0 fi else dlcnt=0 fi if [ "$dlcnt" -gt 1 ] then cp "/jffs/addons/vpnmon-r3.d/vr3svrtmp.txt" "/jffs/addons/vpnmon-r3.d/vr3wgsvr2.txt" >/dev/null 2>&1 rm -f "/jffs/addons/vpnmon-r3.d/vr3svrtmp.txt" >/dev/null 2>&1 echo "" echo -e "${CGreen}[$dlcnt Rows Retrieved From Source]${CClear}" echo "" echo -e "${CGreen}[Saved to WG Client Slot 2 Server List]${CClear}" echo "" echo -e "${CGreen}[Execution Complete]${CClear}" echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - INFO: Custom WG Server List Command executed for WG Slot 2" >> $logfile echo "" skynetwhitelist wg2 echo "" read -rsp $'Press any key to acknowledge...\n' -n1 key else rm -f "/jffs/addons/vpnmon-r3.d/vr3svrtmp.txt" >/dev/null 2>&1 echo "" echo -e "${CGreen}[$dlcnt Rows Retrieved From Source - Preserving Original Server List]${CClear}" echo "" echo -e "${CGreen}[Please check Query Language or WG Service API may be down]${CClear}" echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - ERROR: Custom WG Client Server List Query for WG Slot 2 yielded 0 rows -- Query may be invalid or WG API service may be down" >> $logfile echo "" read -rsp $'Press any key to acknowledge...\n' -n1 key fi ;; s7) echo "" echo -e "${CGreen}[Executing Skynet Whitelist Import]${CClear}" awk -F',' '{print $2}' /jffs/addons/vpnmon-r3.d/vr3wgsvr2.txt > /jffs/addons/vpnmon-r3.d/vr3svrtmp.txt firewall import whitelist /jffs/addons/vpnmon-r3.d/vr3svrtmp.txt "VPNMON-R3 WG Slot 2 Import" >/dev/null 2>&1 rm -f "/jffs/addons/vpnmon-r3.d/vr3svrtmp.txt" >/dev/null 2>&1 echo "" echo -e "${CGreen}[Contents of WG Slot 2 Imported]${CClear}" echo "" echo -e "${CGreen}[Execution Complete]${CClear}" echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - INFO: Skynet Whitelist imported for WG Slot 2" >> $logfile echo "" read -rsp $'Press any key to acknowledge...\n' -n1 key ;; e8) echo "" if [ "$wgautomation3" = "" ] || [ -z "$wgautomation3" ]; then echo -e "${CClear}Old Script: " echo "" else echo -en "${CClear}Old Script: "; echo "$wgautomation3" | openssl enc -d -base64 -A echo "" fi read -rp 'Enter New Script (e=Exit): ' wgautomation3new if [ "$wgautomation3new" = "" ] || [ -z "$wgautomation3new" ]; then wgautomation3="" saveconfig elif [ "$wgautomation3new" = "e" ]; then echo ""; echo -e "${CGreen}[Exiting]${CClear}"; sleep 1 else wgautomation3=`echo $wgautomation3new | openssl enc -base64 -A` echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - INFO: New Custom WG Server List Command entered for WG Slot 3" >> $logfile saveconfig fi ;; x8) echo "" echo -e "${CGreen}[Executing Script]${CClear}" wgautomation3unenc=$(echo "$wgautomation3" | openssl enc -d -base64 -A) echo -e "${CClear}Running: $wgautomation3unenc" echo "" eval "$wgautomation3unenc" > /jffs/addons/vpnmon-r3.d/vr3svrtmp.txt #Determine how many server entries are in each of the vpn slot alternate server files if [ -f /jffs/addons/vpnmon-r3.d/vr3svrtmp.txt ]; then dlcnt=$(cat /jffs/addons/vpnmon-r3.d/vr3svrtmp.txt | wc -l) >/dev/null 2>&1 if [ $dlcnt -lt 1 ]; then dlcnt=0 elif [ -z $dlcnt ]; then dlcnt=0 fi else dlcnt=0 fi if [ "$dlcnt" -gt 1 ] then cp "/jffs/addons/vpnmon-r3.d/vr3svrtmp.txt" "/jffs/addons/vpnmon-r3.d/vr3wgsvr3.txt" >/dev/null 2>&1 rm -f "/jffs/addons/vpnmon-r3.d/vr3svrtmp.txt" >/dev/null 2>&1 echo "" echo -e "${CGreen}[$dlcnt Rows Retrieved From Source]${CClear}" echo "" echo -e "${CGreen}[Saved to WG Client Slot 3 Server List]${CClear}" echo "" echo -e "${CGreen}[Execution Complete]${CClear}" echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - INFO: Custom WG Server List Command executed for WG Slot 3" >> $logfile echo "" skynetwhitelist wg3 echo "" read -rsp $'Press any key to acknowledge...\n' -n1 key else rm -f "/jffs/addons/vpnmon-r3.d/vr3svrtmp.txt" >/dev/null 2>&1 echo "" echo -e "${CGreen}[$dlcnt Rows Retrieved From Source - Preserving Original Server List]${CClear}" echo "" echo -e "${CGreen}[Please check Query Language or WG Service API may be down]${CClear}" echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - ERROR: Custom WG Client Server List Query for WG Slot 3 yielded 0 rows -- Query may be invalid or WG API service may be down" >> $logfile echo "" read -rsp $'Press any key to acknowledge...\n' -n1 key fi ;; s8) echo "" echo -e "${CGreen}[Executing Skynet Whitelist Import]${CClear}" awk -F',' '{print $2}' /jffs/addons/vpnmon-r3.d/vr3wgsvr3.txt > /jffs/addons/vpnmon-r3.d/vr3svrtmp.txt firewall import whitelist /jffs/addons/vpnmon-r3.d/vr3svrtmp.txt "VPNMON-R3 WG Slot 3 Import" >/dev/null 2>&1 rm -f "/jffs/addons/vpnmon-r3.d/vr3svrtmp.txt" >/dev/null 2>&1 echo "" echo -e "${CGreen}[Contents of WG Slot 3 Imported]${CClear}" echo "" echo -e "${CGreen}[Execution Complete]${CClear}" echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - INFO: Skynet Whitelist imported for WG Slot 3" >> $logfile echo "" read -rsp $'Press any key to acknowledge...\n' -n1 key ;; e9) echo "" if [ "$wgautomation4" = "" ] || [ -z "$wgautomation4" ]; then echo -e "${CClear}Old Script: " echo "" else echo -en "${CClear}Old Script: "; echo "$wgautomation4" | openssl enc -d -base64 -A echo "" fi read -rp 'Enter New Script (e=Exit): ' wgautomation4new if [ "$wgautomation4new" = "" ] || [ -z "$wgautomation4new" ]; then wgautomation4="" saveconfig elif [ "$wgautomation4new" = "e" ]; then echo ""; echo -e "${CGreen}[Exiting]${CClear}"; sleep 1 else wgautomation4=`echo $wgautomation4new | openssl enc -base64 -A` echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - INFO: New Custom WG Server List Command entered for WG Slot 4" >> $logfile saveconfig fi ;; x9) echo "" echo -e "${CGreen}[Executing Script]${CClear}" wgautomation4unenc=$(echo "$wgautomation4" | openssl enc -d -base64 -A) echo -e "${CClear}Running: $wgautomation4unenc" echo "" eval "$wgautomation4unenc" > /jffs/addons/vpnmon-r3.d/vr3svrtmp.txt #Determine how many server entries are in each of the vpn slot alternate server files if [ -f /jffs/addons/vpnmon-r3.d/vr3svrtmp.txt ]; then dlcnt=$(cat /jffs/addons/vpnmon-r3.d/vr3svrtmp.txt | wc -l) >/dev/null 2>&1 if [ $dlcnt -lt 1 ]; then dlcnt=0 elif [ -z $dlcnt ]; then dlcnt=0 fi else dlcnt=0 fi if [ "$dlcnt" -gt 1 ] then cp "/jffs/addons/vpnmon-r3.d/vr3svrtmp.txt" "/jffs/addons/vpnmon-r3.d/vr3wgsvr4.txt" >/dev/null 2>&1 rm -f "/jffs/addons/vpnmon-r3.d/vr3svrtmp.txt" >/dev/null 2>&1 echo "" echo -e "${CGreen}[$dlcnt Rows Retrieved From Source]${CClear}" echo "" echo -e "${CGreen}[Saved to WG Client Slot 4 Server List]${CClear}" echo "" echo -e "${CGreen}[Execution Complete]${CClear}" echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - INFO: Custom WG Server List Command executed for WG Slot 4" >> $logfile echo "" skynetwhitelist wg4 echo "" read -rsp $'Press any key to acknowledge...\n' -n1 key else rm -f "/jffs/addons/vpnmon-r3.d/vr3svrtmp.txt" >/dev/null 2>&1 echo "" echo -e "${CGreen}[$dlcnt Rows Retrieved From Source - Preserving Original Server List]${CClear}" echo "" echo -e "${CGreen}[Please check Query Language or WG Service API may be down]${CClear}" echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - ERROR: Custom WG Client Server List Query for WG Slot 4 yielded 0 rows -- Query may be invalid or WG API service may be down" >> $logfile echo "" read -rsp $'Press any key to acknowledge...\n' -n1 key fi ;; s9) echo "" echo -e "${CGreen}[Executing Skynet Whitelist Import]${CClear}" awk -F',' '{print $2}' /jffs/addons/vpnmon-r3.d/vr3wgsvr4.txt > /jffs/addons/vpnmon-r3.d/vr3svrtmp.txt firewall import whitelist /jffs/addons/vpnmon-r3.d/vr3svrtmp.txt "VPNMON-R3 WG Slot 4 Import" >/dev/null 2>&1 rm -f "/jffs/addons/vpnmon-r3.d/vr3svrtmp.txt" >/dev/null 2>&1 echo "" echo -e "${CGreen}[Contents of WG Slot 4 Imported]${CClear}" echo "" echo -e "${CGreen}[Execution Complete]${CClear}" echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - INFO: Skynet Whitelist imported for WG Slot 4" >> $logfile echo "" read -rsp $'Press any key to acknowledge...\n' -n1 key ;; e0) echo "" if [ "$wgautomation5" = "" ] || [ -z "$wgautomation5" ]; then echo -e "${CClear}Old Script: " echo "" else echo -en "${CClear}Old Script: "; echo "$wgautomation5" | openssl enc -d -base64 -A echo "" fi read -rp 'Enter New Script (e=Exit): ' wgautomation5new if [ "$wgautomation5new" = "" ] || [ -z "$wgautomation5new" ]; then wgautomation5="" saveconfig elif [ "$wgautomation5new" = "e" ]; then echo ""; echo -e "${CGreen}[Exiting]${CClear}"; sleep 1 else wgautomation5=`echo $wgautomation5new | openssl enc -base64 -A` echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - INFO: New Custom WG Server List Command entered for WG Slot 5" >> $logfile saveconfig fi ;; x0) echo "" echo -e "${CGreen}[Executing Script]${CClear}" wgautomation5unenc=$(echo "$wgautomation5" | openssl enc -d -base64 -A) echo -e "${CClear}Running: $wgautomation5unenc" echo "" eval "$wgautomation5unenc" > /jffs/addons/vpnmon-r3.d/vr3svrtmp.txt #Determine how many server entries are in each of the vpn slot alternate server files if [ -f /jffs/addons/vpnmon-r3.d/vr3svrtmp.txt ]; then dlcnt=$(cat /jffs/addons/vpnmon-r3.d/vr3svrtmp.txt | wc -l) >/dev/null 2>&1 if [ $dlcnt -lt 1 ]; then dlcnt=0 elif [ -z $dlcnt ]; then dlcnt=0 fi else dlcnt=0 fi if [ "$dlcnt" -gt 1 ] then cp "/jffs/addons/vpnmon-r3.d/vr3svrtmp.txt" "/jffs/addons/vpnmon-r3.d/vr3wgsvr5.txt" >/dev/null 2>&1 rm -f "/jffs/addons/vpnmon-r3.d/vr3svrtmp.txt" >/dev/null 2>&1 echo "" echo -e "${CGreen}[$dlcnt Rows Retrieved From Source]${CClear}" echo "" echo -e "${CGreen}[Saved to WG Client Slot 5 Server List]${CClear}" echo "" echo -e "${CGreen}[Execution Complete]${CClear}" echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - INFO: Custom WG Server List Command executed for WG Slot 5" >> $logfile echo "" skynetwhitelist wg5 echo "" read -rsp $'Press any key to acknowledge...\n' -n1 key else rm -f "/jffs/addons/vpnmon-r3.d/vr3svrtmp.txt" >/dev/null 2>&1 echo "" echo -e "${CGreen}[$dlcnt Rows Retrieved From Source - Preserving Original Server List]${CClear}" echo "" echo -e "${CGreen}[Please check Query Language or WG Service API may be down]${CClear}" echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - ERROR: Custom WG Client Server List Query for WG Slot 5 yielded 0 rows -- Query may be invalid or WG API service may be down" >> $logfile echo "" read -rsp $'Press any key to acknowledge...\n' -n1 key fi ;; s0) echo "" echo -e "${CGreen}[Executing Skynet Whitelist Import]${CClear}" awk -F',' '{print $2}' /jffs/addons/vpnmon-r3.d/vr3wgsvr5.txt > /jffs/addons/vpnmon-r3.d/vr3svrtmp.txt firewall import whitelist /jffs/addons/vpnmon-r3.d/vr3svrtmp.txt "VPNMON-R3 WG Slot 5 Import" >/dev/null 2>&1 rm -f "/jffs/addons/vpnmon-r3.d/vr3svrtmp.txt" >/dev/null 2>&1 echo "" echo -e "${CGreen}[Contents of WG Slot 5 Imported]${CClear}" echo "" echo -e "${CGreen}[Execution Complete]${CClear}" echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - INFO: Skynet Whitelist imported for WG Slot 5" >> $logfile echo "" read -rsp $'Press any key to acknowledge...\n' -n1 key ;; [Ee]) timer="$timerloop" break;; esac fi done } # ------------------------------------------------------------------------------------------------------------------------- # timerloopconfig lets you configure how long you want the timer cycle to last between vpn connection checks ##----------------------------------------## ## Modified by Martinski W. [2024-Nov-02] ## ##----------------------------------------## timerloopconfig() { while true do clear echo -e "${InvGreen} ${InvDkGray}${CWhite} Timer Loop Configuration / Recovery Timeout Opportunities ${CClear}" echo -e "${InvGreen} ${CClear}" echo -e "${InvGreen} ${CClear} Please indicate how long the timer cycle should take between Connectivity checks,${CClear}" echo -e "${InvGreen} ${CClear} as well as the number of Recovery Timeout Opportunities the loop should complete${CClear}" echo -e "${InvGreen} ${CClear} before issuing a connection reset.${CClear}" echo -e "${InvGreen} ${CClear}" echo -e "${InvGreen} ${CClear} Recovery Timeout Opportunities are simply the number of chances the script will${CClear}" echo -e "${InvGreen} ${CClear} give the connection to recover on its own before intervening. With this value${CClear}" echo -e "${InvGreen} ${CClear} defaulting to 1x, if connectivity issues occur within the default 60 second Timer${CClear}" echo -e "${InvGreen} ${CClear} Loop, the connectivity will be reset after those 60 seconds." echo -e "${InvGreen} ${CClear}" echo -e "${InvGreen} ${CClear} Example: 60 Second Timer Loops with 3x Recovery Timeouts would reset the connection${CClear}" echo -e "${InvGreen} ${CClear} after 3 minutes." echo -e "${InvGreen} ${CClear}" echo -e "${InvGreen} ${CClear} (Defaults: Timer Loop = 60 seconds | Recovery Timeouts = 1x)${CClear}" echo -e "${InvGreen} ${CClear}${CDkGray}---------------------------------------------------------------------------------------${CClear}" echo -e "${InvGreen} ${CClear}" echo -e "${InvGreen} ${CClear} Current: Timer Loop = ${CGreen}$timerloop sec ${CClear}| Recovery Timeouts: ${CGreen}${recover}x${CClear}" echo read -p "Please enter new Timer Loop value in seconds [10-999] (e=Exit): " newTimerLoop if [ -z "$newTimerLoop" ] || echo "$newTimerLoop" | grep -qE "^(e|E)$" then if echo "$timerloop" | grep -qE "^([1-9][0-9]{0,2})$" && \ [ "$timerloop" -ge 10 ] && [ "$timerloop" -le 999 ] then timer="$timerloop" printf "\n${CClear}[Exiting]\n" sleep 1 ; break else printf "\n${CRed}*ERROR*: Please enter a valid number between 10 and 999.${CClear}\n" sleep 3 fi elif echo "$newTimerLoop" | grep -qE "^([1-9][0-9]{0,2})$" && \ [ "$newTimerLoop" -ge 10 ] && [ "$newTimerLoop" -le 999 ] then timerloop="$newTimerLoop" echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - INFO: New Timer Loop configuration saved" >> $logfile saveconfig timer="$timerloop" printf "\n${CClear}[OK]\n" sleep 1 else printf "\n${CRed}*ERROR*: Please enter a valid number between 10 and 999.${CClear}\n" sleep 3 fi echo "" read -p "Please enter new Recovery Timeout value [1-9] (e=Exit): " newRecoveryTimeout if [ -z "$newRecoveryTimeout" ] || echo "$newRecoveryTimeout" | grep -qE "^(e|E)$" then if echo "$recover" | grep -qE "^([1-9])$" && \ [ "$recover" -ge 1 ] && [ "$recover" -le 9 ] then printf "\n${CClear}[Exiting]\n" sleep 1 ; break else printf "\n${CRed}*ERROR*: Please enter a valid number between 1 and 9.${CClear}\n" sleep 3 fi elif echo "$newRecoveryTimeout" | grep -qE "^([1-9])$" && \ [ "$newRecoveryTimeout" -ge 1 ] && [ "$newRecoveryTimeout" -le 9 ] then recover="$newRecoveryTimeout" echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - INFO: New Recovery Timeout Opportunity configuration saved" >> $logfile saveconfig printf "\n${CClear}[OK]\n" sleep 1 ; break else printf "\n${CRed}*ERROR*: Please enter a valid number between 1 and 9.${CClear}\n" sleep 3 fi done } # ------------------------------------------------------------------------------------------------------------------------- # maxping lets you configure how high the vpn tunnel ping will get before it's reset ##----------------------------------------## ## Modified by Martinski W. [2024-Oct-05] ## ##----------------------------------------## maxping() { while true do clear echo -e "${InvGreen} ${InvDkGray}${CWhite} Maximum Ping Before Reset ${CClear}" echo -e "${InvGreen} ${CClear}" echo -e "${InvGreen} ${CClear} Please indicate how high the PING can be across your VPN tunnel before resetting the${CClear}" echo -e "${InvGreen} ${CClear} connection in favor of a different server with a lower PING? A connection with a${CClear}" echo -e "${InvGreen} ${CClear} lower PING may provide better network performance and less latency.${CClear}" echo -e "${InvGreen} ${CClear} (Default = 500 milliseconds, Disabled = 0)${CClear}" echo -e "${InvGreen} ${CClear}${CDkGray}---------------------------------------------------------------------------------------${CClear}" echo -e "${InvGreen} ${CClear}" echo -e "${InvGreen} ${CClear} Current: ${CGreen}$pingreset ms${CClear}" echo read -p "Please enter numeric value (0-999)? (0=Disabled, e=Exit): " newPingReset if echo "$newPingReset" | grep -qE "^(0|[1-9][0-9]{0,2})$" && \ [ "$newPingReset" -ge 0 ] && [ "$newPingReset" -le 999 ] then pingreset="$newPingReset" echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - INFO: PING Reset Configuration saved" >> $logfile saveconfig elif [ -z "$newPingReset" ] || echo "$newPingReset" | grep -qE "^(E|e)$" then echo ; echo -e "${CClear}[Exiting]" timer="$timerloop" sleep 2 break else echo echo -e "${CClear}[Please enter value between 0 and 999, e=Exit]" sleep 3 fi done } ##-------------------------------------## ## Added by Martinski W. [2024-Oct-06] ## ##-------------------------------------## _ValidateCronJobHour_() { if [ $# -eq 0 ] || [ -z "$1" ] ; then return 1 ; fi if echo "$1" | grep -qE "^(0|[1-9][0-9]?)$" && \ [ "$1" -ge 0 ] && [ "$1" -lt 24 ] then return 0 ; else return 1 ; fi } _ValidateCronJobMinute_() { if [ $# -eq 0 ] || [ -z "$1" ] ; then return 1 ; fi if echo "$1" | grep -qE "^(0|[1-9][0-9]?)$" && \ [ "$1" -ge 0 ] && [ "$1" -lt 60 ] then return 0 ; else return 1 ; fi } # ------------------------------------------------------------------------------------------------------------------------- # schedulevpnreset lets you enable and set a time for a scheduled daily vpn reset ##----------------------------------------## ## Modified by Martinski W. [2024-Oct-06] ## ##----------------------------------------## schedulevpnreset() { while true do clear echo -e "${InvGreen} ${InvDkGray}${CWhite} VPN Reset Scheduler ${CClear}" echo -e "${InvGreen} ${CClear}" echo -e "${InvGreen} ${CClear} Please indicate below if you would like to enable and schedule a daily VPN Reset CRON" echo -e "${InvGreen} ${CClear} job. This will reset each monitored VPN connection. (Default = Disabled)" echo -e "${InvGreen} ${CClear}${CDkGray}---------------------------------------------------------------------------------------${CClear}" echo -e "${InvGreen} ${CClear}" if [ "$schedule" = "0" ] then echo -e "${InvGreen} ${CClear} Current: ${CRed}Disabled${CClear}" elif [ "$schedule" = "1" ] then schedhrs="$(awk "BEGIN {printf \"%02.f\",${schedulehrs}}")" schedmin="$(awk "BEGIN {printf \"%02.f\",${schedulemin}}")" schedtime="${CGreen}$schedhrs:$schedmin${CClear}" echo -e "${InvGreen} ${CClear} Current: ${CGreen}Enabled, Daily @ $schedtime${CClear}" fi echo read -p 'Schedule Daily Reset? (0=No, 1=Yes, e=Exit): ' newSchedule if [ -z "$newSchedule" ] ; then newSchedule="${schedule:=0}" ; fi if [ "$newSchedule" = "0" ] then schedule=0 if [ -f /jffs/scripts/services-start ] then sed -i -e '/vpnmon-r3.sh/d' /jffs/scripts/services-start cru d RunVPNMONR3reset schedulehrs=1 schedulemin=0 echo "" echo -e "${CGreen}[Modifiying SERVICES-START file]..." sleep 2 echo "" echo -e "${CGreen}[Modifying CRON jobs]..." sleep 2 echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - INFO: VPN Reset Schedule Disabled" >> $logfile saveconfig timer="$timerloop" break fi elif [ "$newSchedule" = "1" ] then schedule=1 echo echo -e "${InvGreen} ${InvDkGray}${CWhite} VPN Reset Scheduler ${CClear}" echo -e "${InvGreen} ${CClear}" echo -e "${InvGreen} ${CClear} Please indicate below what time you would like to schedule a daily VPN Reset CRON" echo -e "${InvGreen} ${CClear} job. (Default = 1 hr, 0 min = 01:00 = 1:00am)" echo -e "${InvGreen} ${CClear}${CDkGray}---------------------------------------------------------------------------------------${CClear}" echo read -p 'Schedule HOURS [0-23]?: ' newScheduleHrs if [ -z "$newScheduleHrs" ] then if _ValidateCronJobHour_ "$schedulehrs" then scheduleHrsOK=true else scheduleHrsOK=false fi elif _ValidateCronJobHour_ "$newScheduleHrs" then scheduleHrsOK=true schedulehrs="$newScheduleHrs" else scheduleHrsOK=false schedulehrs="${schedulehrs:=1}" printf "${CRed}*ERROR*: INVALID Entry.${CClear}\n\n" fi read -p 'Schedule MINUTES [0-59]?: ' newScheduleMins if [ -z "$newScheduleMins" ] then if _ValidateCronJobMinute_ "$schedulemin" then scheduleMinsOK=true else scheduleMinsOK=false fi elif _ValidateCronJobMinute_ "$newScheduleMins" then scheduleMinsOK=true schedulemin="$newScheduleMins" else scheduleMinsOK=false schedulemin="${schedulemin:=0}" printf "${CRed}*ERROR*: INVALID Entry.${CClear}\n" fi if ! "$scheduleHrsOK" || ! "$scheduleMinsOK" then doResetSave=false if ! "$scheduleHrsOK" && ! _ValidateCronJobHour_ "$schedulehrs" then schedulehrs=1 ; doResetSave=true fi if ! "$scheduleMinsOK" && ! _ValidateCronJobMinute_ "$schedulemin" then schedulemin=0 ; doResetSave=true fi if "$doResetSave" then schedule=0 saveconfig printf "\n${CRed}INVALID input found. Resetting values.${CClear}\n\n" else printf "\n${CRed}INVALID input found. No changes made.${CClear}\n\n" fi echo -e "${CClear}[Exiting]" timer="$timerloop" sleep 3 break fi echo echo -e "${CGreen}[Modifying SERVICES-START file]..." sleep 2 if [ -f /jffs/scripts/services-start ] then if ! grep -q -F "sh /jffs/scripts/vpnmon-r3.sh -reset" /jffs/scripts/services-start then echo 'cru a RunVPNMONR3reset "'"$schedulemin $schedulehrs * * * sh /jffs/scripts/vpnmon-r3.sh -reset"'"' >> /jffs/scripts/services-start cru a RunVPNMONR3reset "$schedulemin $schedulehrs * * * sh /jffs/scripts/vpnmon-r3.sh -reset" else #delete and re-add if it already exists in case there's a time change sed -i -e '/vpnmon-r3.sh/d' /jffs/scripts/services-start cru d RunVPNMONR3reset echo 'cru a RunVPNMONR3reset "'"$schedulemin $schedulehrs * * * sh /jffs/scripts/vpnmon-r3.sh -reset"'"' >> /jffs/scripts/services-start cru a RunVPNMONR3reset "$schedulemin $schedulehrs * * * sh /jffs/scripts/vpnmon-r3.sh -reset" fi else echo 'cru a RunVPNMONR3reset "'"$schedulemin $schedulehrs * * * sh /jffs/scripts/vpnmon-r3.sh -reset"'"' >> /jffs/scripts/services-start chmod 755 /jffs/scripts/services-start cru a RunVPNMONR3reset "$schedulemin $schedulehrs * * * sh /jffs/scripts/vpnmon-r3.sh -reset" fi echo echo -e "${CGreen}[Modifying CRON jobs]..." sleep 2 echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - INFO: VPN Reset Schedule Enabled" >> $logfile saveconfig timer="$timerloop" break elif [ "$newSchedule" = "e" ] then echo ; echo -e "${CClear}[Exiting]" timer="$timerloop" sleep 2 break else schedule="${schedule:=0}" schedulehrs="${schedulehrs:=1}" schedulemin="${schedulemin:=0}" saveconfig fi done } # ------------------------------------------------------------------------------------------------------------------------- # autostart lets you enable the ability for vpnmon-r3 to autostart after a router reboot autostart() { while true; do clear echo -e "${InvGreen} ${InvDkGray}${CWhite} Reboot Protection ${CClear}" echo -e "${InvGreen} ${CClear}" echo -e "${InvGreen} ${CClear} Please indicate below if you would like to enable VPNMON-R3 to autostart after a" echo -e "${InvGreen} ${CClear} router reboot. This will ensure continued, uninterrupted VPN connection monitoring." echo -e "${InvGreen} ${CClear} (Default = Disabled)" echo -e "${InvGreen} ${CClear}${CDkGray}---------------------------------------------------------------------------------------${CClear}" echo -e "${InvGreen} ${CClear}" if [ "$autostart" = "0" ] then echo -e "${InvGreen} ${CClear} Current: ${CRed}Disabled${CClear}" elif [ "$autostart" = "1" ] then echo -e "${InvGreen} ${CClear} Current: ${CGreen}Enabled${CClear}" fi echo read -p 'Enable Reboot Protection? (0=No, 1=Yes, e=Exit): ' newAutoStart # Use default value on enter keypress or invalid input # if [ -z "$newAutoStart" ] ; then newAutoStart="${autostart:=0}" ; fi if [ "$newAutoStart" = "0" ] then autostart=0 if [ -f /jffs/scripts/post-mount ] then sed -i -e '/vpnmon-r3.sh/d' /jffs/scripts/post-mount echo "" echo -e "${CGreen}[Modifying POST-MOUNT file]..." echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - INFO: Reboot Protection Disabled" >> $logfile saveconfig sleep 2 timer="$timerloop" break fi elif [ "$newAutoStart" = "1" ] then autostart=1 if [ -f /jffs/scripts/post-mount ] then if ! grep -q -F "(sleep 30 && /jffs/scripts/vpnmon-r3.sh -screen) & # Added by vpnmon-r3" /jffs/scripts/post-mount then echo "(sleep 30 && /jffs/scripts/vpnmon-r3.sh -screen) & # Added by vpnmon-r3" >> /jffs/scripts/post-mount echo echo -e "${CGreen}[Modifying POST-MOUNT file]..." echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - INFO: Reboot Protection Enabled" >> $logfile saveconfig sleep 2 timer="$timerloop" break else saveconfig sleep 1 fi else echo "#!/bin/sh" > /jffs/scripts/post-mount echo "" >> /jffs/scripts/post-mount echo "(sleep 30 && /jffs/scripts/vpnmon-r3.sh -screen) & # Added by vpnmon-r3" >> /jffs/scripts/post-mount chmod 755 /jffs/scripts/post-mount echo echo -e "${CGreen}[Modifying POST-MOUNT file]..." echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - INFO: Reboot Protection Enabled" >> $logfile saveconfig sleep 2 timer="$timerloop" break fi elif [ "$newAutoStart" = "e" ] then echo ; echo -e "${CClear}[Exiting]" timer="$timerloop" sleep 2 break else autostart="${autostart:=0}" saveconfig fi done } # ------------------------------------------------------------------------------------------------------------------------- # trimlogs will cut down log size (in rows) based on custom value trimlogs() { if [ "$logsize" -gt 0 ] then currlogsize="$(wc -l $logfile | awk '{ print $1 }')" # Determine the number of rows in the log if [ "$currlogsize" -gt "$logsize" ] # If it's bigger than the max allowed, tail/trim it! then echo "$(tail -$logsize $logfile)" > $logfile echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - INFO: Trimmed the log file down to $logsize lines" >> $logfile fi fi } # ------------------------------------------------------------------------------------------------------------------------- # saveconfig saves the vpnmon-r3.cfg file after every major change, and applies that to the script on the fly saveconfig() { { echo 'availableslots="'"$availableslots"'"' echo 'PINGHOST="'"$PINGHOST"'"' echo 'logsize='$logsize echo 'timerloop='$timerloop echo 'recover='$recover echo 'schedule='$schedule echo 'schedulehrs='$schedulehrs echo 'schedulemin='$schedulemin echo 'autostart='$autostart echo 'pingreset='$pingreset echo 'automation1="'"$automation1"'"' echo 'automation2="'"$automation2"'"' echo 'automation3="'"$automation3"'"' echo 'automation4="'"$automation4"'"' echo 'automation5="'"$automation5"'"' echo 'wgautomation1="'"$wgautomation1"'"' echo 'wgautomation2="'"$wgautomation2"'"' echo 'wgautomation3="'"$wgautomation3"'"' echo 'wgautomation4="'"$wgautomation4"'"' echo 'wgautomation5="'"$wgautomation5"'"' echo 'refreshserverlists='$refreshserverlists echo 'unboundclient='$unboundclient echo 'unboundwgclient='$unboundwgclient echo 'unboundshowip='$unboundshowip echo 'monitorwan='$monitorwan echo 'useovpn='$useovpn echo 'usewg='$usewg echo 'updateskynet='$updateskynet echo 'amtmemailsuccess='$amtmemailsuccess echo 'amtmemailfailure='$amtmemailfailure echo 'rstspdmerlin='$rstspdmerlin echo 'ratelimit='$ratelimit echo 'selectionmethod='$selectionmethod echo 'lowutilspd='$lowutilspd echo 'medutilspd='$medutilspd echo 'lowutilspdup='$lowutilspdup echo 'medutilspdup='$medutilspdup echo 'bwdisp='$bwdisp } > "$config" echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - INFO: New vpnmon-r3.cfg File Saved" >> $logfile if [ -f "$config" ] then source "$config" fi } # ------------------------------------------------------------------------------------------------------------------------- # VPN_GetClientState was created by @Martinski in many thanks to trying to eliminate unknown operand errors due to null # vpn_clientX_state values _VPN_GetClientState_() { if [ $# -lt 1 ] || [ -z "$1" ] || ! echo "$1" | grep -qE "^[1-5]$" then echo "**ERROR**" ; return 1 ; fi local nvramVal="$($timeoutcmd$timeoutsec nvram get "vpn_client${1}_state")" if [ -z "$nvramVal" ] || ! echo "$nvramVal" | grep -qE "^[+-]?[0-9]$" then echo "0" ; else echo "$nvramVal" ; fi return 0 } # ------------------------------------------------------------------------------------------------------------------------- # WG_GetClientState is based off _VPN_GetClientState_ _WG_GetClientState_() { if [ $# -lt 1 ] || [ -z "$1" ] || ! echo "$1" | grep -qE "^[1-5]$" then echo "**ERROR**" ; return 1 ; fi # Inspiration from ZebMcKayHan's WGC Watchdog Script last_handshake=$(wg show wgc$1 latest-handshakes | awk '{print $2}') >/dev/null 2>&1 if [ -z $last_handshake ] then WGnvramVal=0 #disconnected else WGnvramVal=2 #connected fi #local WGnvramVal="$($timeoutcmd$timeoutsec nvram get "wgc${1}_enable")" if [ -z "$WGnvramVal" ] || ! echo "$WGnvramVal" | grep -qE "^[+-]?[0-9]$" then echo "0" ; else echo "$WGnvramVal" ; fi return 0 } # ------------------------------------------------------------------------------------------------------------------------- ######################################################################## # AMTM Email Notification Functionality generously donated by @Martinski! # # Creation Date: 2020-Jun-11 [Martinski W.] # Last Modified: 2024-Feb-07 [Martinski W.] # Modified for VPNMON-R3 Purposes [Viktor Jaep] ######################################################################## #-----------------------------------------------------------# _DownloadCEMLibraryFile_() { local msgStr retCode case "$1" in update) msgStr="Updating" ;; install) msgStr="Installing" ;; *) return 1 ;; esac printf "\33[2K\r" printf "${CGreen}\r[INFO: ${msgStr} the shared AMTM email library script file to support email notifications...]${CClear}" echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - INFO: ${msgStr} the shared AMTM email library script file to support email notifications..." >> $logfile mkdir -m 755 -p "$CUSTOM_EMAIL_LIBDir" curl -kLSs --retry 3 --retry-delay 5 --retry-connrefused \ "${CEM_LIB_URL}/$CUSTOM_EMAIL_LIBName" -o "$CUSTOM_EMAIL_LIBFile" curlCode="$?" if [ "$curlCode" -eq 0 ] && [ -f "$CUSTOM_EMAIL_LIBFile" ] then retCode=0 chmod 755 "$CUSTOM_EMAIL_LIBFile" . "$CUSTOM_EMAIL_LIBFile" #printf "\nDone.\n" else retCode=1 printf "\33[2K\r" printf "${CRed}\r[ERROR: Unable to download the shared library script file ($CUSTOM_EMAIL_LIBName).]${CClear}" echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - **ERROR**: Unable to download the shared AMTM email library script file [$CUSTOM_EMAIL_LIBName]." >> $logfile fi return "$retCode" } #-----------------------------------------------------------# # ARG1: The email name/alias to be used as "FROM_NAME" # ARG2: The email Subject string. # ARG3: Full path of file containing the email Body text. # ARG4: The email Body Title string [OPTIONAL]. #-----------------------------------------------------------# _SendEMailNotification_() { if [ -z "${amtmIsEMailConfigFileEnabled:+xSETx}" ] then printf "\33[2K\r" printf "${CRed}\r[ERROR: Email library script ($CUSTOM_EMAIL_LIBFile) *NOT* FOUND.]${CClear}" sleep 5 echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - **ERROR**: Email library script [$CUSTOM_EMAIL_LIBFile] *NOT* FOUND." >> $logfile return 1 fi if [ $# -lt 3 ] || [ -z "$1" ] || [ -z "$2" ] || [ -z "$3" ] then printf "\33[2K\r" printf "${CRed}\r[ERROR: INSUFFICIENT email parameters]${CClear}" sleep 5 echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - **ERROR**: INSUFFICIENT email parameters." >> $logfile return 1 fi local retCode emailBodyTitleStr="" [ $# -gt 3 ] && [ -n "$4" ] && emailBodyTitleStr="$4" FROM_NAME="$1" _SendEMailNotification_CEM_ "$2" "-F=$3" "$emailBodyTitleStr" retCode="$?" if [ "$retCode" -eq 0 ] then printf "\33[2K\r" printf "${CGreen}\r[Email notification was sent successfully ($2)]${CClear}" echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - INFO: Email notification was sent successfully [$2]" >> $logfile sleep 5 else printf "\33[2K\r" printf "${CRed}\r[ERROR: Failure to send email notification (Error Code: $retCode - $2).]${CClear}" echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - **ERROR**: Failure to send email notification [$2]" >> $logfile sleep 5 fi return "$retCode" } # ------------------------------------------------------------------------------------------------------------------------- # sendmessage is a function that sends an AMTM email based on activity within VPNMON-R3 # $1 = Success/Failure 0/1 # $2 = Component # $3 = VPN Slot sendmessage() { #If AMTM email functionality is disabled, return back to the function call if [ "$amtmemailsuccess" = "0" ] && [ "$amtmemailfailure" = "0" ]; then return fi #Load, install or update the shared AMTM Email integration library if [ -f "$CUSTOM_EMAIL_LIBFile" ] then . "$CUSTOM_EMAIL_LIBFile" if [ -z "${CEM_LIB_VERSION:+xSETx}" ] || \ _CheckLibraryUpdates_CEM_ "$CUSTOM_EMAIL_LIBDir" quiet then _DownloadCEMLibraryFile_ "update" fi else _DownloadCEMLibraryFile_ "install" fi cemIsFormatHTML=true cemIsVerboseMode=false tmpEMailBodyFile="/tmp/var/tmp/tmpEMailBody_${scriptFileNTag}.$$.TXT" ratelimiter emaillimit="$?" if [ "$emaillimit" -eq 0 ] then #Pick the scenario and send email if [ "$1" = "1" ] && [ "$amtmemailfailure" = "1" ]; then if [ "$2" = "Recovering from WAN Down" ]; then emailSubject="ALERT: Router Recovering from WAN Down" emailBodyTitle="ALERT: Router Recovering from WAN Down" { printf "Date/Time: $(date +'%b %d %Y %X')\n" printf "Asus Router Model: ${ROUTERMODEL}\n" printf "Firmware/Build Number: ${FWBUILD}\n" printf "\n" printf "ALERT: VPNMON-R3 is currently recovering from a WAN Down Situation!\n" printf "Router has detected a WAN Link/Modem and waited 300 seconds for general network.\n" printf "connectivity to stabilize before re-establishing VPN connectivity.\n" printf "\n" } > "$tmpEMailBodyFile" elif [ "$2" = "VPN Slot In Error State" ]; then emailSubject="FAILURE: VPN Slot $3 in Error State" emailBodyTitle="FAILURE: VPN Slot $3 in Error State" { printf "Date/Time: $(date +'%b %d %Y %X')\n" printf "Asus Router Model: ${ROUTERMODEL}\n" printf "Firmware/Build Number: ${FWBUILD}\n" printf "\n" printf "FAILURE: VPNMON-R3 has detected that VPN Slot $3 is in an error state. VPN Slot $3 has been reset.\n" printf "Please check your network environment and configuration if this error continues to persist." printf "\n" } > "$tmpEMailBodyFile" elif [ "$2" = "VPN Tunnel Disconnected" ]; then emailSubject="FAILURE: VPN Slot $3 has Disconnected" emailBodyTitle="FAILURE: VPN Slot $3 has Disconnected" { printf "Date/Time: $(date +'%b %d %Y %X')\n" printf "Asus Router Model: ${ROUTERMODEL}\n" printf "Firmware/Build Number: ${FWBUILD}\n" printf "\n" printf "FAILURE: VPNMON-R3 has detected that VPN Slot $3 has disconnected. VPN Slot $3 has been reset.\n" printf "Please check your network environment and configuration if this error continues to persist." printf "\n" } > "$tmpEMailBodyFile" elif [ "$2" = "VPN Slot Is Non-Responsive" ]; then emailSubject="FAILURE: VPN Slot $3 is Non-Responsive" emailBodyTitle="FAILURE: VPN Slot $3 is Non-Responsive" { printf "Date/Time: $(date +'%b %d %Y %X')\n" printf "Asus Router Model: ${ROUTERMODEL}\n" printf "Firmware/Build Number: ${FWBUILD}\n" printf "\n" printf "FAILURE: VPNMON-R3 has detected that VPN Slot $3 is non-responsive. VPN Slot $3 has been reset.\n" printf "Please check your network environment and configuration if this error continues to persist." printf "\n" } > "$tmpEMailBodyFile" elif [ "$2" = "VPN Slot Exceeded Max Ping" ]; then emailSubject="WARNING: VPN Slot $3 Exceeded Max Ping" emailBodyTitle="WARNING: VPN Slot $3 Exceeded Max Ping" { printf "Date/Time: $(date +'%b %d %Y %X')\n" printf "Asus Router Model: ${ROUTERMODEL}\n" printf "Firmware/Build Number: ${FWBUILD}\n" printf "\n" printf "WARNING: VPNMON-R3 has detected that VPN Slot $3 exceeded max ping. VPN Slot $3 has been reset.\n" printf "Please check your network environment and configuration if this error continues to persist." printf "\n" } > "$tmpEMailBodyFile" elif [ "$2" = "VPN Slot Not Synced With Unbound" ]; then emailSubject="WARNING: VPN Slot $3 Not Synced with Unbound" emailBodyTitle="WARNING: VPN Slot $3 Not Synced with Unbound" { printf "Date/Time: $(date +'%b %d %Y %X')\n" printf "Asus Router Model: ${ROUTERMODEL}\n" printf "Firmware/Build Number: ${FWBUILD}\n" printf "\n" printf "WARNING: VPNMON-R3 has detected that VPN Slot $3 is not synced with Unbound. VPN Slot $3 has been reset.\n" printf "Please check your network environment and configuration if this error continues to persist." printf "\n" } > "$tmpEMailBodyFile" elif [ "$2" = "WG Slot Not Synced With Unbound" ]; then emailSubject="WARNING: WG Slot $3 Not Synced with Unbound" emailBodyTitle="WARNING: WG Slot $3 Not Synced with Unbound" { printf "Date/Time: $(date +'%b %d %Y %X')\n" printf "Asus Router Model: ${ROUTERMODEL}\n" printf "Firmware/Build Number: ${FWBUILD}\n" printf "\n" printf "WARNING: VPNMON-R3 has detected that WG Slot $3 is not synced with Unbound. WG Slot $3 has been reset.\n" printf "Please check your network environment and configuration if this error continues to persist." printf "\n" } > "$tmpEMailBodyFile" ##-------------------------------------## ## Modified by Dan G. [2025-Jul-16] ## ##-------------------------------------## elif [ "$2" = "VPN Server List Query Yielded 0 Rows" ]; then emailSubject="WARNING: VPN Slot $3 Server List Query Yielded 0 Rows" emailBodyTitle="WARNING: VPN Slot $3 Server List Query Yielded 0 Rows" { printf "Date/Time: $(date +'%b %d %Y %X')\n" printf "Asus Router Model: ${ROUTERMODEL}\n" printf "Firmware/Build Number: ${FWBUILD}\n" printf "\n" printf "WARNING: VPNMON-R3 has detected that the Custom Server List Query for VPN Slot $3 yielded 0 results.\n" printf "This may be due to an error in the query, or the VPN provider API service may be down or unreachable." printf "Please check your network environment and configuration if this error continues to persist." printf "\n" } > "$tmpEMailBodyFile" elif [ "$2" = "WG Server List Query Yielded 0 Rows" ]; then emailSubject="WARNING: WG Slot $3 Server List Query Yielded 0 Rows" emailBodyTitle="WARNING: WG Slot $3 Server List Query Yielded 0 Rows" { printf "Date/Time: $(date +'%b %d %Y %X')\n" printf "Asus Router Model: ${ROUTERMODEL}\n" printf "Firmware/Build Number: ${FWBUILD}\n" printf "\n" printf "WARNING: VPNMON-R3 has detected that the Custom Server List Query for WG Slot $3 yielded 0 results.\n" printf "This may be due to an error in the query, or the VPN provider API service may be down or unreachable." printf "Please check your network environment and configuration if this error continues to persist." printf "\n" } > "$tmpEMailBodyFile" elif [ "$2" = "WG Slot Exceeded Max Ping" ]; then emailSubject="WARNING: WG Slot $3 Exceeded Max Ping" emailBodyTitle="WARNING: WG Slot $3 Exceeded Max Ping" { printf "Date/Time: $(date +'%b %d %Y %X')\n" printf "Asus Router Model: ${ROUTERMODEL}\n" printf "Firmware/Build Number: ${FWBUILD}\n" printf "\n" printf "WARNING: VPNMON-R3 has detected that WG Slot $3 exceeded max ping. WG Slot $3 has been reset.\n" printf "Please check your network environment and configuration if this error continues to persist." printf "\n" } > "$tmpEMailBodyFile" elif [ "$2" = "WG Handshake Exceeded" ]; then emailSubject="WARNING: WG Slot $3 Exceeded Handshake" emailBodyTitle="WARNING: WG Slot $3 Exceeded Handshake" { printf "Date/Time: $(date +'%b %d %Y %X')\n" printf "Asus Router Model: ${ROUTERMODEL}\n" printf "Firmware/Build Number: ${FWBUILD}\n" printf "\n" printf "WARNING: VPNMON-R3 has detected that WG Slot $3 exceeded a 200s handshake. WG Slot $3 has been reset.\n" printf "Please check your network environment and configuration if this error continues to persist." printf "\n" } > "$tmpEMailBodyFile" elif [ "$2" = "WG Tunnel Disconnected" ]; then emailSubject="WARNING: WG Slot $3 Tunnel Disconnected" emailBodyTitle="WARNING: WG Slot $3 Tunnel Disconnected" { printf "Date/Time: $(date +'%b %d %Y %X')\n" printf "Asus Router Model: ${ROUTERMODEL}\n" printf "Firmware/Build Number: ${FWBUILD}\n" printf "\n" printf "WARNING: VPNMON-R3 has detected that WG Slot $3 tunnel disconnected. WG Slot $3 has been reset.\n" printf "Please check your network environment and configuration if this error continues to persist." printf "\n" } > "$tmpEMailBodyFile" elif [ "$2" = "WG Slot Is Non-Responsive" ]; then emailSubject="WARNING: WG Slot $3 is Non-Responsive" emailBodyTitle="WARNING: WG Slot $3 is Non-Responsive" { printf "Date/Time: $(date +'%b %d %Y %X')\n" printf "Asus Router Model: ${ROUTERMODEL}\n" printf "Firmware/Build Number: ${FWBUILD}\n" printf "\n" printf "WARNING: VPNMON-R3 has detected that WG Slot $3 is not responding. WG Slot $3 has been reset.\n" printf "Please check your network environment and configuration if this error continues to persist." printf "\n" } > "$tmpEMailBodyFile" fi _SendEMailNotification_ "VPNMON-R3 v$version" "$emailSubject" "$tmpEMailBodyFile" "$emailBodyTitle" fi if [ "$1" = "0" ] && [ "$amtmemailsuccess" = "1" ]; then if [ "$2" = "VPN Connection Scheduled Reset" ]; then emailSubject="SUCCESS: VPN Slot $3 Manual/Scheduled Reset" emailBodyTitle="SUCCESS: VPN Slot $3 Manual/Scheduled Reset" { printf "Date/Time: $(date +'%b %d %Y %X')\n" printf "Asus Router Model: ${ROUTERMODEL}\n" printf "Firmware/Build Number: ${FWBUILD}\n" printf "\n" printf "SUCCESS: VPNMON-R3 completed a successful manual/scheduled reset on VPN Slot $3\n" printf "\n" } > "$tmpEMailBodyFile" elif [ "$2" = "VPN Reset" ]; then emailSubject="SUCCESS: VPN Slot $3 Manual Reset" emailBodyTitle="SUCCESS: VPN Slot $3 Manual Reset" { printf "Date/Time: $(date +'%b %d %Y %X')\n" printf "Asus Router Model: ${ROUTERMODEL}\n" printf "Firmware/Build Number: ${FWBUILD}\n" printf "\n" printf "SUCCESS: VPNMON-R3 completed a successful manual reset on VPN Slot $3\n" printf "\n" } > "$tmpEMailBodyFile" elif [ "$2" = "VPN Killed" ]; then emailSubject="SUCCESS: VPN Slot $3 Manually Stopped & Unmonitored" emailBodyTitle="SUCCESS: VPN Slot $3 Manually Stopped & Unmonitored" { printf "Date/Time: $(date +'%b %d %Y %X')\n" printf "Asus Router Model: ${ROUTERMODEL}\n" printf "Firmware/Build Number: ${FWBUILD}\n" printf "\n" printf "SUCCESS: VPNMON-R3 successfully manually stopped and unmonitored VPN Slot $3\n" printf "\n" } > "$tmpEMailBodyFile" ##-------------------------------------## ## Added by Dan G. [2025-Jul-16] ## ##-------------------------------------## elif [ "$2" = "WG Connection Scheduled Reset" ]; then emailSubject="SUCCESS: WG Slot $3 Manual/Scheduled Reset" emailBodyTitle="SUCCESS: WG Slot $3 Manual/Scheduled Reset" { printf "Date/Time: $(date +'%b %d %Y %X')\n" printf "Asus Router Model: ${ROUTERMODEL}\n" printf "Firmware/Build Number: ${FWBUILD}\n" printf "\n" printf "SUCCESS: VPNMON-R3 completed a successful manual/scheduled reset on WG Slot $3\n" printf "\n" } > "$tmpEMailBodyFile" elif [ "$2" = "WG Reset" ]; then emailSubject="SUCCESS: WG Slot $3 Manual Reset" emailBodyTitle="SUCCESS: WG Slot $3 Manual Reset" { printf "Date/Time: $(date +'%b %d %Y %X')\n" printf "Asus Router Model: ${ROUTERMODEL}\n" printf "Firmware/Build Number: ${FWBUILD}\n" printf "\n" printf "SUCCESS: VPNMON-R3 completed a successful manual reset on WG Slot $3\n" printf "\n" } > "$tmpEMailBodyFile" elif [ "$2" = "WG Killed" ]; then emailSubject="SUCCESS: WG Slot $3 Manually Stopped & Unmonitored" emailBodyTitle="SUCCESS: WG Slot $3 Manually Stopped & Unmonitored" { printf "Date/Time: $(date +'%b %d %Y %X')\n" printf "Asus Router Model: ${ROUTERMODEL}\n" printf "Firmware/Build Number: ${FWBUILD}\n" printf "\n" printf "SUCCESS: VPNMON-R3 successfully manually stopped and unmonitored WG Slot $3\n" printf "\n" } > "$tmpEMailBodyFile" fi _SendEMailNotification_ "VPNMON-R3 v$version" "$emailSubject" "$tmpEMailBodyFile" "$emailBodyTitle" fi fi } # ------------------------------------------------------------------------------------------------------------------------- # Function to keep track of emails sent, and determine if they need to be rate-limited ratelimiter() { #if rate limiting is disabled, exit right away if [ "$ratelimit" = "0" ]; then return 0 fi #Make sure log file exists touch "$vr3emails" #check current time and 1h into the past current_time=$(date +%s) cutoff_time=$((current_time - 3600)) #create a temp file where current data will get moved over into that is less than 1hr old vr3emailstemp="${vr3emails}.tmp" awk -v cutoff="$cutoff_time" '$1 > cutoff' "$vr3emails" > "$vr3emailstemp" #check to see how many emails have been sent in the last hour recent_email_count=$(wc -l < "$vr3emailstemp" | tr -d ' ') printf "\33[2K\r" printf "${CGreen}\r[Checking email rate limit... $recent_email_count/$ratelimit emails sent within the last hour]" sleep 2 #logic to determine if rate limit has been hit if [ "$recent_email_count" -ge "$ratelimit" ] then printf "\33[2K\r" printf "${CGreen}\r[Rate limit exceeded. Emails will be prevented from sending]" echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - INFO: Email Rate limit exceeded ($ratelimit). Emails will be prevented from sending." >> $logfile sleep 2 mv "$vr3emailstemp" "$vr3emails" return 1 else printf "\33[2K\r" printf "${CGreen}\r[Rate within limits. Proceeding to send email]" sleep 1 echo "$current_time" >> "$vr3emailstemp" mv "$vr3emailstemp" "$vr3emails" return 0 fi } # ------------------------------------------------------------------------------------------------------------------------- # Testing to see if VPNMON-R3 external reset is currently running, and if so, hold off until it finishes lockcheck() { while [ -f "$lockfile" ]; do clear echo -e "${InvGreen} ${InvDkGray}${CWhite} External VPN Reset Currently In-Progress ${CClear}" echo -e "${InvGreen} ${CClear}" echo -e "${InvGreen} ${CClear} VPNMON-R3 is currently performing an external scheduled reset of the VPN through${CClear}" echo -e "${InvGreen} ${CClear} the means of the '-reset' commandline option, or scheduled CRON job.${CClear}" echo -e "${InvGreen} ${CClear}" echo -e "${InvGreen} ${CClear} [Retrying to resume normal operations every 15 seconds]${CClear}" echo -e "${InvGreen} ${CClear}${CDkGray}---------------------------------------------------------------------------------------${CClear}" echo "" spinner 15 lockactive=1 done if [ "$lockactive" = "1" ]; then timerreset=1 lockactive=0 fi } # ------------------------------------------------------------------------------------------------------------------------- # Initiate a VPN restart - $1 = slot number restartvpn() { echo -e "${CGreen}\nMessages: ${CClear}" echo "" #Check the current connection state of vpn slot currvpnstate="$(_VPN_GetClientState_ "$1")" if [ "$currvpnstate" -ne 0 ]; then printf "${CGreen}\r[Stopping VPN Client $1]" service stop_vpnclient$1 >/dev/null 2>&1 sleep 20 if [ "$currvpnstate" = "-1" ]; then nvram set vpn_client$1_state=0 fi printf "\33[2K\r" fi #Determine how many server entries are in the assigned vpn slot alternate servers file if [ -f "/jffs/addons/vpnmon-r3.d/vr3svr$1.txt" ] then servers=$(cat "/jffs/addons/vpnmon-r3.d/vr3svr$1.txt" | wc -l) >/dev/null 2>&1 if [ -z "$servers" ] || [ "$servers" -eq 0 ] then #Restart the same server currently allocated to that vpn slot currvpnhost=$($timeoutcmd$timeoutsec nvram get vpn_client$1_addr) printf "\33[2K\r" printf "${CGreen}\r[Starting VPN Client $1]" service start_vpnclient$1 >/dev/null 2>&1 echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - INFO: VPN$1 Connection Restarted - Current Server: $currvpnhost" >> $logfile resettimer $1 "VPN" sleep 10 printf "\33[2K\r" printf "${CGreen}\r[Letting VPN$1 Settle]" sleep 10 return elif [ "$selectionmethod" -eq 1 ] # 1=roundrobin then robintracker="/jffs/addons/vpnmon-r3.d/vr3robin.txt" # If the robintracker file doesn't exist, create it and start all from 0. if [ ! -f "$robintracker" ]; then { echo 'VPN1RR=0' echo 'VPN2RR=0' echo 'VPN3RR=0' echo 'VPN4RR=0' echo 'VPN5RR=0' echo 'WG1RR=0' echo 'WG2RR=0' echo 'WG3RR=0' echo 'WG4RR=0' echo 'WG5RR=0' } > "$robintracker" printf "\33[2K\r" printf "${CGreen}\r[Writing New Sequential Tracker File]" sleep 1 fi # Read the last used line number from the tracker file, calculate next lastused=$(grep 'VPN'$1'RR=' "$robintracker" | cut -d'=' -f2) nextup="$((lastused+1))" # Check if we've reached the end of the file. If so, loop back to line 1. if [ "$nextup" -gt "$servers" ]; then nextup=1 fi printf "\33[2K\r" printf "${CGreen}\r[Selecting Next Sequential Entry]" #---------OVPN-specific nvram values # Extract the target line and parse it RNDVPNIP=$(sed -n "${nextup}p" /jffs/addons/vpnmon-r3.d/vr3svr$1.txt) nvram set vpn_client"$1"_addr="$RNDVPNIP" nvram set vpn_client"$1"_desc="VPN$1 - $RNDVPNIP added by VPNMON-R3" sleep 2 #---------OVPN-specific nvram values # Update the tracker file with the line number we just used. sed -i "s/^VPN$1RR=.*/VPN$1RR=$nextup/" "$robintracker" #Restart the new server currently allocated to that vpn slot printf "\33[2K\r" printf "${CGreen}\r[Starting VPN Client $1]" service start_vpnclient$1 >/dev/null 2>&1 echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - INFO: VPN$1 Connection Restarted [SEQ] - New Server: $RNDVPNIP" >> $logfile resettimer $1 "VPN" sleep 10 printf "\33[2K\r" printf "${CGreen}\r[Letting VPN$1 Settle]" sleep 10 elif [ "$selectionmethod" -eq 0 ] # 0=Random then #Pick a random server from the alternate servers file, populate in vpn client slot, and restart printf "\33[2K\r" printf "${CGreen}\r[Selecting Random Entry]" RANDOM=$(awk 'BEGIN {srand(); print int(32768 * rand())}') R_LINE=$(( RANDOM % servers + 1 )) #---------OVPN-specific nvram values RNDVPNIP=$(sed -n "${R_LINE}p" /jffs/addons/vpnmon-r3.d/vr3svr$1.txt) nvram set vpn_client"$1"_addr="$RNDVPNIP" nvram set vpn_client"$1"_desc="VPN$1 - $RNDVPNIP added by VPNMON-R3" sleep 2 #---------OVPN-specific nvram values #Restart the new server currently allocated to that vpn slot printf "\33[2K\r" printf "${CGreen}\r[Starting VPN Client $1]" service start_vpnclient$1 >/dev/null 2>&1 echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - INFO: VPN$1 Connection Restarted [RND] - New Server: $RNDVPNIP" >> $logfile resettimer $1 "VPN" sleep 10 printf "\33[2K\r" printf "${CGreen}\r[Letting VPN$1 Settle]" sleep 10 fi else #Restart the same server currently allocated to that vpn slot printf "\33[2K\r" printf "${CGreen}\r[Starting VPN Client $1]" currvpnhost="$($timeoutcmd$timeoutsec nvram get vpn_client$1_addr)" service start_vpnclient$1 >/dev/null 2>&1 echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - INFO: VPN$1 Connection Restarted - Current Server: $currvpnhost" >> $logfile resettimer $1 "VPN" sleep 10 printf "\33[2K\r" printf "${CGreen}\r[Letting VPN$1 Settle]" sleep 10 fi } # ------------------------------------------------------------------------------------------------------------------------- # Initiate a WG restart - $1 = slot number restartwg() { echo -e "${CGreen}\nMessages: ${CClear}" echo "" #Check the current connection state of vpn slot currwgstate="$(_WG_GetClientState_ $1)" if [ "$currwgstate" -ne 0 ]; then printf "${CGreen}\r[Stopping WG Client $1]" service "stop_wgc $1" >/dev/null 2>&1 sleep 20 printf "\33[2K\r" fi #Determine how many server entries are in the assigned vpn slot alternate servers file if [ -f "/jffs/addons/vpnmon-r3.d/vr3wgsvr$1.txt" ] then servers=$(cat "/jffs/addons/vpnmon-r3.d/vr3wgsvr$1.txt" | wc -l) >/dev/null 2>&1 if [ -z "$servers" ] || [ "$servers" -eq 0 ] then #Restart the same server currently allocated to that wg slot currwghost="$($timeoutcmd$timeoutsec nvram get wgc$1_ep_addr)" currwghostname="$($timeoutcmd$timeoutsec nvram get wgc$1_desc)" printf "\33[2K\r" printf "${CGreen}\r[Starting WG Client $1]" service "start_wgc $1" >/dev/null 2>&1 echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - INFO: WGC$1 Connection Restarted - Current Server: $currwghostname | $currwghost" >> $logfile resettimer $1 "WG" sleep 10 printf "\33[2K\r" printf "${CGreen}\r[Letting WGC$1 Settle]" sleep 10 return elif [ "$selectionmethod" -eq 1 ] # 1=roundrobin then robintracker="/jffs/addons/vpnmon-r3.d/vr3robin.txt" # If the robintracker file doesn't exist, create it and start from 0. if [ ! -f "$robintracker" ]; then { echo 'VPN1RR=0' echo 'VPN2RR=0' echo 'VPN3RR=0' echo 'VPN4RR=0' echo 'VPN5RR=0' echo 'WG1RR=0' echo 'WG2RR=0' echo 'WG3RR=0' echo 'WG4RR=0' echo 'WG5RR=0' } > "$robintracker" printf "\33[2K\r" printf "${CGreen}\r[Writing New Round-Robin Tracker File]" sleep 1 fi # Read the last used line number from the tracker file, calculate next lastused=$(grep 'WG'$1'RR=' "$robintracker" | cut -d'=' -f2) nextup="$((lastused+1))" # Check if we've reached the end of the file. If so, loop back to line 1. if [ "$nextup" -gt "$servers" ]; then nextup=1 fi printf "\33[2K\r" printf "${CGreen}\r[Selecting Next Sequential Entry]" #---------WG-specific nvram values # Extract the target line and parse it WGLINE=$(sed -n "${nextup}p" /jffs/addons/vpnmon-r3.d/vr3wgsvr$1.txt) wgdescription=$(echo "$WGLINE" | cut -d ',' -f 1) interfaceip=$(echo "$WGLINE" | cut -d ',' -f 2) endpointip=$(echo "$WGLINE" | cut -d ',' -f 3) endpointport=$(echo "$WGLINE" | cut -d ',' -f 4) privatekey=$(echo "$WGLINE" | cut -d ',' -f 5) publickey=$(echo "$WGLINE" | cut -d ',' -f 6) presharedkey=$(echo "$WGLINE" | cut -d ',' -f 7) #Optional, required by AirVPN nvram set wgc"$1"_desc="$wgdescription" nvram set wgc"$1"_addr="$interfaceip" nvram set wgc"$1"_ep_addr="$endpointip" nvram set wgc"$1"_ep_addr_r="$endpointip" nvram set wgc"$1"_ep_port="$endpointport" nvram set wgc"$1"_priv="${privatekey}" nvram set wgc"$1"_ppub="${publickey}" nvram set wgc"$1"_psk="${presharedkey}" #Optional, required by AirVPN sleep 2 #---------WG-specific nvram values # Update the tracker file with the line number we just used. sed -i "s/^WG$1RR=.*/WG$1RR=$nextup/" "$robintracker" #Restart the new server currently allocated to that wg slot printf "\33[2K\r" printf "${CGreen}\r[Starting WG Client $1]" service "start_wgc $1" >/dev/null 2>&1 echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - INFO: WGC$1 Connection Restarted [SEQ] - New Server: $wgdescription | $endpointip" >> $logfile resettimer $1 "WG" sleep 10 printf "\33[2K\r" printf "${CGreen}\r[Letting WGC$1 Settle]" sleep 10 elif [ "$selectionmethod" -eq 0 ] # 0=random then # Pick a random server from the alternate servers file, populate in wg client slot, and restart printf "\33[2K\r" printf "${CGreen}\r[Selecting Random Entry]" RANDOM=$(awk 'BEGIN {srand(); print int(32768 * rand())}') R_LINE=$(( RANDOM % servers + 1 )) #---------WG-specific nvram values WGLINE=$(sed -n "${R_LINE}p" /jffs/addons/vpnmon-r3.d/vr3wgsvr$1.txt) wgdescription=$(echo "$WGLINE" | cut -d ',' -f 1) interfaceip=$(echo "$WGLINE" | cut -d ',' -f 2) endpointip=$(echo "$WGLINE" | cut -d ',' -f 3) endpointport=$(echo "$WGLINE" | cut -d ',' -f 4) privatekey=$(echo "$WGLINE" | cut -d ',' -f 5) publickey=$(echo "$WGLINE" | cut -d ',' -f 6) presharedkey=$(echo "$WGLINE" | cut -d ',' -f 7) #Optional, required by AirVPN nvram set wgc"$1"_desc="$wgdescription" nvram set wgc"$1"_addr="$interfaceip" nvram set wgc"$1"_ep_addr="$endpointip" nvram set wgc"$1"_ep_addr_r="$endpointip" nvram set wgc"$1"_ep_port="$endpointport" nvram set wgc"$1"_priv="${privatekey}" nvram set wgc"$1"_ppub="${publickey}" nvram set wgc"$1"_psk="${presharedkey}" #Optional, required by AirVPN sleep 2 #---------WG-specific nvram values # Restart the new server currently allocated to that wg slot printf "\33[2K\r" printf "${CGreen}\r[Starting WG Client $1]" service "start_wgc $1" >/dev/null 2>&1 echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - INFO: WGC$1 Connection Restarted [RND] - New Server: $wgdescription | $endpointip" >> $logfile resettimer $1 "WG" sleep 10 printf "\33[2K\r" printf "${CGreen}\r[Letting WGC$1 Settle]" sleep 10 fi else #Restart the same server currently allocated to that wg slot printf "\33[2K\r" printf "${CGreen}\r[Starting WG Client $1]" currwghost="$($timeoutcmd$timeoutsec nvram get wgc$1_ep_addr)" service "start_wgc $1" >/dev/null 2>&1 echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - INFO: WGC$1 Connection Restarted - Current Server: $currwghost" >> $logfile resettimer $1 "WG" sleep 10 printf "\33[2K\r" printf "${CGreen}\r[Letting WGC$1 Settle]" sleep 10 fi } # ------------------------------------------------------------------------------------------------------------------------- # Separating off the vpnrouting service restart restartrouting() { printf "\33[2K\r" printf "${CGreen}\r[Restarting VPN Routing]" service restart_vpnrouting0 >/dev/null 2>&1 echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - INFO: VPN Director Routing Service Restarted" >> $logfile sleep 5 printf "\33[2K\r" trimlogs } # ------------------------------------------------------------------------------------------------------------------------- # Optionally reset spdMerlin interfaces resetspdmerlin() { if [ "$rstspdmerlin" = "1" ] then printf "\33[2K\r" printf "${CGreen}\r[Reset spdMerlin Interfaces]" /jffs/scripts/spdmerlin reset_interfaces force >/dev/null 2>&1 echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - INFO: spdMerlin Interfaces Reset" >> $logfile sleep 5 printf "\33[2K\r" fi } # ------------------------------------------------------------------------------------------------------------------------- # Kill a vpn connnection, and unmonitor it - $1 = slot number killunmonvpn() { # Stop the service echo -e "${CGreen}\nMessages: ${CClear}" echo "" printf "${CGreen}\r[Stopping VPN Client $1]" service stop_vpnclient$1 >/dev/null 2>&1 echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - INFO: VPN$1 has been stopped and no longer being monitored" >> $logfile sleep 15 printf "\33[2K\r" printf "${CGreen}\r[Unmonitoring VPN Client $1]" # Write the VPN client file back with the correct monitoring configuration sed -i "s/^VPN$1=.*/VPN$1=0/" "/jffs/addons/vpnmon-r3.d/vr3clients.txt" sed -i "s/^VPNTIMER$1=.*/VPNTIMER$1=0/" "/jffs/addons/vpnmon-r3.d/vr3timers.txt" sleep 5 # Restart VPN Director Routing Services restartrouting } # ------------------------------------------------------------------------------------------------------------------------- # Kill a wg connnection, and unmonitor it - $1 = slot number killunmonwg() { # Stop the service echo -e "${CGreen}\nMessages: ${CClear}" echo "" printf "${CGreen}\r[Stopping WG Client $1]" service "stop_wgc $1" >/dev/null 2>&1 echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - INFO: WGC$1 has been stopped and no longer being monitored" >> $logfile sleep 15 printf "\33[2K\r" printf "${CGreen}\r[Unmonitoring WG Client $1]" # Write the VPN client file back with the correct monitoring configuration sed -i "s/^WG$1=.*/WG$1=0/" "/jffs/addons/vpnmon-r3.d/vr3clients.txt" sed -i "s/^WGTIMER$1=.*/WGTIMER$1=0/" "/jffs/addons/vpnmon-r3.d/vr3timers.txt" sleep 5 # Restart VPN Director Routing Services restartrouting } # ------------------------------------------------------------------------------------------------------------------------- # Whitelist Server Slot IP lists in Skynet - $1 = VPN Slot skynetwhitelist() { if [ "$updateskynet" = "1" ] then ##-------------------------------------## ## Modified by Dan G. [2025-Jul-15] ## ##-------------------------------------## if echo "$1" | grep -q "wg"; then slotnum=$(echo "$1" | tr -cd '0-9') printf "${CGreen}\r[Whitelisting WG Server Slot $slotnum List in the Skynet Firewall]${CClear}\n" awk -F',' '{print $2}' /jffs/addons/vpnmon-r3.d/vr3wgsvr${slotnum}.txt > /jffs/addons/vpnmon-r3.d/vr3svrtmp.txt firewall import whitelist /jffs/addons/vpnmon-r3.d/vr3svrtmp.txt "VPNMON-R3 - WG Server Slot $slotnum Whitelist" >/dev/null 2>&1 rm -f "/jffs/addons/vpnmon-r3.d/vr3svrtmp.txt" >/dev/null 2>&1 echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - INFO: WG Server Slot $slotnum List has been whitelisted in Skynet" >> $logfile else printf "${CGreen}\r[Whitelisting VPN Server Slot $1 List in the Skynet Firewall]${CClear}\n" firewall import whitelist /jffs/addons/vpnmon-r3.d/vr3svr$1.txt "VPNMON-R3 - VPN Server Slot $1 Whitelist" >/dev/null 2>&1 echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - INFO: VPN Server Slot $1 List has been whitelisted in Skynet" >> $logfile fi sleep 5 fi } # ------------------------------------------------------------------------------------------------------------------------- # Reset the VPN connection timer resettimer() { # Create initial vr3timers.txt file if it does not exist if [ ! -f /jffs/addons/vpnmon-r3.d/vr3timers.txt ]; then if [ "$availableslots" = "1 2" ]; then { echo 'VPNTIMER1=0' echo 'VPNTIMER2=0' } > /jffs/addons/vpnmon-r3.d/vr3timers.txt elif [ "$availableslots" = "1 2 3 4 5" ]; then { echo 'VPNTIMER1=0' echo 'VPNTIMER2=0' echo 'VPNTIMER3=0' echo 'VPNTIMER4=0' echo 'VPNTIMER5=0' echo 'WGTIMER1=0' echo 'WGTIMER2=0' echo 'WGTIMER3=0' echo 'WGTIMER4=0' echo 'WGTIMER5=0' } > /jffs/addons/vpnmon-r3.d/vr3timers.txt fi fi source /jffs/addons/vpnmon-r3.d/vr3timers.txt source /jffs/addons/vpnmon-r3.d/vr3clients.txt vpnslottmp="VPN${1}" eval vpnslottmp="\$${vpnslottmp}" wgslottmp="WG${1}" eval wgslottmp="\$${wgslottmp}" if [ "$2" = "VPN" ] && [ "$vpnslottmp" = "1" ]; then sed -i "s/^VPNTIMER$1=.*/VPNTIMER$1=$(date +%s)/" "/jffs/addons/vpnmon-r3.d/vr3timers.txt" elif [ "$2" = "WG" ] && [ "$wgslottmp" = "1" ]; then sed -i "s/^WGTIMER$1=.*/WGTIMER$1=$(date +%s)/" "/jffs/addons/vpnmon-r3.d/vr3timers.txt" fi source /jffs/addons/vpnmon-r3.d/vr3timers.txt source /jffs/addons/vpnmon-r3.d/vr3clients.txt } # ------------------------------------------------------------------------------------------------------------------------- # Reset the managed VPN connections vreset() { # Grab the VPNMON-R3 config file and read it in if [ -f "$config" ] then source "$config" else clear echo -e "${CRed}ERROR: VPNMON-R3 is not configured. Please run 'vpnmon-r3.sh -setup' first." echo "" echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - ERROR: VPNMON-R3 config file not found. Please run the setup/configuration utility" >> $logfile echo -e "${CClear}" exit 1 fi # Grab the monitored slots file and read it in if [ -f /jffs/addons/vpnmon-r3.d/vr3clients.txt ] then source /jffs/addons/vpnmon-r3.d/vr3clients.txt else clear echo -e "${CRed}ERROR: VPNMON-R3 is not configured. Please run 'vpnmon-r3.sh -setup' first." echo "" echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - ERROR: VPNMON-R3 VPN Client Monitoring file not found. Please run the setup/configuration utility" >> $logfile echo -e "${CClear}" exit 1 fi # Create a rudimentary lockfile so that VPNMON-R3 doesn't interfere during the reset echo -n > $lockfile slot=0 for slot in $availableslots #loop through the 2/5 vpn slots do clear echo -e "${InvGreen} ${InvDkGray}${CWhite} VPNMON-R3 - v$version | $(date) ${CClear}\n" echo -e "${CGreen}[VPN Connection Reset Commencing]" echo "" echo -e "${CGreen}[Checking VPN Slot $slot]" echo "" sleep 2 #determine if the slot is monitored and reset it if [ "$((VPN$slot))" = "1" ] then if [ "$refreshserverlists" -eq 1 ] then if [ -f "/jffs/addons/vpnmon-r3.d/vr3svr$slot.txt" ] then echo -e "${CGreen}[Executing Custom Server List Script for VPN Slot $slot]${CClear}" slottmp="automation${slot}" eval slottmp="\$${slottmp}" if [ -z "$slottmp" ] then echo "" echo -e "${CGreen}[Custom VPN Client Server Query not found for VPN Slot $slot]${CClear}" else automationunenc="$(echo "$slottmp" | openssl enc -d -base64 -A)" echo "" echo -e "${CClear}Running: $automationunenc" echo "" eval "$automationunenc" > "/jffs/addons/vpnmon-r3.d/vr3svrtmp.txt" if [ -f "/jffs/addons/vpnmon-r3.d/vr3svrtmp.txt" ] then dlcnt=$(cat "/jffs/addons/vpnmon-r3.d/vr3svrtmp.txt" | wc -l) >/dev/null 2>&1 if [ -z "$dlcnt" ] || [ "$dlcnt" -lt 1 ] then dlcnt=0 ; fi else dlcnt=0 fi if [ "$dlcnt" -gt 1 ] then cp "/jffs/addons/vpnmon-r3.d/vr3svrtmp.txt" "/jffs/addons/vpnmon-r3.d/vr3svr$slot.txt" >/dev/null 2>&1 rm -f "/jffs/addons/vpnmon-r3.d/vr3svrtmp.txt" >/dev/null 2>&1 echo -e "${CGreen}[$dlcnt Rows Retrieved From Source]${CClear}" echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - INFO: Custom VPN Client Server List Query Executed for VPN Slot $slot ($dlcnt rows)" >> $logfile sleep 3 echo "" skynetwhitelist $slot echo "" else rm -f "/jffs/addons/vpnmon-r3.d/vr3svrtmp.txt" >/dev/null 2>&1 echo -e "${CGreen}[$dlcnt Rows Retrieved From Source - Preserving Original Server List]${CClear}" echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - ERROR: Custom VPN Client Server List Query for VPN Slot $slot yielded 0 rows -- Query may be invalid or VPN API service may be down" >> $logfile sendmessage 1 "VPN Server List Query Yielded 0 Rows" $slot sleep 3 echo "" fi fi else echo "" echo -e "${CRed}[Custom VPN Client Server List File not found for VPN Slot $slot]${CClear}" echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - ERROR: Custom VPN Client Server List File not found for VPN Slot $slot" >> $logfile sleep 3 fi fi restartvpn $slot sendmessage 0 "VPN Connection Scheduled Reset" $slot fi done slot=0 for slot in $availableslots #loop through the 5 wg slots do clear echo -e "${InvGreen} ${InvDkGray}${CWhite} VPNMON-R3 - v$version | $(date) ${CClear}\n" echo -e "${CGreen}[WG Connection Reset Commencing]" echo "" echo -e "${CGreen}[Checking WG Slot $slot]" echo "" sleep 2 #determine if the slot is monitored and reset it if [ "$((WG$slot))" = "1" ] then if [ "$refreshserverlists" -eq 1 ] then if [ -f "/jffs/addons/vpnmon-r3.d/vr3wgsvr$slot.txt" ] then echo -e "${CGreen}[Executing Custom WG Server List Script for WG Slot $slot]${CClear}" slottmp="wgautomation${slot}" eval slottmp="\$${slottmp}" if [ -z "$slottmp" ] then echo "" echo -e "${CGreen}[Custom WG Client Server Query not found for WG Slot $slot]${CClear}" else wgautomationunenc="$(echo "$slottmp" | openssl enc -d -base64 -A)" echo "" echo -e "${CClear}Running: $wgautomationunenc" echo "" eval "$wgautomationunenc" > "/jffs/addons/vpnmon-r3.d/vr3svrtmp.txt" if [ -f "/jffs/addons/vpnmon-r3.d/vr3svrtmp.txt" ] then dlcnt=$(cat "/jffs/addons/vpnmon-r3.d/vr3svrtmp.txt" | wc -l) >/dev/null 2>&1 if [ -z "$dlcnt" ] || [ "$dlcnt" -lt 1 ] then dlcnt=0 ; fi else dlcnt=0 fi if [ "$dlcnt" -gt 1 ] then cp "/jffs/addons/vpnmon-r3.d/vr3svrtmp.txt" "/jffs/addons/vpnmon-r3.d/vr3wgsvr$slot.txt" >/dev/null 2>&1 rm -f "/jffs/addons/vpnmon-r3.d/vr3svrtmp.txt" >/dev/null 2>&1 echo -e "${CGreen}[$dlcnt Rows Retrieved From Source]${CClear}" echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - INFO: Custom WG Client Server List Query Executed for WG Slot $slot ($dlcnt rows)" >> $logfile sleep 3 echo "" skynetwhitelist wg$slot echo "" else rm -f "/jffs/addons/vpnmon-r3.d/vr3svrtmp.txt" >/dev/null 2>&1 echo -e "${CGreen}[$dlcnt Rows Retrieved From Source - Preserving Original Server List]${CClear}" echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - ERROR: Custom WG Client Server List Query for WG Slot $slot yielded 0 rows -- Query may be invalid or WG API service may be down" >> $logfile sendmessage 1 "WG Server List Query Yielded 0 Rows" $slot sleep 3 echo "" fi fi else echo "" echo -e "${CRed}[Custom WG Client Server List File not found for WG Slot $slot]${CClear}" echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - ERROR: Custom WG Client Server List File not found for WG Slot $slot" >> $logfile sleep 3 fi fi restartwg $slot sendmessage 0 "WG Connection Scheduled Reset" $slot fi done restartrouting resetspdmerlin echo -e "${CGreen}[Reset Complete]${CClear}" # Clean up lockfile rm -f $lockfile >/dev/null 2>&1 echo -e "\n${CClear}" exit 0 } # ------------------------------------------------------------------------------------------------------------------------- ##----------------------------------------## ## Modified by Martinski W. [2024-Oct-18] ## ##----------------------------------------## # Find the VPN IP getvpnip() { ubsync="" TUN="tun1$1" icanhazvpnip="$($timeoutcmd$timeoutsec nvram get vpn_client$1_rip)" if [ -z "$icanhazvpnip" ] || [ "$icanhazvpnip" = "unknown" ] then # Grab the public IP of the VPN Connection # icanhazvpnip="curl --silent --retry 3 --retry-delay 2 --retry-all-errors --fail --interface "$TUN" --request GET --url https://ipv4.icanhazip.com" icanhazvpnip="$(eval $icanhazvpnip)" if [ -z "$icanhazvpnip" ] || echo "$icanhazvpnip" | grep -qoE 'Internet|traffic|Error|error' ; then icanhazvpnip="0.0.0.0" ; fi fi if [ -z "$icanhazvpnip" ] then vpnip="000.000.000.000" return else vpnip="$(printf '%15s' "$icanhazvpnip")" fi if [ "$unboundclient" -ne 0 ] && [ "$unboundclient" -eq "$1" ] then if [ "$ResolverTimer" -eq 1 ]; then ResolverTimer=0 if [ "$unboundshowip" -eq 0 ]; then ubsync="${CYellow}-?[UB]${CClear}" else ubsync="${CYellow}-?[UB:Resolving]${CClear}" fi else # Huge thanks to @SomewhereOverTheRainbow for his expertise in troublshooting and coming up with this DNS Resolver methodology! DNSResolver="$({ unbound-control flush whoami.akamai.net >/dev/null 2>&1; } && dig whoami.akamai.net +short @"$(netstat -nlp 2>/dev/null | awk '/.*(unbound){1}.*/{split($4, ip_addr, ":");if(substr($4,11) !~ /.*953.*/)print ip_addr[1];if(substr($4,11) !~ /.*953.*/)exit}')" -p "$(netstat -nlp 2>/dev/null | awk '/.*(unbound){1}.*/{if(substr($4,11) !~ /.*953.*/)print substr($4,11);if(substr($4,11) !~ /.*953.*/)exit}')" 2>/dev/null)" if [ -z "$DNSResolver" ] then if [ "$unboundshowip" -eq 0 ]; then ubsync="${CRed}-X[UB]${CClear}" else ubsync="${CRed}-X[UB:$DNSResolver]${CClear}" fi # rudimentary check to make sure value coming back is in the format of an IP address... Don't care if it's more than 255. elif expr "$DNSResolver" : '[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*$' >/dev/null then # If the DNS resolver and public VPN IP address don't match in our Unbound scenario, reset! if [ "$DNSResolver" != "$icanhazvpnip" ] then if [ "$unboundshowip" -eq 0 ]; then ubsync="${CRed}-X[UB]${CClear}" else ubsync="${CRed}-X[UB:$DNSResolver]${CClear}" fi ResolverTimer=1 unboundreset=$1 else if [ "$unboundshowip" -eq 0 ]; then ubsync="${CGreen}->[UB]${CClear}" else ubsync="${CGreen}->[UB:$DNSResolver]${CClear}" fi fi else if [ "$unboundshowip" -eq 0 ]; then ubsync="${CYellow}-?[UB]${CClear}" else ubsync="${CYellow}-?[UB:$DNSResolver]${CClear}" fi fi fi else ubsync="" fi # Insert bogus IP if screenshotmode is on # if [ "$screenshotmode" = "1" ]; then vpnip="$(printf '%15s' "12.34.56.78")" fi } # ------------------------------------------------------------------------------------------------------------------------- ##-----------------------------------------------------------------------------------------## ## Modified by ViktorJp [2025-Jul-06], origial getvpnip modded by Martinski. [2024-Oct-18] ## ##-----------------------------------------------------------------------------------------## # Find the WG IP getwgip() { ubsync="" TUN="wgc$1" # Added ping workaround for site2site scenarios based on suggestion from @ZebMcKayhan TUN_IP=$($timeoutcmd$timeoutsec nvram get "$TUN"_addr | cut -d '/' -f1) ip rule add from $TUN_IP lookup $TUN prio 10 >/dev/null 2>&1 icanhazwgip="curl --silent --retry 3 --retry-delay 2 --retry-all-errors --fail --interface "$TUN" --request GET --url https://ipv4.icanhazip.com" icanhazwgip="$(eval $icanhazwgip)" if [ -z "$icanhazwgip" ] || echo "$icanhazwgip" | grep -qoE 'Internet|traffic|Error|error' ; then icanhazwgip="0.0.0.0" ; fi if [ -z "$icanhazwgip" ] then wgip="000.000.000.000" return else wgip="$(printf '%15s' "$icanhazwgip")" fi if [ "$unboundwgclient" -ne 0 ] && [ "$unboundwgclient" -eq "$1" ] then if [ "$ResolverTimer" -eq 1 ]; then ResolverTimer=0 if [ "$unboundshowip" -eq 0 ]; then ubsync="${CYellow}-?[UB]${CClear}" else ubsync="${CYellow}-?[UB:Resolving]${CClear}" fi else # Huge thanks to @SomewhereOverTheRainbow for his expertise in troublshooting and coming up with this DNS Resolver methodology! DNSResolver="$({ unbound-control flush whoami.akamai.net >/dev/null 2>&1; } && dig whoami.akamai.net +short @"$(netstat -nlp 2>/dev/null | awk '/.*(unbound){1}.*/{split($4, ip_addr, ":");if(substr($4,11) !~ /.*953.*/)print ip_addr[1];if(substr($4,11) !~ /.*953.*/)exit}')" -p "$(netstat -nlp 2>/dev/null | awk '/.*(unbound){1}.*/{if(substr($4,11) !~ /.*953.*/)print substr($4,11);if(substr($4,11) !~ /.*953.*/)exit}')" 2>/dev/null)" if [ -z "$DNSResolver" ] then if [ "$unboundshowip" -eq 0 ]; then ubsync="${CRed}-X[UB]${CClear}" else ubsync="${CRed}-X[UB:$DNSResolver]${CClear}" fi # rudimentary check to make sure value coming back is in the format of an IP address... Don't care if it's more than 255. elif expr "$DNSResolver" : '[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*$' >/dev/null then # If the DNS resolver and public VPN IP address don't match in our Unbound scenario, reset! if [ "$DNSResolver" != "$icanhazwgip" ] then if [ "$unboundshowip" -eq 0 ]; then ubsync="${CRed}-X[UB]${CClear}" else ubsync="${CRed}-X[UB:$DNSResolver]${CClear}" fi ResolverTimer=1 unboundreset=$1 else if [ "$unboundshowip" -eq 0 ]; then ubsync="${CGreen}->[UB]${CClear}" else ubsync="${CGreen}->[UB:$DNSResolver]${CClear}" fi fi else if [ "$unboundshowip" -eq 0 ]; then ubsync="${CYellow}-?[UB]${CClear}" else ubsync="${CYellow}-?[UB:$DNSResolver]${CClear}" fi fi fi else ubsync="" fi # Added based on suggestion from @ZebMcKayhan ip rule del prio 10 >/dev/null 2>&1 # Insert bogus IP if screenshotmode is on # if [ "$screenshotmode" = "1" ]; then wgip="$(printf '%15s' "12.34.56.78")" fi } # ------------------------------------------------------------------------------------------------------------------------- ##----------------------------------------## ## Modified by Martinski W. [2024-Oct-18] ## ##----------------------------------------## # Find and remember the VPN city so it doesn't have to make successive API lookups getvpncity() { if [ "$icanhazvpnip" = "0.0.0.0" ]; then vpncity="Undetermined" return fi if [ "$1" = "1" ] then lastvpnip1="$icanhazvpnip" if [ "$lastvpnip1" != "$oldvpnip1" ] then vpncity="curl --silent --retry 3 --retry-delay 2 --retry-all-errors --request GET --url http://ip-api.com/json/$icanhazvpnip | jq --raw-output .city" vpncity="$(eval $vpncity)" if [ -z "$vpncity" ] || echo "$vpncity" | grep -qoE '\b(error.*:.*True.*|Undefined)\b' ; then vpncity="Undetermined" ; fi citychange="${CGreen}- NEW ${CClear}" vpncity1="$vpncity" fi vpncity="$vpncity1" oldvpnip1="$lastvpnip1" elif [ "$1" = "2" ] then lastvpnip2="$icanhazvpnip" if [ "$lastvpnip2" != "$oldvpnip2" ] then vpncity="curl --silent --retry 3 --retry-delay 2 --retry-all-errors --request GET --url http://ip-api.com/json/$icanhazvpnip | jq --raw-output .city" vpncity="$(eval $vpncity)" if [ -z "$vpncity" ] || echo "$vpncity" | grep -qoE '\b(error.*:.*True.*|Undefined)\b' ; then vpncity="Undetermined" ; fi citychange="${CGreen}- NEW ${CClear}" vpncity2="$vpncity" fi vpncity="$vpncity2" oldvpnip2="$lastvpnip2" elif [ "$1" = "3" ] then lastvpnip3="$icanhazvpnip" if [ "$lastvpnip3" != "$oldvpnip3" ] then vpncity="curl --silent --retry 3 --retry-delay 2 --retry-all-errors --request GET --url http://ip-api.com/json/$icanhazvpnip | jq --raw-output .city" vpncity="$(eval $vpncity)" if [ -z "$vpncity" ] || echo "$vpncity" | grep -qoE '\b(error.*:.*True.*|Undefined)\b' ; then vpncity="Undetermined" ; fi citychange="${CGreen}- NEW ${CClear}" vpncity3="$vpncity" fi vpncity="$vpncity3" oldvpnip3="$lastvpnip3" elif [ "$1" = "4" ] then lastvpnip4="$icanhazvpnip" if [ "$lastvpnip4" != "$oldvpnip4" ] then vpncity="curl --silent --retry 3 --retry-delay 2 --retry-all-errors --request GET --url http://ip-api.com/json/$icanhazvpnip | jq --raw-output .city" vpncity="$(eval $vpncity)" if [ -z "$vpncity" ] || echo "$vpncity" | grep -qoE '\b(error.*:.*True.*|Undefined)\b' ; then vpncity="Undetermined" ; fi citychange="${CGreen}- NEW ${CClear}" vpncity4="$vpncity" fi vpncity="$vpncity4" oldvpnip4="$lastvpnip4" elif [ "$1" = "5" ] then lastvpnip5="$icanhazvpnip" if [ "$lastvpnip5" != "$oldvpnip5" ] then vpncity="curl --silent --retry 3 --retry-delay 2 --retry-all-errors --request GET --url http://ip-api.com/json/$icanhazvpnip | jq --raw-output .city" vpncity="$(eval $vpncity)" if [ -z "$vpncity" ] || echo "$vpncity" | grep -qoE '\b(error.*:.*True.*|Undefined)\b' ; then vpncity="Undetermined" ; fi citychange="${CGreen}- NEW ${CClear}" vpncity5="$vpncity" fi vpncity="$vpncity5" oldvpnip5="$lastvpnip5" fi # Insert bogus City if screenshotmode is on if [ "$screenshotmode" = "1" ]; then vpncity="Gotham City" fi } # ------------------------------------------------------------------------------------------------------------------------- ##------------------------------------------------------------------------------------------------## ## Modified by ViktorJp [2025-Jul-06], Original getvpncity() modded bt Martinski W. [2024-Oct-18] ## ##------------------------------------------------------------------------------------------------## # Find and remember the WG city so it doesn't have to make successive API lookups getwgcity() { if [ "$icanhazwgip" = "0.0.0.0" ]; then wgcity="Undetermined" return fi # Added ping workaround for site2site scenarios based on suggestion from @ZebMcKayhan TUN_IP=$($timeoutcmd$timeoutsec nvram get "$TUN"_addr | cut -d '/' -f1) ip rule add from $TUN_IP lookup $TUN prio 10 >/dev/null 2>&1 if [ "$1" = "1" ] then lastwgip1="$icanhazwgip" if [ "$lastwgip1" != "$oldwgip1" ] then wgcity="curl --silent --retry 3 --retry-delay 2 --retry-all-errors --request GET --url http://ip-api.com/json/$icanhazwgip | jq --raw-output .city" wgcity="$(eval $wgcity)" if [ -z "$wgcity" ] || echo "$wgcity" | grep -qoE '\b(error.*:.*True.*|Undefined)\b' ; then wgcity="Undetermined" ; fi wgcitychange="${CGreen}- NEW ${CClear}" wgcity1="$wgcity" fi wgcity="$wgcity1" oldwgip1="$lastwgip1" elif [ "$1" = "2" ] then lastwgip2="$icanhazwgip" if [ "$lastwgip2" != "$oldwgip2" ] then wgcity="curl --silent --retry 3 --retry-delay 2 --retry-all-errors --request GET --url http://ip-api.com/json/$icanhazwgip | jq --raw-output .city" wgcity="$(eval $wgcity)" if [ -z "$wgcity" ] || echo "$wgcity" | grep -qoE '\b(error.*:.*True.*|Undefined)\b' ; then wgcity="Undetermined" ; fi wgcitychange="${CGreen}- NEW ${CClear}" wgcity2="$wgcity" fi wgcity="$wgcity2" oldwgip2="$lastwgip2" elif [ "$1" = "3" ] then lastwgip3="$icanhazwgip" if [ "$lastwgip3" != "$oldwgip3" ] then wgcity="curl --silent --retry 3 --retry-delay 2 --retry-all-errors --request GET --url http://ip-api.com/json/$icanhazwgip | jq --raw-output .city" wgcity="$(eval $wgcity)" if [ -z "$wgcity" ] || echo "$wgcity" | grep -qoE '\b(error.*:.*True.*|Undefined)\b' ; then wgcity="Undetermined" ; fi wgcitychange="${CGreen}- NEW ${CClear}" wgcity3="$wgcity" fi wgcity="$wgcity3" oldwgip3="$lastwgip3" elif [ "$1" = "4" ] then lastwgip4="$icanhazwgip" if [ "$lastwgip4" != "$oldwgip4" ] then wgcity="curl --silent --retry 3 --retry-delay 2 --retry-all-errors --request GET --url http://ip-api.com/json/$icanhazwgip | jq --raw-output .city" wgcity="$(eval $wgcity)" if [ -z "$wgcity" ] || echo "$wgcity" | grep -qoE '\b(error.*:.*True.*|Undefined)\b' ; then wgcity="Undetermined" ; fi wgcitychange="${CGreen}- NEW ${CClear}" wgcity4="$wgcity" fi wgcity="$wgcity4" oldwgip4="$lastwgip4" elif [ "$1" = "5" ] then lastwgip5="$icanhazwgip" if [ "$lastwgip5" != "$oldwgip5" ] then wgcity="curl --silent --retry 3 --retry-delay 2 --retry-all-errors --request GET --url http://ip-api.com/json/$icanhazwgip | jq --raw-output .city" wgcity="$(eval $wgcity)" if [ -z "$wgcity" ] || echo "$wgcity" | grep -qoE '\b(error.*:.*True.*|Undefined)\b' ; then wgcity="Undetermined" ; fi wgcitychange="${CGreen}- NEW ${CClear}" wgcity5="$wgcity" fi wgcity="$wgcity5" oldwgip5="$lastwgip5" fi # Added based on suggestion from @ZebMcKayhan ip rule del prio 10 >/dev/null 2>&1 # Insert bogus City if screenshotmode is on if [ "$screenshotmode" = "1" ]; then wgcity="Gotham City" fi } # ------------------------------------------------------------------------------------------------------------------------- # Check health of the vpn connection using PING and CURL checkvpn() { CNT=0 TRIES=3 TUN="tun1$1" while [ "$CNT" -lt "$TRIES" ]; do # Loop through number of tries ping -I $TUN -q -c 1 -W 2 $PINGHOST > /dev/null 2>&1 # First try pings RC=$? # Grab the public IP of the VPN Connection # ICANHAZIP="$(curl --silent --retry 3 --retry-delay 2 --retry-all-errors --fail --interface "$TUN" --request GET --url https://ipv4.icanhazip.com)" IC=$? if [ "$RC" -eq 0 ] && [ "$IC" -eq 0 ]; then # If both ping/curl come back successful, then proceed vpnping=$(ping -I $TUN -c 1 -W 2 $PINGHOST | awk -F'time=| ms' 'NF==3{print $(NF-1)}' | sort -rn) > /dev/null 2>&1 VP=$? if [ "$VP" -eq 0 ]; then vpnhealth="${CGreen}[ OK ]${CClear}" vpnindicator="${InvGreen} ${CClear}" if [ "$problemvpnslot" -eq "$1" ]; then vrcnt=0 problemvpnslot=0 fi else vpnping=0 vpnhealth="${CYellow}[UNKN]${CClear}" vpnindicator="${InvYellow} ${CClear}" fi printf "\33[2K\r" break else CNT="$((CNT+1))" printf "\33[2K\r" printf "\r${InvDkGray} ${CWhite} VPN$1${CClear} [Attempt $CNT]" sleep 1 # Giving the VPN a chance to recover a certain number of times if [ "$CNT" -eq "$TRIES" ];then # But if it fails, report back that we have an issue requiring a VPN reset printf "\33[2K\r" vpnping=0 vpnhealth="${CRed}[FAIL]${CClear}" vpnindicator="${InvRed} ${CClear}" echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - WARNING: VPN$1 failed to respond" >> $logfile vrcnt="$((vrcnt+1))" problemvpnslot="$1" if [ "$vrcnt" -ge 10 ]; then monitored="${CRed}[!]${CClear}" else monitored="${CRed}[$vrcnt]${CClear}" fi echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - WARNING: VPN$1 attempt $vrcnt of $recover to allow connection to recover" >> $logfile if [ "$vrcnt" -eq "$recover" ]; then if [ "$((VPN$1))" = "1" ]; then echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - WARNING: VPN$1 failed to respond after $recover attempt(s)" >> $logfile resetvpn=$1 fi fi fi fi done } # ------------------------------------------------------------------------------------------------------------------------- # Check health of the WG connection using PING and CURL checkwg() { CNT=0 TRIES=3 TUN="wgc$1" # Added ping workaround for site2site scenarios based on suggestion from @ZebMcKayhan TUN_IP=$($timeoutcmd$timeoutsec nvram get "$TUN"_addr | cut -d '/' -f1) ip rule add from $TUN_IP lookup $TUN prio 10 >/dev/null 2>&1 while [ "$CNT" -lt "$TRIES" ]; do # Loop through number of tries ping -I $TUN -q -c 1 -W 2 $PINGHOST > /dev/null 2>&1 # First try pings RC=$? # Grab the public IP of the VPN Connection # ICANHAZIP="$(curl --silent --retry 3 --retry-delay 2 --retry-all-errors --fail --interface "$TUN" --request GET --url https://ipv4.icanhazip.com)" IC=$? if [ "$RC" -eq 0 ] && [ "$IC" -eq 0 ]; then # If both ping/curl come back successful, then proceed wgping=$(ping -I $TUN -c 1 -W 2 $PINGHOST | awk -F'time=| ms' 'NF==3{print $(NF-1)}' | sort -rn) > /dev/null 2>&1 VP=$? if [ "$VP" -eq 0 ]; then wghealth="${CGreen}[ OK ]${CClear}" wgindicator="${InvGreen} ${CClear}" if [ "$problemwgslot" -eq "$1" ]; then wrcnt=0 problemwgslot=0 fi else wgping=0 wghealth="${CYellow}[UNKN]${CClear}" wgindicator="${InvYellow} ${CClear}" fi printf "\33[2K\r" break else CNT="$((CNT+1))" printf "\33[2K\r" printf "\r${InvDkGray} ${CWhite} WGC$1${CClear} [Attempt $CNT]" sleep 1 # Giving the VPN a chance to recover a certain number of times if [ "$CNT" -eq "$TRIES" ]; then # But if it fails, report back that we have an issue requiring a VPN reset printf "\33[2K\r" wgping=0 wghealth="${CRed}[FAIL]${CClear}" wgindicator="${InvRed} ${CClear}" echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - WARNING: WGC$1 failed to respond" >> $logfile wrcnt="$((wrcnt+1))" problemwgslot="$1" if [ "$wrcnt" -ge 10 ]; then wgmonitored="${CRed}[!]${CClear}" else wgmonitored="${CRed}[$wrcnt]${CClear}" fi echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - WARNING: WGC$1 attempt $wrcnt of $recover to allow connection to recover" >> $logfile if [ "$wrcnt" -eq "$recover" ]; then if [ "$((WG$1))" = "1" ]; then echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - WARNING: WGC$1 failed to respond after $recover attempt(s)" >> $logfile resetwg=$1 fi fi fi fi done # Added based on suggestion from @ZebMcKayhan ip rule del prio 10 >/dev/null 2>&1 } # ------------------------------------------------------------------------------------------------------------------------- # Checkwan is a function that checks the viability of the current WAN connection and will loop until the WAN connection is restored. checkwan() { # Using Google's DNS server as default to test for WAN connectivity over verified SSL Handshake wandownbreakertrip=0 testssl="$PING_HOST_Deflt" printf "\33[2K\r" printf "\r${InvYellow} ${CClear} [Checking WAN Connectivity]..." #Run main checkwan loop while true do # Check the actual WAN State from NVRAM before running connectivity test, or insert itself into loop after failing an SSL handshake test if [ "$($timeoutcmd$timeoutsec nvram get wan0_state_t)" -eq 2 ] || [ "$($timeoutcmd$timeoutsec nvram get wan1_state_t)" -eq 2 ] then # Test the active WAN connection using 443 and verifying a handshake... if this fails, then the WAN connection is most likely down... or Google is down ;) if ($timeoutcmd$timeoutlng nc -w3 $testssl 443 >/dev/null 2>&1 && echo | $timeoutcmd$timeoutlng openssl s_client -connect $testssl:443 >/dev/null 2>&1 | awk 'handshake && $1 == "Verification" { if ($2=="OK") exit; exit 1 } $1 $2 == "SSLhandshake" { handshake = 1 }' >/dev/null 2>&1) ##OFF##if ($timeoutcmd$timeoutlng nc -w1 $testssl 443 >/dev/null 2>&1 && echo | $timeoutcmd$timeoutlng openssl s_client -connect $testssl:443 >/dev/null 2>&1 | awk '$1 == "SSL" && $2 == "handshake" { handshake = 1 } handshake && $1 == "Verification:" { ok = $2; exit } END { exit ok != "OK" }' >/dev/null 2>&1) then printf "\r${InvGreen} ${CClear} [Checking WAN Connectivity]...ACTIVE" sleep 1 printf "\33[2K\r" return else wandownbreakertrip=1 echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - ERROR: WAN Connectivity Issue Detected" >> $logfile fi else wandownbreakertrip=1 echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - ERROR: WAN Connectivity Issue Detected" >> $logfile fi if [ "$wandownbreakertrip" = "1" ] then # The WAN is most likely down, and keep looping through until NVRAM reports that it's back up while [ "$wandownbreakertrip" = "1" ] do if [ "$availableslots" = "1 2" ] then state1="$(_VPN_GetClientState_ 1)" state2="$(_VPN_GetClientState_ 2)" printf "\r${InvGreen} ${CClear} [Confirming VPN Clients Disconnected]... 1:$state1 2:$state2 " sleep 3 elif [ "$availableslots" = "1 2 3 4 5" ] then state1="$(_VPN_GetClientState_ 1)" state2="$(_VPN_GetClientState_ 2)" state3="$(_VPN_GetClientState_ 3)" state4="$(_VPN_GetClientState_ 4)" state5="$(_VPN_GetClientState_ 5)" printf "\r${InvGreen} ${CClear} [Confirming VPN Clients Disconnected]... 1:$state1 2:$state2 3:$state3 4:$state4 5:$state5 " sleep 3 fi # Preemptively kill all the VPN Clients incase they're trying to reconnect on their own for slot in $availableslots do if [ $((state$slot)) -ne 0 ]; then printf "\r${InvGreen} ${CClear} [Retrying Kill Command on VPN$slot Client Connection]... " service stop_vpnclient$slot >/dev/null 2>&1 sleep 3 fi done # Check the wireguard side and bring those down as well if [ "$availableslots" = "1 2 3 4 5" ] then wgstate1="$(_WG_GetClientState_ 1)" wgstate2="$(_WG_GetClientState_ 2)" wgstate3="$(_WG_GetClientState_ 3)" wgstate4="$(_WG_GetClientState_ 4)" wgstate5="$(_WG_GetClientState_ 5)" printf "\r${InvGreen} ${CClear} [Confirming WG Clients Disconnected]... 1:$wgstate1 2:$wgstate2 3:$wgstate3 4:$wgstate4 5:$wgstate5 " sleep 3 fi # Preemptively kill all the WG Clients incase they're trying to reconnect on their own for slot in $availableslots do if [ $((wgstate$slot)) -ne 0 ]; then printf "\r${InvGreen} ${CClear} [Retrying Kill Command on WGC$slot Client Connection]... " service "stop_wgc $slot" >/dev/null 2>&1 sleep 3 fi done # Continue to test for WAN connectivity while in this loop. If it comes back up, break out of the loop and reset VPN if [ "$($timeoutcmd$timeoutsec nvram get wan0_state_t)" -ne 2 ] && [ "$($timeoutcmd$timeoutsec nvram get wan1_state_t)" -ne 2 ] then # Continue to loop and retest the WAN every 15 seconds echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - ERROR: WAN DOWN" >> $logfile clear echo -e "${InvGreen} ${InvDkGray}${CWhite} Router is Currently Experiencing a WAN Down Situation ${CClear}" echo -e "${InvGreen} ${CClear}" echo -e "${InvGreen} ${CClear} Router is unable to provide a stable WAN connection. Please reboot your modem,${CClear}" echo -e "${InvGreen} ${CClear} check with your ISP, or perform general internet connectivity troubleshooting${CClear}" echo -e "${InvGreen} ${CClear} in order to re-establish a stable VPN connection.${CClear}" echo -e "${InvGreen} ${CClear}" echo -e "${InvGreen} ${CClear} [Retrying to resume normal operations roughly every 60 seconds]${CClear}" echo -e "${InvGreen} ${CClear}${CDkGray}---------------------------------------------------------------------------------------${CClear}" echo "" spinner 60 wandownbreakertrip=1 else wandownbreakertrip=2 break fi done fi # If the WAN was down, and now it has just reset, then run a VPN Reset, and try to establish a new VPN connection if [ "$wandownbreakertrip" = "2" ] then echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - WARNING: WAN Link Detected -- Trying to Reconnect/Reset VPN/WG" >> $logfile wandownbreakertrip=0 clear echo -e "${InvGreen} ${InvDkGray}${CWhite} VPNMON-R3 is currently recovering from a WAN Down Situation ${CClear}" echo -e "${InvGreen} ${CClear}" echo -e "${InvGreen} ${CClear} Router has detected a WAN Link/Modem and waiting 300 seconds for general network${CClear}" echo -e "${InvGreen} ${CClear} connectivity to stabilize before re-establishing VPN/WG connectivity.${CClear}" echo -e "${InvGreen} ${CClear}" echo -e "${InvGreen} ${CClear} [Retrying to resume normal operations in roughly 300 seconds...Please stand by!]${CClear}" echo -e "${InvGreen} ${CClear}${CDkGray}---------------------------------------------------------------------------------------${CClear}" echo "" spinner 300 #sendmessage 1 "Recovering from WAN Down" - this doesn't work when the internet is down exec sh /jffs/scripts/vpnmon-r3.sh -noswitch fi done } # ------------------------------------------------------------------------------------------------------------------------- ##----------------------------------------## ## Modified by Martinski W. [2024-Oct-18] ## ##----------------------------------------## # wancheck is a function that checks each wan connection to see if its active, and performs a ping and a city lookup... wancheck() { WANIF="$1" WANIFNAME="$(get_wan_setting ifname)" DUALWANMODE="$($timeoutcmd$timeoutsec nvram get wans_mode)" # Uptime calc # uptimeStr="$(awk '{printf("%dd %02dh:%02dm\n",($1/60/60/24),($1/60/60%24),($1/60%60),($1%60))}' /proc/uptime)" # If WAN 0 or 1 is connected, then proceed, else display that it's inactive if [ "$WANIF" = "0" ] then if [ "$($timeoutcmd$timeoutsec nvram get wan0_state_t)" -eq 2 ] then # Call the get_wan_setting function courtesy of @dave14305 and using this interface name to ping and get a city name from WAN0IFNAME="$(get_wan_setting0 ifname)" # Ping through the WAN interface # if [ "$WANIFNAME" = "$WAN0IFNAME" ] || [ "$DUALWANMODE" = "lb" ] then WAN0PING="$(ping -I "$WAN0IFNAME" -c 1 "$PINGHOST" 2>/dev/null | awk -F'[/=]' 'END{print $5}')" ## No need to do left-padding with zeros for alignment ## [ -n "${WAN0PING:+xSETx}" ] && WAN0PING="$(printf "[%8.3f]" "$WAN0PING")" else WAN0PING="[FAILOVER]" fi # On the rare occasion where it's unable to get the Ping time, show ERROR # if [ -z "$WAN0PING" ] ; then WAN0PING="${CRed}[PING ERR]${CClear}" ; fi # Get the public IP of the WAN, determine the city from it, and display it on screen # if [ -z "${WAN0IP:+xSETx}" ] then WAN0IP="$(curl --silent --retry 3 --retry-delay 2 --retry-all-errors --fail --interface "$WAN0IFNAME" --request GET --url https://ipv4.icanhazip.com)" WAN0CITY="curl --silent --retry 3 --retry-delay 2 --retry-all-errors --request GET --url http://ip-api.com/json/$WAN0IP | jq --raw-output .city" WAN0CITY="$(eval $WAN0CITY)" if [ -z "$WAN0CITY" ] || echo "$WAN0CITY" | grep -qoE '\b(error.*:.*True.*|Undefined)\b' ; then WAN0CITY="$WAN0IP" ; fi WAN0IP="$(printf '%15s' "$WAN0IP")" fi # Insert bogus IP and City if screenshotmode is on if [ "$screenshotmode" = "1" ] then WAN0CITY="Metropolis" WAN0IP="$(printf '%15s' "11.22.33.44")" fi WAN0BWRX="$(printf '%4s' "$diffwan0rxbytes")" if [ -z "$diffwan0rxbytes" ] || [ "$diffwan0rxbytes" = "" ] || [ "$diffwan0rxbytes" -lt 0 ] then WAN0RX1="${CRed}[UNKN]${CClear}" elif [ "$diffwan0rxbytes" -ge 0 ] && [ "$diffwan0rxbytes" -le "$lowutilspd" ] then WAN0RX1="${CGreen}[$WAN0BWRX]${CClear}" elif [ "$diffwan0rxbytes" -gt "$lowutilspd" ] && [ "$diffwan0rxbytes" -le "$medutilspd" ] then WAN0RX1="${CYellow}[$WAN0BWRX]${CClear}" elif [ "$diffwan0rxbytes" -gt "$medutilspd" ] then WAN0RX1="${CRed}[$WAN0BWRX]${CClear}" fi WAN0BWTX="$(printf '%4s' "$diffwan0txbytes")" if [ -z "$diffwan0txbytes" ] || [ "$diffwan0txbytes" = "" ] || [ "$diffwan0txbytes" -lt 0 ] then WAN0TX1="${CRed}[UNKN]${CClear}" elif [ "$diffwan0txbytes" -ge 0 ] && [ "$diffwan0txbytes" -le "$lowutilspdup" ] then WAN0TX1="${CGreen}[$WAN0BWTX]${CClear}" elif [ "$diffwan0txbytes" -gt "$lowutilspdup" ] && [ "$diffwan0txbytes" -le "$medutilspdup" ] then WAN0TX1="${CYellow}[$WAN0BWTX]${CClear}" elif [ "$diffwan0txbytes" -gt "$medutilspdup" ] then WAN0TX1="${CRed}[$WAN0BWTX]${CClear}" fi WAN0TPRX="$(printf '%4s' "$thruwan0rxbytes")" if [ -z "$thruwan0rxbytes" ] || [ "$thruwan0rxbytes" = "" ] || [ "$thruwan0rxbytes" -lt 0 ] then WAN0RX2="${CRed}[UNKN]${CClear}" elif [ "$thruwan0rxbytes" -ge 0 ] && [ "$thruwan0rxbytes" -le "$lowutilspd" ] then WAN0RX2="${CGreen}[$WAN0TPRX]${CClear}" elif [ "$thruwan0rxbytes" -gt "$lowutilspd" ] && [ "$thruwan0rxbytes" -le "$medutilspd" ] then WAN0RX2="${CYellow}[$WAN0TPRX]${CClear}" elif [ "$thruwan0rxbytes" -gt "$medutilspd" ] then WAN0RX2="${CRed}[$WAN0TPRX]${CClear}" fi WAN0TPTX="$(printf '%4s' "$thruwan0txbytes")" if [ -z "$thruwan0txbytes" ] || [ "$thruwan0txbytes" = "" ] || [ "$thruwan0txbytes" -lt 0 ] then WAN0TX2="${CRed}[UNKN]${CClear}" elif [ "$thruwan0txbytes" -ge 0 ] && [ "$thruwan0txbytes" -le "$lowutilspdup" ] then WAN0TX2="${CGreen}[$WAN0TPTX]${CClear}" elif [ "$thruwan0txbytes" -gt "$lowutilspdup" ] && [ "$thruwan0txbytes" -le "$medutilspdup" ] then WAN0TX2="${CYellow}[$WAN0TPTX]${CClear}" elif [ "$thruwan0txbytes" -gt "$medutilspdup" ] then WAN0TX2="${CRed}[$WAN0TPTX]${CClear}" fi if [ "$WAN0PING" = "[FAILOVER]" ] then echo -en "${InvGreen} ${InvDkGray}${CWhite} WAN0${CClear} | ${CGreen}[X]${CClear} | " printf "%-6s" "$WAN0IFNAME" if [ "$bwdisp" = "1" ]; then echo -e " | ${CGreen}[ OK ]${CClear} | Failover | $WAN0IP | $WAN0PING | $WAN0RX1 | $WAN0TX1 | $WAN0CITY: $uptimeStr" else echo -e " | ${CGreen}[ OK ]${CClear} | Failover | $WAN0IP | $WAN0PING | $WAN0RX2 | $WAN0TX2 | $WAN0CITY: $uptimeStr" fi else echo -en "${InvGreen} ${InvDkGray}${CWhite} WAN0${CClear} | ${CGreen}[X]${CClear} | " printf "%-6s" "$WAN0IFNAME" if [ "$bwdisp" = "1" ]; then echo -e " | ${CGreen}[ OK ]${CClear} | Active | $WAN0IP | $WAN0PING | $WAN0RX1 | $WAN0TX1 | $WAN0CITY: $uptimeStr" else echo -e " | ${CGreen}[ OK ]${CClear} | Active | $WAN0IP | $WAN0PING | $WAN0RX2 | $WAN0TX2 | $WAN0CITY: $uptimeStr" fi fi else echo -e "${InvDkGray}${CWhite} WAN0${CClear} | ${CGreen}[X]${CClear} | ${CDkGray}[n/a]${CClear} | ${CDkGray}[n/a ]${CClear} | Inactive | ${CDkGray}[n/a]${CClear} | ${CDkGray}[n/a]${CClear} | ${CDkGray}[n/a ]${CClear} | ${CDkGray}[n/a ]${CClear} | ${CDkGray}[n/a]${CClear}" fi fi if [ "$WANIF" = "1" ] then if [ "$($timeoutcmd$timeoutsec nvram get wan1_state_t)" -eq 2 ] then # Call the get_wan_setting function courtesy of @dave14305 and using this interface name to ping and get a city name from WAN1IFNAME="$(get_wan_setting1 ifname)" # Ping through the WAN interface # if [ "$WANIFNAME" = "$WAN1IFNAME" ] || [ "$DUALWANMODE" = "lb" ] then WAN1PING="$(ping -I "$WAN1IFNAME" -c 1 "$PINGHOST" 2>/dev/null | awk -F'[/=]' 'END{print $5}')" ## No need to do left-padding with zeros for alignment ## [ -n "${WAN1PING:+xSETx}" ] && WAN1PING="$(printf "[%8.3f]" "$WAN1PING")" else WAN1PING="[FAILOVER]" fi # On the rare occasion where it's unable to get the Ping time, show ERROR # if [ -z "$WAN1PING" ] ; then WAN1PING="${CRed}[PING ERR]${CClear}" ; fi # Get the public IP of the WAN, determine the city from it, and display it on screen # if [ -z "${WAN1IP:+xSETx}" ] then WAN1IP="$(curl --silent --retry 3 --retry-delay 2 --retry-all-errors --fail --interface "$WAN1IFNAME" --request GET --url https://ipv4.icanhazip.com)" WAN1CITY="curl --silent --retry 3 --retry-delay 2 --retry-all-errors --request GET --url http://ip-api.com/json/$WAN1IP | jq --raw-output .city" WAN1CITY="$(eval $WAN1CITY)" if [ -z "$WAN1CITY" ] || echo "$WAN1CITY" | grep -qoE '\b(error.*:.*True.*|Undefined)\b' ; then WAN1CITY="$WAN1IP" ; fi WAN1IP="$(printf '%15s' "$WAN1IP")" fi WAN1BWRX="$(printf '%4s' "$diffwan1rxbytes")" if [ -z "$diffwan1rxbytes" ] || [ "$diffwan1rxbytes" = "" ] || [ "$diffwan1rxbytes" -lt 0 ] then WAN1RX1="${CRed}[UNKN]${CClear}" elif [ "$diffwan1rxbytes" -ge 0 ] && [ "$diffwan1rxbytes" -le "$lowutilspd" ] then WAN1RX1="${CGreen}[$WAN1BWRX]${CClear}" elif [ "$diffwan1rxbytes" -gt "$lowutilspd" ] && [ "$diffwan1rxbytes" -le "$medutilspd" ] then WAN1RX1="${CYellow}[$WAN1BWRX]${CClear}" elif [ "$diffwan1rxbytes" -gt "$medutilspd" ] then WAN1RX1="${CRed}[$WAN1BWRX]${CClear}" fi WAN1BWTX="$(printf '%4s' "$diffwan1txbytes")" if [ -z "$diffwan1txbytes" ] || [ "$diffwan1txbytes" = "" ] || [ "$diffwan1txbytes" -lt 0 ] then WAN1TX1="${CRed}[UNKN]${CClear}" elif [ "$diffwan1txbytes" -ge 0 ] && [ "$diffwan1txbytes" -le "$lowutilspdup" ] then WAN1TX1="${CGreen}[$WAN1BWTX]${CClear}" elif [ "$diffwan1txbytes" -gt "$lowutilspdup" ] && [ "$diffwan1txbytes" -le "$medutilspdup" ] then WAN1TX1="${CYellow}[$WAN1BWTX]${CClear}" elif [ "$diffwan1txbytes" -gt "$medutilspdup" ] then WAN1TX1="${CRed}[$WAN1BWTX]${CClear}" fi WAN1TPRX="$(printf '%4s' "$thruwan1rxbytes")" if [ -z "$thruwan1rxbytes" ] || [ "$thruwan1rxbytes" = "" ] || [ "$thruwan1rxbytes" -lt 0 ] then WAN1RX2="${CRed}[UNKN]${CClear}" elif [ "$thruwan1rxbytes" -ge 0 ] && [ "$thruwan1rxbytes" -le "$lowutilspd" ] then WAN1RX2="${CGreen}[$WAN1TPRX]${CClear}" elif [ "$thruwan1rxbytes" -gt "$lowutilspd" ] && [ "$thruwan1rxbytes" -le "$medutilspd" ] then WAN1RX2="${CYellow}[$WAN1TPRX]${CClear}" elif [ "$thruwan1rxbytes" -gt "$medutilspd" ] then WAN1RX2="${CRed}[$WAN1TPRX]${CClear}" fi WAN1TPTX="$(printf '%4s' "$thruwan1txbytes")" if [ -z "$thruwan1txbytes" ] || [ "$thruwan1txbytes" = "" ] || [ "$thruwan1txbytes" -lt 0 ] then WAN1TX2="${CRed}[UNKN]${CClear}" elif [ "$thruwan1txbytes" -ge 0 ] && [ "$thruwan1txbytes" -le "$lowutilspdup" ] then WAN1TX2="${CGreen}[$WAN1TPTX]${CClear}" elif [ "$thruwan1txbytes" -gt "$lowutilspdup" ] && [ "$thruwan1txbytes" -le "$medutilspdup" ] then WAN1TX2="${CYellow}[$WAN1TPTX]${CClear}" elif [ "$thruwan1txbytes" -gt "$medutilspdup" ] then WAN1TX2="${CRed}[$WAN1TPTX]${CClear}" fi if [ "$WAN1PING" = "[FAILOVER]" ] then echo -en "${InvGreen} ${InvDkGray}${CWhite} WAN1${CClear} | ${CGreen}[X]${CClear} | " printf "%-6s" "$WAN1IFNAME" if [ "$bwdisp" = "1" ]; then echo -e " | ${CGreen}[ OK ]${CClear} | Failover | $WAN1IP | $WAN1PING | $WAN1RX1 | $WAN1TX1 | $WAN1CITY: $uptimeStr" else echo -e " | ${CGreen}[ OK ]${CClear} | Failover | $WAN1IP | $WAN1PING | $WAN1RX2 | $WAN1TX2 | $WAN1CITY: $uptimeStr" fi else echo -en "${InvGreen} ${InvDkGray}${CWhite} WAN1${CClear} | ${CGreen}[X]${CClear} | " printf "%-6s" "$WAN1IFNAME" if [ "$bwdisp" = "1" ]; then echo -e " | ${CGreen}[ OK ]${CClear} | Active | $WAN1IP | $WAN1PING | $WAN1RX1 | $WAN1TX1 | $WAN1CITY: $uptimeStr" else echo -e " | ${CGreen}[ OK ]${CClear} | Active | $WAN1IP | $WAN1PING | $WAN1RX2 | $WAN1TX2 | $WAN1CITY: $uptimeStr" fi fi else echo -e "${InvDkGray}${CWhite} WAN1${CClear} | ${CGreen}[X]${CClear} | ${CDkGray}[n/a]${CClear} | ${CDkGray}[n/a ]${CClear} | Inactive | ${CDkGray}[n/a]${CClear} | ${CDkGray}[n/a]${CClear} | ${CDkGray}[n/a ]${CClear} | ${CDkGray}[n/a ]${CClear} | ${CDkGray}[n/a]${CClear}" fi fi } # ------------------------------------------------------------------------------------------------------------------------- # This function was "borrowed" graciously from @dave14305 from his FlexQoS script to determine the active WAN connection. # Thanks much for your troubleshooting help as we tackled how to best derive the active WAN interface, Dave! get_wan_setting() { local varname varval varname="${1}" prefixes="wan0_ wan1_" if [ "$($timeoutcmd$timeoutsec nvram get wans_mode)" = "lb" ] ; then for prefix in $prefixes; do state="$($timeoutcmd$timeoutsec nvram get "${prefix}"state_t)" sbstate="$($timeoutcmd$timeoutsec nvram get "${prefix}"sbstate_t)" auxstate="$($timeoutcmd$timeoutsec nvram get "${prefix}"auxstate_t)" # is_wan_connect() [ "${state}" = "2" ] || continue [ "${sbstate}" = "0" ] || continue [ "${auxstate}" = "0" ] || [ "${auxstate}" = "2" ] || continue # get_wan_ifname() proto="$($timeoutcmd$timeoutsec nvram get "${prefix}"proto)" if [ "${proto}" = "pppoe" ] || [ "${proto}" = "pptp" ] || [ "${proto}" = "l2tp" ] ; then varval="$($timeoutcmd$timeoutsec nvram get "${prefix}"pppoe_"${varname}")" else varval="$($timeoutcmd$timeoutsec nvram get "${prefix}""${varname}")" fi done else for prefix in $prefixes; do primary="$($timeoutcmd$timeoutsec nvram get "${prefix}"primary)" [ "${primary}" = "1" ] && break done proto="$($timeoutcmd$timeoutsec nvram get "${prefix}"proto)" if [ "${proto}" = "pppoe" ] || [ "${proto}" = "pptp" ] || [ "${proto}" = "l2tp" ] ; then varval="$($timeoutcmd$timeoutsec nvram get "${prefix}"pppoe_"${varname}")" else varval="$($timeoutcmd$timeoutsec nvram get "${prefix}""${varname}")" fi fi printf "%s" "${varval}" } # Separated these out to get the ifname for a dual-wan/failover situation where both WAN connections are on get_wan_setting0() { local varname varval varname="${1}" prefixes="wan0_" if [ "$($timeoutcmd$timeoutsec nvram get wans_mode)" = "lb" ] ; then for prefix in $prefixes; do state="$($timeoutcmd$timeoutsec nvram get "${prefix}"state_t)" sbstate="$($timeoutcmd$timeoutsec nvram get "${prefix}"sbstate_t)" auxstate="$($timeoutcmd$timeoutsec nvram get "${prefix}"auxstate_t)" # is_wan_connect() [ "${state}" = "2" ] || continue [ "${sbstate}" = "0" ] || continue [ "${auxstate}" = "0" ] || [ "${auxstate}" = "2" ] || continue # get_wan_ifname() proto="$($timeoutcmd$timeoutsec nvram get "${prefix}"proto)" if [ "${proto}" = "pppoe" ] || [ "${proto}" = "pptp" ] || [ "${proto}" = "l2tp" ] ; then varval="$($timeoutcmd$timeoutsec nvram get "${prefix}"pppoe_"${varname}")" else varval="$($timeoutcmd$timeoutsec nvram get "${prefix}""${varname}")" fi done else for prefix in $prefixes; do primary="$($timeoutcmd$timeoutsec nvram get "${prefix}"primary)" [ "${primary}" = "1" ] && break done proto="$($timeoutcmd$timeoutsec nvram get "${prefix}"proto)" if [ "${proto}" = "pppoe" ] || [ "${proto}" = "pptp" ] || [ "${proto}" = "l2tp" ] ; then varval="$($timeoutcmd$timeoutsec nvram get "${prefix}"pppoe_"${varname}")" else varval="$($timeoutcmd$timeoutsec nvram get "${prefix}""${varname}")" fi fi printf "%s" "${varval}" } # Separated these out to get the ifname for a dual-wan/failover situation where both WAN connections are on get_wan_setting1() { local varname varval varname="${1}" prefixes="wan1_" if [ "$($timeoutcmd$timeoutsec nvram get wans_mode)" = "lb" ] ; then for prefix in $prefixes; do state="$($timeoutcmd$timeoutsec nvram get "${prefix}"state_t)" sbstate="$($timeoutcmd$timeoutsec nvram get "${prefix}"sbstate_t)" auxstate="$($timeoutcmd$timeoutsec nvram get "${prefix}"auxstate_t)" # is_wan_connect() [ "${state}" = "2" ] || continue [ "${sbstate}" = "0" ] || continue [ "${auxstate}" = "0" ] || [ "${auxstate}" = "2" ] || continue # get_wan_ifname() proto="$($timeoutcmd$timeoutsec nvram get "${prefix}"proto)" if [ "${proto}" = "pppoe" ] || [ "${proto}" = "pptp" ] || [ "${proto}" = "l2tp" ] ; then varval="$($timeoutcmd$timeoutsec nvram get "${prefix}"pppoe_"${varname}")" else varval="$($timeoutcmd$timeoutsec nvram get "${prefix}""${varname}")" fi done else for prefix in $prefixes; do primary="$($timeoutcmd$timeoutsec nvram get "${prefix}"primary)" [ "${primary}" = "1" ] && break done proto="$($timeoutcmd$timeoutsec nvram get "${prefix}"proto)" if [ "${proto}" = "pppoe" ] || [ "${proto}" = "pptp" ] || [ "${proto}" = "l2tp" ] ; then varval="$($timeoutcmd$timeoutsec nvram get "${prefix}"pppoe_"${varname}")" else varval="$($timeoutcmd$timeoutsec nvram get "${prefix}""${varname}")" fi fi printf "%s" "${varval}" } # ------------------------------------------------------------------------------------------------------------------------- # These functions grab the difference between WAN, OVPN and WG connection stats and calculate Mbps getifacestats() { if [ ! -z "$WAN0IFNAME" ] then oldwan0rxbytes="$($timeoutcmd$timeoutsec cat /sys/class/net/$WAN0IFNAME/statistics/rx_bytes)" oldwan0txbytes="$($timeoutcmd$timeoutsec cat /sys/class/net/$WAN0IFNAME/statistics/tx_bytes)" fi if [ ! -z "$WAN1IFNAME" ] then oldwan1rxbytes="$($timeoutcmd$timeoutsec cat /sys/class/net/$WAN1IFNAME/statistics/rx_bytes)" oldwan1txbytes="$($timeoutcmd$timeoutsec cat /sys/class/net/$WAN1IFNAME/statistics/tx_bytes)" fi if [ "$availableslots" = "1 2" ] then state1="$(_VPN_GetClientState_ 1)" state2="$(_VPN_GetClientState_ 2)" state3=0 state4=0 state5=0 wgstate1=0 wgstate2=0 wgstate3=0 wgstate4=0 wgstate5=0 elif [ "$availableslots" = "1 2 3 4 5" ] then state1="$(_VPN_GetClientState_ 1)" state2="$(_VPN_GetClientState_ 2)" state3="$(_VPN_GetClientState_ 3)" state4="$(_VPN_GetClientState_ 4)" state5="$(_VPN_GetClientState_ 5)" wgstate1="$(_WG_GetClientState_ 1)" wgstate2="$(_WG_GetClientState_ 2)" wgstate3="$(_WG_GetClientState_ 3)" wgstate4="$(_WG_GetClientState_ 4)" wgstate5="$(_WG_GetClientState_ 5)" fi if [ "$state1" -eq 2 ]; then oldvpn1txrxbytes=$(awk -F',' '1 == /TUN\/TAP read bytes/ {print $2} 1 == /TUN\/TAP write bytes/ {print $2}' /tmp/etc/openvpn/client1/status 2>/dev/null) oldvpn1rxbytes="$(echo $oldvpn1txrxbytes | cut -d' ' -f1)" oldvpn1txbytes="$(echo $oldvpn1txrxbytes | cut -d' ' -f2)" if [ -z $oldvpn1rxbytes ]; then oldvpn1rxbytes=0; fi if [ -z $oldvpn1txbytes ]; then oldvpn1txbytes=0; fi fi if [ "$state2" -eq 2 ]; then oldvpn2txrxbytes=$(awk -F',' '1 == /TUN\/TAP read bytes/ {print $2} 1 == /TUN\/TAP write bytes/ {print $2}' /tmp/etc/openvpn/client2/status 2>/dev/null) oldvpn2rxbytes="$(echo $oldvpn2txrxbytes | cut -d' ' -f1)" oldvpn2txbytes="$(echo $oldvpn2txrxbytes | cut -d' ' -f2)" if [ -z $oldvpn2rxbytes ]; then oldvpn2rxbytes=0; fi if [ -z $oldvpn2txbytes ]; then oldvpn2txbytes=0; fi fi if [ "$state3" -eq 2 ]; then oldvpn3txrxbytes=$(awk -F',' '1 == /TUN\/TAP read bytes/ {print $2} 1 == /TUN\/TAP write bytes/ {print $2}' /tmp/etc/openvpn/client3/status 2>/dev/null) oldvpn3rxbytes="$(echo $oldvpn3txrxbytes | cut -d' ' -f1)" oldvpn3txbytes="$(echo $oldvpn3txrxbytes | cut -d' ' -f2)" if [ -z $oldvpn3rxbytes ]; then oldvpn3rxbytes=0; fi if [ -z $oldvpn3txbytes ]; then oldvpn3txbytes=0; fi fi if [ "$state4" -eq 2 ]; then oldvpn4txrxbytes=$(awk -F',' '1 == /TUN\/TAP read bytes/ {print $2} 1 == /TUN\/TAP write bytes/ {print $2}' /tmp/etc/openvpn/client4/status 2>/dev/null) oldvpn4rxbytes="$(echo $oldvpn4txrxbytes | cut -d' ' -f1)" oldvpn4txbytes="$(echo $oldvpn4txrxbytes | cut -d' ' -f2)" if [ -z $oldvpn4rxbytes ]; then oldvpn4rxbytes=0; fi if [ -z $oldvpn4txbytes ]; then oldvpn4txbytes=0; fi fi if [ "$state5" -eq 2 ]; then oldvpn5txrxbytes=$(awk -F',' '1 == /TUN\/TAP read bytes/ {print $2} 1 == /TUN\/TAP write bytes/ {print $2}' /tmp/etc/openvpn/client5/status 2>/dev/null) oldvpn5rxbytes="$(echo $oldvpn5txrxbytes | cut -d' ' -f1)" oldvpn5txbytes="$(echo $oldvpn5txrxbytes | cut -d' ' -f2)" if [ -z $oldvpn5rxbytes ]; then oldvpn5rxbytes=0; fi if [ -z $oldvpn5txbytes ]; then oldvpn5txbytes=0; fi fi if [ "$wgstate1" -eq 2 ]; then oldwg1txrxbytes=$(wg show wgc1 transfer) oldwg1rxbytes="$(echo $oldwg1txrxbytes | cut -d' ' -f2)" oldwg1txbytes="$(echo $oldwg1txrxbytes | cut -d' ' -f3)" if [ -z $oldwg1rxbytes ] || [ $oldwg1rxbytes -le 0 ]; then oldwg1rxbytes=0; fi if [ -z $oldwg1txbytes ] || [ $oldwg1txbytes -le 0 ]; then oldwg1txbytes=0; fi fi if [ "$wgstate2" -eq 2 ]; then oldwg2txrxbytes=$(wg show wgc2 transfer) oldwg2rxbytes="$(echo $oldwg2txrxbytes | cut -d' ' -f2)" oldwg2txbytes="$(echo $oldwg2txrxbytes | cut -d' ' -f3)" if [ -z $oldwg2rxbytes ] || [ $oldwg2rxbytes -le 0 ]; then oldwg2rxbytes=0; fi if [ -z $oldwg2txbytes ] || [ $oldwg2txbytes -le 0 ]; then oldwg2txbytes=0; fi fi if [ "$wgstate3" -eq 2 ]; then oldwg3txrxbytes=$(wg show wgc3 transfer) oldwg3rxbytes="$(echo $oldwg3txrxbytes | cut -d' ' -f2)" oldwg3txbytes="$(echo $oldwg3txrxbytes | cut -d' ' -f3)" if [ -z $oldwg3rxbytes ] || [ $oldwg3rxbytes -le 0 ]; then oldwg3rxbytes=0; fi if [ -z $oldwg3txbytes ] || [ $oldwg3txbytes -le 0 ]; then oldwg3txbytes=0; fi fi if [ "$wgstate4" -eq 2 ]; then oldwg4txrxbytes=$(wg show wgc4 transfer) oldwg4rxbytes="$(echo $oldwg4txrxbytes | cut -d' ' -f2)" oldwg4txbytes="$(echo $oldwg4txrxbytes | cut -d' ' -f3)" if [ -z $oldwg4rxbytes ] || [ $oldwg4rxbytes -le 0 ]; then oldwg4rxbytes=0; fi if [ -z $oldwg4txbytes ] || [ $oldwg4txbytes -le 0 ]; then oldwg4txbytes=0; fi fi if [ "$wgstate5" -eq 2 ]; then oldwg5txrxbytes=$(wg show wgc5 transfer) oldwg5rxbytes="$(echo $oldwg5txrxbytes | cut -d' ' -f2)" oldwg5txbytes="$(echo $oldwg5txrxbytes | cut -d' ' -f3)" if [ -z $oldwg5rxbytes ] || [ $oldwg5rxbytes -le 0 ]; then oldwg5rxbytes=0; fi if [ -z $oldwg5txbytes ] || [ $oldwg5txbytes -le 0 ]; then oldwg5txbytes=0; fi fi } calcifacestats() { if [ "$resetifacestatsswitch" -eq 1 ] then resetifacestatsswitch=0 return fi if [ ! -z "$WAN0IFNAME" ] then newwan0rxbytes="$($timeoutcmd$timeoutsec cat /sys/class/net/$WAN0IFNAME/statistics/rx_bytes)" newwan0txbytes="$($timeoutcmd$timeoutsec cat /sys/class/net/$WAN0IFNAME/statistics/tx_bytes)" diffwan0rxbytes=$(awk -v new=$newwan0rxbytes -v old=$oldwan0rxbytes -v mb=125000 -v lp=$timerloop 'BEGIN{printf "%.0f\n", ((new-old)/mb)/lp}') diffwan0txbytes=$(awk -v new=$newwan0txbytes -v old=$oldwan0txbytes -v mb=125000 -v lp=$timerloop 'BEGIN{printf "%.0f\n", ((new-old)/mb)/lp}') thruwan0rxbytes=$(awk -v new=$newwan0rxbytes -v old=$oldwan0rxbytes -v mb=1000000 'BEGIN{printf "%.0f\n", (new-old)/mb}') thruwan0txbytes=$(awk -v new=$newwan0txbytes -v old=$oldwan0txbytes -v mb=1000000 'BEGIN{printf "%.0f\n", (new-old)/mb}') fi if [ ! -z "$WAN1IFNAME" ] then newwan1rxbytes="$($timeoutcmd$timeoutsec cat /sys/class/net/$WAN1IFNAME/statistics/rx_bytes)" newwan1txbytes="$($timeoutcmd$timeoutsec cat /sys/class/net/$WAN1IFNAME/statistics/tx_bytes)" diffwan1rxbytes=$(awk -v new=$newwan1rxbytes -v old=$oldwan1rxbytes -v mb=125000 -v lp=$timerloop 'BEGIN{printf "%.0f\n", ((new-old)/mb)/lp}') diffwan1txbytes=$(awk -v new=$newwan1txbytes -v old=$oldwan1txbytes -v mb=125000 -v lp=$timerloop 'BEGIN{printf "%.0f\n", ((new-old)/mb)/lp}') thruwan1rxbytes=$(awk -v new=$newwan1rxbytes -v old=$oldwan1rxbytes -v mb=1000000 'BEGIN{printf "%.0f\n", (new-old)/mb}') thruwan1txbytes=$(awk -v new=$newwan1txbytes -v old=$oldwan1txbytes -v mb=1000000 'BEGIN{printf "%.0f\n", (new-old)/mb}') fi if [ "$availableslots" = "1 2" ] then state1="$(_VPN_GetClientState_ 1)" state2="$(_VPN_GetClientState_ 2)" elif [ "$availableslots" = "1 2 3 4 5" ] then state1="$(_VPN_GetClientState_ 1)" state2="$(_VPN_GetClientState_ 2)" state3="$(_VPN_GetClientState_ 3)" state4="$(_VPN_GetClientState_ 4)" state5="$(_VPN_GetClientState_ 5)" wgstate1="$(_WG_GetClientState_ 1)" wgstate2="$(_WG_GetClientState_ 2)" wgstate3="$(_WG_GetClientState_ 3)" wgstate4="$(_WG_GetClientState_ 4)" wgstate5="$(_WG_GetClientState_ 5)" fi if [ "$state1" -eq 2 ]; then newvpn1txrxbytes=$(awk -F',' '1 == /TUN\/TAP read bytes/ {print $2} 1 == /TUN\/TAP write bytes/ {print $2}' /tmp/etc/openvpn/client1/status 2>/dev/null) newvpn1rxbytes="$(echo $newvpn1txrxbytes | cut -d' ' -f1)" newvpn1txbytes="$(echo $newvpn1txrxbytes | cut -d' ' -f2)" if [ -z $newvpn1rxbytes ]; then newvpn1rxbytes=0; fi if [ -z $newvpn1txbytes ]; then newvpn1txbytes=0; fi diffvpn1rxbytes=$(awk -v new=$newvpn1rxbytes -v old=$oldvpn1rxbytes -v mb=125000 -v lp=$timerloop 'BEGIN{printf "%.0f\n", ((new-old)/mb)/lp}') diffvpn1txbytes=$(awk -v new=$newvpn1txbytes -v old=$oldvpn1txbytes -v mb=125000 -v lp=$timerloop 'BEGIN{printf "%.0f\n", ((new-old)/mb)/lp}') thruvpn1rxbytes=$(awk -v new=$newvpn1rxbytes -v old=$oldvpn1rxbytes -v mb=1000000 'BEGIN{printf "%.0f\n", (new-old)/mb}') thruvpn1txbytes=$(awk -v new=$newvpn1txbytes -v old=$oldvpn1txbytes -v mb=1000000 'BEGIN{printf "%.0f\n", (new-old)/mb}') else diffvpn1rxbytes="" diffvpn1txbytes="" thruvpn1rxbytes="" thruvpn1txbytes="" fi if [ "$state2" -eq 2 ]; then newvpn2txrxbytes=$(awk -F',' '1 == /TUN\/TAP read bytes/ {print $2} 1 == /TUN\/TAP write bytes/ {print $2}' /tmp/etc/openvpn/client2/status 2>/dev/null) newvpn2rxbytes="$(echo $newvpn2txrxbytes | cut -d' ' -f1)" newvpn2txbytes="$(echo $newvpn2txrxbytes | cut -d' ' -f2)" if [ -z $newvpn2rxbytes ]; then newvpn2rxbytes=0; fi if [ -z $newvpn2txbytes ]; then newvpn2txbytes=0; fi diffvpn2rxbytes=$(awk -v new=$newvpn2rxbytes -v old=$oldvpn2rxbytes -v mb=125000 -v lp=$timerloop 'BEGIN{printf "%.0f\n", ((new-old)/mb)/lp}') diffvpn2txbytes=$(awk -v new=$newvpn2txbytes -v old=$oldvpn2txbytes -v mb=125000 -v lp=$timerloop 'BEGIN{printf "%.0f\n", ((new-old)/mb)/lp}') thruvpn2rxbytes=$(awk -v new=$newvpn2rxbytes -v old=$oldvpn2rxbytes -v mb=1000000 'BEGIN{printf "%.0f\n", (new-old)/mb}') thruvpn2txbytes=$(awk -v new=$newvpn2txbytes -v old=$oldvpn2txbytes -v mb=1000000 'BEGIN{printf "%.0f\n", (new-old)/mb}') else diffvpn2rxbytes="" diffvpn2txbytes="" thruvpn2rxbytes="" thruvpn2txbytes="" fi if [ "$state3" -eq 2 ]; then newvpn3txrxbytes=$(awk -F',' '1 == /TUN\/TAP read bytes/ {print $2} 1 == /TUN\/TAP write bytes/ {print $2}' /tmp/etc/openvpn/client3/status 2>/dev/null) newvpn3rxbytes="$(echo $newvpn3txrxbytes | cut -d' ' -f1)" newvpn3txbytes="$(echo $newvpn3txrxbytes | cut -d' ' -f2)" if [ -z $newvpn3rxbytes ]; then newvpn3rxbytes=0; fi if [ -z $newvpn3txbytes ]; then newvpn3txbytes=0; fi diffvpn3rxbytes=$(awk -v new=$newvpn3rxbytes -v old=$oldvpn3rxbytes -v mb=125000 -v lp=$timerloop 'BEGIN{printf "%.0f\n", ((new-old)/mb)/lp}') diffvpn3txbytes=$(awk -v new=$newvpn3txbytes -v old=$oldvpn3txbytes -v mb=125000 -v lp=$timerloop 'BEGIN{printf "%.0f\n", ((new-old)/mb)/lp}') thruvpn3rxbytes=$(awk -v new=$newvpn3rxbytes -v old=$oldvpn3rxbytes -v mb=1000000 'BEGIN{printf "%.0f\n", (new-old)/mb}') thruvpn3txbytes=$(awk -v new=$newvpn3txbytes -v old=$oldvpn3txbytes -v mb=1000000 'BEGIN{printf "%.0f\n", (new-old)/mb}') else diffvpn3rxbytes="" diffvpn3txbytes="" thruvpn3rxbytes="" thruvpn3txbytes="" fi if [ "$state4" -eq 2 ]; then newvpn4txrxbytes=$(awk -F',' '1 == /TUN\/TAP read bytes/ {print $2} 1 == /TUN\/TAP write bytes/ {print $2}' /tmp/etc/openvpn/client4/status 2>/dev/null) newvpn4rxbytes="$(echo $newvpn4txrxbytes | cut -d' ' -f1)" newvpn4txbytes="$(echo $newvpn4txrxbytes | cut -d' ' -f2)" if [ -z $newvpn4rxbytes ]; then newvpn4rxbytes=0; fi if [ -z $newvpn4txbytes ]; then newvpn4txbytes=0; fi diffvpn4rxbytes=$(awk -v new=$newvpn4rxbytes -v old=$oldvpn4rxbytes -v mb=125000 -v lp=$timerloop 'BEGIN{printf "%.0f\n", ((new-old)/mb)/lp}') diffvpn4txbytes=$(awk -v new=$newvpn4txbytes -v old=$oldvpn4txbytes -v mb=125000 -v lp=$timerloop 'BEGIN{printf "%.0f\n", ((new-old)/mb)/lp}') thruvpn4rxbytes=$(awk -v new=$newvpn4rxbytes -v old=$oldvpn4rxbytes -v mb=1000000 'BEGIN{printf "%.0f\n", (new-old)/mb}') thruvpn4txbytes=$(awk -v new=$newvpn4txbytes -v old=$oldvpn4txbytes -v mb=1000000 'BEGIN{printf "%.0f\n", (new-old)/mb}') else diffvpn4rxbytes="" diffvpn4txbytes="" thruvpn4rxbytes="" thruvpn4txbytes="" fi if [ "$state5" -eq 2 ]; then newvpn5txrxbytes=$(awk -F',' '1 == /TUN\/TAP read bytes/ {print $2} 1 == /TUN\/TAP write bytes/ {print $2}' /tmp/etc/openvpn/client5/status 2>/dev/null) newvpn5rxbytes="$(echo $newvpn5txrxbytes | cut -d' ' -f1)" newvpn5txbytes="$(echo $newvpn5txrxbytes | cut -d' ' -f2)" if [ -z $newvpn5rxbytes ]; then newvpn5rxbytes=0; fi if [ -z $newvpn5txbytes ]; then newvpn5txbytes=0; fi diffvpn5rxbytes=$(awk -v new=$newvpn5rxbytes -v old=$oldvpn5rxbytes -v mb=125000 -v lp=$timerloop 'BEGIN{printf "%.0f\n", ((new-old)/mb)/lp}') diffvpn5txbytes=$(awk -v new=$newvpn5txbytes -v old=$oldvpn5txbytes -v mb=125000 -v lp=$timerloop 'BEGIN{printf "%.0f\n", ((new-old)/mb)/lp}') thruvpn5rxbytes=$(awk -v new=$newvpn5rxbytes -v old=$oldvpn5rxbytes -v mb=1000000 'BEGIN{printf "%.0f\n", (new-old)/mb}') thruvpn5txbytes=$(awk -v new=$newvpn5txbytes -v old=$oldvpn5txbytes -v mb=1000000 'BEGIN{printf "%.0f\n", (new-old)/mb}') else diffvpn5rxbytes="" diffvpn5txbytes="" thruvpn5rxbytes="" thruvpn5txbytes="" fi if [ "$wgstate1" -eq 2 ]; then newwg1txrxbytes=$(wg show wgc1 transfer) newwg1rxbytes="$(echo $newwg1txrxbytes | cut -d' ' -f2)" newwg1txbytes="$(echo $newwg1txrxbytes | cut -d' ' -f3)" if [ -z $newwg1rxbytes ] || [ $newwg1rxbytes -le 0 ]; then newwg1rxbytes=0; fi if [ -z $newwg1txbytes ] || [ $newwg1txbytes -le 0 ]; then newwg1txbytes=0; fi diffwg1rxbytes=$(awk -v new=$newwg1rxbytes -v old=$oldwg1rxbytes -v mb=125000 -v lp=$timerloop 'BEGIN{printf "%.0f\n", ((new-old)/mb)/lp}') diffwg1txbytes=$(awk -v new=$newwg1txbytes -v old=$oldwg1txbytes -v mb=125000 -v lp=$timerloop 'BEGIN{printf "%.0f\n", ((new-old)/mb)/lp}') thruwg1rxbytes=$(awk -v new=$newwg1rxbytes -v old=$oldwg1rxbytes -v mb=1000000 'BEGIN{printf "%.0f\n", (new-old)/mb}') thruwg1txbytes=$(awk -v new=$newwg1txbytes -v old=$oldwg1txbytes -v mb=1000000 'BEGIN{printf "%.0f\n", (new-old)/mb}') else diffwg1rxbytes="" diffwg1txbytes="" thruwg1rxbytes="" thruwg1txbytes="" fi if [ "$wgstate2" -eq 2 ]; then newwg2txrxbytes=$(wg show wgc2 transfer) newwg2rxbytes="$(echo $newwg2txrxbytes | cut -d' ' -f2)" newwg2txbytes="$(echo $newwg2txrxbytes | cut -d' ' -f3)" if [ -z $newwg2rxbytes ] || [ $newwg2rxbytes -le 0 ]; then newwg2rxbytes=0; fi if [ -z $newwg2txbytes ] || [ $newwg2txbytes -le 0 ]; then newwg2txbytes=0; fi diffwg2rxbytes=$(awk -v new=$newwg2rxbytes -v old=$oldwg2rxbytes -v mb=125000 -v lp=$timerloop 'BEGIN{printf "%.0f\n", ((new-old)/mb)/lp}') diffwg2txbytes=$(awk -v new=$newwg2txbytes -v old=$oldwg2txbytes -v mb=125000 -v lp=$timerloop 'BEGIN{printf "%.0f\n", ((new-old)/mb)/lp}') thruwg2rxbytes=$(awk -v new=$newwg2rxbytes -v old=$oldwg2rxbytes -v mb=1000000 'BEGIN{printf "%.0f\n", (new-old)/mb}') thruwg2txbytes=$(awk -v new=$newwg2txbytes -v old=$oldwg2txbytes -v mb=1000000 'BEGIN{printf "%.0f\n", (new-old)/mb}') else diffwg2rxbytes="" diffwg2txbytes="" thruwg2rxbytes="" thruwg2txbytes="" fi if [ "$wgstate3" -eq 2 ]; then newwg3txrxbytes=$(wg show wgc3 transfer) newwg3rxbytes="$(echo $newwg3txrxbytes | cut -d' ' -f2)" newwg3txbytes="$(echo $newwg3txrxbytes | cut -d' ' -f3)" if [ -z $newwg3rxbytes ] || [ $newwg3rxbytes -le 0 ]; then newwg3rxbytes=0; fi if [ -z $newwg3txbytes ] || [ $newwg3txbytes -le 0 ]; then newwg3txbytes=0; fi diffwg3rxbytes=$(awk -v new=$newwg3rxbytes -v old=$oldwg3rxbytes -v mb=125000 -v lp=$timerloop 'BEGIN{printf "%.0f\n", ((new-old)/mb)/lp}') diffwg3txbytes=$(awk -v new=$newwg3txbytes -v old=$oldwg3txbytes -v mb=125000 -v lp=$timerloop 'BEGIN{printf "%.0f\n", ((new-old)/mb)/lp}') thruwg3rxbytes=$(awk -v new=$newwg3rxbytes -v old=$oldwg3rxbytes -v mb=1000000 'BEGIN{printf "%.0f\n", (new-old)/mb}') thruwg3txbytes=$(awk -v new=$newwg3txbytes -v old=$oldwg3txbytes -v mb=1000000 'BEGIN{printf "%.0f\n", (new-old)/mb}') else diffwg3rxbytes="" diffwg3txbytes="" thruwg3rxbytes="" thruwg3txbytes="" fi if [ "$wgstate4" -eq 2 ]; then newwg4txrxbytes=$(wg show wgc4 transfer) newwg4rxbytes="$(echo $newwg4txrxbytes | cut -d' ' -f2)" newwg4txbytes="$(echo $newwg4txrxbytes | cut -d' ' -f3)" if [ -z $newwg4rxbytes ] || [ $newwg4rxbytes -le 0 ]; then newwg4rxbytes=0; fi if [ -z $newwg4txbytes ] || [ $newwg4txbytes -le 0 ]; then newwg4txbytes=0; fi diffwg4rxbytes=$(awk -v new=$newwg4rxbytes -v old=$oldwg4rxbytes -v mb=125000 -v lp=$timerloop 'BEGIN{printf "%.0f\n", ((new-old)/mb)/lp}') diffwg4txbytes=$(awk -v new=$newwg4txbytes -v old=$oldwg4txbytes -v mb=125000 -v lp=$timerloop 'BEGIN{printf "%.0f\n", ((new-old)/mb)/lp}') thruwg4rxbytes=$(awk -v new=$newwg4rxbytes -v old=$oldwg4rxbytes -v mb=1000000 'BEGIN{printf "%.0f\n", (new-old)/mb}') thruwg4txbytes=$(awk -v new=$newwg4txbytes -v old=$oldwg4txbytes -v mb=1000000 'BEGIN{printf "%.0f\n", (new-old)/mb}') else diffwg4rxbytes="" diffwg4txbytes="" thruwg4rxbytes="" thruwg4txbytes="" fi if [ "$wgstate5" -eq 2 ]; then newwg5txrxbytes=$(wg show wgc5 transfer) newwg5rxbytes="$(echo $newwg5txrxbytes | cut -d' ' -f2)" newwg5txbytes="$(echo $newwg5txrxbytes | cut -d' ' -f3)" if [ -z $newwg5rxbytes ] || [ $newwg5rxbytes -le 0 ]; then newwg5rxbytes=0; fi if [ -z $newwg5txbytes ] || [ $newwg5txbytes -le 0 ]; then newwg5txbytes=0; fi diffwg5rxbytes=$(awk -v new=$newwg5rxbytes -v old=$oldwg5rxbytes -v mb=125000 -v lp=$timerloop 'BEGIN{printf "%.0f\n", ((new-old)/mb)/lp}') diffwg5txbytes=$(awk -v new=$newwg5txbytes -v old=$oldwg5txbytes -v mb=125000 -v lp=$timerloop 'BEGIN{printf "%.0f\n", ((new-old)/mb)/lp}') thruwg5rxbytes=$(awk -v new=$newwg5rxbytes -v old=$oldwg5rxbytes -v mb=1000000 'BEGIN{printf "%.0f\n", (new-old)/mb}') thruwg5txbytes=$(awk -v new=$newwg5txbytes -v old=$oldwg5txbytes -v mb=1000000 'BEGIN{printf "%.0f\n", (new-old)/mb}') else diffwg5rxbytes="" diffwg5txbytes="" thruwg5rxbytes="" thruwg5txbytes="" fi } resetifacestats() { diffwan0rxbytes="" diffwan0txbytes="" diffwan1rxbytes="" diffwan1txbytes="" diffvpn1rxbytes="" diffvpn1txbytes="" diffvpn2rxbytes="" diffvpn2txbytes="" diffvpn3rxbytes="" diffvpn3txbytes="" diffvpn4rxbytes="" diffvpn4txbytes="" diffvpn5rxbytes="" diffvpn5txbytes="" diffwg1rxbytes="" diffwg1txbytes="" diffwg2rxbytes="" diffwg2txbytes="" diffwg3rxbytes="" diffwg3txbytes="" diffwg4rxbytes="" diffwg4txbytes="" diffwg5rxbytes="" diffwg5txbytes="" thruwan0rxbytes="" thruwan0txbytes="" thruwan1rxbytes="" thruwan1txbytes="" thruvpn1rxbytes="" thruvpn1txbytes="" thruvpn2rxbytes="" thruvpn2txbytes="" thruvpn3rxbytes="" thruvpn3txbytes="" thruvpn4rxbytes="" thruvpn4txbytes="" thruvpn5rxbytes="" thruvpn5txbytes="" thruwg1rxbytes="" thruwg1txbytes="" thruwg2rxbytes="" thruwg2txbytes="" thruwg3rxbytes="" thruwg3txbytes="" thruwg4rxbytes="" thruwg4txbytes="" thruwg5rxbytes="" thruwg5txbytes="" resetifacestatsswitch=1 } # ------------------------------------------------------------------------------------------------------------------------- # This function displays the operations menu ##----------------------------------------## ## Modified by Martinski W. [2024-Oct-05] ## ##----------------------------------------## displayopsmenu() { #scheduler colors and indicators if [ "$schedule" = "0" ] then schedtime="${CDkGray}01:00${CClear}" elif [ "$schedule" = "1" ] then schedhrs="$(printf "%02d" "$schedulehrs")" schedmin="$(printf "%02d" "$schedulemin")" schedtime="${CGreen}$schedhrs:$schedmin${CClear}" fi #autostart colors and indicators if [ "$autostart" = "0" ]; then rebootprot="${CDkGray}Disabled${CClear}" elif [ "$autostart" = "1" ]; then rebootprot="${CGreen}Enabled${CClear}" fi if [ "$logsize" -eq 0 ]; then logSizeStr="${CDkGray}n/a${CClear}" else logSizeStr="${CGreen}${logsize}${CClear}" fi if [ -z "$timerloop" ]; then timerLoopStr="${CDkGray}n/a${CClear}" else timerLoopStr="${CGreen}$timerloop sec${CClear}" fi if [ "$pingreset" -eq 0 ]; then pingResetStr="${CDkGray}Disabled${CClear}" else pingResetStr="${CGreen}$pingreset ms${CClear}" fi if [ "$amtmemailsuccess" = "0" ] && [ "$amtmemailfailure" = "0" ]; then amtmdisp="${CDkGray}Disabled " elif [ "$amtmemailsuccess" = "1" ] && [ "$amtmemailfailure" = "0" ]; then amtmdisp="${CGreen}Success " elif [ "$amtmemailsuccess" = "0" ] && [ "$amtmemailfailure" = "1" ]; then amtmdisp="${CGreen}Failure " elif [ "$amtmemailsuccess" = "1" ] && [ "$amtmemailfailure" = "1" ]; then amtmdisp="${CGreen}Success, Failure" else amtmdisp="${CDkGray}Disabled " fi rldisp="" if [ "$amtmemailsuccess" = "1" ] || [ "$amtmemailfailure" = "1" ] then if [ "$ratelimit" = "0" ]; then rldisp="| ${CRed}RL" else rldisp="| RL: ${CGreen}$ratelimit/h" fi fi recoverdisp="${CClear}Recovery: ${CGreen}${recover}x${CClear}" #display operations menu if [ "$availableslots" = "1 2" ] then echo -e "${InvGreen} ${InvDkGray}${CWhite} Operations Menu ${CClear}" echo -e "${InvGreen} ${CClear} Reset/Reconnect VPN 1:${CGreen}(1)${CClear} 2:${CGreen}(2)${CClear} ${InvGreen} ${CClear} ${CGreen}(C)${CClear}onfiguration Menu / Main Setup Menu $rldisp${CClear}" echo -e "${InvGreen} ${CClear} Stop/Unmonitor VPN 1:${CGreen}(!)${CClear} 2:${CGreen}(@)${CClear} ${InvGreen} ${CClear} ${CGreen}(R)${CClear}eset VPN/WG CRON Time Scheduler: $schedtime" echo -e "${InvGreen} ${CClear} Enable/Disable ${CGreen}(M)${CClear}onitored VPN Slots | Time Reset ${InvGreen} ${CClear} ${CGreen}(L)${CClear}og Viewer / Trim Log Size (rows): $logSizeStr" echo -e "${InvGreen} ${CClear} Update/Maintain ${CGreen}(V)${CClear}PN Server Lists ${InvGreen} ${CClear} ${CGreen}(A)${CClear}utostart VPNMON-R3 on Reboot: $rebootprot" echo -e "${InvGreen} ${CClear} Edit/R${CGreen}(U)${CClear}n Server List Automation ${InvGreen} ${CClear} ${CGreen}(T)${CClear}imer Loop Check Interval: $timerLoopStr | $recoverdisp" echo -e "${InvGreen} ${CClear} AMTM Email Not${CGreen}(I)${CClear}fications: $amtmdisp ${InvGreen} ${CClear} ${CGreen}(P)${CClear}ing Maximum Before Reset in ms: $pingResetStr" echo -e "${InvGreen} ${CClear}${CDkGray}--------------------------------------------------------------------------------------------------------------------------------${CClear}" echo "" elif [ "$availableslots" = "1 2 3 4 5" ] then echo -e "${InvGreen} ${InvDkGray}${CWhite} Operations Menu ${CClear}" echo -e "${InvGreen} ${CClear} Reset/Reconnect VPN 1:${CGreen}(1)${CClear} 2:${CGreen}(2)${CClear} 3:${CGreen}(3)${CClear} 4:${CGreen}(4)${CClear} 5:${CGreen}(5)${CClear} ${InvGreen} ${CClear} ${CGreen}(C)${CClear}onfiguration Menu / Main Setup Menu $rldisp${CClear}" echo -e "${InvGreen} ${CClear} Stop/Unmonitor VPN 1:${CGreen}(!)${CClear} 2:${CGreen}(@)${CClear} 3:${CGreen}(#)${CClear} 4:${CGreen}($)${CClear} 5:${CGreen}(%)${CClear} ${InvGreen} ${CClear} ${CGreen}(R)${CClear}eset VPN/WG CRON Time Scheduler: $schedtime" echo -e "${InvGreen} ${CClear} Reset/Reconnect WG 1:${CGreen}(6)${CClear} 2:${CGreen}(7)${CClear} 3:${CGreen}(8)${CClear} 4:${CGreen}(9)${CClear} 5:${CGreen}(0)${CClear} ${InvGreen} ${CClear} ${CGreen}(L)${CClear}og Viewer / Trim Log Size (rows): $logSizeStr" echo -e "${InvGreen} ${CClear} Stop/Unmonitor WG 1:${CGreen}(^)${CClear} 2:${CGreen}(&)${CClear} 3:${CGreen}(-)${CClear} 4:${CGreen}(+)${CClear} 5:${CGreen}(=)${CClear} ${InvGreen} ${CClear} ${CGreen}(A)${CClear}utostart VPNMON-R3 on Reboot: $rebootprot" echo -e "${InvGreen} ${CClear} Enable/Disable ${CGreen}(M)${CClear}onitored VPN/WG Slots | Time Reset ${InvGreen} ${CClear} ${CGreen}(T)${CClear}imer Loop Check Interval: $timerLoopStr | $recoverdisp" echo -e "${InvGreen} ${CClear} Update/Maintain ${CGreen}(V)${CClear}PN/${CGreen}(W)${CClear}G Server Lists ${InvGreen} ${CClear} ${CGreen}(P)${CClear}ing Maximum Before Reset in ms: $pingResetStr" echo -e "${InvGreen} ${CClear} Edit/R${CGreen}(U)${CClear}n Server List Automation ${InvGreen} ${CClear} AMTM Email Not${CGreen}(I)${CClear}fications: $amtmdisp" echo -e "${InvGreen} ${CClear}${CDkGray}--------------------------------------------------------------------------------------------------------------------------------${CClear}" echo "" fi } # ------------------------------------------------------------------------------------------------------------------------- # Begin VPNMON-R2 Main Loop # ------------------------------------------------------------------------------------------------------------------------- #DEBUG=; set -x # uncomment/comment to enable/disable debug mode #{ # uncomment/comment to enable/disable debug mode # Create the necessary folder/file structure for VPNMON-R3 under /jffs/addons if [ ! -d "/jffs/addons/vpnmon-r3.d" ]; then mkdir -p "/jffs/addons/vpnmon-r3.d" fi # Check for and add an alias for VPNMON-R3 if ! grep -F "sh /jffs/scripts/vpnmon-r3.sh" /jffs/configs/profile.add >/dev/null 2>/dev/null; then echo "alias vpnmon-r3=\"sh /jffs/scripts/vpnmon-r3.sh\" # added by vpnmon-r3" >> /jffs/configs/profile.add fi ##-------------------------------------## ## Added by Martinski W. [2024-Oct-05] ## ##-------------------------------------## _SetUpTimeoutCmdVars_ _SetLAN_HostName_ ##-------------------------------------## ## Added by Martinski W. [2024-Nov-04] ## ##-------------------------------------## ROUTERMODEL="$($timeoutcmd$timeoutsec nvram get odmpid)" [ -z "$ROUTERMODEL" ] && ROUTERMODEL="$($timeoutcmd$timeoutsec nvram get productid)" FWVER="$($timeoutcmd$timeoutsec nvram get firmver | tr -d '.')" BUILDNO="$($timeoutcmd$timeoutsec nvram get buildno)" EXTENDNO="$($timeoutcmd$timeoutsec nvram get extendno)" if [ -z "$EXTENDNO" ]; then EXTENDNO=0; fi FWBUILD="${FWVER}.${BUILDNO}_${EXTENDNO}" # Check for updates updatecheck # Check and see if any commandline option is being used if [ $# -eq 0 ] || [ -z "$1" ] then clear exec sh /jffs/scripts/vpnmon-r3.sh -noswitch exit 0 fi # Check and see if an invalid commandline option is being used if [ "$1" = "-h" ] || [ "$1" = "-help" ] || [ "$1" = "-setup" ] || [ "$1" = "-reset" ] || [ "$1" = "-bw" ] || [ "$1" = "-noswitch" ] || [ "$1" = "-screen" ] || [ "$1" = "-now" ] || [ "$1" = "-uowginitstart" ] || [ "$1" = "-uowgnatstart" ] then clear else clear echo "" echo "VPNMON-R3 v$version" echo "" echo "Exiting due to invalid commandline options!" echo "(run 'vpnmon-r3 -h' for help)" echo "" echo -e "${CClear}" exit 0 fi # Check to see if the help option is being called if [ "$1" = "-h" ] || [ "$1" = "-help" ] then clear echo "" echo "VPNMON-R3 v$version Commandline Option Usage:" echo "" echo "vpnmon-r3 -h | -help" echo "vpnmon-r3 -setup" echo "vpnmon-r3 -reset" echo "vpnmon-r3 -bw" echo "vpnmon-r3 -screen" echo "vpnmon-r3 -screen -now" echo "" echo " -h | -help (this output)" echo " -setup (displays the setup menu)" echo " -reset (resets vpn connections and exits)" echo " -bw (runs vpnmon-r3 in monochrome mode)" echo " -screen (runs vpnmon-r3 in screen background)" echo " -screen -now (runs vpnmon-r3 in screen background immediately)" echo "" echo -e "${CClear}" exit 0 fi # Check to see if the Unbound-over-WG init-start action is being called if [ "$1" = "-uowginitstart" ] then uowginitstart exit 0 fi # Check to see if the Unbound-over-WG nat-start action is being called if [ "$1" = "-uowgnatstart" ] then uowgnatstart exit 0 fi # Check to see if a second command is being passed to remove color if [ "$1" = "-bw" ] || { [ $# -gt 1 ] && [ "$2" = "-bw" ] ; } then blackwhite fi # Check to see if the -now parameter is being called to bypass the screen timer if [ $# -gt 1 ] && [ "$2" = "-now" ] then bypassscreentimer=1 fi # Check to see if the setup option is being called if [ "$1" = "-setup" ] then logoNM vsetup exit 0 fi # Check to see if the reset option is being called if [ "$1" = "-reset" ] then echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - INFO: VPN Reset initiated through -RESET switch" >> $logfile vreset fi # Check to see if the screen option is being called and run operations normally using the screen utility if [ "$1" = "-screen" ] then screen -wipe >/dev/null 2>&1 # Kill any dead screen sessions sleep 1 ScreenSess=$(screen -ls | grep "vpnmon-r3" | awk '{print $1}' | cut -d . -f 1) if [ -z $ScreenSess ]; then if [ "$bypassscreentimer" = "1" ]; then screen -dmS "vpnmon-r3" $apppath -noswitch sleep 1 screen -r vpnmon-r3 else clear echo -e "${CClear}Executing ${CGreen}VPNMON-R3 v$version${CClear} using the SCREEN utility..." echo "" echo -e "${CClear}IMPORTANT:" echo -e "${CClear}In order to keep VPNMON-R3 running in the background," echo -e "${CClear}properly exit the SCREEN session by using: ${CGreen}CTRL-A + D${CClear}" echo "" screen -dmS "vpnmon-r3" $apppath -noswitch sleep 5 screen -r vpnmon-r3 exit 0 fi else if [ "$bypassscreentimer" = "1" ]; then sleep 1 else clear echo -e "${CClear}Connecting to existing ${CGreen}VPNMON-R3 v$version${CClear} SCREEN session...${CClear}" echo "" echo -e "${CClear}IMPORTANT:${CClear}" echo -e "${CClear}In order to keep VPNMON-R3 running in the background,${CClear}" echo -e "${CClear}properly exit the SCREEN session by using: ${CGreen}CTRL-A + D${CClear}" echo "" echo -e "${CClear}Switching to the SCREEN session in T-5 sec...${CClear}" echo -e "${CClear}" spinner 5 fi fi screen -dr $ScreenSess exit 0 fi # Check to see if the noswitch option is being called if [ "$1" = "-noswitch" ] then clear #last switch before the main program starts firstrun=1 # Clean up lockfile rm -f $lockfile >/dev/null 2>&1 if [ ! -f "$config" ] && [ ! -f "/opt/bin/timeout" ] && [ ! -f "/opt/sbin/screen" ] && [ ! -f "/opt/bin/jq" ] then echo -e "${CRed}ERROR: VPNMON-R3 is not configured. Please run 'vpnmon-r3 -setup' first.${CClear}" echo "" echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - ERROR: VPNMON-R3 is not configured. Please run the setup/configuration utility" >> $logfile exit 0 fi fi ubsync="" firstDataCollection=true resetifacestatsswitch=0 ##----------------------------------------## ## Modified by Martinski W. [2024-Nov-02] ## ##----------------------------------------## while true do _SetUpTimeoutCmdVars_ _SetLAN_HostName_ # Grab the VPNMON-R3 config file and read it in if [ -f "$config" ] then source "$config" else clear echo -e "${CRed}ERROR: VPNMON-R3 is not configured. Please run 'vpnmon-r3.sh -setup' first." echo "" echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - ERROR: VPNMON-R3 config file not found. Please run the setup/configuration utility" >> $logfile echo -e "${CClear}" exit 1 fi # Grab the monitored slots file and read it in if [ -f /jffs/addons/vpnmon-r3.d/vr3clients.txt ] then source /jffs/addons/vpnmon-r3.d/vr3clients.txt else clear echo -e "${CRed}ERROR: VPNMON-R3 is not configured. Please run 'vpnmon-r3.sh -setup' first." echo "" echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - ERROR: VPNMON-R3 VPN Client Monitoring file not found. Please run the setup/configuration utility" >> $logfile echo -e "${CClear}" exit 1 fi createconfigs # Grab the monitored slots file and read it in if [ -f /jffs/addons/vpnmon-r3.d/vr3timers.txt ] then source /jffs/addons/vpnmon-r3.d/vr3timers.txt else clear echo -e "${CRed}ERROR: VPNMON-R3 is not configured. Please run 'vpnmon-r3.sh -setup' first." echo "" echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - ERROR: VPNMON-R3 VPN Timer Monitoring file not found. Please run the setup/configuration utility" >> $logfile echo -e "${CClear}" exit 1 fi #Set variables resetvpn=0 resetwg=0 #Check to see if a reset is currently underway lockcheck clear #display the header if [ "$hideoptions" = "0" ] && [ "$hideoptions" != "$prevHideOpts" ] then timerreset=0 displayopsmenu else timerreset=0 fi prevHideOpts="$hideoptions" tzone="$(date +%Z)" tzonechars="${#tzone}" if [ "$tzonechars" = "1" ]; then tzspaces=" "; elif [ "$tzonechars" = "2" ]; then tzspaces=" "; elif [ "$tzonechars" = "3" ]; then tzspaces=" "; elif [ "$tzonechars" = "4" ]; then tzspaces=" "; elif [ "$tzonechars" = "5" ]; then tzspaces=" "; fi #Display VPNMON-R3 client header echo -en "${InvGreen} ${InvDkGray}${CWhite} VPNMON-R3 - v" printf "%-8s" $version echo -e " ${CGreen}(S)${CWhite}how/${CGreen}(H)${CWhite}ide Operations Menu ${InvDkGray} $tzspaces$(date) ${CClear}" #Display VPNMON-R2 Found Warning if [ -f /jffs/scripts/vpnmon-r2.sh ]; then echo -e "${InvYellow} ${InvRed}${CWhite} VPNMON-R2 Install Detected. Support and availability for R2 is being sunset. Press (X) for Uninstall Menu. ${CClear}" fi #Display VPNMON-R3 Update Notifications if [ "$UpdateNotify" != "0" ]; then echo -e "$UpdateNotify\n"; else echo -e "${CClear}"; fi #If WAN Monitoring is enabled, test WAN connection and show the following grid if [ "$monitorwan" = "1" ] && [ "$firstrun" = "1" ] then #Check to see if the WAN is up checkwan firstrun=0 fi if [ "$monitorwan" = "1" ] && [ "$firstrun" = "0" ] then #Display WAN ports grid if [ "$bwdisp" = "1" ]; then echo -e "${CClear} Port | Mon | IFace | Health | WAN State | Public WAN IP | Ping-->WAN | Rx Avg | Tx Avg | City Exit / Uptime" else echo -e "${CClear} Port | Mon | IFace | Health | WAN State | Public WAN IP | Ping-->WAN | Rx Ttl | Tx Ttl | City Exit / Uptime" fi echo -e "-------|-----|--------|--------|--------------|-----------------|------------|--------|------------------------------------------" #Cycle through the WANCheck connection function to display ping/city info wans=0 for wans in 0 1 do wancheck "$wans" done echo -e "-------|-----|--------|--------|--------------|-----------------|------------|--------|------------------------------------------" echo "" fi if [ "$useovpn" = "1" ] then echo -e "${InvDkGray} OpenVPN ${CClear}" echo "" #Display VPN client slot grid if [ "$unboundclient" != "0" ]; then if [ "$bwdisp" = "1" ]; then echo -e " Slot | Mon | Svrs | Health | VPN State | Public VPN IP | Ping-->VPN | Rx Avg | Tx Avg | City Exit / Time Connected / UB" else echo -e " Slot | Mon | Svrs | Health | VPN State | Public VPN IP | Ping-->VPN | Rx Ttl | Tx Ttl | City Exit / Time Connected / UB" fi else if [ "$bwdisp" = "1" ]; then echo -e " Slot | Mon | Svrs | Health | VPN State | Public VPN IP | Ping-->VPN | Rx Avg | Tx Avg | City Exit / Time Connected" else echo -e " Slot | Mon | Svrs | Health | VPN State | Public VPN IP | Ping-->VPN | Rx Ttl | Tx Ttl | City Exit / Time Connected" fi fi echo -e "-------|-----|--------|--------|--------------|-----------------|------------|--------|------------------------------------------" if "$firstDataCollection" ; then printf "\r\033[0K${InvYellow} ${CClear} Please wait..." ; sleep 1 ; fi i=0 for i in $availableslots #loop through the VPN slots do #Set variables citychange="" ubsync="" vpnrx1="" vpntx1="" vpnrx2="" vpntx2="" #determine if the slot is monitored# if [ "$((VPN$i))" = "1" ]; then monitored="${CGreen}[X]${CClear}" else monitored="[ ]" fi #determine the vpn state, and if connected, get vpn IP and city vpnstate="$(_VPN_GetClientState_ "$i")" if [ "$vpnstate" = "0" ] then vpnstate="Disconnected" vpnhealth="${CDkGray}[n/a ]${CClear}" vpnindicator="${InvDkGray} ${CClear}" vpnip=" ${CDkGray}[n/a]${CClear}" vpncity="${CDkGray}[n/a]${CClear}" svrping=" ${CDkGray}[n/a]${CClear}" vpnrx1="${CDkGray}[n/a ]${CClear}" vpntx1="${CDkGray}[n/a ]${CClear}" vpnrx2="${CDkGray}[n/a ]${CClear}" vpntx2="${CDkGray}[n/a ]${CClear}" elif [ "$vpnstate" = "-1" ] then vpnstate="Error State " vpnhealth="${CDkGray}[n/a ]${CClear}" vpnindicator="${InvDkGray} ${CClear}" vpnip="${CDkGray} [n/a]${CClear}" vpncity="${CDkGray}[n/a]${CClear}" svrping=" ${CDkGray}[n/a]${CClear}" vpnrx1="${CDkGray}[n/a ]${CClear}" vpntx1="${CDkGray}[n/a ]${CClear}" vpnrx2="${CDkGray}[n/a ]${CClear}" vpntx2="${CDkGray}[n/a ]${CClear}" elif [ "$vpnstate" = "1" ] then vpnstate="Connecting " vpnhealth="${CDkGray}[n/a ]${CClear}" vpnindicator="${InvYellow} ${CClear}" vpnip=" ${CDkGray}[n/a]${CClear}" vpncity="${CDkGray}[n/a]${CClear}" svrping=" ${CDkGray}[n/a]${CClear}" vpnrx1="${CDkGray}[n/a ]${CClear}" vpntx1="${CDkGray}[n/a ]${CClear}" vpnrx2="${CDkGray}[n/a ]${CClear}" vpntx2="${CDkGray}[n/a ]${CClear}" elif [ "$vpnstate" = "2" ] then vpnstate="Connected " checkvpn "$i" getvpnip "$i" getvpncity "$i" if [ -z "$vpnping" ] then svrping="${CRed}[PING ERR]${CClear}" vpnhealth="${CYellow}[UNKN]${CClear}" vpnindicator="${InvYellow} ${CClear}" else ## No need to do left-padding with zeros for alignment ## svrping="$(printf "[%8.3f]" "$vpnping")" fi else vpnstate="Unknown " vpnhealth="${CDkGray}[n/a ]${CClear}" vpnindicator="${InvDkGray} ${CClear}" vpnip=" ${CDkGray}[n/a]${CClear}" vpncity="${CDkGray}[n/a]${CClear}" svrping=" ${CDkGray}[n/a]${CClear}" fi #Determine how many server entries are in each of the vpn slot alternate server files# if [ -s "/jffs/addons/vpnmon-r3.d/vr3svr$i.txt" ] then servercnt="$(cat "/jffs/addons/vpnmon-r3.d/vr3svr$i.txt" | wc -l)" if [ -z "$servercnt" ] || [ "$servercnt" -lt 1 ] then servercnt="${CRed}[0000]${CClear}" else ## No need to do left-padding with zeros for alignment ## servercnt="$(printf "[%4d]" "$servercnt")" fi else servercnt="${CRed}[0000]${CClear}" fi #Calculate connected time for current VPN slot if [ $((VPNTIMER$i)) = "0" ] || [ "$((VPN$i))" = "0" ] then sincelastreset="" else currtime=$(date +%s) timediff=$((currtime-VPNTIMER$i)) sincelastreset=$(printf ': %dd %02dh:%02dm\n' $(($timediff/86400)) $(($timediff%86400/3600)) $(($timediff%3600/60))) fi if [ -z "$vpnrx1" ] then vpnbwrx="" tmpvpnslot="diffvpn${i}rxbytes" eval currentvpnslot=\$$tmpvpnslot vpnbwtx="$(printf '%4s' "$currentvpnslot")" if [ -z "$currentvpnslot" ] || [ "$currentvpnslot" = "" ] || [ "$currentvpnslot" -lt 0 ] then vpnrx1="${CRed}[UNKN]${CClear}" elif [ "$currentvpnslot" -ge 0 ] && [ "$currentvpnslot" -le "$lowutilspd" ] then vpnrx1="${CGreen}[$vpnbwtx]${CClear}" elif [ "$currentvpnslot" -gt "$lowutilspd" ] && [ "$currentvpnslot" -le "$medutilspd" ] then vpnrx1="${CYellow}[$vpnbwtx]${CClear}" elif [ "$currentvpnslot" -gt "$medutilspd" ] then vpnrx1="${CRed}[$vpnbwtx]${CClear}" fi fi if [ -z "$vpnrx2" ] then vpntprx="" tmpvpntpslot="thruvpn${i}rxbytes" eval currentvpntpslot=\$$tmpvpntpslot vpntptx="$(printf '%4s' "$currentvpntpslot")" if [ -z "$currentvpntpslot" ] || [ "$currentvpntpslot" = "" ] || [ "$currentvpntpslot" -lt 0 ] then vpnrx2="${CRed}[UNKN]${CClear}" elif [ "$currentvpntpslot" -ge 0 ] && [ "$currentvpntpslot" -le "$lowutilspd" ] then vpnrx2="${CGreen}[$vpntptx]${CClear}" elif [ "$currentvpntpslot" -gt "$lowutilspd" ] && [ "$currentvpntpslot" -le "$medutilspd" ] then vpnrx2="${CYellow}[$vpntptx]${CClear}" elif [ "$currentvpntpslot" -gt "$medutilspd" ] then vpnrx2="${CRed}[$vpntptx]${CClear}" fi fi if [ -z "$vpntx1" ] then vpnbwtx="" tmpvpnslot="diffvpn${i}txbytes" eval currentvpnslot=\$$tmpvpnslot vpnbwtx="$(printf '%4s' "$currentvpnslot")" if [ -z "$currentvpnslot" ] || [ "$currentvpnslot" = "" ] || [ "$currentvpnslot" -lt 0 ] then vpntx1="${CRed}[UNKN]${CClear}" elif [ "$currentvpnslot" -ge 0 ] && [ "$currentvpnslot" -le "$lowutilspdup" ] then vpntx1="${CGreen}[$vpnbwtx]${CClear}" elif [ "$currentvpnslot" -gt "$lowutilspdup" ] && [ "$currentvpnslot" -le "$medutilspdup" ] then vpntx1="${CYellow}[$vpnbwtx]${CClear}" elif [ "$currentvpnslot" -gt "$medutilspdup" ] then vpntx1="${CRed}[$vpnbwtx]${CClear}" fi fi if [ -z "$vpntx2" ] then vpntptx="" tmpvpntpslot="thruvpn${i}txbytes" eval currentvpntpslot=\$$tmpvpntpslot vpntptx="$(printf '%4s' "$currentvpntpslot")" if [ -z "$currentvpntpslot" ] || [ "$currentvpntpslot" = "" ] || [ "$currentvpntpslot" -lt 0 ] then vpntx2="${CRed}[UNKN]${CClear}" elif [ "$currentvpntpslot" -ge 0 ] && [ "$currentvpntpslot" -le "$lowutilspdup" ] then vpntx2="${CGreen}[$vpntptx]${CClear}" elif [ "$currentvpntpslot" -gt "$lowutilspdup" ] && [ "$currentvpntpslot" -le "$medutilspdup" ] then vpntx2="${CYellow}[$vpntptx]${CClear}" elif [ "$currentvpntpslot" -gt "$medutilspdup" ] then vpntx2="${CRed}[$vpntptx]${CClear}" fi fi if "$firstDataCollection" ; then printf "\r\033[0K" ; firstDataCollection=false ; fi # Print the results of all data gathered sofar # if [ "$bwdisp" = "1" ]; then echo -e "$vpnindicator${InvDkGray}${CWhite} VPN$i${CClear} | $monitored | $servercnt | $vpnhealth | $vpnstate | $vpnip | $svrping | $vpntx1 | $vpnrx1 | $vpncity$sincelastreset $citychange$ubsync" else echo -e "$vpnindicator${InvDkGray}${CWhite} VPN$i${CClear} | $monitored | $servercnt | $vpnhealth | $vpnstate | $vpnip | $svrping | $vpntx2 | $vpnrx2 | $vpncity$sincelastreset $citychange$ubsync" fi #if a vpn is monitored and disconnected, try to restart it if [ "$((VPN$i))" = "1" ] && [ "$vpnstate" = "Disconnected" ] then #reconnect echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - WARNING: VPN$i has disconnected" >> $logfile echo "" printf "\33[2K\r" #Display a standard timer# timer=0 while [ $timer -ne 5 ] do timer="$((timer+1))" preparebar 46 "|" progressbarpause $timer 5 "" "s" "Standard" done printf "\33[2K\r" restartvpn $i sendmessage 1 "VPN Tunnel Disconnected" $i restartrouting resetspdmerlin exec sh /jffs/scripts/vpnmon-r3.sh -noswitch fi #if a vpn is monitored and in error state, try to restart it if [ "$((VPN$i))" = "1" ] && [ "$vpnstate" = "Error State " ] then #reconnect echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - WARNING: VPN$i is in an error state and being reconnected" >> $logfile echo "" printf "\33[2K\r" #display a standard timer# timer=0 while [ $timer -ne 5 ] do timer="$((timer+1))" preparebar 46 "|" progressbarpause $timer 5 "" "s" "Standard" #sleep 1 done printf "\33[2K\r" restartvpn $i sendmessage 1 "VPN Slot In Error State" $i restartrouting resetspdmerlin exec sh /jffs/scripts/vpnmon-r3.sh -noswitch fi #if a vpn is monitored and not responsive, try to restart it if [ "$((VPN$i))" = "1" ] && [ "$resetvpn" != "0" ] then #reconnect echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - WARNING: VPN$i is non-responsive and being reconnected" >> $logfile echo "" printf "\33[2K\r" #display a standard timer# timer=0 while [ $timer -ne 5 ] do timer="$((timer+1))" preparebar 46 "|" progressbarpause $timer 5 "" "s" "Standard" #sleep 1 done printf "\33[2K\r" restartvpn $resetvpn sendmessage 1 "VPN Slot Is Non-Responsive" $resetvpn restartrouting resetspdmerlin exec sh /jffs/scripts/vpnmon-r3.sh -noswitch fi if [ "$((VPN$i))" = "1" ]; then # if a vpn connection ping is greater than a certain amount, restart it maxsvrping=$(awk "BEGIN {printf \"%3.0f\", ${vpnping}}") >/dev/null 2>&1 MP=$? if [ $MP -ne 0 ]; then if [ -z "$maxsvrping" ] || [ "$maxsvrping" = "" ]; then maxsvrping="Null" fi echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - WARNING: VPN$i received invalid PING information. Contents: $maxsvrping" >> $logfile maxsvrping=0 fi else maxsvrping=0 fi if [ "$pingreset" -gt 0 ] then if [ "$maxsvrping" -ge "$pingreset" ] then echo "" printf "\33[2K\r" echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - WARNING: VPN$i PING exceeds max allowed ($pingreset ms)" >> $logfile printf "${CGreen}\r[Maximum PING Exceeded]" sleep 3 printf "\33[2K\r" #display a standard timer# timer=0 while [ $timer -ne 5 ] do timer="$((timer+1))" preparebar 46 "|" progressbarpause $timer 5 "" "s" "Standard" #sleep 1 done printf "\33[2K\r" restartvpn $i sendmessage 1 "VPN Slot Exceeded Max Ping" $i restartrouting resetspdmerlin exec sh /jffs/scripts/vpnmon-r3.sh -noswitch fi fi #Reset variables ubsync="" sincelastreset="" done echo -e "-------|-----|--------|--------|--------------|-----------------|------------|--------|------------------------------------------" echo "" fi #-----------------Wireguard if [ "$availableslots" = "1 2 3 4 5" ] && [ "$usewg" = "1" ]; then echo -e "${InvDkGray} Wireguard ${CClear}" echo "" #Display WG client slot grid if [ "$unboundwgclient" != "0" ]; then if [ "$bwdisp" = "1" ]; then echo -e " Slot | Mon | Svrs | Health | WG State | Public WG IP | Ping--->WG | Rx Avg | Tx Avg | City Exit / Time Connected / UB" else echo -e " Slot | Mon | Svrs | Health | WG State | Public WG IP | Ping--->WG | Rx Ttl | Tx Ttl | City Exit / Time Connected / UB" fi else if [ "$bwdisp" = "1" ]; then echo -e " Slot | Mon | Svrs | Health | WG State | Public WG IP | Ping--->WG | Rx Avg | Tx Avg | City Exit / Time Connected" else echo -e " Slot | Mon | Svrs | Health | WG State | Public WG IP | Ping--->WG | Rx Ttl | Tx Ttl | City Exit / Time Connected" fi fi echo -e "-------|-----|--------|--------|--------------|-----------------|------------|--------|------------------------------------------" i=0 for i in $availableslots #loop through the VPN slots do #Set variables wgcitychange="" ubsync="" wgrx1="" wgtx1="" wgrx2="" wgtx2="" #determine if the slot is monitored# if [ "$((WG$i))" = "1" ]; then wgmonitored="${CGreen}[X]${CClear}" else wgmonitored="[ ]" fi #determine the vpn state, and if connected, get vpn IP and city wgstate="$(_WG_GetClientState_ "$i")" if [ "$wgstate" = "0" ] then wgstate="Disconnected" wghealth="${CDkGray}[n/a ]${CClear}" wgindicator="${InvDkGray} ${CClear}" wgip=" ${CDkGray}[n/a]${CClear}" wgcity="${CDkGray}[n/a]${CClear}" wgsvrping=" ${CDkGray}[n/a]${CClear}" wgrx1="${CDkGray}[n/a ]${CClear}" wgtx1="${CDkGray}[n/a ]${CClear}" wgrx2="${CDkGray}[n/a ]${CClear}" wgtx2="${CDkGray}[n/a ]${CClear}" elif [ "$wgstate" = "2" ] then wgstate="Connected " checkwg "$i" getwgip "$i" getwgcity "$i" if [ -z "$wgping" ] then wgsvrping="${CRed}[PING ERR]${CClear}" wghealth="${CYellow}[UNKN]${CClear}" wgindicator="${InvYellow} ${CClear}" else ## No need to do left-padding with zeros for alignment ## wgsvrping="$(printf "[%8.3f]" "$wgping")" fi else wgstate="Unknown " wghealth="${CDkGray}[n/a ]${CClear}" wgindicator="${InvDkGray} ${CClear}" wgip=" ${CDkGray}[n/a]${CClear}" wgcity="${CDkGray}[n/a]${CClear}" wgsvrping=" ${CDkGray}[n/a]${CClear}" wgrx1="${CDkGray}[n/a ]${CClear}" wgtx1="${CDkGray}[n/a ]${CClear}" wgrx2="${CDkGray}[n/a ]${CClear}" wgtx2="${CDkGray}[n/a ]${CClear}" fi #Determine how many server entries are in each of the vpn slot alternate server files# if [ -s "/jffs/addons/vpnmon-r3.d/vr3wgsvr$i.txt" ] then wgservercnt="$(cat "/jffs/addons/vpnmon-r3.d/vr3wgsvr$i.txt" | wc -l)" if [ -z "$wgservercnt" ] || [ "$wgservercnt" -lt 1 ] then wgservercnt="${CRed}[0000]${CClear}" else ## No need to do left-padding with zeros for alignment ## wgservercnt="$(printf "[%4d]" "$wgservercnt")" fi else wgservercnt="${CRed}[0000]${CClear}" fi #Calculate connected time for current VPN slot if [ $((WGTIMER$i)) = "0" ] || [ "$((WG$i))" = "0" ] then wgsincelastreset="" else wgcurrtime=$(date +%s) wgtimediff=$((wgcurrtime-WGTIMER$i)) wgsincelastreset=$(printf ': %dd %02dh:%02dm\n' $(($wgtimediff/86400)) $(($wgtimediff%86400/3600)) $(($wgtimediff%3600/60))) fi if [ -z "$wgrx1" ] then wgbwrx="" tmpwgslot="diffwg${i}rxbytes" eval currentwgslot=\$$tmpwgslot wgbwrx="$(printf '%4s' "$currentwgslot")" if [ -z "$currentwgslot" ] || [ "$currentwgslot" = "" ] || [ "$currentwgslot" -lt 0 ] then wgrx1="${CRed}[UNKN]${CClear}" elif [ "$currentwgslot" -ge 0 ] && [ "$currentwgslot" -le "$lowutilspd" ] then wgrx1="${CGreen}[$wgbwrx]${CClear}" elif [ "$currentwgslot" -gt "$lowutilspd" ] && [ "$currentwgslot" -le "$medutilspd" ] then wgrx1="${CYellow}[$wgbwrx]${CClear}" elif [ "$currentwgslot" -gt "$medutilspd" ] then wgrx1="${CRed}[$wgbwrx]${CClear}" fi fi if [ -z "$wgrx2" ] then wgtprx="" tmpwgtpslot="thruwg${i}rxbytes" eval currentwgtpslot=\$$tmpwgtpslot wgtprx="$(printf '%4s' "$currentwgtpslot")" if [ -z "$currentwgtpslot" ] || [ "$currentwgtpslot" = "" ] || [ "$currentwgtpslot" -lt 0 ] then wgrx2="${CRed}[UNKN]${CClear}" elif [ "$currentwgtpslot" -ge 0 ] && [ "$currentwgtpslot" -le "$lowutilspd" ] then wgrx2="${CGreen}[$wgtprx]${CClear}" elif [ "$currentwgtpslot" -gt "$lowutilspd" ] && [ "$currentwgtpslot" -le "$medutilspd" ] then wgrx2="${CYellow}[$wgtprx]${CClear}" elif [ "$currentwgtpslot" -gt "$medutilspd" ] then wgrx2="${CRed}[$wgtprx]${CClear}" fi fi if [ -z "$wgtx1" ] then wgbwtx="" tmpwgslot="diffwg${i}txbytes" eval currentwgslot=\$$tmpwgslot wgbwtx="$(printf '%4s' "$currentwgslot")" if [ -z "$currentwgslot" ] || [ "$currentwgslot" = "" ] || [ "$currentwgslot" -lt 0 ] then wgtx1="${CRed}[UNKN]${CClear}" elif [ "$currentwgslot" -ge 0 ] && [ "$currentwgslot" -le "$lowutilspdup" ] then wgtx1="${CGreen}[$wgbwtx]${CClear}" elif [ "$currentwgslot" -gt "$lowutilspdup" ] && [ "$currentwgslot" -le "$medutilspdup" ] then wgtx1="${CYellow}[$wgbwtx]${CClear}" elif [ "$currentwgslot" -gt "$medutilspdup" ] then wgtx1="${CRed}[$wgbwtx]${CClear}" fi fi if [ -z "$wgtx2" ] then wgtptx="" tmpwgtpslot="thruwg${i}txbytes" eval currentwgtpslot=\$$tmpwgtpslot wgtptx="$(printf '%4s' "$currentwgtpslot")" if [ -z "$currentwgtpslot" ] || [ "$currentwgtpslot" = "" ] || [ "$currentwgtpslot" -lt 0 ] then wgtx2="${CRed}[UNKN]${CClear}" elif [ "$currentwgtpslot" -ge 0 ] && [ "$currentwgtpslot" -le "$lowutilspdup" ] then wgtx2="${CGreen}[$wgtptx]${CClear}" elif [ "$currentwgtpslot" -gt "$lowutilspdup" ] && [ "$currentwgtpslot" -le "$medutilspdup" ] then wgtx2="${CYellow}[$wgtptx]${CClear}" elif [ "$currentwgtpslot" -gt "$medutilspdup" ] then wgtx2="${CRed}[$wgtptx]${CClear}" fi fi # Print the results of all data gathered sofar # if [ "$bwdisp" = "1" ]; then echo -e "$wgindicator${InvDkGray}${CWhite} WGC$i${CClear} | $wgmonitored | $wgservercnt | $wghealth | $wgstate | $wgip | $wgsvrping | $wgrx1 | $wgtx1 | $wgcity$wgsincelastreset $wgcitychange$ubsync" else echo -e "$wgindicator${InvDkGray}${CWhite} WGC$i${CClear} | $wgmonitored | $wgservercnt | $wghealth | $wgstate | $wgip | $wgsvrping | $wgrx2 | $wgtx2 | $wgcity$wgsincelastreset $wgcitychange$ubsync" fi #if a wg connection is monitored and disconnected, try to restart it if [ "$((WG$i))" = "1" ] && [ "$wgstate" = "Disconnected" ] then #reconnect echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - WARNING: WGC$i has disconnected" >> $logfile echo "" printf "\33[2K\r" #Display a standard timer# timer=0 while [ $timer -ne 5 ] do timer="$((timer+1))" preparebar 46 "|" progressbarpause $timer 5 "" "s" "Standard" done printf "\33[2K\r" restartwg $i sendmessage 1 "WG Tunnel Disconnected" $i restartrouting resetspdmerlin exec sh /jffs/scripts/vpnmon-r3.sh -noswitch fi #if the wg handshake exceeds 200s, try to restart it # Inspiration from ZebMcKayHan's WGC Watchdog Script if [ "$((WG$i))" = "1" ] && [ "$wgstate" = "Connected" ] then last_handshake=$(wg show wgc$i latest-handshakes | awk '{print $2}') >/dev/null 2>&1 if [ ! -z $last_handshake ] then idle_seconds=$((`date +%s`-${last_handshake})) if [ "$idle_seconds" -gt "200" ] then #reconnect echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - WARNING: WGC$i handshake exceeded 200s" >> $logfile echo "" printf "\33[2K\r" #Display a standard timer# timer=0 while [ $timer -ne 5 ] do timer="$((timer+1))" preparebar 46 "|" progressbarpause $timer 5 "" "s" "Standard" done printf "\33[2K\r" restartwg $i sendmessage 1 "WG Handshake Exceeded" $i restartrouting resetspdmerlin exec sh /jffs/scripts/vpnmon-r3.sh -noswitch fi fi fi if [ "$((WG$i))" = "1" ]; then # if a wg connection ping is greater than a certain amount, restart it maxsvrping=$(awk "BEGIN {printf \"%3.0f\", ${wgping}}") >/dev/null 2>&1 MP=$? if [ $MP -ne 0 ]; then if [ -z "$maxsvrping" ] || [ "$maxsvrping" = "" ]; then maxsvrping="Null" fi echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - WARNING: WGC$i received invalid PING information. Contents: $maxsvrping" >> $logfile maxsvrping=0 fi else maxsvrping=0 fi if [ "$pingreset" -gt 0 ] then if [ "$maxsvrping" -ge "$pingreset" ] then echo "" printf "\33[2K\r" echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - WARNING: WGC$i PING exceeds max allowed ($pingreset ms)" >> $logfile printf "${CGreen}\r[Maximum PING Exceeded]" sleep 3 printf "\33[2K\r" #display a standard timer# timer=0 while [ $timer -ne 5 ] do timer="$((timer+1))" preparebar 46 "|" progressbarpause $timer 5 "" "s" "Standard" #sleep 1 done printf "\33[2K\r" restartwg $i sendmessage 1 "WG Slot Exceeded Max Ping" $i restartrouting resetspdmerlin exec sh /jffs/scripts/vpnmon-r3.sh -noswitch fi fi #if a wg is monitored and not responsive, try to restart it if [ "$((WG$i))" = "1" ] && [ "$resetwg" != "0" ] then #reconnect echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - WARNING: WGC$i is non-responsive and being reconnected" >> $logfile echo "" printf "\33[2K\r" #display a standard timer# timer=0 while [ $timer -ne 5 ] do timer="$((timer+1))" preparebar 46 "|" progressbarpause $timer 5 "" "s" "Standard" #sleep 1 done printf "\33[2K\r" restartwg $resetwg sendmessage 1 "WG Slot Is Non-Responsive" $resetwg restartrouting resetspdmerlin exec sh /jffs/scripts/vpnmon-r3.sh -noswitch fi #Reset variables wgsincelastreset="" done echo -e "-------|-----|--------|--------|--------------|-----------------|------------|--------|------------------------------------------" echo "" #----------------- fi #display a standard timer# timer=0 lastTimerSec=0 updateTimer=true getifacestats # Grab fresh interface stats while [ "$timer" -lt "$timerloop" ] do if "$updateTimer" then updateTimer=false timer="$((timer+1))" lastTimerSec="$(date +%s)" fi preparebar 46 "|" progressbaroverride "$timer" "$timerloop" "" "s" "Standard" lockcheck #Check to see if a reset is currently underway if [ "$timerreset" = "1" ]; then timer="$timerloop" ; fi ## Prevent repeatedly fast key presses from updating the timer ## [ "$(date +%s)" -gt "$lastTimerSec" ] && updateTimer=true done calcifacestats # Grab new stats after the timer completes for comparison #Check to see if a reset is currently underway lockcheck prevHideOpts=X #if Unbound is active and out of sync, try to restart it if [ "$unboundclient" != "0" ] && [ "$ResolverTimer" = "1" ] then if [ "$useovpn" = "1" ] then printf "\33[2K\r" echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - WARNING: VPN$unboundreset is out of sync with Unbound DNS Resolver" >> $logfile printf "${CGreen}\r[Unbound is out of sync]" sleep 3 printf "\33[2K\r" #display a standard timer timer=0 while [ $timer -ne 5 ] do timer="$((timer+1))" preparebar 46 "|" progressbarpause $timer 5 "" "s" "Standard" done printf "\33[2K\r" restartvpn $unboundreset sendmessage 1 "VPN Slot Not Synced With Unbound" $unboundreset restartrouting resetspdmerlin exec sh /jffs/scripts/vpnmon-r3.sh -noswitch fi fi if [ "$unboundwgclient" != "0" ] && [ "$ResolverTimer" = "1" ] then if [ "$usewg" = "1" ] then printf "\33[2K\r" echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - WARNING: WGC$unboundreset is out of sync with Unbound DNS Resolver" >> $logfile printf "${CGreen}\r[Unbound is out of sync]" sleep 3 printf "\33[2K\r" #display a standard timer timer=0 while [ $timer -ne 5 ] do timer="$((timer+1))" preparebar 46 "|" progressbarpause $timer 5 "" "s" "Standard" done printf "\33[2K\r" restartwg $unboundreset sendmessage 1 "WG Slot Not Synced With Unbound" $unboundreset restartrouting resetspdmerlin exec sh /jffs/scripts/vpnmon-r3.sh -noswitch fi fi #Check to see if the WAN is up if [ "$monitorwan" = "1" ] && [ "$bypasswancheck" = "0" ]; then checkwan fi firstrun=0 done echo -e "${CClear}" exit 0 #} #2>&1 | tee $LOG | logger -t $(basename $0)[$$] # uncomment/comment to enable/disable debug mode