iOS: Some apps seem to bypass NEPacketTunnelProvider. How to enforce it? - ios

I am working on a NetworkExtension which uses the NEPacketTunnelProvider to provide VPN-like tunnel so I can modify the traffic.
This works great for basically all the apps I tried so far, but Facebook Messenger seems to be able to ignore it. I first see that the traffic goes through the tunnel, should be blocked (for testing), but then the messages are successfully sent anyway.
To me this suggests that Messenger first goes through the tunnel and when that does not work, it has some kind of fallback. This happens whether I am on Wifi or cellular data. At first I thought that it may somehow fallback to cellular when WiFi does not work, but even when I disable cellular on the iOS level, Messenger still works when the tunnel is active.
I tried getting all the system routes (meaning the IPs and masks) and manually setting them to includedRoutes on the NEIPv4Settings but this has no effect.
Does this look like the Messenger is indeed bypassing the VPN tunnel? Or maybe something else is at play?
So far I have tried basically all configuration combinations and nothing seems to affect Messenger in any way. Apps like Signal, Instagram, YouTube and other can be successfully cut off the network with the tunnel.
EDIT: Found this on the official Apple forums: https://developer.apple.com/forums/thread/122330
Actually Facebook Messanger sends traffic to all active interfaces in iOS. It even sends tarffic out trough Cellular, when mobile data is disabled from settings.
EDIT 2: I tried the new iOS 14 configuration option includeAllNetworks which seems to work for Messenger but somehow messes up other apps like Signal or WhatsApp.
When I don't have this flag on, Signal work with my VPN on and I can see its traffic, but when I enable this flag Signal does not send messages nor receives them.

Apps can use low level API and force traffic via some interface (using bind for example), and go outside your VPN.
The way to enforce using the VPN is to enable the flag includeAllNetworks on your VPN configuration -
manager.protocolConfiguration!.includeAllNetworks = true

Related

iOS app cannot connect to server over LTE network on iOS 14.7.1

Since last week one user of an app of mine is reporting that the app cannot reach the server on a cellular network. His phone is running iOS 14.7.1 and he has an LTE network connection. The app works perfectly on wifi and I have not had any reports of other users not being able to use the app on cellular networks.
First I thought it was a network detection issue (reachability not being able to see the cellular network), but when I ignore the network detection and simply make the HTTPS request, it does not connect. There is no response from the server. The weird thing is that this is an app with a Google map. The map loads, but the location markers that come from my server are not loaded.
I cannot think of any reason why this is happening and as my testing options are very limited (only this one user is reporting it, I cannot replicate myself), I am kind of lost as to what causes the issue, let alone how to fix it. Are there any settings that I should be aware of for connections over LTE networks to work? Have any new settings been introduced in iOS 14.7 that might affect this? Should the user make any changes on his phone to allow my app to use the cellular network?
I am using a very standard URLSession datatask with an URLRequest to make the call (which works without any issue over wifi).

See devices connect to my wifi router using Swift and allow/block wifi acces

