mirror of
https://github.com/outbackdingo/firezone.git
synced 2026-01-27 10:18:54 +00:00
fix(apple): don't call setConfiguration when not connected (#10747)
Skip `setConfiguration()` IPC call when not in connected state; this was observed as the root cause of the utun interface increments which we've seen recently. Note: `utun` increments can still happen during other IPC calls when not signed in, notably during log export when signed out of Firezone. This is not a major issue though, as other IPC calls happen only as a result of user interaction between network extension sleeps. To fully get rid of the problem, we should address #10754. To ensure we still are able to pass on configuration before sign in, we are now passing configuration directly in the startTunnel() options dictionary. Fixes #10603
This commit is contained in:
committed by
GitHub
parent
04f4415344
commit
ac6b3922be
@@ -50,14 +50,24 @@ class IPCClient {
|
||||
let decoder = PropertyListDecoder()
|
||||
|
||||
// Auto-connect
|
||||
func start() throws {
|
||||
try session().startTunnel(options: nil)
|
||||
@MainActor
|
||||
func start(configuration: Configuration) throws {
|
||||
let tunnelConfiguration = configuration.toTunnelConfiguration()
|
||||
let configData = try encoder.encode(tunnelConfiguration)
|
||||
let options: [String: NSObject] = [
|
||||
"configuration": configData as NSObject
|
||||
]
|
||||
try session().startTunnel(options: options)
|
||||
}
|
||||
|
||||
// Sign in
|
||||
func start(token: String) throws {
|
||||
@MainActor
|
||||
func start(token: String, configuration: Configuration) throws {
|
||||
let tunnelConfiguration = configuration.toTunnelConfiguration()
|
||||
let configData = try encoder.encode(tunnelConfiguration)
|
||||
let options: [String: NSObject] = [
|
||||
"token": token as NSObject
|
||||
"token": token as NSObject,
|
||||
"configuration": configData as NSObject,
|
||||
]
|
||||
|
||||
try session().startTunnel(options: options)
|
||||
@@ -76,8 +86,14 @@ class IPCClient {
|
||||
// On macOS, IPC calls to the system extension won't work after it's been upgraded, until the startTunnel call.
|
||||
// Since we rely on IPC for the GUI to function, we need to send a dummy `startTunnel` that doesn't actually
|
||||
// start the tunnel, but causes the system to wake the extension.
|
||||
func dryStartStopCycle() throws {
|
||||
let options: [String: NSObject] = ["dryRun": true as NSObject]
|
||||
@MainActor
|
||||
func dryStartStopCycle(configuration: Configuration) throws {
|
||||
let tunnelConfiguration = configuration.toTunnelConfiguration()
|
||||
let configData = try encoder.encode(tunnelConfiguration)
|
||||
let options: [String: NSObject] = [
|
||||
"dryRun": true as NSObject,
|
||||
"configuration": configData as NSObject,
|
||||
]
|
||||
try session().startTunnel(options: options)
|
||||
}
|
||||
#endif
|
||||
@@ -87,6 +103,10 @@ class IPCClient {
|
||||
let tunnelConfiguration = configuration.toTunnelConfiguration()
|
||||
let message = ProviderMessage.setConfiguration(tunnelConfiguration)
|
||||
|
||||
if sessionStatus() != .connected {
|
||||
Log.trace("Not setting configuration whilst not connected")
|
||||
return
|
||||
}
|
||||
try await sendMessageWithoutResponse(message)
|
||||
}
|
||||
|
||||
|
||||
@@ -193,7 +193,7 @@ public final class Store: ObservableObject {
|
||||
private func maybeAutoConnect() async throws {
|
||||
if configuration.connectOnStart {
|
||||
try await manager().enable()
|
||||
try ipcClient().start()
|
||||
try ipcClient().start(configuration: configuration)
|
||||
}
|
||||
}
|
||||
func installVPNConfiguration() async throws {
|
||||
@@ -232,7 +232,7 @@ public final class Store: ObservableObject {
|
||||
if vpnStatus == .connected || vpnStatus == .connecting || vpnStatus == .reasserting {
|
||||
try ipcClient().stop()
|
||||
} else {
|
||||
try ipcClient().dryStartStopCycle()
|
||||
try ipcClient().dryStartStopCycle(configuration: configuration)
|
||||
}
|
||||
#else
|
||||
try ipcClient().stop()
|
||||
@@ -251,14 +251,13 @@ public final class Store: ObservableObject {
|
||||
Telemetry.accountSlug = accountSlug
|
||||
|
||||
try await manager().enable()
|
||||
try await ipcClient().setConfiguration(configuration)
|
||||
|
||||
// Clear shown alerts when starting a new session so user can see new errors
|
||||
shownAlertIds.removeAll()
|
||||
UserDefaults.standard.removeObject(forKey: "shownAlertIds")
|
||||
|
||||
// Bring the tunnel up and send it a token to start
|
||||
try ipcClient().start(token: authResponse.token)
|
||||
// Bring the tunnel up and send it a token and configuration to start
|
||||
try ipcClient().start(token: authResponse.token, configuration: configuration)
|
||||
}
|
||||
|
||||
func signOut() async throws {
|
||||
|
||||
@@ -68,6 +68,20 @@ class PacketTunnelProvider: NEPacketTunnelProvider {
|
||||
let build = Bundle.main.object(forInfoDictionaryKey: "CFBundleVersion") as? String ?? "unknown"
|
||||
Log.info("Starting tunnel - Version: \(version), Build: \(build)")
|
||||
|
||||
// Try to load configuration from options first (passed from client at startup)
|
||||
if let configData = options?["configuration"] as? Data {
|
||||
do {
|
||||
let decoder = PropertyListDecoder()
|
||||
let configFromOptions = try decoder.decode(TunnelConfiguration.self, from: configData)
|
||||
Log.info("Loaded configuration from startTunnel options")
|
||||
// Save it for future fallback (e.g., system-initiated restarts)
|
||||
configFromOptions.save()
|
||||
self.tunnelConfiguration = configFromOptions
|
||||
} catch {
|
||||
Log.error(error)
|
||||
}
|
||||
}
|
||||
|
||||
// If the tunnel starts up before the GUI after an upgrade crossing the 1.4.15 version boundary,
|
||||
// the old system settings-based config will still be present and the new configuration will be empty.
|
||||
// So handle that edge case gracefully.
|
||||
|
||||
@@ -48,7 +48,9 @@ private func forwardEvents(from session: Session, to eventSender: Sender<Event>)
|
||||
}
|
||||
|
||||
/// Forwards commands from the command receiver to the session.
|
||||
private func forwardCommands(from commandReceiver: Receiver<SessionCommand>, to session: Session) async {
|
||||
private func forwardCommands(from commandReceiver: Receiver<SessionCommand>, to session: Session)
|
||||
async
|
||||
{
|
||||
for await command in commandReceiver.stream {
|
||||
if Task.isCancelled {
|
||||
Log.log("Command forwarding cancelled")
|
||||
|
||||
Reference in New Issue
Block a user