Catalina GM seed SystemExtension-based NEPacketTunnelProvider setTunnelNetworkSettings stuck forever

I'm working on moving App NetworkExtension based Packet Tunnel Provider VPN client to SystemExtension in Catalina. The way to set network setting is like

[ g_packettunnel setTunnelNetworkSettings:tns completionHandler:^(NSError * _Nullable error){

if (error) {

os_log(OS_LOG_DEFAULT, "Set tunnel settings failed with error %@", error);

} else {

os_log(OS_LOG_DEFAULT, "Set tunnel settings success");

}

[tns release];

}].

In SystemExtension, the compmletionHandler never be called. However, in App NetworkExtension, it works well.

Does anybody has similar issue? Is this a SystemExtension bug?

Accepted Reply

Just to close this loop on this, there’s a known bug in 10.15.x (r. 56414481) which causes

-setTunnelNetworkSettings:
to never call its completion handler when used in a system extension (as opposed to an app extension). This is reported fixed in the 10.15.4 beta. If you hit this bug, please retry on the current 10.15.4 beta seed (10.15.4b2, 19E234g) and let us know if you continue to have problems.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Replies

Off the top of my head, I’ve no idea what’s causing the call to never complete. My recommendation is that you look in the system log (via the Console app) to see if there’s any hints there.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

The system log (via Console.app) stopped at


[Extension com.mycompany.mytestbundleID]: provider set tunnel configuration to

tunnelRemoteAddress = <10-char-str>

DNSSettings = {

server = (

<11-char-str>,

<9-char-str>,

)

searchDomains = ()

matchDomains = (

<0-char-str>,

)

matchDomainsNoSearch = NO

}

IPv4Settings = {

configMethod = PPP

addresses = (

<11-char-str>,

)

subnetMasks = (

255.255.255.255,

)

includedRoutes = (

{

destinationAddress = <7-char-str>

destinationSubnetMask = 0.0.0.0

},

)

excludedRoutes = (

{

destinationAddress = <10-char-str>

destinationSubnetMask = 255.255.255.255

},

)

overridePrimary = NO

}

MTU = 1400


In App NetworkExtension, after this log, the compmletionHandler be called immediately. The network settings are exact same.

To try and narrow down further what could be happening:


1) If you pass in `nil` once into the NETunnelNetworkSettings, does this clear out any cached or current tunneling sessions and produce a different result in the console app when you try your `tns` network settings again? Is there anything different about this result in the console than your previous?


2) Using a packet capturing tool, and excluding all other traffic, are you able to see any DNS or connection setup attempts? What this may tell us is if the connection is attempting at all.

1) I passed "nil" first, the completionHandler be called immediately with success (error is nil). Then I passed "tns", no completionHandler be called at all. The system log in console.app is like,

//passing "nil"

2019-10-11 13:38:11.046842-0700 0x14be9f Info 0xe2a83 13364 0 nesessionmanager: (NetworkExtension) [com.apple.networkextension:] [Host com.mycompany.mytestbundleID]: setting tunnel configuration

2019-10-11 13:38:11.046581-0700 0x14bf4d Default 0xe2a83 21346 0 com.mycompany.mytestExtensionbundleID: (NetworkExtension) [com.apple.networkextension:Large] [Extension com.mycompany.mytestbundleID]: provider set tunnel configuration to (null)

2019-10-11 13:38:11.048107-0700 0x14bfc3 Default 0xe2a83 21346 0 com.mycompany.mytestExtensionbundleID: Successfully Clear tunnel settings //my log shows completionHandler with nil error be called.

//then passing "tns"

2019-10-11 13:38:11.048510-0700 0x14bf4d Default 0xe2a83 21346 0 com.mycompany.mytestExtensionbundleID: (NetworkExtension) [com.apple.networkextension:Large] [Extension com.mycompany.mytestbundleID]: provider set tunnel configuration to

tunnelRemoteAddress = <10-char-str>

DNSSettings = {

server = (

<11-char-str>,

<9-char-str>,

)

searchDomains = ()

matchDomains = (

<0-char-str>,

)

matchDomainsNoSearch = NO

}

IPv4Settings = {

configMethod = PPP

addresses = (

<11-char-str>,

)

subnetMasks = (

255.255.255.255,

)

includedRoutes = (

{

destinationAddress = <7-char-str>

destinationSubnetMask = 0.0.0.0

},

)

excludedRoutes = (

{

destinationAddress = <10-char-str>

destinationSubnetMask = 255.255.255.255

},

)

overridePrimary = NO

}

MTU = 1400

//After 10 seconds, no completionHandler be called. I tried even 90 seconds, the result is the same.

2019-10-11 13:38:21.050124-0700 0x14bf4d Default 0xe2a83 21346 0 com.mycompany.mytestExtensionbundleID: Setting tunnel parameters timed out


2) I use tcpdump to capture all network packets. Unfortunately, I didn't see any ARP or DNS network packages at the time of "setTunnelNetworkSettings:tns" being called.


I call setTunnelNetworkSettings in NEPacketTunnelProvider handleAppMessage:completionHandler: method. I tried creating a new dispatch queue to invoke it, the result is the same.



Thanks,

Xin

