Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# VPNMON-R3 v1.9.3
# VPNMON-R3 v1.9.4
Asus-Merlin OpenVPN/Wireguard Monitor R3

Updated on 2026-Apr-15
Updated on 2026-May-02

---

Expand Down
File renamed without changes.
10 changes: 9 additions & 1 deletion changelog.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,12 @@
v1.9.3 - (April 15, 2025)
v1.9.4 - (May 2, 2026)
- PATCH: Found that if the VPN/WG host is used as a hostname in NVRAM, that the double-hop
VPN will incorrectly display 9.9.9.9 (or whatever your WAN DNS is configured as), instead
of the VPN/WG endpoint IP address. This was also causing a failure when running a double-
hop VPN diagnostic, and would fail because it wasn't able to determine a subnet when using
this hostname instead of an IP. The script is now forcing an nslookup on the hostname if
it's not already an IP to ensure this info is displayed and processed correctly.

v1.9.3 - (April 15, 2026)
- MINOR: Based on some feedback from @JTnola, questioning my infallible code, he noted that
the SSL handshake test was failing in RTRMON on his router. Looking into this deeper, and
thanks to the keen eyes of @dave14305 and @ColinTaylor, they determined that the SSL hand-
Expand Down
2 changes: 1 addition & 1 deletion enhancements.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
To-Do:
- If the WAN doesn't respond after X minutes, issue a router reboot?
- ...

Done:
- Double-Hop VPN capabilities
Expand Down
2 changes: 1 addition & 1 deletion version.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1.9.3
1.9.4
10,853 changes: 10,853 additions & 0 deletions vpnmon-r3-v1.9.3.sh

Large diffs are not rendered by default.

56 changes: 35 additions & 21 deletions vpnmon-r3.sh
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
#!/bin/sh

# VPNMON-R3 v1.9.3 (VPNMON-R3.SH) is an all-in-one script that is optimized to maintain multiple VPN connections and is
# VPNMON-R3 v1.9.4 (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-Mar-15
#
# Last Modified: 2026-May-02
##########################################################################################

#Preferred standard router binaries path
Expand All @@ -21,7 +22,7 @@ unset LD_LIBRARY_PATH
export SCREENDIR="${HOME}/.screen"

#Static Variables - please do not change
version="1.9.3" # Version tracker
version="1.9.4" # 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
Expand Down Expand Up @@ -894,8 +895,33 @@ dvpn_get_wan()
}

# -------------------------------------------------------------------------------------------------------------------------
# dvpn_get_endpoint - return current endpoint IP for a tunnel from NVRAM
# WireGuard: wgcN_ep_addr (IP:port - strip port)
# dvpn_resolve_host - resolve a hostname to an IPv4 address.

dvpn_resolve_host()
{
local h="$1" ip

if ! echo "$h" | grep -qE '[a-zA-Z]'; then
echo "$h"; return
fi

ip=$(nslookup "$h" 2>/dev/null | awk '
/^Server:/ { match($0,/[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+/); s=substr($0,RSTART,RLENGTH) }
/^Address/ { match($0,/[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+/); v=substr($0,RSTART,RLENGTH)
if (v != "" && v != s) { print v; exit } }
')

# Fallback: ping resolves the hostname and prints it in parens on the first line
if [ -z "$ip" ]; then
ip=$(ping -c1 -w2 "$h" 2>/dev/null | sed -n '1s/.*(\([0-9.]*\)).*/\1/p')
fi

[ -n "$ip" ] && echo "$ip" || echo "$h"
}

# -------------------------------------------------------------------------------------------------------------------------
# dvpn_get_endpoint - return current endpoint IP for a tunnel from NVRAM.
# WireGuard: wgcN_ep_addr (IP:port or hostname:port - strip port, resolve if hostname)
# OpenVPN: vpn_clientN_addr (hostname or IP - resolve if hostname)

dvpn_get_endpoint()
Expand All @@ -905,16 +931,10 @@ dvpn_get_endpoint()

if [ "$type" = "wg" ]; then
raw=$(nvram get "wgc${slot}_ep_addr" 2>/dev/null)
ep=$(echo "$raw" | cut -d: -f1)
ep=$(dvpn_resolve_host "$(echo "$raw" | cut -d: -f1)")
else
raw=$(nvram get "vpn_client${slot}_addr" 2>/dev/null)
if echo "$raw" | grep -qE '[a-zA-Z]'; then
# Hostname - resolve to IP
ep=$(nslookup "$raw" 2>/dev/null | awk '/^Address/ && !/#/ {print $3; exit}')
[ -z "$ep" ] && ep="$raw"
else
ep="$raw"
fi
ep=$(dvpn_resolve_host "$raw")
fi
echo "$ep"
}
Expand Down Expand Up @@ -2828,10 +2848,7 @@ echo -e " ${CDkGray}T2 endpoint must be pinned through T1 (${DVPN_TUNNEL1_IF}),
echo ""

# T1 endpoint -> WAN
T1_EP=$(nvram get "wgc${DVPN_TUNNEL1_SLOT}_ep_addr" 2>/dev/null | cut -d: -f1)
if [ "$DVPN_TUNNEL1_TYPE" = "ovpn" ]; then
T1_EP=$(nvram get "vpn_client${DVPN_TUNNEL1_SLOT}_addr" 2>/dev/null)
fi
T1_EP=$(dvpn_get_endpoint "$DVPN_TUNNEL1_TYPE" "$DVPN_TUNNEL1_SLOT")

if [ -z "$T1_EP" ]; then
warn "Cannot determine T1 endpoint from NVRAM"
Expand All @@ -2855,10 +2872,7 @@ fi
echo ""

# T2 endpoint -> via T1 interface
T2_EP=$(nvram get "wgc${DVPN_TUNNEL2_SLOT}_ep_addr" 2>/dev/null | cut -d: -f1)
if [ "$DVPN_TUNNEL2_TYPE" = "ovpn" ]; then
T2_EP=$(nvram get "vpn_client${DVPN_TUNNEL2_SLOT}_addr" 2>/dev/null)
fi
T2_EP=$(dvpn_get_endpoint "$DVPN_TUNNEL2_TYPE" "$DVPN_TUNNEL2_SLOT")

if [ -z "$T2_EP" ]; then
warn "Cannot determine T2 endpoint from NVRAM"
Expand Down