mvpg/scripts/security-monitor.sh

259 lines
7.2 KiB
Bash
Raw Normal View History

2025-08-10 15:34:34 +02:00
#############################################################
# scripts/security-monitor.sh #
#############################################################
cat > scripts/security-monitor.sh << 'EOFSECMON'
#!/bin/bash
# VPN Security Monitor
# Continuous monitoring of killswitch and VPN status
# Version: 1.0.0
# Configuration
CHECK_INTERVAL=10 # seconds
ALERT_EMAIL="" # Set email for alerts
LOG_FILE="/var/log/vpn-security-monitor.log"
STATE_FILE="/var/run/vpn-monitor.state"
# Source network config
if [ -f /opt/vpn-gateway/network.conf ]; then
source /opt/vpn-gateway/network.conf
fi
# Logging functions
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" >> "$LOG_FILE"
}
alert() {
local message="$1"
log "ALERT: $message"
# Send email alert if configured
if [ -n "$ALERT_EMAIL" ]; then
echo "$message" | mail -s "VPN Security Alert" "$ALERT_EMAIL" 2>/dev/null || true
fi
# System notification (if available)
if command -v notify-send >/dev/null 2>&1; then
notify-send "VPN Security Alert" "$message" -u critical
fi
# Log to syslog
logger -t "vpn-security" -p auth.crit "$message"
}
# Check functions
check_killswitch() {
# Verify DROP policies are active
local policies_ok=true
for chain in INPUT OUTPUT FORWARD; do
if ! iptables -L $chain -n | grep -q "policy DROP"; then
alert "Killswitch policy missing for chain $chain!"
policies_ok=false
fi
done
if [ "$policies_ok" = false ]; then
log "Reactivating killswitch..."
/usr/local/bin/vpn-killswitch.sh enable
return 1
fi
return 0
}
check_vpn_connection() {
if wg show wg0 >/dev/null 2>&1; then
# VPN interface exists, check if it's actually working
local endpoint=$(wg show wg0 endpoints | awk '{print $2}')
if [ -z "$endpoint" ]; then
log "WARNING: VPN interface exists but no endpoint configured"
return 1
fi
# Check last handshake
local last_handshake=$(wg show wg0 latest-handshakes | awk '{print $2}')
local current_time=$(date +%s)
if [ -n "$last_handshake" ] && [ "$last_handshake" -ne 0 ]; then
local time_diff=$((current_time - last_handshake))
# If last handshake was more than 3 minutes ago, connection might be dead
if [ $time_diff -gt 180 ]; then
log "WARNING: Last WireGuard handshake was ${time_diff} seconds ago"
return 2
fi
fi
return 0
else
return 1
fi
}
check_dns_leaks() {
# Check if DNS is going through VPN
local dns_servers=$(cat /etc/resolv.conf | grep "^nameserver" | awk '{print $2}')
for dns in $dns_servers; do
# Check if DNS server is in private range or VPN provider's DNS
case "$dns" in
10.*|172.16.*|172.17.*|172.18.*|172.19.*|172.2*|172.30.*|172.31.*|192.168.*|100.64.*)
# Private IP, likely VPN DNS
;;
127.*)
# Localhost, check if it's a DNS proxy
if systemctl is-active systemd-resolved >/dev/null 2>&1; then
log "WARNING: systemd-resolved is active, checking for leaks"
# Additional checks for systemd-resolved
fi
;;
*)
alert "Potential DNS leak detected! Public DNS server: $dns"
return 1
;;
esac
done
return 0
}
check_leak_test() {
# Try to reach internet without VPN
local vpn_active=$(check_vpn_connection; echo $?)
if [ $vpn_active -eq 1 ]; then
# VPN not active, internet should be blocked
if ping -c 1 -W 1 8.8.8.8 >/dev/null 2>&1; then
alert "CRITICAL: Internet accessible without VPN! Leak detected!"
# Immediately re-enable killswitch
/usr/local/bin/vpn-killswitch.sh enable
return 1
fi
fi
return 0
}
check_processes() {
# Check for processes that might bypass VPN
local suspicious_processes=$(netstat -tunp 2>/dev/null | grep -v "127.0.0.1\|::1\|$LAN_NET" | grep ESTABLISHED)
if [ -n "$suspicious_processes" ]; then
log "WARNING: Detected network connections that might bypass VPN:"
echo "$suspicious_processes" >> "$LOG_FILE"
fi
}
monitor_bandwidth() {
# Monitor bandwidth to detect unusual activity
if command -v vnstat >/dev/null 2>&1; then
local current_tx=$(vnstat --oneline | cut -d';' -f9)
local current_rx=$(vnstat --oneline | cut -d';' -f10)
if [ -f "$STATE_FILE" ]; then
source "$STATE_FILE"
# Compare with previous values
# Alert if sudden spike in traffic when VPN is down
if ! check_vpn_connection && [ -n "$LAST_TX" ]; then
# Calculate difference
# If significant traffic when VPN is down, alert
log "Bandwidth check: TX=$current_tx RX=$current_rx"
fi
fi
# Save current state
echo "LAST_TX='$current_tx'" > "$STATE_FILE"
echo "LAST_RX='$current_rx'" >> "$STATE_FILE"
fi
}
auto_recovery() {
local vpn_status=$(check_vpn_connection; echo $?)
if [ $vpn_status -eq 2 ]; then
# Connection stale, try to reconnect
log "Attempting auto-recovery of VPN connection..."
# Get last used server from config
if [ -f /etc/wireguard/wg0.conf ]; then
systemctl restart wg-quick@wg0 2>/dev/null || \
wg-quick down wg0 2>/dev/null && wg-quick up wg0 2>/dev/null
sleep 5
if check_vpn_connection; then
log "Auto-recovery successful"
return 0
else
alert "Auto-recovery failed - manual intervention required"
return 1
fi
fi
fi
return 0
}
# Main monitoring loop
main() {
log "VPN Security Monitor started"
log "Check interval: ${CHECK_INTERVAL}s"
# Initial checks
check_killswitch
check_vpn_connection
check_dns_leaks
local error_count=0
while true; do
# Run all checks
local all_ok=true
if ! check_killswitch; then
all_ok=false
((error_count++))
fi
if ! check_leak_test; then
all_ok=false
((error_count++))
fi
if ! check_dns_leaks; then
all_ok=false
((error_count++))
fi
check_processes
monitor_bandwidth
# Auto-recovery if needed
if [ $error_count -gt 3 ]; then
auto_recovery
error_count=0
fi
# Status indicator
if [ "$all_ok" = true ]; then
echo -n "."
error_count=0
else
echo -n "!"
fi
sleep "$CHECK_INTERVAL"
done
}
# Signal handlers
trap 'log "Security monitor stopped"; exit 0' SIGTERM SIGINT
# Run main loop
main