""" WireGuard Tunnel Monitor Checks VPN tunnel between Nave (10.0.0.2) and VPS (10.0.0.1). Uses: TCP socket test to verify connectivity (no ping/raw socket needed) """ import socket import time from typing import Dict class TunnelMonitor: """Monitor WireGuard tunnel health""" VPS_TUNNEL_IP = '10.0.0.1' # From vault/config.txt VPS_SSH_PORT = 22 # SSH port for connectivity test def check(self) -> Dict: """ Check tunnel connectivity using TCP socket test. Tests: 1. TCP connection to VPS SSH port (10.0.0.1:22) 2. Measure connection time (proxy for latency) 3. Multiple attempts for reliability Returns: { 'status': 'healthy' | 'warning' | 'critical', 'connected': True/False, 'latency_ms': X, 'packet_loss': 0, 'message': '...' } """ try: # Perform 3 connection attempts attempts = 3 successful = 0 total_time = 0 for i in range(attempts): try: start = time.time() sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.settimeout(2) # 2 second timeout sock.connect((self.VPS_TUNNEL_IP, self.VPS_SSH_PORT)) elapsed = (time.time() - start) * 1000 # Convert to ms sock.close() successful += 1 total_time += elapsed except (socket.timeout, ConnectionRefusedError, OSError): pass if successful == 0: return { 'status': 'critical', 'connected': False, 'latency_ms': 0, 'packet_loss': 100, 'message': 'Tunnel down - VPS unreachable' } # Calculate average latency and packet loss avg_latency = total_time / successful packet_loss = ((attempts - successful) / attempts) * 100 # Determine status if packet_loss == 0 and avg_latency < 200: status = 'healthy' elif packet_loss <= 33 and avg_latency < 500: status = 'warning' else: status = 'critical' return { 'status': status, 'connected': True, 'latency_ms': round(avg_latency, 1), 'packet_loss': packet_loss, 'message': f"Connected ({int(avg_latency)}ms, {packet_loss:.0f}% loss)" } except Exception as e: return { 'status': 'critical', 'connected': False, 'error': str(e), 'message': f'Tunnel check failed: {e}' }