How can I know if my app is communicating via VPN? - ios

I am trying to create a flutter+swift app for iOS which could determine if there is an active VPN connection and which could determine if my app is communicating via VPN.
Currently, I am trying to check in my app, if there is any network interface like these (if there is, that would mean the VPN connection is active):
tap, tun, ppp, ipsec, ipsec0, utun1, utun2, pptp
Unfortunately, this doesn't work well. On some iOS devices, I see that there is an existing "ipsec" interface, but there is actually no VPN connection. And on some other devices, I see it working correctly (mostly iOS14+).
I read about it, and it seems that "ipsec" interface is often used for handling WiFi calls and to communicate between Apple devices. Is this right? Does it mean that it's not determinable if this interface will be set (because it can be controlled by the network provider or by the Apple ecosystem)?
I am also wondering if there is a reliable way to tell if the device has an active VPN connection, or at least tell if the given app is using a per-app VPN at the moment?

I think we should just check for tun, ppp, pptp for vpn connections. ipsec and others can be used in WebRTC for video and voice calls.
Future<bool> isVpnActive() async {
bool isVpnActive;
List<NetworkInterface> interfaces = await NetworkInterface.list(
includeLoopback: false, type: InternetAddressType.any);
interfaces.isNotEmpty
? isVpnActive = interfaces.any((interface) =>
interface.name.contains("tun") ||
interface.name.contains("ppp") ||
interface.name.contains("pptp"))
: isVpnActive = false;
return isVpnActive;
}

Related

Knowing status of a bonjour service

I'm using NSNetService and NSNetServiceBrowser to publish and scan for Bonjour services on the network. The implementation is working fine, the services are found on the network and they are capable of communicating. I'm currently trying to understand the framework's lifecycle and this what I've got so far:
// Scanning
netServiceBrowserWillSearch:
netServiceBrowser:didFindService:moreComing: // The device finds itself
// Advertising
netServiceWillPublish:
netServiceDidPublish:
This happens if I start the services with the adapter on. Now I need to know, at all times, whether the service is being actively advertised on the network; that is, if other devices are capable of finding it. So I test it with turning the Wi-Fi adapter off:
netServiceBrowser:didRemoveService:moreComing:
netServiceBrowser:didFindService:moreComing: // The device finds itself again, even after the adapter is turned off
Then I turn the adapter back on:
netServiceBrowser:didRemoveService:moreComing:
netServiceBrowser:didFindService:moreComing: // Yet again
The problem is that there is absolutely no difference in turning the adapter on or off, so I can't look for a pattern. Is there any other way that I can catch these events?
Edit: It gets worst. Even if I start the services with both adapters off (airplane mode) netServiceDidPublish: still gets called. So far it seems that netServiceDidNotPublish: is called only when I try to register the same service twice. This is very counter intuitive to me; maybe the service got published to the adapter, but not the network, and as such these callbacks are very misleading. At this point there is no way I can know whether the service is visible on the network.
For future reference, I needed to use workarounds to solve this. The problem is that Bonjour publishes its services to the protocol stack, so the adapter never gets queried for state. This makes sense, as Bonjour is a multi-transport protocol. In order to solve this I used an adaptation of Apple's reachability framework to listen to adapter state changes for Infrastructural Wi-Fi, at which point I query the adapter for the presence of the adwl0 interface for Wi-Fi direct support. Important note: that article claims to find support for general Wi-Fi connectivity which is not true; the awdl0 interface is the Wi-Fi Direct interface, which is why this will fail in devices such as the iPhone 4/4S. This is OK, because those devices do not support Wi-Fi Direct. As Bonjour also works with Bluetooth, I use CoreBluetooth to listen to Bluetooth adapter state changes. Although this framework is meant for Bluetooth Low Energy, I believe the Bluetooth adapter being on is a strong assurance that the Bonjour services are visible on the network. It's a bit unfortunate that Apple doesn't allow doing this without workarounds, but that's what we get, I guess.

Is there a way to prevent On-demand VPN from being turnned off?

I want to create a VPN configuration profile and enable the use of the On-demand feature. My main goal is to always keep the VPN on, that every connection will go out through the VPN tunnel.
I'm looking for a (programmatic preferred) way to prevent a user from disabling the On-demand feature.
The trick is - I can't use an MDM profile in no way.
Is there anyone here that is familiar with a way to prevent from a user from turning off the On-demand option? No MDM usage?
Thank you
If the user connects via your app why dont you check for a connected state and call
self.targetManager.onDemandEnabled = true;
self.targetManager.saveToPreferencesWithCompletionHandler({ (NSError) -> Void in
})
This way it will save on demand as a preference.
If you can get access to the phone before giving it to the user, and make it supervised, then yes.
From Apple's deployment guide:
Always-on VPN
Overview
Always-on VPN gives your organization full control over device traffic by tunneling all IP traffic back to the organization. The default tunneling protocol, IKEv2, secures traffic transmission with data encryption. Your organizations can now monitor and filter traffic to and from its devices, secure data within its network, and restrict device access to the Internet.
Always-on VPN activation requires device supervision. Once the Always-on VPN profile is installed on a device, Always-on VPN automatically activates with no user interaction. Always-on VPN stays activated (including across reboots) until the Always-on VPN profile is uninstalled.
Swift 5
let targetManager: NEVPNManager = NEVPNManager.shared()
targetManager.isOnDemandEnabled = true;
targetManager.saveToPreferences(completionHandler: { (NSError) -> Void in
})

