Autarch/modules/wireguard_manager.py
DigiJ ffe47c51b5 Initial public release — AUTARCH v1.0.0
Full security platform with web dashboard, 16 Flask blueprints, 26 modules,
autonomous AI agent, WebUSB hardware support, and Archon Android companion app.

Includes Hash Toolkit, debug console, anti-stalkerware shield, Metasploit/RouterSploit
integration, WireGuard VPN, OSINT reconnaissance, and multi-backend LLM support.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 03:57:32 -08:00

504 lines
19 KiB
Python

"""
WireGuard VPN Manager - Server management, client CRUD, remote ADB
Manage WireGuard VPN server, clients, and remote ADB connections over VPN tunnel.
"""
DESCRIPTION = "WireGuard VPN + Remote ADB manager"
AUTHOR = "AUTARCH"
VERSION = "1.0"
CATEGORY = "defense"
class WireGuardVPN:
"""Interactive WireGuard VPN menu."""
def __init__(self):
from core.wireguard import get_wireguard_manager
self.mgr = get_wireguard_manager()
def show_menu(self):
status = self.mgr.get_server_status()
running = status.get('running', False)
endpoint = status.get('endpoint', 'N/A')
clients = self.mgr.get_all_clients()
peer_status = self.mgr.get_peer_status() if running else {}
# Count online peers
online = 0
for c in clients:
ps = peer_status.get(c.get('public_key', ''), {})
hs = ps.get('latest_handshake')
if hs is not None and hs < 180:
online += 1
print(f"\n{'='*55}")
print(" WireGuard VPN Manager")
print(f"{'='*55}")
print(f" Interface: {status.get('interface', 'wg0')} | "
f"Status: {'Running' if running else 'Stopped'}")
print(f" Endpoint: {endpoint}")
print(f" Clients: {len(clients)} ({online} online)")
print()
print(" -- Server --")
print(" 1) Server Status")
print(" 2) Start Interface")
print(" 3) Stop Interface")
print(" 4) Restart Interface")
print()
print(" -- Clients --")
print(" 10) List All Clients")
print(" 11) Create New Client")
print(" 12) View Client Detail")
print(" 13) Delete Client")
print(" 14) Enable/Disable Client")
print(" 15) Import Existing Peers")
print()
print(" -- Remote ADB --")
print(" 20) ADB Connect (TCP/IP)")
print(" 21) ADB Disconnect")
print(" 22) Auto-Connect All Peers")
print(" 23) List Remote ADB Devices")
print()
print(" -- USB/IP --")
print(" 30) USB/IP Status")
print(" 31) Load USB/IP Modules")
print(" 32) List Remote USB Devices")
print(" 33) Attach USB Device")
print(" 34) Detach USB Device")
print(" 35) List Attached Ports")
print()
print(" -- Config --")
print(" 40) Generate Client Config")
print(" 41) Show QR Code (terminal)")
print(" 42) Refresh UPnP Mapping")
print()
print(" 0) Back")
print()
# ── Helpers ─────────────────────────────────────────────────────
def _pick_client(self, prompt=" Select client #: "):
"""Select a client from the list."""
clients = self.mgr.get_all_clients()
if not clients:
print(" No clients configured.")
return None
print("\n Clients:")
for i, c in enumerate(clients, 1):
status = "ON " if c.get('enabled', True) else "OFF"
print(f" {i}) [{status}] {c['name']} ({c['assigned_ip']})")
try:
choice = int(input(prompt).strip())
if 1 <= choice <= len(clients):
return clients[choice - 1]
except (ValueError, EOFError, KeyboardInterrupt):
pass
return None
def _pick_client_ip(self, prompt=" Client IP (or # to select): "):
"""Get a client IP either directly or by selection."""
try:
val = input(prompt).strip()
except (EOFError, KeyboardInterrupt):
return None
if not val:
return None
# If numeric, treat as selection
if val.isdigit():
clients = self.mgr.get_all_clients()
idx = int(val) - 1
if 0 <= idx < len(clients):
return clients[idx]['assigned_ip']
print(" Invalid selection.")
return None
return val
# ── Server ─────────────────────────────────────────────────────
def do_server_status(self):
status = self.mgr.get_server_status()
print(f"\n Server Status:")
print(f" Interface: {status.get('interface', 'wg0')}")
print(f" Running: {status.get('running', False)}")
print(f" Public Key: {status.get('public_key', 'N/A')}")
print(f" Endpoint: {status.get('endpoint', 'N/A')}")
print(f" Listen Port: {status.get('listen_port', 'N/A')}")
print(f" Peers: {status.get('peer_count', 0)}")
if status.get('error'):
print(f" Error: {status['error']}")
def do_start(self):
print(" Starting WireGuard interface...")
result = self.mgr.start_interface()
if result.get('ok'):
print(f" {result['message']}")
else:
print(f" Error: {result.get('error', 'Failed')}")
def do_stop(self):
print(" Stopping WireGuard interface...")
result = self.mgr.stop_interface()
if result.get('ok'):
print(f" {result['message']}")
else:
print(f" Error: {result.get('error', 'Failed')}")
def do_restart(self):
print(" Restarting WireGuard interface...")
result = self.mgr.restart_interface()
if result.get('ok'):
print(f" {result['message']}")
else:
print(f" Error: {result.get('error', 'Failed')}")
# ── Clients ────────────────────────────────────────────────────
def do_list_clients(self):
clients = self.mgr.get_all_clients()
peer_status = self.mgr.get_peer_status()
if not clients:
print("\n No clients configured.")
return
print(f"\n {'Name':<20} {'IP':<16} {'Status':<8} {'Handshake':<20} {'RX/TX'}")
print(f" {'-'*80}")
for c in clients:
ps = peer_status.get(c.get('public_key', ''), {})
hs = ps.get('latest_handshake')
hs_str = ps.get('latest_handshake_str', 'never')
if hs is not None and hs < 180:
status = 'ONLINE'
elif hs is not None:
status = 'idle'
else:
status = 'offline'
if not c.get('enabled', True):
status = 'disabled'
rx = ps.get('transfer_rx_str', '-')
tx = ps.get('transfer_tx_str', '-')
print(f" {c['name']:<20} {c['assigned_ip']:<16} {status:<8} "
f"{hs_str:<20} {rx}/{tx}")
def do_create_client(self):
try:
name = input(" Client name: ").strip()
except (EOFError, KeyboardInterrupt):
return
if not name:
print(" Name required.")
return
try:
dns = input(f" DNS [{self.mgr._default_dns}]: ").strip()
allowed = input(f" Allowed IPs [{self.mgr._default_allowed_ips}]: ").strip()
except (EOFError, KeyboardInterrupt):
return
print(f" Creating client '{name}'...")
result = self.mgr.create_client(
name,
dns=dns or None,
allowed_ips=allowed or None)
if result.get('ok'):
client = result['client']
print(f" Created: {client['name']} ({client['assigned_ip']})")
print(f" ID: {client['id']}")
else:
print(f" Error: {result.get('error', 'Failed')}")
def do_view_client(self):
client = self._pick_client()
if not client:
return
print(f"\n Client: {client['name']}")
print(f" ID: {client['id']}")
print(f" IP: {client['assigned_ip']}")
print(f" Public Key: {client['public_key']}")
print(f" PSK: {'Yes' if client.get('preshared_key') else 'No'}")
print(f" DNS: {client.get('dns', 'default')}")
print(f" Allowed IPs: {client.get('allowed_ips', 'default')}")
print(f" Enabled: {client.get('enabled', True)}")
print(f" Created: {client.get('created_at', 'N/A')}")
# Show live status
peer_status = self.mgr.get_peer_status()
ps = peer_status.get(client['public_key'], {})
if ps:
print(f" Handshake: {ps.get('latest_handshake_str', 'never')}")
print(f" Endpoint: {ps.get('endpoint', 'N/A')}")
print(f" RX: {ps.get('transfer_rx_str', '-')}")
print(f" TX: {ps.get('transfer_tx_str', '-')}")
def do_delete_client(self):
client = self._pick_client()
if not client:
return
try:
confirm = input(f" Delete '{client['name']}'? (y/N): ").strip().lower()
except (EOFError, KeyboardInterrupt):
return
if confirm != 'y':
print(" Cancelled.")
return
result = self.mgr.delete_client(client['id'])
if result.get('ok'):
print(f" {result['message']}")
else:
print(f" Error: {result.get('error', 'Failed')}")
def do_toggle_client(self):
client = self._pick_client()
if not client:
return
current = client.get('enabled', True)
new_state = not current
action = 'Enable' if new_state else 'Disable'
try:
confirm = input(f" {action} '{client['name']}'? (y/N): ").strip().lower()
except (EOFError, KeyboardInterrupt):
return
if confirm != 'y':
print(" Cancelled.")
return
result = self.mgr.toggle_client(client['id'], new_state)
if result.get('ok'):
print(f" {result['message']}")
else:
print(f" Error: {result.get('error', 'Failed')}")
def do_import_peers(self):
print(" Importing existing peers from wg0.conf...")
result = self.mgr.import_existing_peers()
if result.get('ok'):
print(f" Imported {result['imported']} peers.")
else:
print(f" Error: {result.get('error', 'Failed')}")
# ── Remote ADB ─────────────────────────────────────────────────
def do_adb_connect(self):
clients = self.mgr.get_all_clients()
if clients:
print("\n Available clients:")
for i, c in enumerate(clients, 1):
print(f" {i}) {c['name']} ({c['assigned_ip']})")
ip = self._pick_client_ip()
if not ip:
return
print(f" Connecting to {ip}:5555...")
result = self.mgr.adb_connect(ip)
if result.get('ok'):
print(f" {result['message']}")
else:
print(f" Error: {result.get('error', 'Failed')}")
def do_adb_disconnect(self):
ip = self._pick_client_ip(" Client IP to disconnect: ")
if not ip:
return
result = self.mgr.adb_disconnect(ip)
print(f" {result.get('message', 'Done')}")
def do_auto_connect(self):
print(" Auto-connecting to all active WG peers...")
result = self.mgr.auto_connect_peers()
for r in result.get('results', []):
status = "OK" if r['result'].get('ok') else "FAIL"
print(f" [{status}] {r['name']} ({r['ip']}): "
f"{r['result'].get('message', r['result'].get('error', ''))}")
if not result.get('results'):
print(" No active peers found.")
def do_list_adb_devices(self):
devices = self.mgr.get_adb_remote_devices()
if not devices:
print("\n No remote ADB devices connected via WireGuard.")
return
print(f"\n Remote ADB Devices:")
for d in devices:
print(f" {d['serial']} - {d['state']} "
f"{'(' + d['model'] + ')' if d.get('model') else ''}")
# ── USB/IP ─────────────────────────────────────────────────────
def do_usbip_status(self):
status = self.mgr.get_usbip_status()
print(f"\n USB/IP Status:")
print(f" Available: {status['available']}")
print(f" Modules loaded: {status['modules_loaded']}")
print(f" Active imports: {status['active_imports']}")
if status.get('ports'):
for p in status['ports']:
print(f" Port {p['port']}: {p['status']}")
def do_load_modules(self):
result = self.mgr.load_usbip_modules()
if result.get('ok'):
print(f" {result['message']}")
else:
print(f" Error: {result.get('error', 'Failed')}")
def do_list_remote_usb(self):
ip = self._pick_client_ip()
if not ip:
return
print(f" Listing USB devices on {ip}...")
result = self.mgr.usbip_list_remote(ip)
if not result.get('ok'):
print(f" Error: {result.get('error', 'Failed')}")
return
devices = result.get('devices', [])
if not devices:
print(" No exportable USB devices found.")
return
for d in devices:
print(f" [{d['busid']}] {d['description']}")
def do_attach_usb(self):
ip = self._pick_client_ip(" Remote host IP: ")
if not ip:
return
# List devices first
result = self.mgr.usbip_list_remote(ip)
devices = result.get('devices', [])
if not devices:
print(" No exportable devices found.")
return
print("\n Available devices:")
for i, d in enumerate(devices, 1):
print(f" {i}) [{d['busid']}] {d['description']}")
try:
choice = input(" Attach #: ").strip()
except (EOFError, KeyboardInterrupt):
return
if choice.isdigit():
idx = int(choice) - 1
if 0 <= idx < len(devices):
busid = devices[idx]['busid']
else:
print(" Invalid selection.")
return
else:
busid = choice
print(f" Attaching {busid} from {ip}...")
result = self.mgr.usbip_attach(ip, busid)
if result.get('ok'):
print(f" {result['message']}")
else:
print(f" Error: {result.get('error', 'Failed')}")
def do_detach_usb(self):
# Show current ports
ports = self.mgr.usbip_port_status()
if not ports.get('ports'):
print(" No attached USB/IP devices.")
return
print("\n Attached ports:")
for p in ports['ports']:
print(f" Port {p['port']}: {p['status']}")
try:
port = input(" Detach port #: ").strip()
except (EOFError, KeyboardInterrupt):
return
if not port:
return
result = self.mgr.usbip_detach(port)
if result.get('ok'):
print(f" {result['message']}")
else:
print(f" Error: {result.get('error', 'Failed')}")
def do_list_ports(self):
result = self.mgr.usbip_port_status()
if not result.get('ok'):
print(f" Error: {result.get('error', 'Failed')}")
return
ports = result.get('ports', [])
if not ports:
print(" No attached USB/IP ports.")
return
for p in ports:
detail = f" - {p['detail']}" if p.get('detail') else ''
print(f" Port {p['port']}: {p['status']}{detail}")
# ── Config ─────────────────────────────────────────────────────
def do_gen_config(self):
client = self._pick_client()
if not client:
return
config = self.mgr.generate_client_config(client)
print(f"\n Config for {client['name']}:\n")
print(f" {''*40}")
for line in config.split('\n'):
print(f" {line}")
print(f" {''*40}")
def do_show_qr(self):
client = self._pick_client()
if not client:
return
config = self.mgr.generate_client_config(client)
try:
import qrcode
qr = qrcode.QRCode(box_size=1, border=1)
qr.add_data(config)
qr.make(fit=True)
qr.print_ascii(invert=True)
except ImportError:
print(" qrcode module not installed. Install: pip install qrcode")
def do_refresh_upnp(self):
print(" Refreshing UPnP mapping for WireGuard port...")
result = self.mgr.refresh_upnp_mapping()
if result.get('ok'):
print(f" UPnP mapping refreshed.")
else:
print(f" Error: {result.get('error', 'Failed')}")
# ── Main Loop ──────────────────────────────────────────────────
def run_interactive(self):
while True:
self.show_menu()
try:
choice = input(" Select > ").strip()
except (EOFError, KeyboardInterrupt):
break
if choice == '0':
break
actions = {
'1': self.do_server_status,
'2': self.do_start,
'3': self.do_stop,
'4': self.do_restart,
'10': self.do_list_clients,
'11': self.do_create_client,
'12': self.do_view_client,
'13': self.do_delete_client,
'14': self.do_toggle_client,
'15': self.do_import_peers,
'20': self.do_adb_connect,
'21': self.do_adb_disconnect,
'22': self.do_auto_connect,
'23': self.do_list_adb_devices,
'30': self.do_usbip_status,
'31': self.do_load_modules,
'32': self.do_list_remote_usb,
'33': self.do_attach_usb,
'34': self.do_detach_usb,
'35': self.do_list_ports,
'40': self.do_gen_config,
'41': self.do_show_qr,
'42': self.do_refresh_upnp,
}
action = actions.get(choice)
if action:
action()
else:
print(" Invalid choice.")
def run():
wg = WireGuardVPN()
wg.run_interactive()