From 23b91a1a3e236efba56af8161455710b2ff1e1e1 Mon Sep 17 00:00:00 2001 From: chahinebrini Date: Fri, 22 May 2026 19:07:31 +0200 Subject: [PATCH] =?UTF-8?q?fix(ios-vpn):=20PacketTunnel=20Self-Heal=20?= =?UTF-8?q?=E2=80=94=20Blocklist-Retry=20bei=20leerem=20Start?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit startTunnel lädt blocklist.bin manchmal mit 0 Hashes (Datei wegen Data-Protection bei gesperrtem Gerät noch nicht lesbar). Bisher blieb Layer 1 dann tot bis zum nächsten App-Sync — in den Geräte-Logs als ~30-Min-Fenster mit 0 Hashes sichtbar (z.B. 16:22 startTunnel→0, erst 16:55 per Darwin-Reload geheilt). scheduleBlocklistRetryIfEmpty: lädt nach 3/10/30/60/120/300s erneut, bis Hashes da sind (max 20 Versuche). Sobald das Gerät entsperrt ist, wird die Datei lesbar → Self-Heal greift, ohne auf einen App-Sync zu warten. Co-Authored-By: Claude Opus 4.7 --- .../PacketTunnelProvider.swift | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/apps/rebreak-native/modules/rebreak-protection/ios/RebreakPacketTunnelExtension/PacketTunnelProvider.swift b/apps/rebreak-native/modules/rebreak-protection/ios/RebreakPacketTunnelExtension/PacketTunnelProvider.swift index 0850a11..572f68d 100644 --- a/apps/rebreak-native/modules/rebreak-protection/ios/RebreakPacketTunnelExtension/PacketTunnelProvider.swift +++ b/apps/rebreak-native/modules/rebreak-protection/ios/RebreakPacketTunnelExtension/PacketTunnelProvider.swift @@ -189,6 +189,9 @@ class PacketTunnelProvider: NEPacketTunnelProvider { ExtLog.write("✅ TUN-Settings gesetzt — Read-Loop startet") self.running = true self.readPackets() + // Self-Heal: war die Blocklist beim Start leer (Data-Protection bei + // gesperrtem Gerät), per Backoff erneut laden bis Hashes da sind. + self.scheduleBlocklistRetryIfEmpty(attempt: 0) completionHandler(nil) } } @@ -448,4 +451,37 @@ class PacketTunnelProvider: NEPacketTunnelProvider { hashList?.load() ExtLog.write("blocklist reloaded — \(hashList?.count() ?? 0) Hashes") } + + /// Self-Heal: wenn `startTunnel` die Blocklist leer geladen hat (Datei wegen + /// iOS-Data-Protection noch nicht lesbar — Tunnel-Start vor dem ersten + /// Entsperren seit Boot, oder eine alte mit `.complete` geschriebene Datei), + /// wird `load()` mit Backoff erneut versucht, bis Hashes da sind. + /// + /// Ohne das bliebe Layer 1 still tot, bis die App das nächste Mal synct und + /// die Darwin-Notification feuert — beobachtet in den Geräte-Logs als + /// ~30-Minuten-Fenster mit 0 Hashes. Der Retry läuft auf `forwardQueue`. + private func scheduleBlocklistRetryIfEmpty(attempt: Int) { + guard running else { return } + guard let list = hashList, list.count() == 0 else { return } // schon ok + + let maxAttempts = 20 + guard attempt < maxAttempts else { + ExtLog.write("⚠️ Blocklist nach \(maxAttempts) Retries leer — warte auf App-Sync") + return + } + // Backoff in Sekunden; ab Index 5 konstant 300 s. + let backoff: [Double] = [3, 10, 30, 60, 120] + let delay = attempt < backoff.count ? backoff[attempt] : 300 + + forwardQueue.asyncAfter(deadline: .now() + delay) { [weak self] in + guard let self = self, self.running else { return } + self.hashList?.load() + let n = self.hashList?.count() ?? 0 + if n > 0 { + ExtLog.write("✅ blocklist self-heal — \(n) Hashes (Versuch \(attempt + 1))") + } else { + self.scheduleBlocklistRetryIfEmpty(attempt: attempt + 1) + } + } + } }