I need to detect whether iphone is connected to VPN or not, programatically. I am developing a app which try to load URL, this page open only when device is connected to VPN. Before loading this URL I need to check VPN connectivity. I tried the following . But this is not working as expected.
- (BOOL)checkForVPNConnectivity {
NSDictionary *dict = (__bridge NSDictionary *)(CFNetworkCopySystemProxySettings());
//NSLog(@"cfnetwork proxy setting : %@", dict);
return [dict count] > 0;
}
Tip: When you're connected, you'll see VPN on . Open your phone's Settings app. VPN. If you can't find it, search for "VPN." If you still can't find it, get help from your device manufacturer.
Using these loopholes app developers are able to detect users that have an active VPN connection and then correlate a user's true cellular IP to their online activity conducted while using a VPN. This allows Apple or any developer to track VPN use to a particular IP, device, and/or person.
I do not believe that one should determine VPN connectivity by checking for a non-zero number of elements in the CFNetworkCopySystemProxySettings()
. (For example, I see entries when on a WiFi network, but not on a VPN.)
So, two observations:
I would consider using the SystemConfiguration.framework
and use the following code with the hostname of something on your VPN:
- (BOOL)checkForConnectivity:(NSString *)hostName
{
BOOL success = false;
SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithName(NULL, [hostName UTF8String]);
SCNetworkReachabilityFlags flags;
success = SCNetworkReachabilityGetFlags(reachability, &flags);
CFRelease(reachability);
NSLog(@"success=%x", flags);
// this is the standard non-VPN logic, you might have to alter it for VPN connectivity
BOOL isAvailable = success && (flags & kSCNetworkFlagsReachable) && !(flags & kSCNetworkFlagsConnectionRequired);
if (isAvailable) {
NSLog(@"Host is reachable: %d", flags);
return YES;
}else{
NSLog(@"Host is unreachable");
return NO;
}
}
Assuming that success
is non-zero, you might have to do some empirical research on the setting of the bits in flags
. See SCNetworkReachability Reference for the technical definitions of these flags. I've heard claims that they get kSCNetworkReachabilityFlagsReachable | kSCNetworkReachabilityFlagsTransientConnection
when the VPN is connected, but I don't have a VPN, so I cannot test that claim. I'd suggest trying it with and without the VPN up and see if you get different flags
returned.
Unrelated to the problem at hand, your code sample will leak. If using ARC, don't forget to use CFBridgingRelease
or __bridge_transfer
. Or regardless of whether in ARC or not, explicitly call CFRelease
before you return.
If you run the static analyzer (press shift+command+B or choose "Analyze" from the "Product" menu) in recent versions of Xcode, it should warn you about the memory management of Core Foundation calls.
Anyway, this is how I'd be inclined to handle it in ARC:
- (BOOL)checkForVPNConnectivity
{
NSDictionary *dict = CFBridgingRelease(CFNetworkCopySystemProxySettings());
return [dict count] > 0;
}
Simple using this method you can acheive. The list of keys has been changed since iOS 12 and iOS 13
2 keys have been added
utun1 and utun2
so the function should be:
static func isConnectedToVPN() -> Bool {
let cfDict = CFNetworkCopySystemProxySettings()
let nsDict = cfDict!.takeRetainedValue() as NSDictionary
let keys = nsDict["__SCOPED__"] as! NSDictionary
for key: String in keys.allKeys as! [String] {
if (key == "tap" || key == "tun" || key == "ppp" || key == "ipsec" || key == "ipsec0" || key == "utun1" || key == "utun2") {
return true
}
}
return false
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With