how to detect iphone's VPN connectivity?
Asked Answered
C

4

5

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; 
 }
Compendious answered 29/4, 2013 at 17:50 Comment(3)
What is CFNetworkCopySystemProxySettings returning when VPN is connected vs when VPN is not connected? You say it's "not working as expected", but you don't say what it's doing.Calcariferous
When we are connected to VPN CFNetworkCopySystemProxySettings should return more than zero objects.Compendious
I've seen posts suggesting CFNetworkCopySystemProxySettings, as well. But for me, I see zero entries when on cellular, but a couple of entries whenever I'm on my home wifi (but not VPN in either scenario). Bottom line, the presence or absence of entries, alone, is clearly not a valid way of detecting VPN. Hopefully the SystemConfiguration.framework suggestion, below, will be more promising.Calcariferous
C
7

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:

  1. 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.

  2. 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;
    }
    
Calcariferous answered 29/4, 2013 at 18:19 Comment(5)
Solution 2 always returns at least 3 elements with wifi for me.Trachoma
@PierredeLESPINAY Agreed. As you see in my comments to the original question, I see the same behavior. I do not believe that one should determine VPN connectivity by checking for a non-zero number of elements in the CFNetworkCopySystemProxySettings(). I was simply fixing the memory leak in the OP's code sample. I've attempted to clarify my answer.Calcariferous
Thx. I've been able to check the VPN status in any case by combining both solutions.Trachoma
I'm also combining these solutions, but I'm still worried about this checking for CFNetworkCopySystemProxySettings() in case of Cellular network. Is there any reliable source for this solution? Why would it always return zero entries when connected via Cellular network + VPN?Sandasandakan
I know it's been decades since this answer was posted/discussed, but does anyone have a list of the variables of the CFNetworkCopySystemProxySettings() that can be related to the VPN? ThanksSpecialist
I
1

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

}

Interlocutrix answered 10/5, 2021 at 11:5 Comment(0)
C
0

You can use simple workaround for the above mentioned problem.

Just use apple reachability to check wherther ios device is connected to internet or not. If not throw no internet connection error.If yes,try to access your VPN dependant URL using NSURLConnection.If you get success 200 like that,i.e you are connected to VPN.If this request returns host not found or any error like -1001 means you are not connected to VPN.Then you can throw corresponding VPN connectivity error to the user.Happy coding.... Arun kumar

For more information please refer my blog http://aruntheiphonedeveloper.blogspot.in

Cran answered 14/2, 2015 at 8:14 Comment(1)
your blog is restricted for everyone!Exhaustive
R
0
let connect=ConnectVPN()
        connect.loadFromPreference()
        DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
            let status=NEVPNManager.shared().connection.status
            print(status)
        }

Where load preference is

 public func loadFromPreference(){
        do {
            try self.vpnManager.loadFromPreferences(completionHandler: {
                error in
            })

        } catch let error {
            print("Could not start VPN Connection: \(error.localizedDescription)" )
        }
    }

Then in status you get vpn status which is disconnected ,invalid and connected etc you can read about it from this link https://developer.apple.com/documentation/networkextension/nevpnstatus hope this will help you happy coding:)

Refugio answered 2/5, 2018 at 5:25 Comment(1)
Can NEVPNManager supported in objective C ?can you show some code in objective C to detect is the connection in vpn or not?Czech

© 2022 - 2024 — McMap. All rights reserved.