Thank you for the response. So if I am understanding your response correctly it sounds like passing in nil into `setTunnelNetworkSettings` gets the completion block called immediately and passing in your `tns` gets no completion activity as well as no connection setup activity on the interface at the packet level.


From here I think we need to see how your entitlements are setup in your app .entitlements file and also how they are activated using any OSSystemExtensionRequest.activationRequest() code.

Yes. You are right about the scenario.


The App entitlement is:


<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">

<plist version="1.0">

<dict>

<key>com.apple.developer.networking.networkextension</key>

<array>

<string>packet-tunnel-provider</string>

</array>

<key>com.apple.developer.system-extension.install</key>

<true/>

<key>com.apple.security.app-sandbox</key>

<true/>

<key>com.apple.security.application-groups</key>

<array>

<string>$(TeamIdentifierPrefix)com.mycompany.mytestbundleID</string>

</array>

<key>com.apple.security.files.downloads.read-write</key>

<true/>

<key>com.apple.security.files.user-selected.read-write</key>

<true/>

<key>com.apple.security.network.client</key>

<true/>

<key>com.apple.security.network.server</key>

<true/>

</dict>

</plist>


The System Extension entitlement is:


<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">

<plist version="1.0">

<dict>

<key>com.apple.developer.networking.networkextension</key>

<array>

<string>packet-tunnel-provider</string>

</array>

<key>com.apple.security.app-sandbox</key>

<true/>

<key>com.apple.security.application-groups</key>

<array>

<string>$(TeamIdentifierPrefix)com.mycompany.mytestbundleID</string>

</array>

<key>com.apple.security.files.downloads.read-write</key>

<true/>

<key>com.apple.security.files.user-selected.read-write</key>

<true/>

<key>com.apple.security.network.client</key>

<true/>

<key>com.apple.security.network.server</key>

<true/>

</dict>

</plist>


I activate SystemExtension in the App is:


OSSystemExtensionRequest* request = [OSSystemExtensionRequest activationRequestForExtension:@"com.mycompany.mytestbundleID.PacketTunnel" queue:dispatch_get_main_queue()];

request.delegate = (id)self;

[[OSSystemExtensionManager sharedManager] submitRequest:request];


System Preferences will be requested to be launched to Allow the SystemExtension. I Allow it. Then I use "systemextensionsctl list", I can see the SystemExtension is "[activated enabled]". After that, in the App, it load NETunnelProviderManager, then call NEVPNConnection.startVPNTunnelAndReturnError, I can see the SysemExtension process ( /Library/SystemExtensions/E7EF657E-F2EB-446A-8630-120A52F6098E/com.mycompany.mytestbundleID.PacketTunnel.systemextension/Contents/MacOS/com.mycompany.mytestbundleID.PacketTunnel ) be launched by launchd, and NEPacketTunnelProvider.startTunnelWithOptions() be invoked.

Thank you for this information and the debugging steps to reproduce this issue. In looking at your System Extension entitlements, I am wondering if your extension needs to access the keychain to use the stored VPN credentials but it is stalling because it does not have access.


<key>keychain-access-groups</key>
<array>
<string>com.apple.managed.vpn.shared</string>
</array>


Referenced from the NETunnelProviderManager docs.

According to Network Extension Framework Entitlements, com.apple.managed.vpn.shared entitlement "is only necessary if your VPN supports configuration via a configuration profile and needs to access credentials from that profile". I don't use any configuration profile, and no keychain accessing required at all in this testing App. I basically programmatically create a testing NETunnelProviderManager, call NETunnelProviderManager.saveToPreferencesWithCompletionHandler to save it, then start tunnle.

Here is my code to create testing NETunnelProviderManager,


NETunnelProviderManager *m = [[NETunnelProviderManager alloc] init];

NETunnelProviderProtocol *protocol = [[NETunnelProviderProtocol alloc] init];

protocol.providerBundleIdentifier = (NSString *)@NEVPN_TEST_EXTENSION_BUNDLE_ID; // bundle ID of tunnel provider

NSMutableDictionary *providerConfig = [NSMutableDictionary new];

providerConfig[@"Testing Configuration"] = @"TestingJDids98aFJ#QFEP#JFEL";

protocol.providerConfiguration = providerConfig;

protocol.serverAddress = @REMOTE_TUNNEL_SERVER_IP;

protocol.username = @"testuser1";

[providerConfig release];

m.protocolConfiguration = protocol;

m.localizedDescription = name;

[protocol release];

Thank you for confirming that your application is not using configuration profiles. Are you still using the Catalina GM Seed or have you updated to the full release?

No. I've updated to macOS Catalina latest official release 10.15 (19A602). For me, nothing is change, system still doesn't invoke setTunnelNetworkSettings.completionHandler.

Thank you for confirming that you are on the latest release of Catalina (19A602). To try and further diagnose what is happening on your project I think it would be good to open up a DTS technical support incident for further investigation.

Thank you for helping. Already filed TSI.

Just to close this loop on this, there’s a known bug in 10.15.x (r. 56414481) which causes

-setTunnelNetworkSettings:
to never call its completion handler when used in a system extension (as opposed to an app extension). This is reported fixed in the 10.15.4 beta. If you hit this bug, please retry on the current 10.15.4 beta seed (10.15.4b2, 19E234g) and let us know if you continue to have problems.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"