iOS NWUDPSession.isViable vs NWUDPSessionState ready

I have a custom PacketTunnelProvider configured to catch all traffic on the 10.0.0 subnet and a server that can handle it listening at port 8080. I can call startTunnel from its containing app, and its completion handler gets called with a NETunnelProviderManager.

I can see the NWUDPSession of the extension go from preparing to ready. When it gets to ready, I set the NWUDPSession read handler and have it start handling packets. However, in settings, the VPN is still connecting, and NWUDPSession.isViable is false.

When I bring up a browser and go to 10.0.0.1:8080, I can see SYNs and ACKs coming out of the tunnel going to the server and back into the tunnel, and then a http request for a favicon going to the server and its 404 coming back followed by a FIN/ACK out of the tunnel. But the request for the specific resource never gets out. Without the VPN, the browser sends the resource request followed by the favicon request.

During this time, the VPN is still connecting, and the browser says there is no internet. What am I missing? It seems there is something else to do to make it connected, but I can't figure out what it is.

It seems there is something else to do to make it connected, but I can't figure out what it is.

The important thing here is that a server actually processing an HTTP request and responding back with a 404 means that the server is reachable over HTTP through the tunnel. It sounds like there is a routing issue between the client / tunnel / server but that is something you will need to determine. If your tunnel was not connected at all your would not even see a 404 or FIN/ACK going through.

As to what is happening with the NEVPNStatus, I would say that if you this does not show up as connected in a second or two after connecting to your tunnel then you may want to scratch what I mentioned above and take a look at your server logs to ensure that your tunnel is actually reaching the server.


Matt Eaton
DTS Engineering, CoreOS
meaton3@apple.com
Hi Matt,

I can log packets coming out of the read handler and going into the write handler, where I write packets to the NEPacketFlow. I also have a wireshark on the server that shows the packets coming in and the ones coming out.

I know that there is something working because of what is going through and coming back. I guess my main question is what exactly what makes the NWUDPSession.isViable == true, which I am also guessing will make the VPN show as Connected in the settings and display the little VPN notification at the top of the screen. All I can get from the API, and handle in the observer, is that the NWUDPSessionState becomes ready, but isViable always == false. What event(s) or trigger(s) has to happen to make NWUDPSession.isViable become true?

The extent of the documentation is that isViable, readonly, is:
Code Block
The viability of a UDP session represents whether or not data can be transferred.

And the NWUDPSessionState ready is:
Code Block
The session is ready for reading and writing data.



Also to add to what you mentioned about NEVPNStatus, I am catching the notifications for this in the container app, and NEVPNStatusConnecting comes in, but NEVPNStatusConnected never does.

Also, do the settings require NEProxySettings to handle http/https traffic? I can see when I used NEProxySettings with a dummy endpoint, 127.0.0.1:54321, that browsers say the server can't be reached rather than saying there is no internet, which tells me that http/https requests go straight to the proxy server because I can see they never come through the NWUDPSession read handler. At this point, I would ask if there is a way to get the http packets as they come out of the VPN using a NWUDPSession read handler.

If a proxy is required, then why does the http request for the favicon make it to the read handler without the proxy setting?
Still more to add...the above was running on an XR with 14.4.1. On a 5s with 12.5.1, the favicon request never makes it to the read handler, which is leading me to the NEProxySettings being required for http/https, at least for a NWUDPSession. If so, is there any way with a PacketTunnelProvider that all ip and tcp packets can be grabbed out of the tunnel without writing a proxy server for http traffic?

I guess my main question is what exactly what makes the NWUDPSession.isViable == true, which I am also guessing will make the VPN show as Connected in the settings and display the little VPN notification at the top of the screen.

If you experiencing inconsistencies with isViable I would use NWUDPSessionState.ready as a status to let your provider know when to read / write data on the connection.

What event(s) or trigger(s) has to happen to make NWUDPSession.isViable become true?

As far as I know this is based off updates to the path. However, I do not see this documented anywhere so I would open an Enhancement Request for documentation on this.

Also, do the settings require NEProxySettings to handle http/https traffic?

The NEProxySettings should be able to handle either HTTP or HTTPS traffic.

If so, is there any way with a PacketTunnelProvider that all ip and tcp packets can be
grabbed out of the tunnel without writing a proxy server for http traffic?

If you are not seeing this traffic I would go back and debug your NEPacketTunnelNetworkSettings.


Matt Eaton
DTS Engineering, CoreOS
meaton3@apple.com
Hi Matt,

As I said in my first post, I am using NWUDPSessionState.ready as a status to let the provider know when to read / write data on the connection:

> I can see the NWUDPSession of the extension go from preparing to ready. When it gets to ready, I set the NWUDPSession read handler and have it start handling packets. However, in settings, the VPN is still connecting, and NWUDPSession.isViable is false.

And I wasn't asking if NEProxySettings should be able to handle either HTTP or HTTPS traffic, I was asking if it is *required* to handle http traffic. Also, there are no inconsistencies with isViable - it is always false.

Seeing that there are no answers for what I thought were direct questions, I'll post back here when I figure it out.
If you get stuck, open a TSI and I can take a deeper look at what is going on with your project.

Matt Eaton
DTS Engineering, CoreOS
meaton3@apple.com
Here is my provider startTunnel code

Code Block
override func startTunnel(options: [String : NSObject]?, completionHandler: @escaping (Error?) -> Void) {
let newTunnel = ClientVpnTunnel()
newTunnel.delegate = self
let settings = NEPacketTunnelNetworkSettings(tunnelRemoteAddress: "127.0.0.1")
settings.ipv4Settings = NEIPv4Settings(addresses: ["10.0.0.8"], subnetMasks: ["255.255.255.255"])
settings.ipv4Settings?.includedRoutes = [NEIPv4Route(destinationAddress: "10.0.0.1", subnetMask: "255.255.255.0")]
settings.ipv4Settings?.excludedRoutes = []
settings.dnsSettings = NEDNSSettings(servers: ["208.67.222.222", "208.67.220.220"])
settings.dnsSettings?.matchDomains = [""]
self.setTunnelNetworkSettings(settings) { error in
if let e = error {
NSLog("Settings error %@", e.localizedDescription)
} else {
simpleTunnelLog("Before newTunnel.startTunnel")
if let error = newTunnel.startTunnel(self) {
completionHandler(error as NSError)
}
else {
simpleTunnelLog("setTunnelNetworkSettings successful")
// Save the completion handler for when the tunnel is fully established.
self.pendingStartCompletion = completionHandler
self.tunnel = newTunnel
}
}
}
}

I see "setTunnelNetworkSettings successful" on the console, and using ios 14.4.1, I can see traffic like I said above from and to 10.0.0.8 and 10.0.0.1 in Wireshark on the server (10.0.0.1). I also have logging statements to the console at the top of the read and write handlers that match the hex I see going in and out of Wireshark on the server.

Yet I see nothing on ios 12.5.1.

I made request 765462285 for this.

I made request 765462285 for this.

Thank you. I see this incident internally and have added it to my queue.


Matt Eaton
DTS Engineering, CoreOS
meaton3@apple.com
iOS NWUDPSession.isViable vs NWUDPSessionState ready
 
 
Q