fix: cross-cell routing for split-tunnel peers

Three related fixes for split-tunnel peers that need to reach connected cells:

1. apply_peer_rules/apply_all_peer_rules now accept wg_subnet (actual local VPN
   subnet) and cell_subnets (connected cells' vpn_subnets) parameters instead of
   hardcoding 10.0.0.0/24. All callers (startup, add_peer, update_peer,
   apply-enforcement endpoint) pass the real values.

2. Explicit ACCEPT rules are inserted in FORWARD for each connected cell's
   subnet so split-tunnel peers (internet_access=False) can still reach
   connected cells via the wg0→wg0 path.

3. apply_ip_range in network_manager now loads cell_links.json and passes it
   to generate_corefile(), fixing a race where the bootstrap DNS thread could
   overwrite the Corefile and wipe cross-cell DNS forwarding zones on startup.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-04 14:36:28 -04:00
parent 8ee1d88e37
commit c2d215ee2e
6 changed files with 171 additions and 19 deletions
+12 -3
View File
@@ -1,4 +1,5 @@
import logging
import ipaddress
from flask import Blueprint, request, jsonify
logger = logging.getLogger('picell')
bp = Blueprint('wireguard', __name__)
@@ -221,11 +222,19 @@ def refresh_external_ip():
@bp.route('/api/wireguard/apply-enforcement', methods=['POST'])
def apply_wireguard_enforcement():
try:
from app import peer_registry, firewall_manager, cell_link_manager, _configured_domain, COREFILE_PATH
from app import (peer_registry, wireguard_manager, firewall_manager,
cell_link_manager, _configured_domain, COREFILE_PATH)
peers = peer_registry.list_peers()
firewall_manager.apply_all_peer_rules(peers)
try:
_wg_addr = wireguard_manager._get_configured_address()
_wg_subnet = str(ipaddress.ip_network(_wg_addr, strict=False)) if _wg_addr else '10.0.0.0/24'
except Exception:
_wg_subnet = '10.0.0.0/24'
_cell_links = cell_link_manager.list_connections()
_cell_subnets = [l['vpn_subnet'] for l in _cell_links if l.get('vpn_subnet')]
firewall_manager.apply_all_peer_rules(peers, wg_subnet=_wg_subnet, cell_subnets=_cell_subnets)
firewall_manager.apply_all_dns_rules(peers, COREFILE_PATH, _configured_domain(),
cell_links=cell_link_manager.list_connections())
cell_links=_cell_links)
return jsonify({'ok': True, 'peers': len(peers)})
except Exception as e:
return jsonify({'error': str(e)}), 500