NETransparentProxyProvider frequent tunnel churn during Dark Wake cycles on macOS.

Description

  • Our NETransparentProxyProvider system extension maintains a persistent TLS/DTLS control channel to a security gateway. To maintain this stateful connection the extension sends application-level "Keep Alive" packets every few seconds (example : 20 seconds).

  • The Issue: When the macOS device enters a sleep state, the Network Extension process is suspended, causing our application-level heartbeat to cease. Consequently, our backend gateway—detecting no activity—terminates the session via Dead Peer Detection (DPD).

  • The problem is exacerbated by macOS Dark Wake cycles. We observe the extension's wake() callback being triggered periodically (approx. every 15 minutes) while the device remains in a sleep state (lid closed). During these brief windows:

  • The extension attempts to use the existing socket, finds it terminated by the backend, and initiates a full re-handshake.

  • Shortly after the connection is re-established, the OS triggers the sleep() callback and suspends the process again.

  • This creates a "connection churn" cycle that generates excessive telemetry noise and misleading "Session Disconnected" alerts for our enterprise customers.

Steps to Reproduce Activate Proxy:

  • Start the NETransparentProxyProvider and establish a TLS session to a gateway.

  • Apply Settings: Configure NETransparentProxyNetworkSettings to intercept outbound TCP/UDP traffic.

  • Initialize Heartbeat: Start a 20-second timer (DispatchSourceTimer) to log and send keep-alive packets.

  • Induce Sleep: Put the Mac to sleep (Apple Menu > Sleep).

  • Observe Logs: Monitor the system via sysdiagnose or the macOS Console.

  • Observation: Logs stop entirely during sleep, indicating process suspension.

  • Observation: wake() and sleep() callbacks are triggered repeatedly during Dark Wake intervals, causing a cycle of re-connections.

Expected Behavior We seek to minimize connection turnover during maintenance wakes and maintain session stability while the device is technically in a sleep state.

Questions for Apple

  • Is it possible to suppress the sleep and wake callback methods of NETransparentProxyProvider when the device is performing a maintenance/Dark Wake, only triggering them for a full user-initiated wake?

  • Is it possible to prevent the NETransparentProxyProvider process from being suspended during sleep, or at least grant it a high-priority background execution slot to maintain the heartbeat?

  • If suspension is mandatory, is there a recommended way to utilize TCP_KEEPALIVE socket options that the kernel can handle on behalf of the suspended extension?

  • How can the extension programmatically identify if a wake() call is a "Dark Wake" versus a "Full User Wake" to avoid unnecessary re-connection logic?

NETransparentProxyProvider frequent tunnel churn during Dark Wake cycles on macOS.
 
 
Q