1
0
mirror of git://f0xx.org/android_cast synced 2026-07-29 03:38:52 +03:00

fix(ra): re-apply wg peers on connect and improve sync_wg_peers

Re-run wg set for existing session keys on each connect so peers survive
wg0 restarts. sync_wg_peers now reconciles active sessions, reports
provision_peers/live peer state, and lists broken/orphan peers before prune.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Anton Afanasyeu
2026-06-17 14:30:23 +02:00
parent 26ef8f5399
commit 1ff1753021
2 changed files with 109 additions and 12 deletions

View File

@@ -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'] ?? '')

View File

@@ -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<string> */
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<array{session_id: string, public_key: string, client_address: string}>
*/
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<array{session_id: string, public_key: string, client_address: string, ok: bool}>
*/
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.
*