mirror of
https://github.com/outbackdingo/firezone.git
synced 2026-01-27 18:18:55 +00:00
fix(apple): call completionHandler only after initialized (#10606)
Apple's [docs state](https://developer.apple.com/documentation/networkextension/nepackettunnelprovider/starttunnel(options:completionhandler:)#Discussion) that we should only call the PacketTunnelProvider's `completionHandler` once the tunnel is ready to route packets. Calling it prematurely, while shouldn't cause packets to get routed to us (we haven't added the routes yet), will however cause the system to think our VPN is "online", which disconnects other VPNs and communicates to the user Firezone is "connected". If the portal is then slow to send us the init, we will be stuck in this quasi-connected state for more than a brief moment of time. To fix this, we thread `completionHandler` through to `Adapter` and call this if we are configuring the tun interface for the first time. This way, we remain in the `connecting` state until the tunnel is fully configured.
This commit is contained in:
@@ -53,6 +53,9 @@ class Adapter: @unchecked Sendable {
|
||||
/// Packet tunnel provider.
|
||||
private weak var packetTunnelProvider: PacketTunnelProvider?
|
||||
|
||||
/// Start completion handler, used to signal to the system the interface is ready to use.
|
||||
private var startCompletionHandler: (Error?) -> Void
|
||||
|
||||
/// Network routes monitor.
|
||||
private var networkMonitor: NWPathMonitor?
|
||||
|
||||
@@ -155,7 +158,8 @@ class Adapter: @unchecked Sendable {
|
||||
logFilter: String,
|
||||
accountSlug: String,
|
||||
internetResourceEnabled: Bool,
|
||||
packetTunnelProvider: PacketTunnelProvider
|
||||
packetTunnelProvider: PacketTunnelProvider,
|
||||
startCompletionHandler: @escaping (Error?) -> Void
|
||||
) {
|
||||
self.apiURL = apiURL
|
||||
self.token = token
|
||||
@@ -164,6 +168,7 @@ class Adapter: @unchecked Sendable {
|
||||
self.accountSlug = accountSlug
|
||||
self.internetResourceEnabled = internetResourceEnabled
|
||||
self.packetTunnelProvider = packetTunnelProvider
|
||||
self.startCompletionHandler = startCompletionHandler
|
||||
}
|
||||
|
||||
// Could happen abruptly if the process is killed.
|
||||
@@ -342,6 +347,8 @@ class Adapter: @unchecked Sendable {
|
||||
let ipv4, let ipv6, let dns, let searchDomain, let ipv4Routes, let ipv6Routes):
|
||||
Log.log("Received TunInterfaceUpdated event")
|
||||
|
||||
let firstStart = self.networkSettings == nil
|
||||
|
||||
// Convert UniFFI types to NetworkExtension types
|
||||
let routes4 = ipv4Routes.compactMap { cidr in
|
||||
NetworkSettings.Cidr(address: cidr.address, prefix: Int(cidr.prefix)).asNEIPv4Route
|
||||
@@ -367,7 +374,11 @@ class Adapter: @unchecked Sendable {
|
||||
networkSettings.setSearchDomain(domain: searchDomain)
|
||||
self.networkSettings = networkSettings
|
||||
|
||||
networkSettings.apply()
|
||||
networkSettings.apply {
|
||||
if firstStart {
|
||||
self.startCompletionHandler(nil)
|
||||
}
|
||||
}
|
||||
|
||||
case .resourcesUpdated(let resourceList):
|
||||
Log.log("Received ResourcesUpdated event with \(resourceList.count) resources")
|
||||
|
||||
@@ -114,7 +114,8 @@ class PacketTunnelProvider: NEPacketTunnelProvider {
|
||||
logFilter: logFilter,
|
||||
accountSlug: accountSlug,
|
||||
internetResourceEnabled: internetResourceEnabled,
|
||||
packetTunnelProvider: self
|
||||
packetTunnelProvider: self,
|
||||
startCompletionHandler: completionHandler
|
||||
)
|
||||
|
||||
// Start the adapter
|
||||
@@ -122,10 +123,6 @@ class PacketTunnelProvider: NEPacketTunnelProvider {
|
||||
|
||||
self.adapter = adapter
|
||||
|
||||
// Tell the system the tunnel is up, moving the tunnel manager status to
|
||||
// `connected`.
|
||||
completionHandler(nil)
|
||||
|
||||
} catch {
|
||||
|
||||
Log.error(error)
|
||||
|
||||
Reference in New Issue
Block a user