feat: peer access config, DNS fix, real routing table, reinstall notifications
Peer creation/edit form now configures: - Tunnel mode: full (0.0.0.0/0) or split (PIC only) - Per-service access toggles (calendar, files, mail, webdav) - Peer-to-peer communication toggle - Optional calendar account creation - Access capability badges in peer list Bug fixes: - DNS in client configs was 8.8.8.8 / 172.20.0.2 — now 172.20.0.3 (CoreDNS) This was why .cell domains didn't resolve on connected VPN peers - get_peer_config API uses stored internet_access to set AllowedIPs - New PUT /api/peers/<name> endpoint with config_changed detection - POST /api/peers/<name>/clear-reinstall clears reinstall flag after download - Routing page reads real host routes via /proc/1/net/route (pid: host) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
+55
-4
@@ -890,8 +890,8 @@ def get_peer_config():
|
||||
# Look up peer details from registry if not supplied
|
||||
peer_ip = data.get('ip', '')
|
||||
peer_private_key = data.get('private_key', '')
|
||||
registered = peer_registry.get_peer(peer_name) if peer_name else {}
|
||||
if peer_name and (not peer_ip or not peer_private_key):
|
||||
registered = peer_registry.get_peer(peer_name)
|
||||
if registered:
|
||||
peer_ip = peer_ip or registered.get('ip', '')
|
||||
peer_private_key = peer_private_key or registered.get('private_key', '')
|
||||
@@ -902,7 +902,12 @@ def get_peer_config():
|
||||
srv = wireguard_manager.get_server_config()
|
||||
server_endpoint = srv.get('endpoint') or '<SERVER_IP>'
|
||||
|
||||
# Determine AllowedIPs: explicit > peer's stored internet_access > default full tunnel
|
||||
allowed_ips = data.get('allowed_ips') or None
|
||||
if not allowed_ips and registered:
|
||||
internet_access = registered.get('internet_access', True)
|
||||
allowed_ips = wireguard_manager.FULL_TUNNEL_IPS if internet_access else wireguard_manager.SPLIT_TUNNEL_IPS
|
||||
|
||||
result = wireguard_manager.get_peer_config(
|
||||
peer_name=peer_name,
|
||||
peer_ip=peer_ip,
|
||||
@@ -980,19 +985,65 @@ def add_peer():
|
||||
'server_endpoint': data.get('server_endpoint'),
|
||||
'allowed_ips': data.get('allowed_ips'),
|
||||
'persistent_keepalive': data.get('persistent_keepalive'),
|
||||
'description': data.get('description')
|
||||
'description': data.get('description'),
|
||||
'internet_access': data.get('internet_access', True),
|
||||
'service_access': data.get('service_access', ['calendar', 'files', 'mail', 'webdav']),
|
||||
'peer_access': data.get('peer_access', True),
|
||||
'config_needs_reinstall': False,
|
||||
}
|
||||
|
||||
|
||||
success = peer_registry.add_peer(peer_info)
|
||||
if success:
|
||||
return jsonify({"message": f"Peer {data['name']} added successfully"}), 201
|
||||
else:
|
||||
return jsonify({"error": f"Peer {data['name']} already exists"}), 400
|
||||
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error adding peer: {e}")
|
||||
return jsonify({"error": str(e)}), 500
|
||||
|
||||
|
||||
@app.route('/api/peers/<peer_name>', methods=['PUT'])
|
||||
def update_peer(peer_name):
|
||||
"""Update peer settings. Marks config_needs_reinstall if VPN config changed."""
|
||||
try:
|
||||
data = request.get_json(silent=True) or {}
|
||||
existing = peer_registry.get_peer(peer_name)
|
||||
if not existing:
|
||||
return jsonify({"error": "Peer not found"}), 404
|
||||
|
||||
# Detect changes that require client to reinstall tunnel config
|
||||
config_changed = (
|
||||
('internet_access' in data and data['internet_access'] != existing.get('internet_access', True)) or
|
||||
('ip' in data and data['ip'] != existing.get('ip')) or
|
||||
('persistent_keepalive' in data and data['persistent_keepalive'] != existing.get('persistent_keepalive'))
|
||||
)
|
||||
|
||||
updates = {k: v for k, v in data.items()}
|
||||
if config_changed:
|
||||
updates['config_needs_reinstall'] = True
|
||||
|
||||
success = peer_registry.update_peer(peer_name, updates)
|
||||
if success:
|
||||
result = {"message": f"Peer {peer_name} updated", "config_changed": config_changed}
|
||||
return jsonify(result)
|
||||
else:
|
||||
return jsonify({"error": "Update failed"}), 500
|
||||
except Exception as e:
|
||||
logger.error(f"Error updating peer {peer_name}: {e}")
|
||||
return jsonify({"error": str(e)}), 500
|
||||
|
||||
|
||||
@app.route('/api/peers/<peer_name>/clear-reinstall', methods=['POST'])
|
||||
def clear_peer_reinstall(peer_name):
|
||||
"""Clear the config_needs_reinstall flag once user has downloaded new config."""
|
||||
try:
|
||||
peer_registry.clear_reinstall_flag(peer_name)
|
||||
return jsonify({"message": "Reinstall flag cleared"})
|
||||
except Exception as e:
|
||||
return jsonify({"error": str(e)}), 500
|
||||
|
||||
|
||||
@app.route('/api/peers/<peer_name>', methods=['DELETE'])
|
||||
def remove_peer(peer_name):
|
||||
"""Remove a peer."""
|
||||
|
||||
@@ -266,6 +266,27 @@ class PeerRegistry(BaseServiceManager):
|
||||
self.logger.error(f"Error removing peer {name}: {e}")
|
||||
return False
|
||||
|
||||
def update_peer(self, name: str, fields: Dict[str, Any]) -> bool:
|
||||
"""Update arbitrary fields on a peer."""
|
||||
try:
|
||||
with self.lock:
|
||||
for peer in self.peers:
|
||||
if peer.get('peer') == name:
|
||||
peer.update(fields)
|
||||
peer['updated_at'] = datetime.utcnow().isoformat()
|
||||
self._save_peers()
|
||||
self.logger.info(f"Updated peer {name}: {list(fields.keys())}")
|
||||
return True
|
||||
self.logger.warning(f"Peer {name} not found for update")
|
||||
return False
|
||||
except Exception as e:
|
||||
self.logger.error(f"Error updating peer {name}: {e}")
|
||||
return False
|
||||
|
||||
def clear_reinstall_flag(self, name: str) -> bool:
|
||||
"""Clear the config_needs_reinstall flag after user downloads new config."""
|
||||
return self.update_peer(name, {'config_needs_reinstall': False})
|
||||
|
||||
def update_peer_ip(self, name: str, new_ip: str) -> bool:
|
||||
"""Update peer IP address"""
|
||||
try:
|
||||
|
||||
Reference in New Issue
Block a user