fix(apple): prevent utun increments from IPC calls (#10855)

On macOS, IPC calls to the network extension can wake it whilst not
connected, causing the system to create a utun device.
If startTunnel() is not subsequently called, these devices
persist and accumulate over time.

The existing dryStartStopCycle() mechanism was introduced to wake the
extension after upgrades, but other IPC operations (log management
functions) could also wake the extension without proper cleanup.

Solution
--------

Add wrapper functions in IPCClient that automatically handle wake-up
and cleanup lifecycle for IPC calls made whilst disconnected:

- Check VPN connection status
- If connected: execute IPC operation directly (utun already exists)
- If disconnected: wake extension → wait 500ms → execute IPC → cleanup

Implementation
--------------

For async IPC operations (clearLogs, getLogFolderSize):
  Created free functions in IPCClient that wrap low-level IPC calls
  with wrapIPCCallIfNeeded():
  - clearLogsWithCleanup(store:session:)
  - getLogFolderSizeWithCleanup(store:session:)

For callback-based exportLogs:
  We cannot use wrapper because exportLogs returns immediately and uses
  callbacks for streaming chunks. Wrapper would call stop() before
  export finishes, killing the extension mid-stream.

  Solution: Manual wake-up/cleanup in LogExporter where we already have
  continuation that waits for chunk.done signal:
  1. Check if extension needs waking (vpnStatus != .connected)
  2. If yes: wake extension, wait 500ms
  3. Start export with callbacks
  4. When chunk.done=true: cleanup utun device, then resume continuation
  5. On error: cleanup utun device, then resume with error
  
  
  Fixes #10580

---------

Co-authored-by: Jamil Bou Kheir <jamilbk@users.noreply.github.com>
This commit is contained in:
Mariusz Klochowicz
2025-11-14 08:31:22 +10:30
committed by GitHub
parent d282b641c5
commit bdffa3a697
7 changed files with 157 additions and 213 deletions

View File

@@ -25,6 +25,10 @@ export default function Apple() {
<Entries downloadLinks={downloadLinks} title="macOS / iOS">
{/* When you cut a release, remove any solved issues from the "known issues" lists over in `client-apps`. This must not be done when the issue's PR merges. */}
<Unreleased>
<ChangeItem pull="10855">
Fixes an issue on macOS where the <code>utun</code> index would
auto-increment by itself on configuration updates.
</ChangeItem>
<ChangeItem pull="10752">
Fixes an issue where the reported client version was out of date.
</ChangeItem>