From a77fa1b23f55168c3c564656803b4b5fae50f500 Mon Sep 17 00:00:00 2001 From: ViktorJp <97465574+ViktorJp@users.noreply.github.com> Date: Tue, 2 Dec 2025 18:47:16 -0500 Subject: [PATCH 01/40] Update changelog.txt --- changelog.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/changelog.txt b/changelog.txt index 6a59e3a..992e672 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,3 +1,7 @@ +v1.8.x - (TBA) + - PATCH: The Recovery Timeout should be defaulting to 1x, but it was inadvertently set to 3x. Thank + you to @Tarek Yag for reporting this. Fixed! + v1.8.2 - (November 23, 2025) - PATCH: Thanks to @JTnola for sharing a "[: bad number" bug he was experiencing. This hard-to-find bug only seemed to come up in certain scenarios when using the limited 2-OVPN slot configuration. From 5cbc034795b63a42b1f88d3267fdf79e9a2fe985 Mon Sep 17 00:00:00 2001 From: ViktorJp <97465574+ViktorJp@users.noreply.github.com> Date: Fri, 5 Dec 2025 17:02:14 -0500 Subject: [PATCH 02/40] Update enhancements.txt --- enhancements.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/enhancements.txt b/enhancements.txt index 123a93e..e3a7498 100644 --- a/enhancements.txt +++ b/enhancements.txt @@ -1,6 +1,9 @@ To-Do: - If the WAN doesn't respond after X minutes, issue a router reboot? - Find a way to remember past bandwidth stats so that it doesn't revert to [UNKN] as often. +- timezone details +- configurable timeouts for wan detection and resets +- wording for custom ping target Done: - Find a way to reset all active VPN/WG counters, and set non-active ones to 0 - @CaptainSTX From 78a361180edc467133a23e7a30b7237d395c03d9 Mon Sep 17 00:00:00 2001 From: ViktorJp <97465574+ViktorJp@users.noreply.github.com> Date: Fri, 5 Dec 2025 18:45:29 -0500 Subject: [PATCH 03/40] Update changelog.txt --- changelog.txt | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/changelog.txt b/changelog.txt index 992e672..176968d 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,6 +1,13 @@ v1.8.x - (TBA) - PATCH: The Recovery Timeout should be defaulting to 1x, but it was inadvertently set to 3x. Thank you to @Tarek Yag for reporting this. Fixed! + - PATCH: Changed the wording for the custom PING host to "Custom PING host for connectivity checks" + to bring more clarity that it wasn't just for VPN checks, but WAN and WG as well. Thanks to + @scootertramp for reporting. + - PATCH: Changed the date/time to include the offset alongside the timezone. This is to give more + visibility for those who aren't assigned a standard timezone name, and in some cases would fall + back to using "GMT". Thanks to @Tarek Yag for reporting this, and for @EmeraldDeer providing a + deep dive into the date command options. v1.8.2 - (November 23, 2025) - PATCH: Thanks to @JTnola for sharing a "[: bad number" bug he was experiencing. This hard-to-find From 548b14189d1429c6ddc6c6fea0ced41ece3653c4 Mon Sep 17 00:00:00 2001 From: ViktorJp <97465574+ViktorJp@users.noreply.github.com> Date: Fri, 5 Dec 2025 18:46:22 -0500 Subject: [PATCH 04/40] Update enhancements.txt --- enhancements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/enhancements.txt b/enhancements.txt index e3a7498..0a5c7a2 100644 --- a/enhancements.txt +++ b/enhancements.txt @@ -1,11 +1,11 @@ To-Do: - If the WAN doesn't respond after X minutes, issue a router reboot? - Find a way to remember past bandwidth stats so that it doesn't revert to [UNKN] as often. -- timezone details -- configurable timeouts for wan detection and resets -- wording for custom ping target +- configurable timeouts for wan detection and resets @scootertramp Done: +- timezone details @Tarek Yag/EmeraldDeer +- wording for custom ping target @scootertramp - Find a way to reset all active VPN/WG counters, and set non-active ones to 0 - @CaptainSTX - avg vs total throughput stats @CaptainSTX - Option for round-robin on lists, instead of random. From 4687ecfe738a8faf9233fd34a1b0f46b6cef7155 Mon Sep 17 00:00:00 2001 From: ViktorJp <97465574+ViktorJp@users.noreply.github.com> Date: Fri, 5 Dec 2025 18:56:23 -0500 Subject: [PATCH 05/40] Update enhancements.txt --- enhancements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/enhancements.txt b/enhancements.txt index 0a5c7a2..39bab88 100644 --- a/enhancements.txt +++ b/enhancements.txt @@ -2,6 +2,7 @@ To-Do: - If the WAN doesn't respond after X minutes, issue a router reboot? - Find a way to remember past bandwidth stats so that it doesn't revert to [UNKN] as often. - configurable timeouts for wan detection and resets @scootertramp +- use recovery timeouts for wan Done: - timezone details @Tarek Yag/EmeraldDeer From e21781d79e6269aa149c14c28766b5298d47d0d0 Mon Sep 17 00:00:00 2001 From: ViktorJp <97465574+ViktorJp@users.noreply.github.com> Date: Fri, 5 Dec 2025 19:55:56 -0500 Subject: [PATCH 06/40] Update changelog.txt --- changelog.txt | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/changelog.txt b/changelog.txt index 176968d..ceaa7a3 100644 --- a/changelog.txt +++ b/changelog.txt @@ -8,6 +8,13 @@ v1.8.x - (TBA) visibility for those who aren't assigned a standard timezone name, and in some cases would fall back to using "GMT". Thanks to @Tarek Yag for reporting this, and for @EmeraldDeer providing a deep dive into the date command options. + - PATCH: Fixed some hardcoded instances where the recovery timeouts were set to 3, instead of using + user-selected values. + - PATCH: Fixed some instances where PINGHOST was hardcoded to 8.8.8.8, instead of using user-selected + values. + - PATCH: Implemented recovery timeouts (if configured) and will apply to the WAN as well. Should the + WAN have issues pinging or establishing an SSL connection with the user-selected PINGHOST, it will + attempt to try the number of times that is user-specified. v1.8.2 - (November 23, 2025) - PATCH: Thanks to @JTnola for sharing a "[: bad number" bug he was experiencing. This hard-to-find From b7d2057294eed5613902f6231eb8156972819781 Mon Sep 17 00:00:00 2001 From: ViktorJp <97465574+ViktorJp@users.noreply.github.com> Date: Fri, 5 Dec 2025 20:29:20 -0500 Subject: [PATCH 07/40] Update enhancements.txt --- enhancements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/enhancements.txt b/enhancements.txt index 39bab88..1f85ef2 100644 --- a/enhancements.txt +++ b/enhancements.txt @@ -2,9 +2,9 @@ To-Do: - If the WAN doesn't respond after X minutes, issue a router reboot? - Find a way to remember past bandwidth stats so that it doesn't revert to [UNKN] as often. - configurable timeouts for wan detection and resets @scootertramp -- use recovery timeouts for wan Done: +- use recovery timeouts for wan @scootertramp - timezone details @Tarek Yag/EmeraldDeer - wording for custom ping target @scootertramp - Find a way to reset all active VPN/WG counters, and set non-active ones to 0 - @CaptainSTX From 06fd325bc63a9dd4d308a19981fd1d439ce0dfd3 Mon Sep 17 00:00:00 2001 From: ViktorJp <97465574+ViktorJp@users.noreply.github.com> Date: Fri, 5 Dec 2025 20:31:10 -0500 Subject: [PATCH 08/40] Update changelog.txt --- changelog.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/changelog.txt b/changelog.txt index ceaa7a3..e69b745 100644 --- a/changelog.txt +++ b/changelog.txt @@ -15,6 +15,9 @@ v1.8.x - (TBA) - PATCH: Implemented recovery timeouts (if configured) and will apply to the WAN as well. Should the WAN have issues pinging or establishing an SSL connection with the user-selected PINGHOST, it will attempt to try the number of times that is user-specified. + - PATCH: Cut down all VPN/WG connection and reset times by half. Will continue to monitor closely + for misbehavior. Done in response to @scootertramp noting the long time it takes to reconnect all + VPN/WG connections after a WAN DOWN event. v1.8.2 - (November 23, 2025) - PATCH: Thanks to @JTnola for sharing a "[: bad number" bug he was experiencing. This hard-to-find From 42613152932ae989b41673e9de0a434cd1bfae2e Mon Sep 17 00:00:00 2001 From: ViktorJp <97465574+ViktorJp@users.noreply.github.com> Date: Fri, 5 Dec 2025 20:36:25 -0500 Subject: [PATCH 09/40] Update changelog.txt --- changelog.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/changelog.txt b/changelog.txt index e69b745..60185c5 100644 --- a/changelog.txt +++ b/changelog.txt @@ -13,8 +13,8 @@ v1.8.x - (TBA) - PATCH: Fixed some instances where PINGHOST was hardcoded to 8.8.8.8, instead of using user-selected values. - PATCH: Implemented recovery timeouts (if configured) and will apply to the WAN as well. Should the - WAN have issues pinging or establishing an SSL connection with the user-selected PINGHOST, it will - attempt to try the number of times that is user-specified. + WAN have issues establishing an SSL connection with the user-selected PINGHOST, it will attempt to + try the number of times that is user-specified. - PATCH: Cut down all VPN/WG connection and reset times by half. Will continue to monitor closely for misbehavior. Done in response to @scootertramp noting the long time it takes to reconnect all VPN/WG connections after a WAN DOWN event. From e3bd0c626d615bf083cb0d06ba393bde7111bed8 Mon Sep 17 00:00:00 2001 From: ViktorJp <97465574+ViktorJp@users.noreply.github.com> Date: Fri, 5 Dec 2025 21:37:53 -0500 Subject: [PATCH 10/40] Update changelog.txt --- changelog.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/changelog.txt b/changelog.txt index 60185c5..7e87fd0 100644 --- a/changelog.txt +++ b/changelog.txt @@ -18,6 +18,9 @@ v1.8.x - (TBA) - PATCH: Cut down all VPN/WG connection and reset times by half. Will continue to monitor closely for misbehavior. Done in response to @scootertramp noting the long time it takes to reconnect all VPN/WG connections after a WAN DOWN event. + - PATCH: Removed the functionality that would reset the Rx/Tx indicators to [UNKN] each time you + went into a different menu item. It will now just show live stats no matter what. For consistent + and more accurate results, wait your full 60 seconds (or whatever you've set your timer value to). v1.8.2 - (November 23, 2025) - PATCH: Thanks to @JTnola for sharing a "[: bad number" bug he was experiencing. This hard-to-find From 3ed19bc85b280ae10bcf388a3660c06285e325eb Mon Sep 17 00:00:00 2001 From: ViktorJp <97465574+ViktorJp@users.noreply.github.com> Date: Fri, 5 Dec 2025 23:03:27 -0500 Subject: [PATCH 11/40] Rename vpnmon-r3.sh to vpnmon-r3-1.8.2.sh --- vpnmon-r3.sh => vpnmon-r3-1.8.2.sh | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename vpnmon-r3.sh => vpnmon-r3-1.8.2.sh (100%) diff --git a/vpnmon-r3.sh b/vpnmon-r3-1.8.2.sh similarity index 100% rename from vpnmon-r3.sh rename to vpnmon-r3-1.8.2.sh From f6132aac783eb8b61f950196f554450a4e569f24 Mon Sep 17 00:00:00 2001 From: ViktorJp <97465574+ViktorJp@users.noreply.github.com> Date: Fri, 5 Dec 2025 23:03:43 -0500 Subject: [PATCH 12/40] Rename vpnmon-r3-1.8.1.sh to archive/vpnmon-r3-1.8.1.sh --- vpnmon-r3-1.8.1.sh => archive/vpnmon-r3-1.8.1.sh | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename vpnmon-r3-1.8.1.sh => archive/vpnmon-r3-1.8.1.sh (100%) diff --git a/vpnmon-r3-1.8.1.sh b/archive/vpnmon-r3-1.8.1.sh similarity index 100% rename from vpnmon-r3-1.8.1.sh rename to archive/vpnmon-r3-1.8.1.sh From 3acaf647699d484475c69b248fdb76fcf34fdd57 Mon Sep 17 00:00:00 2001 From: ViktorJp <97465574+ViktorJp@users.noreply.github.com> Date: Fri, 5 Dec 2025 23:03:59 -0500 Subject: [PATCH 13/40] Create vpnmon-r3.sh --- vpnmon-r3.sh | 8092 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 8092 insertions(+) create mode 100644 vpnmon-r3.sh diff --git a/vpnmon-r3.sh b/vpnmon-r3.sh new file mode 100644 index 0000000..b0a7651 --- /dev/null +++ b/vpnmon-r3.sh @@ -0,0 +1,8092 @@ +#!/bin/sh + +# VPNMON-R3 v1.8.3b1 (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-Dec-5 +########################################################################################## + +#Preferred standard router binaries path +export PATH="/sbin:/bin:/usr/sbin:/usr/bin:$PATH" + +#Static Variables - please do not change +version="1.8.3b1" # Version tracker +beta=1 # 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=1 # 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 +PINGHOST="8.8.8.8" # Default Ping host +WCNT=0 # WAN DOWN counter + +##-------------------------------------## +## Added by Martinski W. [2024-Oct-05] ## +##-------------------------------------## +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 # + +## 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 for connectivity checks : ${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 WAN/VPN/WG health) ${CClear}" + echo -e "${InvGreen} ${CClear}" + echo -e "${InvGreen} ${CClear} Please indicate which host you want to PING in order to determine connectivity health.${CClear}" + echo -e "${InvGreen} ${CClear} By default, the script will ping 8.8.8.8 (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 = 8.8.8.8)${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 + PINGHOST="8.8.8.8" + echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - INFO: Default 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; timer="$timerloop"; 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 10 + 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 5 + printf "\33[2K\r" + printf "${CGreen}\r[Letting VPN$1 Settle]" + sleep 5 + 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 1 + + #---------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 5 + printf "\33[2K\r" + printf "${CGreen}\r[Letting VPN$1 Settle]" + sleep 5 + + 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 1 + + #---------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 5 + printf "\33[2K\r" + printf "${CGreen}\r[Letting VPN$1 Settle]" + sleep 5 + 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 5 + printf "\33[2K\r" + printf "${CGreen}\r[Letting VPN$1 Settle]" + sleep 5 + 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 10 + 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 5 + printf "\33[2K\r" + printf "${CGreen}\r[Letting WGC$1 Settle]" + sleep 5 + 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 1 + + #---------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 5 + printf "\33[2K\r" + printf "${CGreen}\r[Letting WGC$1 Settle]" + sleep 5 + + 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 1 + + #---------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 5 + printf "\33[2K\r" + printf "${CGreen}\r[Letting WGC$1 Settle]" + sleep 5 + 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 5 + printf "\33[2K\r" + printf "${CGreen}\r[Letting WGC$1 Settle]" + sleep 5 + 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 10 + 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 10 + 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 "$recover" ]; 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 "$recover" ];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 "$recover" ]; 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 "$recover" ]; 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="$PINGHOST" + + 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 + WCNT=0 + printf "\33[2K\r" + return + else + wandownbreakertrip=1 + echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - ERROR: WAN Connectivity Issue Detected - Unable to establish SSL connection with $testssl" >> $logfile + fi + else + wandownbreakertrip=1 + echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - ERROR: WAN Connectivity Issue Detected - Unable to establish SSL connection with $testssl" >> $logfile + fi + + if [ "$wandownbreakertrip" = "1" ] + then + + WCNT="$((WCNT+1))" + printf "\33[2K\r" + printf "\r${InvRed} ${CClear} WAN Connectivity Failure Detected [Attempt $WCNT]" + echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - WARNING: WAN attempt $WCNT of $recover to allow connection to recover" >> $logfile + sleep 10 # Giving the WAN a chance to recover a certain number of times + + if [ "$WCNT" -eq "$recover" ] # But if it fails, report back that we have an issue requiring a WAN DOWN event + then + printf "\33[2K\r" + echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - WARNING: WAN failed to respond after $recover attempts" >> $logfile + + # 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 + else + wandownbreakertrip=0 + fi + 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 [ "$WCNT" -ge 1 ]; then + wan0status="${CRed}[$WCNT]${CClear}" + wan0health="${CRed}[FAIL]${CClear}" + else + wan0status="${CGreen}[X]${CClear}" + wan0health="${CGreen}[ OK ]${CClear}" + fi + + if [ "$WAN0PING" = "[FAILOVER]" ] + then + echo -en "${InvGreen} ${InvDkGray}${CWhite} WAN0${CClear} | $wan0status | " + printf "%-6s" "$WAN0IFNAME" + if [ "$bwdisp" = "1" ]; then + echo -e " | $wan0health | Failover | $WAN0IP | $WAN0PING | $WAN0RX1 | $WAN0TX1 | $WAN0CITY: $uptimeStr" + else + echo -e " | $wan0health | Failover | $WAN0IP | $WAN0PING | $WAN0RX2 | $WAN0TX2 | $WAN0CITY: $uptimeStr" + fi + else + echo -en "${InvGreen} ${InvDkGray}${CWhite} WAN0${CClear} | $wan0status | " + printf "%-6s" "$WAN0IFNAME" + if [ "$bwdisp" = "1" ]; then + echo -e " | $wan0health | Active | $WAN0IP | $WAN0PING | $WAN0RX1 | $WAN0TX1 | $WAN0CITY: $uptimeStr" + else + echo -e " | $wan0health | 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 [ "$WCNT" -ge 1 ]; then + wan1status="${CRed}[$WCNT]${CClear}" + wan1health="${CRed}[FAIL]${CClear}" + else + wan1status="${CGreen}[X]${CClear}" + wan1health="${CGreen}[ OK ]${CClear}" + fi + + if [ "$WAN1PING" = "[FAILOVER]" ] + then + echo -en "${InvGreen} ${InvDkGray}${CWhite} WAN1${CClear} | $wan1status | " + printf "%-6s" "$WAN1IFNAME" + if [ "$bwdisp" = "1" ]; then + echo -e " | $wan1health | Failover | $WAN1IP | $WAN1PING | $WAN1RX1 | $WAN1TX1 | $WAN1CITY: $uptimeStr" + else + echo -e " | $wan1health | Failover | $WAN1IP | $WAN1PING | $WAN1RX2 | $WAN1TX2 | $WAN1CITY: $uptimeStr" + fi + else + echo -en "${InvGreen} ${InvDkGray}${CWhite} WAN1${CClear} | $wan1status | " + printf "%-6s" "$WAN1IFNAME" + if [ "$bwdisp" = "1" ]; then + echo -e " | $wan1health | Active | $WAN1IP | $WAN1PING | $WAN1RX1 | $WAN1TX1 | $WAN1CITY: $uptimeStr" + else + echo -e " | $wan1health | 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 +"%a %b %d, %Y %H:%M:%S %Z %z") ${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 From 6de4ff01dc09324408292bdc3cbd838a587cc231 Mon Sep 17 00:00:00 2001 From: ViktorJp <97465574+ViktorJp@users.noreply.github.com> Date: Fri, 5 Dec 2025 23:04:18 -0500 Subject: [PATCH 14/40] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index ae68f4f..beac92f 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ -# VPNMON-R3 v1.8.2 +# VPNMON-R3 v1.8.3b1 Asus-Merlin OpenVPN/Wireguard Monitor R3 -Updated on 2025-Nov-23 +Updated on 2025-Dec-5 --- From 7cdcdc4fc0ff91c0a875d1327f0e61609891ff67 Mon Sep 17 00:00:00 2001 From: ViktorJp <97465574+ViktorJp@users.noreply.github.com> Date: Fri, 5 Dec 2025 23:04:31 -0500 Subject: [PATCH 15/40] Update version.txt --- version.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.txt b/version.txt index 53adb84..a7ee35a 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.8.2 +1.8.3 From 1c639256d65c48e132079da3d50168aef8a9ada1 Mon Sep 17 00:00:00 2001 From: ViktorJp <97465574+ViktorJp@users.noreply.github.com> Date: Fri, 5 Dec 2025 23:04:51 -0500 Subject: [PATCH 16/40] Update changelog.txt --- changelog.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/changelog.txt b/changelog.txt index 7e87fd0..8c39647 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,4 +1,4 @@ -v1.8.x - (TBA) +v1.8.3 - (TBA) - PATCH: The Recovery Timeout should be defaulting to 1x, but it was inadvertently set to 3x. Thank you to @Tarek Yag for reporting this. Fixed! - PATCH: Changed the wording for the custom PING host to "Custom PING host for connectivity checks" From 558e8a2c51c658a5af1b005f3acd05660d993291 Mon Sep 17 00:00:00 2001 From: ViktorJp <97465574+ViktorJp@users.noreply.github.com> Date: Fri, 5 Dec 2025 23:05:34 -0500 Subject: [PATCH 17/40] Update enhancements.txt --- enhancements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/enhancements.txt b/enhancements.txt index 1f85ef2..423d16f 100644 --- a/enhancements.txt +++ b/enhancements.txt @@ -1,9 +1,9 @@ To-Do: - If the WAN doesn't respond after X minutes, issue a router reboot? -- Find a way to remember past bandwidth stats so that it doesn't revert to [UNKN] as often. - configurable timeouts for wan detection and resets @scootertramp Done: +- Find a way to remember past bandwidth stats so that it doesn't revert to [UNKN] as often. - use recovery timeouts for wan @scootertramp - timezone details @Tarek Yag/EmeraldDeer - wording for custom ping target @scootertramp From 97d3f10c5fcecdfc80636d6d4540b6bc46cd6105 Mon Sep 17 00:00:00 2001 From: ViktorJp <97465574+ViktorJp@users.noreply.github.com> Date: Thu, 18 Dec 2025 19:22:11 -0500 Subject: [PATCH 18/40] Update version to 1.8.3b2 and add timer options Updated version number from 1.8.3b1 to 1.8.3b2 and added new timer configuration options for WAN recovery. --- vpnmon-r3.sh | 160 ++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 145 insertions(+), 15 deletions(-) diff --git a/vpnmon-r3.sh b/vpnmon-r3.sh index b0a7651..c2b37f2 100644 --- a/vpnmon-r3.sh +++ b/vpnmon-r3.sh @@ -1,6 +1,6 @@ #!/bin/sh -# VPNMON-R3 v1.8.3b1 (VPNMON-R3.SH) is an all-in-one script that is optimized to maintain multiple VPN connections and is +# VPNMON-R3 v1.8.3b2 (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 @@ -14,7 +14,7 @@ export PATH="/sbin:/bin:/usr/sbin:/usr/bin:$PATH" #Static Variables - please do not change -version="1.8.3b1" # Version tracker +version="1.8.3b2" # Version tracker beta=1 # Beta switch screenshotmode=0 # Switch to present bogus info for screenshots apppath="/jffs/scripts/vpnmon-r3.sh" # Static path to the app @@ -64,6 +64,9 @@ medutilspdup=25 # Upper Limit of bwdisp=1 # Display value for bandwidth/throughput - 1=Average, 2=Total PINGHOST="8.8.8.8" # Default Ping host WCNT=0 # WAN DOWN counter +recoverytimer=10 # Time between recovery attempts before declaring WAN-DOWN +wandowntimer=60 # Time between attempts to determine if WAN is available again +reconnecttimer=300 # Time allotted to giving router time to stabilize before reconnecting tunnels ##-------------------------------------## ## Added by Martinski W. [2024-Oct-05] ## @@ -999,12 +1002,13 @@ do 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}(16)${CClear} : WAN Recovery, Down, Reconnect Timers : " 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 + read -p "Please select? (1-16, e=Exit): " SelectSlot case $SelectSlot in 1) clear @@ -2099,6 +2103,129 @@ do fi ;; + 16) + clear + while true + do + clear + echo -e "${InvGreen} ${InvDkGray}${CWhite} WAN Recovery Timer Configuration ${CClear}" + echo -e "${InvGreen} ${CClear}" + echo -e "${InvGreen} ${CClear} Please indicate how long the various WAN Recovery timers should last during the${CClear}" + echo -e "${InvGreen} ${CClear} different states as the WAN tries to recover, or goes out completely. Depending${CClear}" + echo -e "${InvGreen} ${CClear} on what timer values you choose will have impact on how long your WAN takes to${CClear}" + echo -e "${InvGreen} ${CClear} recover.${CClear}" + echo -e "${InvGreen} ${CClear}" + echo -e "${InvGreen} ${CClear} ${CYellow}Recovery timer${CClear}: The length of time between tries to determine if your router is${CClear}" + echo -e "${InvGreen} ${CClear} able to ping the IP address of your choosing and recover before declaring a WAN${CClear}" + echo -e "${InvGreen} ${CClear} DOWN situation. (Default = 10 sec)${CClear}" + echo -e "${InvGreen} ${CClear}" + echo -e "${InvGreen} ${CClear} ${CYellow}WAN DOWN Timer${CClear}: The length of time between tries while the WAN is DOWN, where${CClear}" + echo -e "${InvGreen} ${CClear} VPNMON-R3 tries to determine if the WAN is available again. (Default = 60 sec)${CClear}" + echo -e "${InvGreen} ${CClear}" + echo -e "${InvGreen} ${CClear} ${CYellow}Reconnect Timer${CClear}: The length of time from when the WAN is declared back up while${CClear}" + echo -e "${InvGreen} ${CClear} giving the router some time to stabilize before it restarts VPN/WG tunnels. You don't${CClear}" + echo -e "${InvGreen} ${CClear} want your router reconnecting tunnels while the router is bouncing up and down.${CClear}" + echo -e "${InvGreen} ${CClear} (Default = 300 sec).${CClear}" + echo -e "${InvGreen} ${CClear}" + echo -e "${InvGreen} ${CClear}${CDkGray}---------------------------------------------------------------------------------------${CClear}" + echo -e "${InvGreen} ${CClear}" + echo -e "${InvGreen} ${CClear} Current:${CClear}" + echo -e "${InvGreen} ${CClear}" + echo -e "${InvGreen} ${CClear} Recovery Timer ${CGreen}(1): $recoverytimer sec${CClear}" + echo -e "${InvGreen} ${CClear} WAN DOWN Timer ${CGreen}(2): $wandowntimer sec ${CClear}" + echo -e "${InvGreen} ${CClear} Reconnect Timer ${CGreen}(3): $reconnecttimer sec ${CClear}" + echo -e "${InvGreen} ${CClear}" + echo + read -p "Please choose a Timer [1-3] and enter new Timer value in seconds (e=Exit): " newTimerChoice + case $newTimerChoice in + 1) echo "" + read -p "Enter new Recovery Timer value in seconds between [10-999] (default=10, e=Exit): " newRecoveryTimerChoice + if [ -z "$newRecoveryTimerChoice" ] || echo "$newRecoveryTimerChoice" | grep -qE "^(e|E)$" + then + if echo "$recoverytimer" | grep -qE "^([1-9][0-9]{0,2})$" && \ + [ "$recoverytimer" -ge 10 ] && [ "$recoverytimer" -le 999 ] + then + 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 "$newRecoveryTimerChoice" | grep -qE "^([1-9][0-9]{0,2})$" && \ + [ "$newRecoveryTimerChoice" -ge 10 ] && [ "$newRecoveryTimerChoice" -le 999 ] + then + recoverytimer="$newRecoveryTimerChoice" + echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - INFO: New Recovery Timer ($recoverytimer sec) configuration saved" >> $logfile + saveconfig + 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 + ;; + + 2) echo "" + read -p "Enter new WAN-DOWN Timer value in seconds between [10-999] (default=60, e=Exit): " newWANDOWNTimerChoice + if [ -z "$newWANDOWNTimerChoice" ] || echo "$newWANDOWNTimerChoice" | grep -qE "^(e|E)$" + then + if echo "$wandowntimer" | grep -qE "^([1-9][0-9]{0,2})$" && \ + [ "$wandowntimer" -ge 10 ] && [ "$wandowntimer" -le 999 ] + then + 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 "$newWANDOWNTimerChoice" | grep -qE "^([1-9][0-9]{0,2})$" && \ + [ "$newWANDOWNTimerChoice" -ge 10 ] && [ "$newWANDOWNTimerChoice" -le 999 ] + then + wandowntimer="$newWANDOWNTimerChoice" + echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - INFO: New WAN-DOWN Timer ($recoverytimer sec) configuration saved" >> $logfile + saveconfig + 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 + ;; + + 3) echo "" + read -p "Enter new Reconnect Timer value in seconds between [10-999] (default=300, e=Exit): " newReconnectTimerChoice + if [ -z "$newReconnectTimerChoice" ] || echo "$newReconnectTimerChoice" | grep -qE "^(e|E)$" + then + if echo "$reconnecttimer" | grep -qE "^([1-9][0-9]{0,2})$" && \ + [ "$reconnecttimer" -ge 10 ] && [ "$reconnecttimer" -le 999 ] + then + 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 "$newReconnectTimerChoice" | grep -qE "^([1-9][0-9]{0,2})$" && \ + [ "$newReconnectTimerChoice" -ge 10 ] && [ "$newReconnectTimerChoice" -le 999 ] + then + reconnecttimer="$newReconnectTimerChoice" + echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - INFO: New Reconnect Timer ($recoverytimer sec) configuration saved" >> $logfile + saveconfig + 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 + ;; + + [Ee]) printf "\n${CClear}[Exiting]\n" + sleep 1 ; break + esac + + done + ;; + esac done } @@ -4298,6 +4425,9 @@ saveconfig() echo 'lowutilspdup='$lowutilspdup echo 'medutilspdup='$medutilspdup echo 'bwdisp='$bwdisp + echo 'recoverytimer='$recoverytimer + echo 'wandowntimer='$wandowntimer + echo 'reconnecttimer='$reconnecttimer } > "$config" echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - INFO: New vpnmon-r3.cfg File Saved" >> $logfile @@ -5987,15 +6117,15 @@ checkwan() if [ "$wandownbreakertrip" = "1" ] then - - WCNT="$((WCNT+1))" + + WCNT="$((WCNT+1))" printf "\33[2K\r" - printf "\r${InvRed} ${CClear} WAN Connectivity Failure Detected [Attempt $WCNT]" + printf "\r${InvRed} ${CClear} WAN Connectivity Failure Detected [Attempt $WCNT | $recoverytimer sec/attempt]" echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - WARNING: WAN attempt $WCNT of $recover to allow connection to recover" >> $logfile - sleep 10 # Giving the WAN a chance to recover a certain number of times + sleep $recoverytimer # Giving the WAN a chance to recover a certain number of times - default: recoverytimer=10 if [ "$WCNT" -eq "$recover" ] # But if it fails, report back that we have an issue requiring a WAN DOWN event - then + then printf "\33[2K\r" echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - WARNING: WAN failed to respond after $recover attempts" >> $logfile @@ -6063,10 +6193,10 @@ checkwan() 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} [Retrying to resume normal operations roughly every $wandowntimer seconds]${CClear}" echo -e "${InvGreen} ${CClear}${CDkGray}---------------------------------------------------------------------------------------${CClear}" echo "" - spinner 60 + spinner $wandowntimer # Time between attempts to determine if WAN becomes available again - Default: wandowntimer=60 wandownbreakertrip=1 else wandownbreakertrip=2 @@ -6086,13 +6216,13 @@ checkwan() 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} Router has detected a WAN Link/Modem and waiting $reconnecttimer 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} [Retrying to resume normal operations in roughly $reconnecttimer seconds...Please stand by!]${CClear}" echo -e "${InvGreen} ${CClear}${CDkGray}---------------------------------------------------------------------------------------${CClear}" echo "" - spinner 300 + spinner $reconnecttimer # Time allotted to give router chance to recover before reconnecting tunnels - Default: reconnecttimer=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 @@ -6331,7 +6461,7 @@ wancheck() then WAN1TX2="${CRed}[$WAN1TPTX]${CClear}" fi - + if [ "$WCNT" -ge 1 ]; then wan1status="${CRed}[$WCNT]${CClear}" wan1health="${CRed}[FAIL]${CClear}" @@ -6339,7 +6469,7 @@ wancheck() wan1status="${CGreen}[X]${CClear}" wan1health="${CGreen}[ OK ]${CClear}" fi - + if [ "$WAN1PING" = "[FAILOVER]" ] then echo -en "${InvGreen} ${InvDkGray}${CWhite} WAN1${CClear} | $wan1status | " From 1f891f1cbc7f27a9d2dbad67f988177b7b7f4630 Mon Sep 17 00:00:00 2001 From: ViktorJp <97465574+ViktorJp@users.noreply.github.com> Date: Thu, 18 Dec 2025 19:25:14 -0500 Subject: [PATCH 19/40] Update changelog with new WAN recovery options Added a new Config Menu option for WAN recovery timers to enhance control over WAN DOWN situations. --- changelog.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/changelog.txt b/changelog.txt index 8c39647..d887f47 100644 --- a/changelog.txt +++ b/changelog.txt @@ -21,6 +21,11 @@ v1.8.3 - (TBA) - PATCH: Removed the functionality that would reset the Rx/Tx indicators to [UNKN] each time you went into a different menu item. It will now just show live stats no matter what. For consistent and more accurate results, wait your full 60 seconds (or whatever you've set your timer value to). + - PATCH: Added Config Menu option #16: "WAN Recovery, Down, Reconnect Timers", giving you more + control over the amount of time the various stages of dealing with a WAN DOWN situation, from the + amount of time your WAN can try to recover on its own, to how long between checking to see if the + WAN has become available again, to the amount of time given to let the router recover after the + WAN has come back up again before reconnecting all tunnels. v1.8.2 - (November 23, 2025) - PATCH: Thanks to @JTnola for sharing a "[: bad number" bug he was experiencing. This hard-to-find From d3edda7b4ff7c051d244ceb0e56cb127260c983c Mon Sep 17 00:00:00 2001 From: ViktorJp <97465574+ViktorJp@users.noreply.github.com> Date: Thu, 18 Dec 2025 19:25:27 -0500 Subject: [PATCH 20/40] Update version to v1.8.3b2 in changelog --- changelog.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/changelog.txt b/changelog.txt index d887f47..f2583f2 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,4 +1,4 @@ -v1.8.3 - (TBA) +v1.8.3b2 - (TBA) - PATCH: The Recovery Timeout should be defaulting to 1x, but it was inadvertently set to 3x. Thank you to @Tarek Yag for reporting this. Fixed! - PATCH: Changed the wording for the custom PING host to "Custom PING host for connectivity checks" From e864294628ac1c8483858f15551bdc722469c64f Mon Sep 17 00:00:00 2001 From: ViktorJp <97465574+ViktorJp@users.noreply.github.com> Date: Thu, 18 Dec 2025 19:25:47 -0500 Subject: [PATCH 21/40] Update version and release date in README --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index beac92f..a2509e6 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ -# VPNMON-R3 v1.8.3b1 +# VPNMON-R3 v1.8.3b2 Asus-Merlin OpenVPN/Wireguard Monitor R3 -Updated on 2025-Dec-5 +Updated on 2025-Dec-18 --- From afb92b760fd7c3bb1313276563a64fcfef20b65d Mon Sep 17 00:00:00 2001 From: ViktorJp <97465574+ViktorJp@users.noreply.github.com> Date: Thu, 18 Dec 2025 19:33:08 -0500 Subject: [PATCH 22/40] Display WAN recovery and reconnect timer values --- vpnmon-r3.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vpnmon-r3.sh b/vpnmon-r3.sh index c2b37f2..16fad57 100644 --- a/vpnmon-r3.sh +++ b/vpnmon-r3.sh @@ -1002,7 +1002,7 @@ do 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}(16)${CClear} : WAN Recovery, Down, Reconnect Timers : " + echo -e "${InvGreen} ${CClear} ${InvDkGray}${CWhite}(16)${CClear} : WAN Recovery, Down, Reconnect Timers : ${CGreen}$recoverytimer ${CClear}|${CGreen} $wandowntimer ${CClear}|${CGreen} $reconnecttimer sec" echo -e "${InvGreen} ${CClear} ${InvDkGray}${CWhite} | ${CClear}" echo -e "${InvGreen} ${CClear} ${InvDkGray}${CWhite}( e)${CClear} : Exit${CClear}" echo -e "${InvGreen} ${CClear}" From d188515b318f795d184c0242c04897afc34dcbb5 Mon Sep 17 00:00:00 2001 From: ViktorJp <97465574+ViktorJp@users.noreply.github.com> Date: Thu, 18 Dec 2025 19:38:51 -0500 Subject: [PATCH 23/40] Update WAN timer display logic in vpnmon-r3.sh --- vpnmon-r3.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/vpnmon-r3.sh b/vpnmon-r3.sh index 16fad57..73ed40e 100644 --- a/vpnmon-r3.sh +++ b/vpnmon-r3.sh @@ -908,8 +908,10 @@ do if [ "$monitorwan" -eq 0 ]; then monitorwandisp="${CDkGray}Disabled" + wantimersdisp="${CDkGray}Disabled" else monitorwandisp="Enabled" + wantimersdisp="${CGreen}$recoverytimer ${CClear}|${CGreen} $wandowntimer ${CClear}|${CGreen} $reconnecttimer sec" fi if [ "$useovpn" -eq 0 ] && [ "$usewg" -eq 0 ]; then @@ -1002,7 +1004,7 @@ do 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}(16)${CClear} : WAN Recovery, Down, Reconnect Timers : ${CGreen}$recoverytimer ${CClear}|${CGreen} $wandowntimer ${CClear}|${CGreen} $reconnecttimer sec" + echo -e "${InvGreen} ${CClear} ${InvDkGray}${CWhite}(16)${CClear} : WAN Recovery, Down, Reconnect Timers : $wantimersdisp" echo -e "${InvGreen} ${CClear} ${InvDkGray}${CWhite} | ${CClear}" echo -e "${InvGreen} ${CClear} ${InvDkGray}${CWhite}( e)${CClear} : Exit${CClear}" echo -e "${InvGreen} ${CClear}" From 513427e8015c17fdc11ec7c7efb84a3d88cfc45b Mon Sep 17 00:00:00 2001 From: ViktorJp <97465574+ViktorJp@users.noreply.github.com> Date: Thu, 18 Dec 2025 19:44:49 -0500 Subject: [PATCH 24/40] Update vpnmon-r3.sh --- vpnmon-r3.sh | 239 ++++++++++++++++++++++++++------------------------- 1 file changed, 120 insertions(+), 119 deletions(-) diff --git a/vpnmon-r3.sh b/vpnmon-r3.sh index 73ed40e..508106f 100644 --- a/vpnmon-r3.sh +++ b/vpnmon-r3.sh @@ -2106,126 +2106,127 @@ do ;; 16) - clear - while true - do + if [ "$monitorwan" -eq 1 ]; then clear - echo -e "${InvGreen} ${InvDkGray}${CWhite} WAN Recovery Timer Configuration ${CClear}" - echo -e "${InvGreen} ${CClear}" - echo -e "${InvGreen} ${CClear} Please indicate how long the various WAN Recovery timers should last during the${CClear}" - echo -e "${InvGreen} ${CClear} different states as the WAN tries to recover, or goes out completely. Depending${CClear}" - echo -e "${InvGreen} ${CClear} on what timer values you choose will have impact on how long your WAN takes to${CClear}" - echo -e "${InvGreen} ${CClear} recover.${CClear}" - echo -e "${InvGreen} ${CClear}" - echo -e "${InvGreen} ${CClear} ${CYellow}Recovery timer${CClear}: The length of time between tries to determine if your router is${CClear}" - echo -e "${InvGreen} ${CClear} able to ping the IP address of your choosing and recover before declaring a WAN${CClear}" - echo -e "${InvGreen} ${CClear} DOWN situation. (Default = 10 sec)${CClear}" - echo -e "${InvGreen} ${CClear}" - echo -e "${InvGreen} ${CClear} ${CYellow}WAN DOWN Timer${CClear}: The length of time between tries while the WAN is DOWN, where${CClear}" - echo -e "${InvGreen} ${CClear} VPNMON-R3 tries to determine if the WAN is available again. (Default = 60 sec)${CClear}" - echo -e "${InvGreen} ${CClear}" - echo -e "${InvGreen} ${CClear} ${CYellow}Reconnect Timer${CClear}: The length of time from when the WAN is declared back up while${CClear}" - echo -e "${InvGreen} ${CClear} giving the router some time to stabilize before it restarts VPN/WG tunnels. You don't${CClear}" - echo -e "${InvGreen} ${CClear} want your router reconnecting tunnels while the router is bouncing up and down.${CClear}" - echo -e "${InvGreen} ${CClear} (Default = 300 sec).${CClear}" - echo -e "${InvGreen} ${CClear}" - echo -e "${InvGreen} ${CClear}${CDkGray}---------------------------------------------------------------------------------------${CClear}" - echo -e "${InvGreen} ${CClear}" - echo -e "${InvGreen} ${CClear} Current:${CClear}" - echo -e "${InvGreen} ${CClear}" - echo -e "${InvGreen} ${CClear} Recovery Timer ${CGreen}(1): $recoverytimer sec${CClear}" - echo -e "${InvGreen} ${CClear} WAN DOWN Timer ${CGreen}(2): $wandowntimer sec ${CClear}" - echo -e "${InvGreen} ${CClear} Reconnect Timer ${CGreen}(3): $reconnecttimer sec ${CClear}" - echo -e "${InvGreen} ${CClear}" - echo - read -p "Please choose a Timer [1-3] and enter new Timer value in seconds (e=Exit): " newTimerChoice - case $newTimerChoice in - 1) echo "" - read -p "Enter new Recovery Timer value in seconds between [10-999] (default=10, e=Exit): " newRecoveryTimerChoice - if [ -z "$newRecoveryTimerChoice" ] || echo "$newRecoveryTimerChoice" | grep -qE "^(e|E)$" - then - if echo "$recoverytimer" | grep -qE "^([1-9][0-9]{0,2})$" && \ - [ "$recoverytimer" -ge 10 ] && [ "$recoverytimer" -le 999 ] - then - 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 "$newRecoveryTimerChoice" | grep -qE "^([1-9][0-9]{0,2})$" && \ - [ "$newRecoveryTimerChoice" -ge 10 ] && [ "$newRecoveryTimerChoice" -le 999 ] - then - recoverytimer="$newRecoveryTimerChoice" - echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - INFO: New Recovery Timer ($recoverytimer sec) configuration saved" >> $logfile - saveconfig - 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 - ;; - - 2) echo "" - read -p "Enter new WAN-DOWN Timer value in seconds between [10-999] (default=60, e=Exit): " newWANDOWNTimerChoice - if [ -z "$newWANDOWNTimerChoice" ] || echo "$newWANDOWNTimerChoice" | grep -qE "^(e|E)$" - then - if echo "$wandowntimer" | grep -qE "^([1-9][0-9]{0,2})$" && \ - [ "$wandowntimer" -ge 10 ] && [ "$wandowntimer" -le 999 ] - then - 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 "$newWANDOWNTimerChoice" | grep -qE "^([1-9][0-9]{0,2})$" && \ - [ "$newWANDOWNTimerChoice" -ge 10 ] && [ "$newWANDOWNTimerChoice" -le 999 ] - then - wandowntimer="$newWANDOWNTimerChoice" - echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - INFO: New WAN-DOWN Timer ($recoverytimer sec) configuration saved" >> $logfile - saveconfig - 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 - ;; - - 3) echo "" - read -p "Enter new Reconnect Timer value in seconds between [10-999] (default=300, e=Exit): " newReconnectTimerChoice - if [ -z "$newReconnectTimerChoice" ] || echo "$newReconnectTimerChoice" | grep -qE "^(e|E)$" - then - if echo "$reconnecttimer" | grep -qE "^([1-9][0-9]{0,2})$" && \ - [ "$reconnecttimer" -ge 10 ] && [ "$reconnecttimer" -le 999 ] - then - 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 "$newReconnectTimerChoice" | grep -qE "^([1-9][0-9]{0,2})$" && \ - [ "$newReconnectTimerChoice" -ge 10 ] && [ "$newReconnectTimerChoice" -le 999 ] - then - reconnecttimer="$newReconnectTimerChoice" - echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - INFO: New Reconnect Timer ($recoverytimer sec) configuration saved" >> $logfile - saveconfig - 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 - ;; - - [Ee]) printf "\n${CClear}[Exiting]\n" - sleep 1 ; break - esac - - done + while true + do + clear + echo -e "${InvGreen} ${InvDkGray}${CWhite} WAN Recovery Timer Configuration ${CClear}" + echo -e "${InvGreen} ${CClear}" + echo -e "${InvGreen} ${CClear} Please indicate how long the various WAN Recovery timers should last during the${CClear}" + echo -e "${InvGreen} ${CClear} different states as the WAN tries to recover, or goes out completely. Depending${CClear}" + echo -e "${InvGreen} ${CClear} on what timer values you choose will have impact on how long your WAN takes to${CClear}" + echo -e "${InvGreen} ${CClear} recover.${CClear}" + echo -e "${InvGreen} ${CClear}" + echo -e "${InvGreen} ${CClear} ${CYellow}Recovery timer${CClear}: The length of time between tries to determine if your router is${CClear}" + echo -e "${InvGreen} ${CClear} able to ping the IP address of your choosing and recover before declaring a WAN${CClear}" + echo -e "${InvGreen} ${CClear} DOWN situation. (Default = 10 sec)${CClear}" + echo -e "${InvGreen} ${CClear}" + echo -e "${InvGreen} ${CClear} ${CYellow}WAN DOWN Timer${CClear}: The length of time between tries while the WAN is DOWN, where${CClear}" + echo -e "${InvGreen} ${CClear} VPNMON-R3 tries to determine if the WAN is available again. (Default = 60 sec)${CClear}" + echo -e "${InvGreen} ${CClear}" + echo -e "${InvGreen} ${CClear} ${CYellow}Reconnect Timer${CClear}: The length of time from when the WAN is declared back up while${CClear}" + echo -e "${InvGreen} ${CClear} giving the router some time to stabilize before it restarts VPN/WG tunnels. You don't${CClear}" + echo -e "${InvGreen} ${CClear} want your router reconnecting tunnels while the router is bouncing up and down.${CClear}" + echo -e "${InvGreen} ${CClear} (Default = 300 sec).${CClear}" + echo -e "${InvGreen} ${CClear}" + echo -e "${InvGreen} ${CClear}${CDkGray}---------------------------------------------------------------------------------------${CClear}" + echo -e "${InvGreen} ${CClear}" + echo -e "${InvGreen} ${CClear} Current:${CClear}" + echo -e "${InvGreen} ${CClear}" + echo -e "${InvGreen} ${CClear} Recovery Timer ${CGreen}(1): $recoverytimer sec${CClear}" + echo -e "${InvGreen} ${CClear} WAN DOWN Timer ${CGreen}(2): $wandowntimer sec ${CClear}" + echo -e "${InvGreen} ${CClear} Reconnect Timer ${CGreen}(3): $reconnecttimer sec ${CClear}" + echo -e "${InvGreen} ${CClear}" + echo + read -p "Please choose a Timer [1-3] and enter new Timer value in seconds (e=Exit): " newTimerChoice + case $newTimerChoice in + 1) echo "" + read -p "Enter new Recovery Timer value in seconds between [10-999] (default=10, e=Exit): " newRecoveryTimerChoice + if [ -z "$newRecoveryTimerChoice" ] || echo "$newRecoveryTimerChoice" | grep -qE "^(e|E)$" + then + if echo "$recoverytimer" | grep -qE "^([1-9][0-9]{0,2})$" && \ + [ "$recoverytimer" -ge 10 ] && [ "$recoverytimer" -le 999 ] + then + 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 "$newRecoveryTimerChoice" | grep -qE "^([1-9][0-9]{0,2})$" && \ + [ "$newRecoveryTimerChoice" -ge 10 ] && [ "$newRecoveryTimerChoice" -le 999 ] + then + recoverytimer="$newRecoveryTimerChoice" + echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - INFO: New Recovery Timer ($recoverytimer sec) configuration saved" >> $logfile + saveconfig + 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 + ;; + + 2) echo "" + read -p "Enter new WAN-DOWN Timer value in seconds between [10-999] (default=60, e=Exit): " newWANDOWNTimerChoice + if [ -z "$newWANDOWNTimerChoice" ] || echo "$newWANDOWNTimerChoice" | grep -qE "^(e|E)$" + then + if echo "$wandowntimer" | grep -qE "^([1-9][0-9]{0,2})$" && \ + [ "$wandowntimer" -ge 10 ] && [ "$wandowntimer" -le 999 ] + then + 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 "$newWANDOWNTimerChoice" | grep -qE "^([1-9][0-9]{0,2})$" && \ + [ "$newWANDOWNTimerChoice" -ge 10 ] && [ "$newWANDOWNTimerChoice" -le 999 ] + then + wandowntimer="$newWANDOWNTimerChoice" + echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - INFO: New WAN-DOWN Timer ($recoverytimer sec) configuration saved" >> $logfile + saveconfig + 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 + ;; + + 3) echo "" + read -p "Enter new Reconnect Timer value in seconds between [10-999] (default=300, e=Exit): " newReconnectTimerChoice + if [ -z "$newReconnectTimerChoice" ] || echo "$newReconnectTimerChoice" | grep -qE "^(e|E)$" + then + if echo "$reconnecttimer" | grep -qE "^([1-9][0-9]{0,2})$" && \ + [ "$reconnecttimer" -ge 10 ] && [ "$reconnecttimer" -le 999 ] + then + 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 "$newReconnectTimerChoice" | grep -qE "^([1-9][0-9]{0,2})$" && \ + [ "$newReconnectTimerChoice" -ge 10 ] && [ "$newReconnectTimerChoice" -le 999 ] + then + reconnecttimer="$newReconnectTimerChoice" + echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - INFO: New Reconnect Timer ($recoverytimer sec) configuration saved" >> $logfile + saveconfig + 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 + ;; + + [Ee]) printf "\n${CClear}[Exiting]\n" + sleep 1 ; break + esac + done + fi ;; esac From 4e54b96dab6f17f9ab262e4a0442a894a2e5b5ca Mon Sep 17 00:00:00 2001 From: ViktorJp <97465574+ViktorJp@users.noreply.github.com> Date: Fri, 19 Dec 2025 07:10:37 -0500 Subject: [PATCH 25/40] Update vpnmon-r3.sh --- vpnmon-r3.sh | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/vpnmon-r3.sh b/vpnmon-r3.sh index 508106f..3aebe95 100644 --- a/vpnmon-r3.sh +++ b/vpnmon-r3.sh @@ -4375,12 +4375,13 @@ trimlogs() { if [ "$logsize" -gt 0 ] then - currlogsize="$(wc -l $logfile | awk '{ print $1 }')" # Determine the number of rows in the log + 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 + tail -"$logsize" "$logfile" > "${logfile}.tmp" + mv "${logfile}.tmp" "$logfile" + echo "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - INFO: Trimmed the log file down to $logsize lines" >> "$logfile" fi fi } From 00734548229a2b92df3a6aefa6e1767d9f7beb82 Mon Sep 17 00:00:00 2001 From: ViktorJp <97465574+ViktorJp@users.noreply.github.com> Date: Fri, 19 Dec 2025 07:15:39 -0500 Subject: [PATCH 26/40] Clarify recovery timeouts application for WAN Reworded the recovery timeouts section for clarity. --- changelog.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/changelog.txt b/changelog.txt index f2583f2..f1fca68 100644 --- a/changelog.txt +++ b/changelog.txt @@ -12,9 +12,9 @@ v1.8.3b2 - (TBA) user-selected values. - PATCH: Fixed some instances where PINGHOST was hardcoded to 8.8.8.8, instead of using user-selected values. - - PATCH: Implemented recovery timeouts (if configured) and will apply to the WAN as well. Should the - WAN have issues establishing an SSL connection with the user-selected PINGHOST, it will attempt to - try the number of times that is user-specified. + - PATCH: Recovery timeouts (if configured) will apply to the WAN as well. Should the WAN have issues + establishing an SSL connection with the user-selected PINGHOST, it will attempt to try the number + of times that is user-specified. - PATCH: Cut down all VPN/WG connection and reset times by half. Will continue to monitor closely for misbehavior. Done in response to @scootertramp noting the long time it takes to reconnect all VPN/WG connections after a WAN DOWN event. From 0864346905a0742e4c92ef719b171e83ba178cf6 Mon Sep 17 00:00:00 2001 From: ViktorJp <97465574+ViktorJp@users.noreply.github.com> Date: Sat, 27 Dec 2025 08:55:48 -0500 Subject: [PATCH 27/40] Update vpnmon-r3.sh --- vpnmon-r3.sh | 84 +++++++++++++++++++++++++++++++++++----------------- 1 file changed, 57 insertions(+), 27 deletions(-) diff --git a/vpnmon-r3.sh b/vpnmon-r3.sh index 3aebe95..5ff6ea9 100644 --- a/vpnmon-r3.sh +++ b/vpnmon-r3.sh @@ -1,20 +1,20 @@ #!/bin/sh -# VPNMON-R3 v1.8.3b2 (VPNMON-R3.SH) is an all-in-one script that is optimized to maintain multiple VPN connections and is +# VPNMON-R3 v1.8.3b3 (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-Dec-5 +# Last Modified: 2025-Dec-27 ########################################################################################## #Preferred standard router binaries path export PATH="/sbin:/bin:/usr/sbin:/usr/bin:$PATH" #Static Variables - please do not change -version="1.8.3b2" # Version tracker +version="1.8.3b3" # Version tracker beta=1 # Beta switch screenshotmode=0 # Switch to present bogus info for screenshots apppath="/jffs/scripts/vpnmon-r3.sh" # Static path to the app @@ -67,6 +67,7 @@ WCNT=0 # WAN DOWN count recoverytimer=10 # Time between recovery attempts before declaring WAN-DOWN wandowntimer=60 # Time between attempts to determine if WAN is available again reconnecttimer=300 # Time allotted to giving router time to stabilize before reconnecting tunnels +loopexit=0 # Switch to determine if the timerloop was exited early ##-------------------------------------## ## Added by Martinski W. [2024-Oct-05] ## @@ -324,6 +325,7 @@ progressbaroverride() *) ;; ##IGNORE INVALID key presses ## esac bypasswancheck=1 + loopexit=1 fi } @@ -6634,6 +6636,14 @@ get_wan_setting1() getifacestats() { + if [ $loopexit -eq 1 ] + then + loopexit=0 + return + else + echo $(date +%s) > "/jffs/addons/vpnmon-r3.d/vr3start.txt" + fi + if [ ! -z "$WAN0IFNAME" ] then oldwan0rxbytes="$($timeoutcmd$timeoutsec cat /sys/class/net/$WAN0IFNAME/statistics/rx_bytes)" @@ -6763,12 +6773,32 @@ calcifacestats() return fi + if [ $loopexit -eq 1 ] + then + return + fi + + if [ -f "/jffs/addons/vpnmon-r3.d/vr3start.txt" ] + then + timerstart=$(cat "/jffs/addons/vpnmon-r3.d/vr3start.txt") + timernow=$(date +%s) + timerdiff=$((timernow-timerstart)) + if [ $timerdiff -gt $timerloop ] + then + newtimer=$timerdiff + else + newtimer=$timerloop + fi + else + newtimer=$timerloop + 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}') + diffwan0rxbytes=$(awk -v new=$newwan0rxbytes -v old=$oldwan0rxbytes -v mb=125000 -v lp=$newtimer 'BEGIN{printf "%.0f\n", ((new-old)/mb)/lp}') + diffwan0txbytes=$(awk -v new=$newwan0txbytes -v old=$oldwan0txbytes -v mb=125000 -v lp=$newtimer '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 @@ -6777,8 +6807,8 @@ calcifacestats() 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}') + diffwan1rxbytes=$(awk -v new=$newwan1rxbytes -v old=$oldwan1rxbytes -v mb=125000 -v lp=$newtimer 'BEGIN{printf "%.0f\n", ((new-old)/mb)/lp}') + diffwan1txbytes=$(awk -v new=$newwan1txbytes -v old=$oldwan1txbytes -v mb=125000 -v lp=$newtimer '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 @@ -6807,8 +6837,8 @@ calcifacestats() 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}') + diffvpn1rxbytes=$(awk -v new=$newvpn1rxbytes -v old=$oldvpn1rxbytes -v mb=125000 -v lp=$newtimer 'BEGIN{printf "%.0f\n", ((new-old)/mb)/lp}') + diffvpn1txbytes=$(awk -v new=$newvpn1txbytes -v old=$oldvpn1txbytes -v mb=125000 -v lp=$newtimer '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 @@ -6824,8 +6854,8 @@ calcifacestats() 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}') + diffvpn2rxbytes=$(awk -v new=$newvpn2rxbytes -v old=$oldvpn2rxbytes -v mb=125000 -v lp=$newtimer 'BEGIN{printf "%.0f\n", ((new-old)/mb)/lp}') + diffvpn2txbytes=$(awk -v new=$newvpn2txbytes -v old=$oldvpn2txbytes -v mb=125000 -v lp=$newtimer '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 @@ -6841,8 +6871,8 @@ calcifacestats() 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}') + diffvpn3rxbytes=$(awk -v new=$newvpn3rxbytes -v old=$oldvpn3rxbytes -v mb=125000 -v lp=$newtimer 'BEGIN{printf "%.0f\n", ((new-old)/mb)/lp}') + diffvpn3txbytes=$(awk -v new=$newvpn3txbytes -v old=$oldvpn3txbytes -v mb=125000 -v lp=$newtimer '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 @@ -6858,8 +6888,8 @@ calcifacestats() 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}') + diffvpn4rxbytes=$(awk -v new=$newvpn4rxbytes -v old=$oldvpn4rxbytes -v mb=125000 -v lp=$newtimer 'BEGIN{printf "%.0f\n", ((new-old)/mb)/lp}') + diffvpn4txbytes=$(awk -v new=$newvpn4txbytes -v old=$oldvpn4txbytes -v mb=125000 -v lp=$newtimer '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 @@ -6875,8 +6905,8 @@ calcifacestats() 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}') + diffvpn5rxbytes=$(awk -v new=$newvpn5rxbytes -v old=$oldvpn5rxbytes -v mb=125000 -v lp=$newtimer 'BEGIN{printf "%.0f\n", ((new-old)/mb)/lp}') + diffvpn5txbytes=$(awk -v new=$newvpn5txbytes -v old=$oldvpn5txbytes -v mb=125000 -v lp=$newtimer '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 @@ -6892,8 +6922,8 @@ calcifacestats() 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}') + diffwg1rxbytes=$(awk -v new=$newwg1rxbytes -v old=$oldwg1rxbytes -v mb=125000 -v lp=$newtimer 'BEGIN{printf "%.0f\n", ((new-old)/mb)/lp}') + diffwg1txbytes=$(awk -v new=$newwg1txbytes -v old=$oldwg1txbytes -v mb=125000 -v lp=$newtimer '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 @@ -6909,8 +6939,8 @@ calcifacestats() 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}') + diffwg2rxbytes=$(awk -v new=$newwg2rxbytes -v old=$oldwg2rxbytes -v mb=125000 -v lp=$newtimer 'BEGIN{printf "%.0f\n", ((new-old)/mb)/lp}') + diffwg2txbytes=$(awk -v new=$newwg2txbytes -v old=$oldwg2txbytes -v mb=125000 -v lp=$newtimer '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 @@ -6926,8 +6956,8 @@ calcifacestats() 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}') + diffwg3rxbytes=$(awk -v new=$newwg3rxbytes -v old=$oldwg3rxbytes -v mb=125000 -v lp=$newtimer 'BEGIN{printf "%.0f\n", ((new-old)/mb)/lp}') + diffwg3txbytes=$(awk -v new=$newwg3txbytes -v old=$oldwg3txbytes -v mb=125000 -v lp=$newtimer '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 @@ -6943,8 +6973,8 @@ calcifacestats() 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}') + diffwg4rxbytes=$(awk -v new=$newwg4rxbytes -v old=$oldwg4rxbytes -v mb=125000 -v lp=$newtimer 'BEGIN{printf "%.0f\n", ((new-old)/mb)/lp}') + diffwg4txbytes=$(awk -v new=$newwg4txbytes -v old=$oldwg4txbytes -v mb=125000 -v lp=$newtimer '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 @@ -6960,8 +6990,8 @@ calcifacestats() 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}') + diffwg5rxbytes=$(awk -v new=$newwg5rxbytes -v old=$oldwg5rxbytes -v mb=125000 -v lp=$newtimer 'BEGIN{printf "%.0f\n", ((new-old)/mb)/lp}') + diffwg5txbytes=$(awk -v new=$newwg5txbytes -v old=$oldwg5txbytes -v mb=125000 -v lp=$newtimer '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 From 64569b2f485e8cd553f44b41dba74db42e663497 Mon Sep 17 00:00:00 2001 From: ViktorJp <97465574+ViktorJp@users.noreply.github.com> Date: Sat, 27 Dec 2025 08:56:04 -0500 Subject: [PATCH 28/40] Bump version to v1.8.3b3 and update date Updated version number and date in README. --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index a2509e6..f5f30c1 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ -# VPNMON-R3 v1.8.3b2 +# VPNMON-R3 v1.8.3b3 Asus-Merlin OpenVPN/Wireguard Monitor R3 -Updated on 2025-Dec-18 +Updated on 2025-Dec-27 --- From 123e277d39a972addac0844189d76c603f5afbf5 Mon Sep 17 00:00:00 2001 From: ViktorJp <97465574+ViktorJp@users.noreply.github.com> Date: Sat, 27 Dec 2025 08:57:54 -0500 Subject: [PATCH 29/40] Update changelog.txt --- changelog.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/changelog.txt b/changelog.txt index f1fca68..2f31cc7 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,4 +1,4 @@ -v1.8.3b2 - (TBA) +v1.8.3b3 - (TBA) - PATCH: The Recovery Timeout should be defaulting to 1x, but it was inadvertently set to 3x. Thank you to @Tarek Yag for reporting this. Fixed! - PATCH: Changed the wording for the custom PING host to "Custom PING host for connectivity checks" @@ -26,6 +26,8 @@ v1.8.3b2 - (TBA) amount of time your WAN can try to recover on its own, to how long between checking to see if the WAN has become available again, to the amount of time given to let the router recover after the WAN has come back up again before reconnecting all tunnels. + - PATCH: Improved the tracking of the timer, plus any time spent in other menus outside of the + regular timer, to provide a more accurate view of the Tx/Rx stats. v1.8.2 - (November 23, 2025) - PATCH: Thanks to @JTnola for sharing a "[: bad number" bug he was experiencing. This hard-to-find From 6d5098aef7a10e30da48814d81aba27e882be1fc Mon Sep 17 00:00:00 2001 From: ViktorJp <97465574+ViktorJp@users.noreply.github.com> Date: Sat, 27 Dec 2025 09:11:05 -0500 Subject: [PATCH 30/40] Update vpnmon-r3.sh --- vpnmon-r3.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/vpnmon-r3.sh b/vpnmon-r3.sh index 5ff6ea9..f30ad78 100644 --- a/vpnmon-r3.sh +++ b/vpnmon-r3.sh @@ -7332,8 +7332,9 @@ then clear #last switch before the main program starts firstrun=1 - # Clean up lockfile + # Clean up lockfile and other files rm -f $lockfile >/dev/null 2>&1 + rm -f /jffs/addons/vpnmon-r3.d/vr3start.txt >/dev/null 2>&1 if [ ! -f "$config" ] && [ ! -f "/opt/bin/timeout" ] && [ ! -f "/opt/sbin/screen" ] && [ ! -f "/opt/bin/jq" ] then From 27474943ae8253e455a5eaaab22c32eda67d48b8 Mon Sep 17 00:00:00 2001 From: ViktorJp <97465574+ViktorJp@users.noreply.github.com> Date: Sun, 28 Dec 2025 15:44:37 -0500 Subject: [PATCH 31/40] Update changelog.txt --- changelog.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/changelog.txt b/changelog.txt index 2f31cc7..1a3986a 100644 --- a/changelog.txt +++ b/changelog.txt @@ -28,6 +28,11 @@ v1.8.3b3 - (TBA) WAN has come back up again before reconnecting all tunnels. - PATCH: Improved the tracking of the timer, plus any time spent in other menus outside of the regular timer, to provide a more accurate view of the Tx/Rx stats. + - PATCH: Based on some feedback that @ComputerSteve was experiencing, I've optimized both the VPN + and WG connectivity tests to fail the curl test if the ping test fails. It seems the ping test + will fail pretty quickly, while the curl test could hang in there for quite some time before + indicating a fail. This should help resolve some of the sluggishness you would see if any of + your tunnels are misbehaving. v1.8.2 - (November 23, 2025) - PATCH: Thanks to @JTnola for sharing a "[: bad number" bug he was experiencing. This hard-to-find From de8e9be2fac3ae33bafe14a9fa99c87d563f7dc6 Mon Sep 17 00:00:00 2001 From: ViktorJp <97465574+ViktorJp@users.noreply.github.com> Date: Sun, 28 Dec 2025 15:44:48 -0500 Subject: [PATCH 32/40] Update changelog.txt --- changelog.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/changelog.txt b/changelog.txt index 1a3986a..b60b468 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,4 +1,4 @@ -v1.8.3b3 - (TBA) +v1.8.3b4 - (TBA) - PATCH: The Recovery Timeout should be defaulting to 1x, but it was inadvertently set to 3x. Thank you to @Tarek Yag for reporting this. Fixed! - PATCH: Changed the wording for the custom PING host to "Custom PING host for connectivity checks" From 82a9e0282567bc2a6e53c9d576fac35456a156a2 Mon Sep 17 00:00:00 2001 From: ViktorJp <97465574+ViktorJp@users.noreply.github.com> Date: Sun, 28 Dec 2025 15:45:03 -0500 Subject: [PATCH 33/40] Update vpnmon-r3.sh --- vpnmon-r3.sh | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/vpnmon-r3.sh b/vpnmon-r3.sh index f30ad78..5073295 100644 --- a/vpnmon-r3.sh +++ b/vpnmon-r3.sh @@ -1,20 +1,20 @@ #!/bin/sh -# VPNMON-R3 v1.8.3b3 (VPNMON-R3.SH) is an all-in-one script that is optimized to maintain multiple VPN connections and is +# VPNMON-R3 v1.8.3b4 (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-Dec-27 +# Last Modified: 2025-Dec-28 ########################################################################################## #Preferred standard router binaries path export PATH="/sbin:/bin:/usr/sbin:/usr/bin:$PATH" #Static Variables - please do not change -version="1.8.3b3" # Version tracker +version="1.8.3b4" # Version tracker beta=1 # Beta switch screenshotmode=0 # Switch to present bogus info for screenshots apppath="/jffs/scripts/vpnmon-r3.sh" # Static path to the app @@ -913,7 +913,7 @@ do wantimersdisp="${CDkGray}Disabled" else monitorwandisp="Enabled" - wantimersdisp="${CGreen}$recoverytimer ${CClear}|${CGreen} $wandowntimer ${CClear}|${CGreen} $reconnecttimer sec" + wantimersdisp="${CGreen}$recoverytimer | $wandowntimer | $reconnecttimer sec" fi if [ "$useovpn" -eq 0 ] && [ "$usewg" -eq 0 ]; then @@ -5961,9 +5961,12 @@ checkvpn() while [ "$CNT" -lt "$recover" ]; 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 ]; then # 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=$? + else + IC=2 + fi 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=$? @@ -6029,9 +6032,12 @@ checkwg() while [ "$CNT" -lt "$recover" ]; 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 ]; then # 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=$? + else + IC=2 + fi 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=$? From 1e5d706161bf42cef62408cca734fe3edcf6ae5a Mon Sep 17 00:00:00 2001 From: ViktorJp <97465574+ViktorJp@users.noreply.github.com> Date: Mon, 12 Jan 2026 20:38:39 -0500 Subject: [PATCH 34/40] Update vpnmon-r3.sh --- vpnmon-r3.sh | 96 ++++++++++++++++++++++++++++++++-------------------- 1 file changed, 59 insertions(+), 37 deletions(-) diff --git a/vpnmon-r3.sh b/vpnmon-r3.sh index 5073295..f961359 100644 --- a/vpnmon-r3.sh +++ b/vpnmon-r3.sh @@ -1,20 +1,20 @@ #!/bin/sh -# VPNMON-R3 v1.8.3b4 (VPNMON-R3.SH) is an all-in-one script that is optimized to maintain multiple VPN connections and is +# VPNMON-R3 v1.8.3b6 (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-Dec-28 +# Last Modified: 2026-Jan-12 ########################################################################################## #Preferred standard router binaries path export PATH="/sbin:/bin:/usr/sbin:/usr/bin:$PATH" #Static Variables - please do not change -version="1.8.3b4" # Version tracker +version="1.8.3b6" # Version tracker beta=1 # Beta switch screenshotmode=0 # Switch to present bogus info for screenshots apppath="/jffs/scripts/vpnmon-r3.sh" # Static path to the app @@ -62,7 +62,8 @@ medutilspd=250 # Upper Limit of 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 -PINGHOST="8.8.8.8" # Default Ping host +PINGHOST="8.8.8.8" # Default Primary PING Host +PINGHOST2="1.1.1.1" # Default Secondary PING Host WCNT=0 # WAN DOWN counter recoverytimer=10 # Time between recovery attempts before declaring WAN-DOWN wandowntimer=60 # Time between attempts to determine if WAN is available again @@ -987,7 +988,7 @@ do 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 for connectivity checks : ${CGreen}$PINGHOST" + echo -e "${InvGreen} ${CClear} ${InvDkGray}${CWhite}( 2)${CClear} : Custom PING hosts for connectivity checks : ${CGreen}$PINGHOST | $PINGHOST2" 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" @@ -1069,29 +1070,45 @@ do 2) clear - echo -e "${InvGreen} ${InvDkGray}${CWhite} Custom PING Host (to determine WAN/VPN/WG health) ${CClear}" + echo -e "${InvGreen} ${InvDkGray}${CWhite} Custom PING Hosts (to determine WAN/VPN/WG health) ${CClear}" echo -e "${InvGreen} ${CClear}" - echo -e "${InvGreen} ${CClear} Please indicate which host you want to PING in order to determine connectivity health.${CClear}" - echo -e "${InvGreen} ${CClear} By default, the script will ping 8.8.8.8 (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} Please indicate which hosts you want to PING in order to determine connectivity${CClear}" + echo -e "${InvGreen} ${CClear} health. By default, the script will ping 8.8.8.8 (Google DNS) and 1.1.1.1 (CloudFlare${CClear}" + echo -e "${InvGreen} ${CClear} DNS) as they are reliable, fairly standard, and typically available globally. You can${CClear}" + echo -e "${InvGreen} ${CClear} change these depending on your local access and connectivity situation. It is${CClear}" + echo -e "${InvGreen} ${CClear} advisable to choose 2 different DNS provider IP addresses for redundancy purposes. If${CClear}" + echo -e "${InvGreen} ${CClear} one fails to PING, the other will redundantly keep your connection from being reset.${CClear}" echo -e "${InvGreen} ${CClear}" - echo -e "${InvGreen} ${CClear} (Default = 8.8.8.8)${CClear}" + echo -e "${InvGreen} ${CClear} (Default = 8.8.8.8 | 1.1.1.1)${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 + echo -e "${CClear}Current Pinghost 1: ${CGreen}${PINGHOST}${CClear}" + echo -e "${CClear}Current Pinghost 2: ${CGreen}${PINGHOST2}${CClear}" ; echo + read -p "Please enter valid IPv4 address for Pinghost 1? (e=Exit): " newPingHost if [ "$newPingHost" = "e" ] then - echo -e "\n[Exiting]"; sleep 2 + echo -e "\n[Exiting]"; sleep 2; continue 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 + echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - INFO: New custom PING host 1 entered: $PINGHOST" >> $logfile else PINGHOST="8.8.8.8" - echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - INFO: Default PING host entered: $PINGHOST" >> $logfile + echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - INFO: Default PING host 1 entered: $PINGHOST" >> $logfile + fi + echo "" + read -p "Please enter valid IPv4 address for Pinghost 2? (e=Exit): " newPingHost2 + if [ "$newPingHost2" = "e" ] + then + echo -e "\n[Exiting]"; sleep 2 + elif [ -n "$newPingHost2" ] && echo "$newPingHost2" | grep -qE "^${IPv4addrs_RegEx}$" + then + PINGHOST2="$newPingHost2" + echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - INFO: New custom PING host 2 entered: $PINGHOST2" >> $logfile + saveconfig + else + PINGHOST2="1.1.1.1" + echo -e "$(date +'%b %d %Y %X') $(_GetLAN_HostName_) VPNMON-R3[$$] - INFO: Default PING host 2 entered: $PINGHOST2" >> $logfile saveconfig fi ;; @@ -2967,7 +2984,7 @@ do 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 + firewall import whitelist /jffs/addons/vpnmon-r3.d/vr3svr1.txt "VPNMON-R3 VPN Slot 1 Manually Whitelisted on $date" >/dev/null 2>&1 echo "" echo -e "${CGreen}[Contents of VPN Slot 1 Imported]${CClear}" echo "" @@ -3048,7 +3065,7 @@ do 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 + firewall import whitelist /jffs/addons/vpnmon-r3.d/vr3svr2.txt "VPNMON-R3 VPN Slot 2 Manually Whitelisted on $date" >/dev/null 2>&1 echo "" echo -e "${CGreen}[Contents of VPN Slot 2 Imported]${CClear}" echo "" @@ -3207,7 +3224,7 @@ do 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 + firewall import whitelist /jffs/addons/vpnmon-r3.d/vr3svr1.txt "VPNMON-R3 VPN Slot 1 Manually Whitelisted on $date" >/dev/null 2>&1 echo "" echo -e "${CGreen}[Contents of VPN Slot 1 Imported]${CClear}" echo "" @@ -3288,7 +3305,7 @@ do 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 + firewall import whitelist /jffs/addons/vpnmon-r3.d/vr3svr2.txt "VPNMON-R3 VPN Slot 2 Manually Whitelisted on $date" >/dev/null 2>&1 echo "" echo -e "${CGreen}[Contents of VPN Slot 2 Imported]${CClear}" echo "" @@ -3369,7 +3386,7 @@ do 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 + firewall import whitelist /jffs/addons/vpnmon-r3.d/vr3svr3.txt "VPNMON-R3 VPN Slot 3 Manually Whitelisted on $date" >/dev/null 2>&1 echo "" echo -e "${CGreen}[Contents of VPN Slot 3 Imported]${CClear}" echo "" @@ -3450,7 +3467,7 @@ do 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 + firewall import whitelist /jffs/addons/vpnmon-r3.d/vr3svr4.txt "VPNMON-R3 VPN Slot 4 Manually Whitelisted on $date" >/dev/null 2>&1 echo "" echo -e "${CGreen}[Contents of VPN Slot 4 Imported]${CClear}" echo "" @@ -3531,7 +3548,7 @@ do 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 + firewall import whitelist /jffs/addons/vpnmon-r3.d/vr3svr5.txt "VPNMON-R3 VPN Slot 5 Manually Whitelisted on $date" >/dev/null 2>&1 echo "" echo -e "${CGreen}[Contents of VPN Slot 5 Imported]${CClear}" echo "" @@ -3613,7 +3630,7 @@ do 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 + firewall import whitelist /jffs/addons/vpnmon-r3.d/vr3svrtmp.txt "VPNMON-R3 WG Slot 1 Manually Whitelisted on $date" >/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}" @@ -3696,7 +3713,7 @@ do 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 + firewall import whitelist /jffs/addons/vpnmon-r3.d/vr3svrtmp.txt "VPNMON-R3 WG Slot 2 Manually Whitelisted on $date" >/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}" @@ -3779,7 +3796,7 @@ do 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 + firewall import whitelist /jffs/addons/vpnmon-r3.d/vr3svrtmp.txt "VPNMON-R3 WG Slot 3 Manually Whitelisted on $date" >/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}" @@ -3862,7 +3879,7 @@ do 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 + firewall import whitelist /jffs/addons/vpnmon-r3.d/vr3svrtmp.txt "VPNMON-R3 WG Slot 4 Manually Whitelisted on $date" >/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}" @@ -3945,7 +3962,7 @@ do 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 + firewall import whitelist /jffs/addons/vpnmon-r3.d/vr3svrtmp.txt "VPNMON-R3 WG Slot 5 Manually Whitelisted on $date" >/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}" @@ -4395,6 +4412,7 @@ saveconfig() { { echo 'availableslots="'"$availableslots"'"' echo 'PINGHOST="'"$PINGHOST"'"' + echo 'PINGHOST2="'"$PINGHOST2"'"' echo 'logsize='$logsize echo 'timerloop='$timerloop echo 'recover='$recover @@ -5345,12 +5363,12 @@ skynetwhitelist() 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 + firewall import whitelist /jffs/addons/vpnmon-r3.d/vr3svrtmp.txt "VPNMON-R3 - WG Server Slot $slotnum Whitelisted on $date" >/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 + firewall import whitelist /jffs/addons/vpnmon-r3.d/vr3svr$1.txt "VPNMON-R3 - VPN Server Slot $1 Whitelisted on $date" >/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 @@ -5959,9 +5977,11 @@ checkvpn() TUN="tun1$1" while [ "$CNT" -lt "$recover" ]; do # Loop through number of tries - ping -I $TUN -q -c 1 -W 2 $PINGHOST > /dev/null 2>&1 # First try pings + ping -I $TUN -q -c 1 -W 2 $PINGHOST > /dev/null 2>&1 # First try pings to Primary PING Host RC=$? - if [ "$RC" -eq 0 ]; then # Grab the public IP of the VPN Connection # + ping -I $TUN -q -c 1 -W 2 $PINGHOST2 > /dev/null 2>&1 # Then try pings to Secondary PING Host + SC=$? + if [ "$RC" -eq 0 ] || [ "$SC" -eq 0 ]; then # 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=$? else @@ -6030,9 +6050,11 @@ checkwg() ip rule add from $TUN_IP lookup $TUN prio 10 >/dev/null 2>&1 while [ "$CNT" -lt "$recover" ]; do # Loop through number of tries - ping -I $TUN -q -c 1 -W 2 $PINGHOST > /dev/null 2>&1 # First try pings + ping -I $TUN -q -c 1 -W 2 $PINGHOST > /dev/null 2>&1 # First try pings to Primary PING Host RC=$? - if [ "$RC" -eq 0 ]; then # Grab the public IP of the VPN Connection # + ping -I $TUN -q -c 1 -W 2 $PINGHOST2 > /dev/null 2>&1 # Then try pings to Secondary PING Host + SC=$? + if [ "$RC" -eq 0 ] || [ "$SC" -eq 0 ]; then # 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=$? else @@ -6364,7 +6386,7 @@ wancheck() if [ "$WAN0PING" = "[FAILOVER]" ] then echo -en "${InvGreen} ${InvDkGray}${CWhite} WAN0${CClear} | $wan0status | " - printf "%-6s" "$WAN0IFNAME" + printf "%-6s" "${WAN0IFNAME:0:6}" if [ "$bwdisp" = "1" ]; then echo -e " | $wan0health | Failover | $WAN0IP | $WAN0PING | $WAN0RX1 | $WAN0TX1 | $WAN0CITY: $uptimeStr" else @@ -6485,7 +6507,7 @@ wancheck() if [ "$WAN1PING" = "[FAILOVER]" ] then echo -en "${InvGreen} ${InvDkGray}${CWhite} WAN1${CClear} | $wan1status | " - printf "%-6s" "$WAN1IFNAME" + printf "%-6s" "${WAN1IFNAME:0:6}" if [ "$bwdisp" = "1" ]; then echo -e " | $wan1health | Failover | $WAN1IP | $WAN1PING | $WAN1RX1 | $WAN1TX1 | $WAN1CITY: $uptimeStr" else From 679df8654e2f1ab77ac531ed570bc08f988b8e9c Mon Sep 17 00:00:00 2001 From: ViktorJp <97465574+ViktorJp@users.noreply.github.com> Date: Mon, 12 Jan 2026 20:43:22 -0500 Subject: [PATCH 35/40] Update changelog for version 1.8.3b6 Updated changelog for version 1.8.3b6 with new patches and improvements. --- changelog.txt | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/changelog.txt b/changelog.txt index b60b468..f9ca2b7 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,4 +1,4 @@ -v1.8.3b4 - (TBA) +v1.8.3b6 - (TBA) - PATCH: The Recovery Timeout should be defaulting to 1x, but it was inadvertently set to 3x. Thank you to @Tarek Yag for reporting this. Fixed! - PATCH: Changed the wording for the custom PING host to "Custom PING host for connectivity checks" @@ -33,6 +33,12 @@ v1.8.3b4 - (TBA) will fail pretty quickly, while the curl test could hang in there for quite some time before indicating a fail. This should help resolve some of the sluggishness you would see if any of your tunnels are misbehaving. + - PATCH: Built in the capability to now use redundant Pinghosts under the configuration menu, using + option #2 "Custom Ping Hosts for Connectivity Checks". By default, Pinghost 1 uses 8.8.8.8 and + Pinghost 2 uses 1.1.1.1. Pinging these hosts through the VPN/WG tunnel is used to determine if the + tunnel is healthy. This now also provides some redundancy, should Pinghost 1 not respond, but + Pinghost 2 does, then the tunnel will not get reset, and should help with those dealing with more + frequent resets. v1.8.2 - (November 23, 2025) - PATCH: Thanks to @JTnola for sharing a "[: bad number" bug he was experiencing. This hard-to-find From 6d10576304d6969e63544330b9d57fd5da5057d9 Mon Sep 17 00:00:00 2001 From: ViktorJp <97465574+ViktorJp@users.noreply.github.com> Date: Tue, 13 Jan 2026 21:06:16 -0500 Subject: [PATCH 36/40] Update vpnmon-r3.sh --- vpnmon-r3.sh | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/vpnmon-r3.sh b/vpnmon-r3.sh index f961359..f05ae31 100644 --- a/vpnmon-r3.sh +++ b/vpnmon-r3.sh @@ -5982,12 +5982,14 @@ checkvpn() ping -I $TUN -q -c 1 -W 2 $PINGHOST2 > /dev/null 2>&1 # Then try pings to Secondary PING Host SC=$? if [ "$RC" -eq 0 ] || [ "$SC" -eq 0 ]; then # Grab the public IP of the VPN Connection # + COMBOPING=0 ICANHAZIP="$(curl --silent --retry 3 --retry-delay 2 --retry-all-errors --fail --interface "$TUN" --request GET --url https://ipv4.icanhazip.com)" IC=$? else + COMBOPING=1 IC=2 fi - if [ "$RC" -eq 0 ] && [ "$IC" -eq 0 ]; then # If both ping/curl come back successful, then proceed + if [ "$COMBOPING" -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 @@ -6055,12 +6057,14 @@ checkwg() ping -I $TUN -q -c 1 -W 2 $PINGHOST2 > /dev/null 2>&1 # Then try pings to Secondary PING Host SC=$? if [ "$RC" -eq 0 ] || [ "$SC" -eq 0 ]; then # Grab the public IP of the VPN Connection # + COMBOPING=0 ICANHAZIP="$(curl --silent --retry 3 --retry-delay 2 --retry-all-errors --fail --interface "$TUN" --request GET --url https://ipv4.icanhazip.com)" IC=$? else + COMBOPING=1 IC=2 fi - if [ "$RC" -eq 0 ] && [ "$IC" -eq 0 ]; then # If both ping/curl come back successful, then proceed + if [ "$COMBOPING" -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 From 06ea9c9e147f6e893b7a4baa57ac375a9c9d1036 Mon Sep 17 00:00:00 2001 From: ViktorJp <97465574+ViktorJp@users.noreply.github.com> Date: Sat, 17 Jan 2026 09:40:28 -0500 Subject: [PATCH 37/40] Update version number and last modified date --- vpnmon-r3.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/vpnmon-r3.sh b/vpnmon-r3.sh index f05ae31..8947a40 100644 --- a/vpnmon-r3.sh +++ b/vpnmon-r3.sh @@ -1,21 +1,21 @@ #!/bin/sh -# VPNMON-R3 v1.8.3b6 (VPNMON-R3.SH) is an all-in-one script that is optimized to maintain multiple VPN connections and is +# VPNMON-R3 v1.8.3 (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: 2026-Jan-12 +# Last Modified: 2026-Jan-17 ########################################################################################## #Preferred standard router binaries path export PATH="/sbin:/bin:/usr/sbin:/usr/bin:$PATH" #Static Variables - please do not change -version="1.8.3b6" # Version tracker -beta=1 # Beta switch +version="1.8.3" # 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 From e5baa64cfaec86d3f551ce56f085ce8212c0b7ad Mon Sep 17 00:00:00 2001 From: ViktorJp <97465574+ViktorJp@users.noreply.github.com> Date: Sat, 17 Jan 2026 09:41:02 -0500 Subject: [PATCH 38/40] Revise changelog for version 1.8.3 Updated version number and date in changelog. --- changelog.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/changelog.txt b/changelog.txt index f9ca2b7..de1448e 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,4 +1,4 @@ -v1.8.3b6 - (TBA) +v1.8.3 - (January 17, 2026) - PATCH: The Recovery Timeout should be defaulting to 1x, but it was inadvertently set to 3x. Thank you to @Tarek Yag for reporting this. Fixed! - PATCH: Changed the wording for the custom PING host to "Custom PING host for connectivity checks" From 51d9a9001ecf4774383da60cf4d311efdc4ea5a7 Mon Sep 17 00:00:00 2001 From: ViktorJp <97465574+ViktorJp@users.noreply.github.com> Date: Sat, 17 Jan 2026 09:41:26 -0500 Subject: [PATCH 39/40] Update version and last updated date in README --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index f5f30c1..7b93072 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ -# VPNMON-R3 v1.8.3b3 +# VPNMON-R3 v1.8.3 Asus-Merlin OpenVPN/Wireguard Monitor R3 -Updated on 2025-Dec-27 +Updated on 2026-Jan-17 --- From 1c98501ed269403f53faa08a78f9f1a95cb84a36 Mon Sep 17 00:00:00 2001 From: ViktorJp <97465574+ViktorJp@users.noreply.github.com> Date: Sat, 17 Jan 2026 09:58:49 -0500 Subject: [PATCH 40/40] Update enhancements.txt --- enhancements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/enhancements.txt b/enhancements.txt index 423d16f..a260e35 100644 --- a/enhancements.txt +++ b/enhancements.txt @@ -1,8 +1,8 @@ To-Do: - If the WAN doesn't respond after X minutes, issue a router reboot? -- configurable timeouts for wan detection and resets @scootertramp Done: +- configurable timeouts for wan detection and resets @scootertramp - Find a way to remember past bandwidth stats so that it doesn't revert to [UNKN] as often. - use recovery timeouts for wan @scootertramp - timezone details @Tarek Yag/EmeraldDeer