Phase 5: extended connectivity — WireGuard ext, OpenVPN, Tor exit routing
- ConnectivityManager: per-peer exit routing via iptables fwmark/policy tables (wg_ext=0x10/t110, openvpn=0x20/t120, tor=0x30/t130) - Dedicated PIC_CONNECTIVITY chains (mangle+nat), kill-switch FORWARD DROP - Config upload with sanitization: strips PostUp/PostDown and OVpn script dirs - Peer exit_via field added to peer registry (backward-compat, default=default) - 7 Flask routes at /api/connectivity/* - Connectivity.jsx: 693-line frontend with exit cards, peer assignment table - 72 new tests for ConnectivityManager (72 passing) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -40,6 +40,9 @@ class ConfigManager:
|
||||
# Ensure _identity key always exists
|
||||
if '_identity' not in self.configs:
|
||||
self.configs['_identity'] = {}
|
||||
# Phase 5: ensure connectivity section exists with empty defaults.
|
||||
if 'connectivity' not in self.configs:
|
||||
self.configs['connectivity'] = {'exits': {}, 'peer_exit_map': {}}
|
||||
if not self.config_file.exists():
|
||||
self._save_all_configs()
|
||||
|
||||
@@ -108,6 +111,14 @@ class ConfigManager:
|
||||
'ca_configured': bool,
|
||||
'fernet_configured': bool
|
||||
}
|
||||
},
|
||||
'connectivity': {
|
||||
'required': [],
|
||||
'optional': ['exits', 'peer_exit_map'],
|
||||
'types': {
|
||||
'exits': dict,
|
||||
'peer_exit_map': dict,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -488,6 +499,28 @@ class ConfigManager:
|
||||
ident.setdefault('service_ips', {}).pop(service_id, None)
|
||||
self._save_all_configs()
|
||||
|
||||
# Phase 5 — Extended connectivity configuration helpers
|
||||
def get_connectivity_config(self) -> Dict[str, Any]:
|
||||
"""Return the full connectivity config (exits + peer_exit_map)."""
|
||||
cfg = self.configs.get('connectivity')
|
||||
if not isinstance(cfg, dict):
|
||||
cfg = {'exits': {}, 'peer_exit_map': {}}
|
||||
self.configs['connectivity'] = cfg
|
||||
cfg.setdefault('exits', {})
|
||||
cfg.setdefault('peer_exit_map', {})
|
||||
return dict(cfg)
|
||||
|
||||
def set_connectivity_field(self, field: str, value: Any) -> bool:
|
||||
"""Set a single field within the connectivity config and persist."""
|
||||
cfg = self.configs.setdefault('connectivity', {'exits': {}, 'peer_exit_map': {}})
|
||||
cfg[field] = value
|
||||
try:
|
||||
self._save_all_configs()
|
||||
return True
|
||||
except Exception as e:
|
||||
logger.error(f"set_connectivity_field({field}): {e}")
|
||||
return False
|
||||
|
||||
def get_all_configs(self) -> Dict[str, Dict]:
|
||||
"""Get all service configurations"""
|
||||
return self.configs.copy()
|
||||
|
||||
Reference in New Issue
Block a user