Commit 782133ea authored by Vitaly Lipatov's avatar Vitaly Lipatov

router: add check-vpn-status.sh for Telegraf VPN monitoring

Auto-detects VPN type and reports status to InfluxDB via Telegraf exec: - IKEv2/strongSwan: swanctl or ipsec* interface + RX bytes - OpenVPN: process + tun0 interface - GRE: gre1 interface + RX bytes changing - OpenConnect: process + vpns/tun interface - Xray: process + SOCKS port listening - AmneziaWG/WireGuard: interface + recent handshake Deployed to all 11 egw/ogw containers with Telegraf integration. Co-Authored-By: 's avatarClaude Opus 4.6 <noreply@anthropic.com>
parent 8b67dd8c
#!/bin/sh
# Check VPN tunnel status for Telegraf exec plugin.
# Outputs InfluxDB line protocol: vpn_status type="...",connected=0/1i
#
# Auto-detects VPN type by running processes/interfaces:
# strongSwan (IKEv2) — swanctl --list-sas → ESTABLISHED
# OpenVPN — process alive + tun interface UP
# GRE — gre1 interface UP + RX bytes increasing
# OpenConnect — process alive + vpns/tun interface UP
# AmneziaWG/WireGuard — awg0/wg0 interface UP + recent handshake
# Xray — process alive + listening on SOCKS port
#
# Install: copy to /usr/local/bin/check-vpn-status.sh
# Telegraf config (add to existing telegraf.conf):
# [[inputs.exec]]
# commands = ["/usr/local/bin/check-vpn-status.sh"]
# interval = "30s"
# timeout = "10s"
# data_format = "influx"
set -e
PATH="/sbin:/usr/sbin:/bin:/usr/bin:$PATH"
STATE_DIR="/var/tmp/vpn-status"
mkdir -p "$STATE_DIR" 2>/dev/null
# --- strongSwan (IKEv2/IPsec) ---
if pgrep -x charon-systemd >/dev/null 2>&1 || pgrep -x charon >/dev/null 2>&1; then
# Try swanctl first (needs vici socket access)
established=$(swanctl --list-sas 2>/dev/null | grep -c ESTABLISHED || true)
if [ "$established" -gt 0 ] 2>/dev/null; then
echo 'vpn_status type="ikev2",connected=1i'
exit 0
fi
# Fallback: check any ipsec* interface UP + RX bytes changing
ipsec_iface=$(ip -o link show 2>/dev/null | grep 'ipsec[0-9]' | grep UP | awk -F'[ :@]+' '{print $2}' | head -1)
if [ -n "$ipsec_iface" ]; then
rx=$(cat "/sys/class/net/$ipsec_iface/statistics/rx_bytes" 2>/dev/null || echo 0)
state_file="$STATE_DIR/${ipsec_iface}_rx_prev"
prev_rx=$(cat "$state_file" 2>/dev/null || echo 0)
echo "$rx" > "$state_file"
if [ "$rx" != "$prev_rx" ] && [ "$prev_rx" != "0" ]; then
echo 'vpn_status type="ikev2",connected=1i'
elif [ "$prev_rx" = "0" ]; then
echo 'vpn_status type="ikev2",connected=1i'
else
echo 'vpn_status type="ikev2",connected=0i'
fi
else
echo 'vpn_status type="ikev2",connected=0i'
fi
exit 0
fi
# --- OpenVPN ---
if pgrep -x openvpn >/dev/null 2>&1; then
if ip -o link show tun0 2>/dev/null | grep -q UP; then
echo 'vpn_status type="openvpn",connected=1i'
else
echo 'vpn_status type="openvpn",connected=0i'
fi
exit 0
fi
# --- OpenConnect ---
if pgrep -x openconnect >/dev/null 2>&1; then
# openconnect uses vpns or tun0
if ip -o link show vpns 2>/dev/null | grep -q UP || ip -o link show tun0 2>/dev/null | grep -q UP; then
echo 'vpn_status type="openconnect",connected=1i'
else
echo 'vpn_status type="openconnect",connected=0i'
fi
exit 0
fi
# --- AmneziaWG / WireGuard ---
for iface in awg0 wg0; do
if ip link show "$iface" >/dev/null 2>&1; then
# Check last handshake (within 3 minutes = 180s)
last_hs=$(wg show "$iface" latest-handshakes 2>/dev/null | awk '{print $2}' | head -1)
if [ -n "$last_hs" ] && [ "$last_hs" -gt 0 ] 2>/dev/null; then
age=$(( $(date +%s) - last_hs ))
if [ "$age" -lt 180 ]; then
echo "vpn_status type=\"wireguard\",iface=\"$iface\",connected=1i"
else
echo "vpn_status type=\"wireguard\",iface=\"$iface\",connected=0i"
fi
else
echo "vpn_status type=\"wireguard\",iface=\"$iface\",connected=0i"
fi
exit 0
fi
done
# --- Xray (SOCKS proxy) ---
if pgrep -x xray >/dev/null 2>&1; then
# Check listening port — ss -tln works without privileges
if ss -tln 2>/dev/null | grep -q ':1080 '; then
echo 'vpn_status type="xray",connected=1i'
else
echo 'vpn_status type="xray",connected=0i'
fi
exit 0
fi
# --- GRE ---
if ip link show gre1 >/dev/null 2>&1; then
if ip -o link show gre1 2>/dev/null | grep -q UP; then
# GRE is stateless; check RX bytes are changing via state file
rx=$(cat /sys/class/net/gre1/statistics/rx_bytes 2>/dev/null || echo 0)
state_file="$STATE_DIR/gre1_rx_prev"
prev_rx=$(cat "$state_file" 2>/dev/null || echo 0)
echo "$rx" > "$state_file"
if [ "$rx" != "$prev_rx" ] && [ "$prev_rx" != "0" ]; then
echo 'vpn_status type="gre",connected=1i'
elif [ "$prev_rx" = "0" ]; then
# First run, assume OK if link is UP
echo 'vpn_status type="gre",connected=1i'
else
echo 'vpn_status type="gre",connected=0i'
fi
else
echo 'vpn_status type="gre",connected=0i'
fi
exit 0
fi
# --- No VPN detected ---
echo 'vpn_status type="none",connected=0i'
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment