NWUDPSession only works when there is a sim card installed

Hi There,

I built a VPN using NEPacketTunnelProvider and created the UDP session using createUDPSessionToEndpoint:fromEndpoint:(https://developer.apple.com/documentation/networkextension/neprovider/1406004-createudpsessiontoendpoint?language=objc).

When I tested on an iPhone with sim card installed, everything works fine with or without a wifi connected.

However, when I removed the sim card from the iPhone, even if my wifi is still connected, I can no longer connect to the backend. And the session above falls into the failed state every time. I disabled the VPN, my phone can open any website as normal.

I tried to reboot my iPhone multiple times, delete the app and reinstall multiple times, no luck. As soon as I inserted my sim card into the device, the app starts working fine again.

However, when I removed the sim card from the iPhone, even if my wifi is still
connected, I can no longer connect to the backend. And the session above falls into the
failed state every time

Interesting. I am assuming that if NWUDPSession is failing that your tunnel is in a disconnected state as well? If so, how are you configuring the routes for your NEPacketTunnelNetworkSettings? Are you using a route that only matches the NEIPv4Route for the cellular interface? Just as a test, if you remove your routes and set the default route(s) to act as a backstop to pickup anything that was not matched in your routing table, do you see this work?



Matt Eaton
DTS Engineering, CoreOS
meaton3@apple.com
Here is how I config the network settings, I am not doing any matches based on my own understanding:

Code Block Objective-C
NWHostEndpoint* hostEndpoint = [NWHostEndpoint endpointWithHostname:address port:port];
NSMutableArray<NSString*>* ipv4Addresses = [[NSMutableArray alloc] init];
NSMutableArray<NSString*>* ipv4Masks = [[NSMutableArray alloc] init];
NSMutableArray<NSString*>* ipv6Addresses = [[NSMutableArray alloc] init];
NSMutableArray<NSNumber*>* ipv6PrefixLengths = [[NSMutableArray alloc] init];
for (...) {
if (ip == IPV4) {
[ipv4Addresses addObject:[NSString stringWithUTF8String: ip]];
[ipv4Masks addObject: mask];
}
if (ip == IPV6) {
[ipv6Addresses addObject:[NSString stringWithUTF8String:ip]];
[ipv6PrefixLengths addObject:@(prefix())];
}
}
NEIPv4Settings* ipv4Settings = [[NEIPv4Settings alloc] initWithAddresses:ipv4Addresses
subnetMasks:ipv4Masks];
ipv4Settings.includedRoutes = @[ [NEIPv4Route defaultRoute] ];
NEIPv6Settings* ipv6Settings = [[NEIPv6Settings alloc] initWithAddresses:ipv6Addresses
networkPrefixLengths:ipv6PrefixLengths];
ipv6Settings.includedRoutes = @[ [NEIPv6Route defaultRoute] ];
NSMutableArray<NSString*>* dns = [[NSMutableArray alloc] init];
for (...) {
[dns addObject:[NSString stringWithUTF8String: dns]];
}
NEDNSSettings* dnsSettings = [[NEDNSSettings alloc] initWithServers:dns];
NEPacketTunnelNetworkSettings* networkSettings =
[[NEPacketTunnelNetworkSettings alloc] initWithTunnelRemoteAddress:address];
networkSettings.DNSSettings = dnsSettings;
networkSettings.IPv4Settings = ipv4Settings;
networkSettings.IPv6Settings = ipv6Settings;
[self setTunnelNetworkSettings:settings
completionHandler:^(NSError *_Nullable error) {
id session = [self createUDPSessionToEndpoint:hostEndpoint fromEndpoint:nil];
...
}];


When debugging a situation like this I find it helpful to remove all of the NEPacketTunnelNetworkSettings down to a few basic rules that you know will claim traffic and then build from there. For example, I find that creating 1 NEIPv4Settings with the NEIPv4Route.defaultRoute, and 1 domain for NEDNSSettings will give your app some traffic to claim and test out. Once you have that going, you should be able to build onto your settings little by little and this should reveal your problem.


Matt Eaton
DTS Engineering, CoreOS
meaton3@apple.com
NWUDPSession only works when there is a sim card installed
 
 
Q