How do I force an iOS app to use 3G instead of WiFi?

I want to use a messaging protocol that works fine over 3G, but not over some corporate firewalls. How can my app force the use of the cellular network when it fails to connect over WiFi even in the case that the WiFi network is reachable?
EDIT: After reading through the implementation of the Reachability class I remain unsure whether the two are indeed mutually exclusive. It could well be possible to discover both interfaces via gethostbyname(), which I might try just to see what comes out.
Use getifaddrs to enumerate the network interfaces. Look for ifa_name that starts with "pdp." This will be the cellular interface (e.g., pdp_ip0). Test (ifa_flags & IFF_UP) to make sure the interface is up, and get the IP address from ifa_addr. Then use bind() to bind your socket to that address.
Not sure how you activate the cellular interface if it is not already up. Normally, I just make a high level http call to get iOS to wake up the network, but not sure under what conditions the cellular service becomes active when wifi is also available. I suspect it is usually there as a fallback to the wifi.
http://iphonedevsdk.com/discussion/comment/120957
From the looks of that thread, it seems like its impossible. Your best bet may be to try using the protocol, and saying something like "please disconnect from wifi and retry" if it doesn't work.
This thread says just about the same thing:
how to programatically start 3g connection on iphone?
You can use the Reachability class which apple wrote in order to test whether the network connection is currently over 3G or WiFi, and even to check if a specific resource is available on the network.
You can use any of the socket library to force to use cellular. Find the cellular interface from getifaddrs, pass the interface to the socket function, socket bind will happen with cellular. e.g. CocoaAsyncSocket

iOS WiFi probe interval

I am writing an app which connects via WiFi to a proprietary device. The proprietary device acts as a WiFi access point.
When the device powers down, the WiFi connection is terminated, as I would expect.
The iPhone continues to send probe requests, looking for networks to connect to. It follows an exponential backoff algorithm for sending probes.
My problem is that eventually the intervals between the probe requests sent by the iPhone are longer than the timeout on my device, so they don't make a connection.
I am using the Reachability code and it works as I would expect.
It seems that pressing the home button will reset the backoff and send a probe request immediately. Does anyone know of a way to have my app do something similar?
Thanks for any help.
Instead of pinging the internet every time with Reachability, ping a host on the local network like the DNS server or the router (192.168.1.1).
I somehow experienced a similar situation to check if the device was connected in a specific VPN connection. The approach was to ping to a machine in the local network, via standard ping or implementing a ping web service.
If you don't have a backend in your local network then the easiest would be the ping. You can check the following code example from the Apple developer site:
http://developer.apple.com/library/mac/#samplecode/SimplePing/Introduction/Intro.html
I would suspect that if you reconfigure the connection (re-set the WiFi configuration) in your app that the iPhone would restart scanning without the backoff. So your app could keep track of how long it was since the connection was lost and then reconfigure the link after an appropriate amount of time. Possibly you would have to reconfigure to a different SSID and then switch back, depending on how smart the iOS-libraries are.
I'm not shure, if i understand you right. You want to check if the device is still connected to the access point?
I've build an app to connect to a scanner via wifi, the scanner acts as access point. for that i check if the SSID the device is currently connected to is the one of the scanner. to check the CurrentSSID you can use the following code:
+(NSString*)currentSSID {
CFArrayRef myArray = CNCopySupportedInterfaces();
CFDictionaryRef myDict = CNCopyCurrentNetworkInfo(CFArrayGetValueAtIndex(myArray, 0));
if (!myDict) {
return nil;
}
NSDictionary *myDictionary = (__bridge_transfer NSDictionary*)myDict;
return [myDictionary objectForKey:#"SSID"];
}
hope that helps.
I am afraid there is no way of doing so without being rejected during the review (you could read on how to access the SBWifiManager). Apple does not enable any way to access the wifi manager from the sandbox environment. I experienced similar issue connecting my device to various access points (for locating with probe request), up to now with the iOS 7 the probe requests were sent between huge intervals (even 15 min). Try to modify your access points.

How to make iOS believe there is Internet Connectivity

I am working on a web application for iOS that is going to be accesed from a local webserver in a network that has NO internet connectivity at all.
My problem is that everytime an iOS device is locked, it disconnects from the WiFi network, so when the device is unlocked again, it has to reconnect. Part of that reconnection process is determining if there is Internet connection (which there isn't). Until the process is not finished iOS does not allow any DNS resolution (so if I write http://10.0.0.1 it will go there, but not if I request http://something.local.com).
Since we control that network, we want to know how to does iOS verifies Internet connectivity so that we can fake the responses it expects.
I don't know if it's possible to resolve DNS without an internet connection on iOS, but if that's the case, that would be a way better solution since you don't need to mess with your router settings. Use my solution only if it really isn't possible with only code.
I'll suggest you to follow this guide: http://blog.jerodsanto.net/2009/06/sniff-your-iphones-network-traffic to check which actions your iPhone executes to detect an internet connection.
Using this information you could forward the is-there-internet-requests on your router to a local server which fakes the there-is-internet-responses.
This assumes Apple really uses an external server to detect this, which I'm not sure about. But it wouldn't hurt to give it a try!
Have you looked at the Reachability Class? You don't have to use the reachabilityForInternetConnection method, which checks if a default route is available. You can use the reachabilityWithAddress: method and check if your server is reachable.

Resources