Matt, Thank you very much for your reply. That looks really promising. I'm using NETransparentProxyManager so I believe that I fill the .onDemandRules instead of the .appRules in the case of your example. Is it possible to write a rule that connects the VPN on any traffic?
Post
Replies
Boosts
Views
Activity
Thank you very much for you guidance. Now everything works as it should.But there is an interesting behaviour with the network extensions, which I spotted also by the SimpleFirewall (content filter) example project.When the network extension and VPN in the System Preferences are going to be installed clean, (i.e. run systemextensionsctl reset + remove VPN from System Preferences) the following sequence doesn't succeed:1. Install - request the extension to be installed - finishes OK - the extension is active and enabled2. Configure - save configuration of the VPN to System Preference - finishes OK - The VPN is disconnected in the System Preferences3. Connect - call startVPNTunnel() of click Connect in System Preferences - Tries to connect the VPN, but noes not succeed.I'm searching the logs for some descriptive clue, but found only the "NEAgentErrorDomain Code=2" so far:default 09:22:55.844285+0100 nesessionmanager com.apple.networkextension NEFlowDivertPlugin([inactive]): Sending start command
error 09:22:55.847394+0100 nesessionmanager com.apple.networkextension Failed to launch
default 09:22:55.848001+0100 nesessionmanager com.apple.networkextension NESMTransparentProxySession[Primary Tunnel:::(null)] in state NESMVPNSessionStateStarting: plugin NEFlowDivertPlugin([inactive]) started with PID 0 error Error Domain=NEAgentErrorDomain Code=2 "(null)"But after a second Install -> Configure -> Connect it works normally - connects the VPN and starts the proxy provider.
I added logging to init() and main().According to the logs I see:start system extension mode
start dispatch mainSo no init() is called.I looked closer at all the logs in Console and there are some additional suspicious lines except the undocumented error:1. LOGSdefault 13:43:00.774746+0100 <my wrapper app> Current bundle (<path to .app>) does not have a PlugIns directory
default 13:43:00.774761+0100 <my wrapper app> Did not find any extension in <path to .app> that implements a provider for com.apple.networkextension.app-proxyI don't understand these line because:- The project was created via the NetworkExtension target- the extension is located in <path to my wrapper app>/Contents/Library/SystemExtensions/<BundleIdentifier>.systemextension- I have developer mode ON via the systemextensionsctl- the main() of the extension runs- In Info.plist of the extension I have:<key>NetworkExtension</key>
<dict>
<key>NEMachServiceName</key>
<string>$(TeamIdentifierPrefix).<BundleIdentifier>.<Extension name></string>
<key>NEProviderClasses</key>
<dict>
<key>com.apple.networkextension.app-proxy</key>
<string>$(PRODUCT_MODULE_NAME).TransparentProxyProvider</string>
</dict>
</dict>(I renamed the class to TransparentProxyProvider and its occurence according to your example from previous post)2. LOGSdefault 13:43:00.828876+0100 taskgated-helper Checking against 1 eligible provisioning profiles
default 13:43:00.828943+0100 taskgated-helper Checking profile: Mac Team Provisioning Profile: <BundleIdentifier>
error 13:43:00.828962+0100 taskgated-helper <BundleIdentifier>: Unsatisfied entitlements: com.apple.security.application-groups
error 13:43:00.828974+0100 taskgated-helper Disallowing: <BundleIdentifier>
error 13:43:00.829235+0100 amfid CPValidateProvisioningDictionariesExtViaBridge returned invalid result: {
success = 0;
}
default 13:43:00.829258+0100 amfid Soft-restriction provisioning profile validation failure: No matching provisioning profile
default 13:43:00.829272+0100 amfid Unsatisfied entitlements key is not type CFString, this should not happen.
default 13:43:00.829283+0100 amfid Provisioning Profile does not provision soft-restricted entitlements.See lines 03. and 04.The line 04. looks kind of serious, but everything somehow runs up to the main() in the extension.In .entitlements for both the wrapper app and the extension I have following:<key>com.apple.security.application-groups</key>
<array>
<string>$(TeamIdentifierPrefix).<my team group></string>
</array>
The code works like a charm! It looks like I had the providerBundleIdentifier set wrong. Thank you very much eskimo!Now I get also the system prompt to allow the VPN and it's listed in the Network Preferences. Also the code from my NetworkExtension's main.swift is executed.But the startProxy(...) of the extension code still doesn't want to be called.My provider class is AppProxyProvider: NEAppProxyProvider.It's listed in the Info.plist asNetworkExtension
...
NEProviderClasses
com.apple.networkextension.app-proxy
$(PRODUCT_MODULE_NAME).AppProxyProvider
I also added this code right after your line 30.IPCConnection.shared.register(withExtension: self.extensionBundle, delegate: self) { success in
DispatchQueue.main.async {
if success {
let session = self.myManager!.connection
if session.status != .connected {
do {
try session.startVPNTunnel(options: nil)
}
catch {
print(error)
}
}
}
}
}And when startVPNTunnel() is called (line 07) I see this error in Console:nesessionmanager NEFlowDivertPlugin([inactive]): Sending start command
nesessionmanager [inactive]: starting
nesessionmanager [1318]: Tearing down XPC connection due to setup error: Error Domain=NEAgentErrorDomain Code=2 "(null)"
nesessionmanager NESMTransparentProxySession[Primary Tunnel::>:(null)] in state NESMVPNSessionStateStarting: plugin NEFlowDivertPlugin([inactive]) started with PID 0 error Error Domain=NEAgentErrorDomain Code=2 "(null)"
nesessionmanager [1318]: XPC connection went away
nesessionmanager [1318]: disposingLines 03 and 04:Error Domain=NEAgentErrorDomain Code=2 "(null)"The same happens if I try to execute Connect the from the Preferences->Network.It looks like there is no information about this kind of an error even on https://developer.apple.com/documentation/.Do you know a meaning of the error?
I got inspired byt these forum threads:https://forums.developer.apple.com/thread/123170https://forums.developer.apple.com/thread/121823because it looks like they have similar goal as me.I switched to the NETransparentProxyManagerset up the NETunnelProviderProtocol with providerBundleIdentifier dummy serverAddressassigned protocol to the manager, isEnabled to true and set the localizedDesriptionsaveToPreferences() ended up with the error:"Failed to save the filter configuration: The operation couldn’t be completed. (NEVPNErrorDomain error 4.)"According to the documentationhttps://developer.apple.com/documentation/networkextension/nevpnerror/code/configurationstale"This error also occurs if the app tries to save the VPN configuration before loading it from the Network Extension preferences the first time after the app launches."I modified the code, so that first I try to call NETransparentProxyManager.loadAllFromPreferences(). Then if it ends with an error, then I try to set up the configuration and save it via saveToPreferences(). But that also results in the same error (NEVPNErrorDomain error 4.).Here is the code snippet:private func loadProvider() {
...
let activationRequest = OSSystemExtensionRequest.activationRequest(forExtensionWithIdentifier: extensionIdentifier, queue: .main)
activationRequest.delegate = self
// Result is handled in
// request(_ request: OSSystemExtensionRequest, didFinishWithResult result: OSSystemExtensionRequest.Result)
OSSystemExtensionManager.shared.submitRequest(activationRequest)
}
func request(_ request: OSSystemExtensionRequest, didFinishWithResult result: OSSystemExtensionRequest.Result) {
guard result == .completed else {
return
}
loadProviderConfiguration();
}
private func loadProviderConfiguration() {
NETransparentProxyManager.loadAllFromPreferences{ error, arg in
if let loadError = error {
let proto = NETunnelProviderProtocol()
proto.serverAddress = "example.com"
proto.providerBundleIdentifier = Bundle.main.infoDictionary!["CFBundleIdentifier"] as? String
let manager = NETransparentProxyManager.shared()
manager.protocolConfiguration = proto
manager.isEnabled = true
manager.localizedDescription = Bundle.main.infoDictionary!["CFBundleName"] as? String
manager.saveToPreferences(completionHandler: { (saveError:Error?) in
DispatchQueue.main.async {
if let error = saveError {
// NOTE: The error is always:
// Failed to save the filter configuration: The operation couldn’t be completed. (NEVPNErrorDomain error 4.)
return
}
}
});
}
}
}
As I stated previousluy, I don't know what configuration needs to be created/set. So maybe that's the problem, that I don't have any configuration yet. About the configuration: I found that the classes NEAppProxyProviderManager and NETransparentProxyManager have protocolConfiguration. Did you mean this by the configuration?I have been using and implementing Kernel Network Extensions, specifically socket filters. After reading the documentation I understand the API but I'm still kinda lost how to just run a 'Hello World' App Proxy implementation.
1.$ codesign -d --entitlements :- /Applications/MyApp.appYes, the container has the NE entitlements.I also have the developer mode turned on via the utility systemextensionsctl.2.In "System Preferences -> Network" I don't see any reference to my network extension or the bundle.3.There is one line from the log which looks suspicios, but it's not an error:sysextd request contains no authorizationref
eskimo, thank you for your reply!I'd like to start it programmatically from my wrapper app, that previously called OSSystemExtensionManager.shared.submitRequest().I have added following code to successful extension request callback:let manager = NEAppProxyProviderManager.shared()
let session = manager.connection
if session.status != .connected {
do {
try session.startVPNTunnel()
}
catch {
print(error)
}
}But the line 6 throws error: Error Domain=NEVPNErrorDomain Code=1 "(null)" which is configurationInvalid. The documentation mentions errors in configuration of the extension/app.Please, what kind of configuration do I need to create and where should I put it in my project? Is there any example of a minimal configuration for an App Proxy Network Extension?