In short i'm trying to build an App that will grant/block wifi access to my son's wifi for his Ipad and his PS4 remotely using an App. I researched the topic and can't figure out how this can be done. Ideally i'd like to be able to grant/block wifi access independently Ie. block wifi to the Ipad and allow PS4.
How can this be done, no need for the full code ( well if you insist i'll take it ) but just point me in the right direction.
Depending on the router you're using you're going to need to write something that interacts with the router's API, if it has one. If it doesn't, you will need to replace the firmware on your router with something like ddwrt that can be scripted. From there, you might be able to create an app that talks to the router's API.
TLDR: You're probably better off simply bookmarking the management page for the router and enabling/disabling access for the devices.
Edit:
It occurred to me that some mainstream consumer router/access point manufacturers (Linksys, Asus, etc) have companion apps for managing their devices from the LAN side. You should see if such an app exists for your router, and if not, perhaps consider getting a different router that supports such an app.

how to disable wifi assist without user interaction

I have couple of URLs that has to be called(programatically) through wifi not with mobile data.
As WIFI ASSIST is on , whenever the wifi is weak ,packets get transferred through Mobile data.
I would like to stop this from happening.
As far as I have researched, there is no API to toggle wifi assist switch on and off programatically
I can find if the user has mobile data and wifi on with the help of Reachability Class I believe and I can alert the user to keep wifi assist off but this is a very bad user experience.
so I decided to look if its possible to be done with the help of iOS mobile configuration file.
But I couldn't find any keys related with wifi-assist in Apple configuration profile reference.
so I am wondering , is it possible to force wifi to be used for certain URLs.
I remember this is possible with VPN ON DEMAND we can have certain domains to be accessed via VPN.
I am wondering if same is possible for wifi as well through configuration profile
Any suggestions are welcome.
As others have mentioned, there is no way to do manipulate this setting programmatically in iOS. This is not really what you are asking, as you seem to already know the answer to this is "No".
You are asking about the configuration profile, so I am assuming these are managed devices. Unfortunately, there is no configuration profile payload I am aware of that forces the managed devices to disable Wi-Fi Assist.
Your intent, however, is a bit different than what is being asked, I believe. I think you basically have an app that communicates with a resource that is only accessible via the Wi-Fi network (likely a corporate Wi-Fi network). If the app tries to connect to the resource while on cellular, it will not be able to connect. In some cases, when the Wi-Fi signal is weak, the device tries to be helpful and switches to cellular, causing issues with the app. If we could figure out a way to force iOS to not take advantage of Wi-Fi Assist when your app is running, you would be in good shape.
If you can install this app as a managed app, there is a way to identify that the app should only be allowed to run on a Wi-Fi connection. Setting the network usage rules AllowCellularData to false should do this (see this for more details). The thing I am not sure of with this solution, is whether this simply causes the connections to fail when Wi-Fi Assist is on and active, or if it makes iOS prefer to not use Wi-Fi assist when the app is running because it cannot connect over cellular. So I think you can tell an app to only connect over WiFi, but it doesn't really give you a better solution to your user experience problem. The only think it really buys you is that your app connection won't ever try to connect when connected to cellular. There is a chance, however, if you change this value to false for your app bundle ID, it will prevent Wi-Fi Assist from enabling when your app is running. I don't have access to MDM to try it out, but you could test and see.
Ultimately, given that this is probably a corporate device situation, I think you are going to have to address this through user training. The good news is that this is a one-time step. Sure, users may have slight degradation of network performance when Wi-Fi signal is weak but cell signal is strong. This does not matter as much if these are corporate devices where the corporate apps will mostly work only on the company's Wi-Fi network.
Another solution is what you mentioned, basically using on-demand VPN to provide a connection to the internal resources. This is additional infrastructure work, and you already mentioned it, so I'm not sure if it is even an option.
Obviously, the other solution would be to expose the network resources through your firewall, which could allow you to access it over cellular. I'm suspecting this is not possible due to security constraints.
Unfortunately, there are not a lot of good options in this space. However, have hope that there is some way to do it, as Sonos appears to have done something to
allow their app to avoid switching to WiFi Assist while streaming to a local network resource: https://sonos.custhelp.com/app/answers/detail/a_id/4257/~/wi-fi-assist-and-sonos
I wonder if you could have your app open a streaming audio connection to a fixed local network resource, which would cause it to use Wi-Fi. It's a pretty crazy hack, but with a low enough bitrate audio file streaming, it might do what you need while not eating up too much of the network throughput.
Per Apple's notes on Wi-Fi Assist:
Wi-Fi Assist won't automatically switch to cellular if you're data
roaming.
Wi-Fi Assist only works when you have apps running in the
foreground and doesn't activate with background downloading of
content.
Wi-Fi Assist doesn’t activate with some third-party apps
that stream audio or video, or download attachments, like an email
app, as they might use large amounts of data.
Of course the other possible solution that you could consider is improving your Wi-Fi coverage to that the signal doesn't get bad enough for Wi-Fi Assist to be needed. I know this may not be feasible, but wanted to put it out there.
Good luck with this!
There is no public API that allows you to enable/disable "Wi-Fi Assist", and even if you find a way to do it your app will be rejected.
No you can not enable or disable WiFi by programmatically and there is no API for this.

How to select specific network interface for NSURLSession connections?

I’m not talking about Reachability.
What I’m talking about is figuring out how to create a network connection from an iOS device across the cellular interface.
Why? Because I have conditions where the device connects to a WiFi access point so it chooses WiFi… but that access point is not internet connected and goes nowhere. I have data which I must make every effort to deliver and it some cases it’s getting lost in the WiFi gateway to purgatory. In both cases of using Reachability and relying on MPTCP, Apple has already given priority to WiFi in the stack.
I know NSURLSessionConfiguration can set allowsCellularAccess to allow cellular access — I’m looking to require cellular for the routing.
Even at the CFNetwork level I’m looking at kCFStreamPropertyConnectionIsCellular for status, kCFStreamPropertyNoCellular to disable cellular.
I can’t find anyway to give preference to the cellular radio. I realize Apple has gone to great lengths to prefer WiFi and I’m going against that — which is why I’m having such difficulty finding an answer to this.
I'd like to keep this up in the Cocoa level, but not opposed to going into Foundation or deeper levels. I would like to avoid trying to parse an interface table (if it's even accessible) to figure out which is the cellular interface.
Has anyone successfully created a network connection across the cellular link despite WiFi appearing to be present?
Is some configuration of Multipath TCP the answer here?
To bind to a particular interface, as far as I'm aware, you'd have to drop all the way down to the raw socket level, and there's no way to provide a custom socket for NSURLSession purposes, so you'd basically be rewriting it from scratch. You should file a bug asking for support for binding an NSURLSession to a source IP.
The behavior you're experiencing is a known problem with iOS and disconnected networks. iOS 9 and later do a better job, but even then, they can be highly problematic; the devices sometimes refuse to talk to the Wi-Fi network, and sometimes refuse to talk to the cellular network. Specifically, it seems to fail spectacularly if either signal is weak. Just this morning, I actually had to force my iPhone (iOS 10) to talk to a disconnected Wi-Fi network by putting it in Airplane mode and enabling only Wi-Fi.
I'm told that you can fix this by configuring the network's DHCP server to not provide a router advertisement; that said, every time I've tried that, the iOS device would just keep asking for an offer repeatedly. Maybe that bug got fixed at some point. If so, it might be worth a shot, but don't expect it to work in older versions of iOS.
Failing that, assuming you don't need to support web browsers in iOS 3 and earlier, you might try eliminating the DHCP server on that Wi-Fi network entirely, and just rely on DNS service discovery with zero-conf IPs. That way, the device won't see a router, and it won't try to send data out that interface except to those link-local IPs.
If that isn't possible for some reason, ordinarily I would suggest using a customized copy of libcurl, except that I doubt this will work in your case, because POSIX networking doesn't wake the cellular hardware.
In iOS 12 and later you can use the Network Framework. Sample code is here.

Examining TCP traffic from an iOS device

Is there an app or clever way to check TCP:IPv4 traffic for a host:port on iOS devices? Users will be connecting to a device with an iOS app, and if there is an existing way to sniff or otherwise log TCP (and any IP traffic) on an iPad that would be super useful. We could eventually add this into the app, but it seems like there has got to be a nice app for inspecting a network... e.g. some of the functionality of wireshark, socat, and nmap. I don't seem to be able to use the right search terms in the app store and I'm also wondering if there is a way to do this in the Safari browser?
I ended up using iTelnet and turning off all the login scripts. That will connect to any ip:port with TCP.

Resources