NEPacketTunnelProvider does not seem to be capturing all the traffic

Hello,

I initially started the discussion over at Swift Forums because I am using SwiftNIO but it appears that it makes more sense here.

I have an app with NetworkExtension of the packet tunnel provider type. So I am using the NEPacketTunnelProvider. As part of the extension, I have SwiftNIO server with connect proxy which is used to route the traffic.

This works great in almost all cases, but apps like Signal or WhatsApp don't work. They don't display any kind of "no connection" indicator but the messages aren't send or received.

Over at Swift Forums I got an answer from Quinn “The Eskimo!” that I think points to the actual problem:


My experience is that a lot of these ‘chat’ apps explicitly bind their
connections to the WWAN interface, which means they don’t use the
default route and thus aren’t seen by the packet tunnel provider.

My packet tunnel provider is configured to use the default routes for IP4 and IP6.

So my concern is how to configure it, that it works also for the chat apps? There are couple of apps from the App Store that I tried which use this same approach and while they are active, Signal works fine.

Yes, I know this solution is not ideal and not the main intended usecase for packet tunnel, but it is the only option available on iOS..

Thanks for help! Happy to clarify further.

Replies

Hello @nemecek_f!

Regarding your questions:

My packet tunnel provider is configured to use the default routes for IP4 and IP6.

So my concern is how to configure it, that it works also for the chat apps?

Quinn is correct, if these applications are binding to an interface that gets routed before the default route is used, then this traffic will never be claimed by your tunnel's default route. One approach that you can use is to interrogate your device's network interfaces to see how your routing table is "presumably" routing traffic before your tunnel is added to the equation. This should point you in the right direction but I will leave that up to you on how to research and implement this. The main thing to remember here is that the default route acts as a catch all if one of the other routes does not claim the traffic first.

Yes, I know this solution is not ideal and not the main intended usecase for packet tunnel, but it is the only option available on iOS..
The use-case I am working on is more a malicious sites and adblocker kind of an app.

Having said that above, I will stand by my comments from the Swift Forums that your use case for blocking or denying traffic that is flagged as malicious is by default a content filter action and not suitable for a Packet Tunnel. An Packet Tunnel assumes that if you read packets from the virtual interface then at some point you write them back after they have traversed the network. Now, there is nothing technically stopping you from doing this, but it would be considered a non-supported use case for a Packet Tunnel.


Matt Eaton
DTS Engineering, CoreOS
meaton3@apple.com

but it would be considered a non-supported use case for a Packet
Tunnel.

… which means you’ll run into various obscure edge cases (this being one of the simpler ones, btw) that may not have good solutions, and such solutions that you do find are likely to be very brittle.

Sorry to be the [co-]bearer of bad news here.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"
So in the end I managed to make some progress. Getting all the IP4 routes and setting them manually seems to help.

But I discovered that Facebook Messenger is somehow bypassing my VPN. This is the only app that seems to do this. But even if I completely stop the traffic going through (just for the test), then nothing obviously works, but sending messages with Messenger works fine.

How is this possible?

Another point I discovered is that if I include the NEIPv4Route.default() then this alone causes Signal and WhatsApp to not work. 🤔
RE: my recent post. So actually the reason for Messenger to circumvent the tunnel is that it somehow fallbacks to cellular data. It did not occur to me to investigate this option

So actually the reason for Messenger to circumvent the tunnel is that it somehow fallbacks to cellular data.

This traffic may be binding to the cellular interface, as mentioned previously. If you had the NEIPv4Route.default() route set only you would miss this traffic.


Matt Eaton
DTS Engineering, CoreOS
meaton3@apple.com
Yes, but I tried it with the cellular data turned off. So even if Messenger were to bind to this interface, it should not go through?
Found the enforceRules configuration property.


A Boolean value that indicates whether route rules for this tunnel take precendence over any locally defined routes.

Which kind of sounds like something I need, but setting it to true does nothing regarding Messenger.
Apologies for talking to myself there 🤪 but I made interesting discovery. If I use the includeAllNetworks configuration, then this finally seems to rein in Messenger and does not let is around the tunnel.

That is great but it has the side-effect of once again breaking Signal, WhatsApp and probably other similar apps. I checked Signal debug logs and found that I cannot find a server by hostname. Which suggested DNS issue. So I re-added DNS configuration, added these IPs to the excludedRoutes and now Signal works but only one way. I can send messages, they are delivered but I cannot receive messages.

I still think that the fact that Messenger can just go around the tunnel is the main issue.

Hi @nemecek_f

I'm having the exactly same issue. Did you manage to solve it? Many thanks!