diff --git a/examples/crash_reporter/backend/scripts/sync_wg_peers.php b/examples/crash_reporter/backend/scripts/sync_wg_peers.php index 17e521e..7314c86 100755 --- a/examples/crash_reporter/backend/scripts/sync_wg_peers.php +++ b/examples/crash_reporter/backend/scripts/sync_wg_peers.php @@ -25,19 +25,61 @@ foreach ($argv as $arg) { } RemoteAccessRepository::ensureSchema(); + +$livePeers = WireGuardPeerProvisioner::listPeerDumpRows(); $keep = RemoteAccessRepository::activeWireGuardSessionPublicKeys(); +$reconciled = RemoteAccessRepository::reconcileActiveWireGuardPeers($dryRun); $pruned = RemoteAccessRepository::pruneOrphanWireGuardPeers($dryRun); fwrite(STDOUT, 'mode=' . ($dryRun ? 'dry-run' : 'apply') . "\n"); +fwrite(STDOUT, 'provision_peers=' . (WireGuardPeerProvisioner::isEnabled() ? 'true' : 'false') . "\n"); +fwrite(STDOUT, 'live_wg_peers=' . count($livePeers) . "\n"); fwrite(STDOUT, 'active_session_peers=' . count($keep) . "\n"); +fwrite(STDOUT, 'reconciled_sessions=' . count($reconciled) . "\n"); fwrite(STDOUT, 'pruned_peers=' . count($pruned) . "\n"); + +foreach ($reconciled as $row) { + $pub = (string) ($row['public_key'] ?? ''); + $short = strlen($pub) > 12 ? substr($pub, 0, 8) . '…' : $pub; + fwrite( + STDOUT, + sprintf( + " reconcile %s allowed_ips=%s ok=%s\n", + $short, + (string) ($row['client_address'] ?? ''), + ($row['ok'] ?? false) ? 'true' : 'false' + ) + ); +} + +foreach ($livePeers as $row) { + $pub = (string) ($row['public_key'] ?? ''); + $allowed = trim((string) ($row['allowed_ips'] ?? '')); + $short = strlen($pub) > 12 ? substr($pub, 0, 8) . '…' : $pub; + $broken = ($allowed === '' || $allowed === '(none)'); + $orphan = !in_array($pub, $keep, true); + if (!$broken && !$orphan) { + continue; + } + fwrite( + STDOUT, + sprintf( + " live %s allowed_ips=%s broken=%s orphan=%s\n", + $short, + $allowed === '' ? '(empty)' : $allowed, + $broken ? 'true' : 'false', + $orphan ? 'true' : 'false' + ) + ); +} + foreach ($pruned as $row) { $pub = $row['public_key'] ?? ''; $short = strlen($pub) > 12 ? substr($pub, 0, 8) . '…' : $pub; fwrite( STDOUT, sprintf( - " %s reason=%s allowed_ips=%s\n", + " pruned %s reason=%s allowed_ips=%s\n", $short, (string) ($row['reason'] ?? ''), (string) ($row['allowed_ips'] ?? '') diff --git a/examples/crash_reporter/backend/src/RemoteAccessRepository.php b/examples/crash_reporter/backend/src/RemoteAccessRepository.php index d0d4758..6739920 100644 --- a/examples/crash_reporter/backend/src/RemoteAccessRepository.php +++ b/examples/crash_reporter/backend/src/RemoteAccessRepository.php @@ -502,6 +502,9 @@ final class RemoteAccessRepository { if ($pub === '') { $pub = WireGuardPeerProvisioner::publicKeyFromPrivate($priv); } + if (!WireGuardPeerProvisioner::addClientPeer($pub, $addr)) { + error_log('RemoteAccess: wg peer re-apply failed for session ' . $sessionId); + } return [ 'client_private' => $priv, 'client_public' => $pub, @@ -755,18 +758,10 @@ final class RemoteAccessRepository { /** @return list */ public static function activeWireGuardSessionPublicKeys(): array { - self::ensureSchema(); - $st = Database::pdo()->query( - "SELECT DISTINCT wg_client_public_key FROM remote_access_sessions - WHERE status IN ('pending','active') AND tunnel = 'wireguard' - AND wg_client_public_key IS NOT NULL AND wg_client_public_key != ''" - ); - if ($st === false) { - return []; - } + $peers = self::activeWireGuardSessionPeers(); $keys = []; - foreach ($st->fetchAll(PDO::FETCH_COLUMN) as $pub) { - $pub = trim((string) $pub); + foreach ($peers as $row) { + $pub = trim((string) ($row['public_key'] ?? '')); if ($pub !== '') { $keys[] = $pub; } @@ -774,6 +769,66 @@ final class RemoteAccessRepository { return $keys; } + /** + * Pending/active WG sessions with client pubkey + tunnel address (for wg set reconcile). + * + * @return list + */ + public static function activeWireGuardSessionPeers(): array { + self::ensureSchema(); + $st = Database::pdo()->query( + "SELECT session_id, wg_client_public_key, wg_client_address FROM remote_access_sessions + WHERE status IN ('pending','active') AND tunnel = 'wireguard' + AND wg_client_public_key IS NOT NULL AND wg_client_public_key != '' + AND wg_client_address IS NOT NULL AND wg_client_address != ''" + ); + if ($st === false) { + return []; + } + $rows = []; + foreach ($st->fetchAll(PDO::FETCH_ASSOC) as $row) { + if (!is_array($row)) { + continue; + } + $pub = trim((string) ($row['wg_client_public_key'] ?? '')); + $addr = trim((string) ($row['wg_client_address'] ?? '')); + if ($pub === '' || $addr === '') { + continue; + } + $rows[] = [ + 'session_id' => (string) ($row['session_id'] ?? ''), + 'public_key' => $pub, + 'client_address' => $addr, + ]; + } + return $rows; + } + + /** + * Ensure wg0 has allowed-ips for every pending/active WG session (idempotent). + * + * @return list + */ + public static function reconcileActiveWireGuardPeers(bool $dryRun = false): array { + $results = []; + foreach (self::activeWireGuardSessionPeers() as $row) { + $ok = true; + if (!$dryRun) { + $ok = WireGuardPeerProvisioner::addClientPeer( + $row['public_key'], + $row['client_address'] + ); + } + $results[] = [ + 'session_id' => $row['session_id'], + 'public_key' => $row['public_key'], + 'client_address' => $row['client_address'], + 'ok' => $ok, + ]; + } + return $results; + } + /** * Drop wg0 peers that are not referenced by pending/active sessions. *