@@ -9,6 +9,8 @@ let CTLIOCGINFO: UInt = 0xC064_4E03
99class PacketTunnelProvider : NEPacketTunnelProvider , @unchecked Sendable {
1010 private let logger = Logger ( subsystem: Bundle . main. bundleIdentifier!, category: " provider " )
1111 private var manager : Manager ?
12+ // a `tunnelRemoteAddress` is required, but not currently used.
13+ private var currentSettings : NEPacketTunnelNetworkSettings = . init( tunnelRemoteAddress: " 127.0.0.1 " )
1214
1315 var tunnelFileDescriptor : Int32 ? {
1416 var ctlInfo = ctl_info ( )
@@ -48,25 +50,37 @@ class PacketTunnelProvider: NEPacketTunnelProvider, @unchecked Sendable {
4850 logger. info ( " startTunnel called " )
4951 guard manager == nil else {
5052 logger. error ( " startTunnel called with non-nil Manager " )
51- completionHandler ( nil )
53+ completionHandler ( PTPError . alreadyRunning )
5254 return
5355 }
56+ guard let proto = protocolConfiguration as? NETunnelProviderProtocol ,
57+ let baseAccessURL = proto. serverAddress
58+ else {
59+ logger. error ( " startTunnel called with nil protocolConfiguration " )
60+ completionHandler ( PTPError . missingConfiguration)
61+ return
62+ }
63+ // HACK: We can't write to the system keychain, and the NE can't read the user keychain.
64+ guard let token = proto. providerConfiguration ? [ " token " ] as? String else {
65+ logger. error ( " startTunnel called with nil token " )
66+ completionHandler ( PTPError . missingToken)
67+ return
68+ }
69+ logger. debug ( " retrieved token & access URL " )
5470 let completionHandler = CallbackWrapper ( completionHandler)
5571 Task {
56- // TODO: Retrieve access URL & Token via Keychain
5772 do throws ( ManagerError) {
58- logger. info ( " creating manager " )
73+ logger. debug ( " creating manager " )
5974 manager = try await Manager (
6075 with: self ,
6176 cfg: . init(
62- apiToken: " qGg1rDGWzL-a814TWDGcTDOs4AX7laDEI " ,
63- serverUrl: . init( string: " https://dev.coder.com " ) !
77+ apiToken: token, serverUrl: . init( string: baseAccessURL) !
6478 )
6579 )
6680 globalXPCListenerDelegate. vpnXPCInterface. setManager ( manager)
67- logger. debug ( " calling manager.startVPN " )
68- // try await manager!.startVPN()
69- logger. debug ( " vpn started " )
81+ logger. debug ( " starting vpn " )
82+ try await manager!. startVPN ( )
83+ logger. info ( " vpn started " )
7084 if let conn = globalXPCListenerDelegate. getActiveConnection ( ) {
7185 conn. onStart ( )
7286 } else {
@@ -75,6 +89,11 @@ class PacketTunnelProvider: NEPacketTunnelProvider, @unchecked Sendable {
7589 completionHandler ( nil )
7690 } catch {
7791 logger. error ( " error starting manager: \( error. description, privacy: . public) " )
92+ if let conn = globalXPCListenerDelegate. getActiveConnection ( ) {
93+ conn. onError ( error as NSError )
94+ } else {
95+ logger. info ( " no active connection " )
96+ }
7897 completionHandler ( error as NSError )
7998 }
8099 }
@@ -84,30 +103,28 @@ class PacketTunnelProvider: NEPacketTunnelProvider, @unchecked Sendable {
84103 with _: NEProviderStopReason , completionHandler: @escaping ( ) -> Void
85104 ) {
86105 logger. debug ( " stopTunnel called " )
87- guard manager != nil else {
106+ guard let manager else {
88107 logger. error ( " stopTunnel called with nil Manager " )
89108 completionHandler ( )
90109 return
91110 }
92111
93- if let conn = globalXPCListenerDelegate. getActiveConnection ( ) {
94- conn. onStop ( )
95- } else {
96- logger. info ( " no active connection " )
97- }
98-
99- let managerCopy = manager
100- Task {
112+ let completionHandler = CompletionWrapper ( completionHandler)
113+ Task { [ manager] in
101114 do throws ( ManagerError) {
102- try await managerCopy ? . stopVPN ( )
115+ try await manager . stopVPN ( )
103116 } catch {
104117 logger. error ( " error stopping manager: \( error. description, privacy: . public) " )
105118 }
119+ if let conn = globalXPCListenerDelegate. getActiveConnection ( ) {
120+ conn. onStop ( )
121+ } else {
122+ logger. info ( " no active connection " )
123+ }
124+ globalXPCListenerDelegate. vpnXPCInterface. setManager ( nil )
125+ completionHandler ( )
106126 }
107-
108- manager = nil
109- globalXPCListenerDelegate. vpnXPCInterface. setManager ( nil )
110- completionHandler ( )
127+ self . manager = nil
111128 }
112129
113130 override func handleAppMessage( _ messageData: Data , completionHandler: ( ( Data ? ) -> Void ) ? ) {
@@ -127,4 +144,33 @@ class PacketTunnelProvider: NEPacketTunnelProvider, @unchecked Sendable {
127144 // Add code here to wake up.
128145 logger. debug ( " wake called " )
129146 }
147+
148+ // Wrapper around `setTunnelNetworkSettings` that supports merging updates
149+ func applyTunnelNetworkSettings( _ diff: Vpn_NetworkSettingsRequest ) async throws {
150+ logger. debug ( " applying settings diff: \( diff. debugDescription, privacy: . public) " )
151+
152+ if diff. hasDnsSettings {
153+ currentSettings. dnsSettings = convertDnsSettings ( diff. dnsSettings)
154+ }
155+
156+ if diff. mtu != 0 {
157+ currentSettings. mtu = NSNumber ( value: diff. mtu)
158+ }
159+
160+ if diff. hasIpv4Settings {
161+ currentSettings. ipv4Settings = convertIPv4Settings ( diff. ipv4Settings)
162+ }
163+ if diff. hasIpv6Settings {
164+ currentSettings. ipv6Settings = convertIPv6Settings ( diff. ipv6Settings)
165+ }
166+
167+ logger. info ( " applying settings: \( self . currentSettings. debugDescription, privacy: . public) " )
168+ try await setTunnelNetworkSettings ( currentSettings)
169+ }
170+ }
171+
172+ enum PTPError : Error {
173+ case alreadyRunning
174+ case missingConfiguration
175+ case missingToken
130176}
0 commit comments