【问题标题】:how to detect iphone's VPN connectivity?如何检测 iPhone 的 VPN 连接?
【发布时间】:2013-04-23 11:59:42
【问题描述】:

我需要以编程方式检测 iphone 是否连接到 VPN。我正在开发一个尝试加载 URL 的应用程序,此页面仅在设备连接到 VPN 时打开。在加载此 URL 之前,我需要检查 VPN 连接。我尝试了以下 .但这并没有按预期工作。

- (BOOL)checkForVPNConnectivity {
  NSDictionary *dict = (__bridge NSDictionary *)(CFNetworkCopySystemProxySettings());
  //NSLog(@"cfnetwork proxy setting : %@", dict);
  return [dict count] > 0; 
 }

【问题讨论】:

  • 什么是CFNetworkCopySystemProxySettings 在 VPN 连接和 VPN 未连接时返回?你说它“没有按预期工作”,但你没有说它在做什么。
  • 当我们连接到 VPN 时,CFNetworkCopySystemProxySettings 应该返回超过零个对象。
  • 我也看到过建议CFNetworkCopySystemProxySettings 的帖子。但对我来说,在蜂窝网络上我看到零条目,但每当我在我的家庭 wifi 上时看到几个条目(但在任何一种情况下都没有 VPN)。归根结底,条目的存在或不存在显然不是检测 VPN 的有效方法。希望下面的SystemConfiguration.framework 建议会更有希望。

标签: iphone ios objective-c vpn


【解决方案1】:

我认为不应通过检查 CFNetworkCopySystemProxySettings() 中的非零元素数来确定 VPN 连接。 (例如,我在 WiFi 网络上看到条目,但在 VPN 上看不到。)

所以,有两个观察结果:

  1. 我会考虑使用SystemConfiguration.framework 并将以下代码与您的 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;
        }
    }
    

    假设success 不为零,您可能需要对flags 中的位设置进行一些实证研究。有关这些标志的技术定义,请参阅 SCNetworkReachability Reference。我听说他们在连接 VPN 时收到 kSCNetworkReachabilityFlagsReachable | kSCNetworkReachabilityFlagsTransientConnection,但我没有 VPN,所以我无法测试该声明。我建议在启用和不启用 VPN 的情况下尝试一下,看看您是否得到不同的 flags 返回。

  2. 与手头的问题无关,您的代码示例会泄漏。如果使用 ARC,请不要忘记使用 CFBridgingRelease__bridge_transfer。或者无论是否在 ARC 中,在返回之前显式调用 CFRelease

    如果您在最新版本的 Xcode,它应该警告您有关 Core Foundation 调用的内存管理。

    无论如何,这就是我倾向于在 ARC 中处理它的方式:

    - (BOOL)checkForVPNConnectivity
    {
        NSDictionary *dict = CFBridgingRelease(CFNetworkCopySystemProxySettings());
    
        return [dict count] > 0;
    }
    

【讨论】:

  • 解决方案 2 总是为我返回至少 3 个带有 wifi 的元素。
  • @PierredeLESPINAY 同意。正如您在我对原始问题的 cmets 中看到的那样,我看到了相同的行为。我不认为应该通过检查CFNetworkCopySystemProxySettings() 中的非零元素数来确定 VPN 连接。我只是在 OP 的代码示例中修复内存泄漏。我试图澄清我的答案。
  • 谢谢。在任何情况下,通过结合这两种解决方案,我都能够检查 VPN 状态。
  • 我也在结合这些解决方案,但我仍然担心在蜂窝网络的情况下检查CFNetworkCopySystemProxySettings()。这个解决方案有可靠的来源吗?为什么通过蜂窝网络 + VPN 连接时总是返回零条目?
  • 我知道自从发布/讨论这个答案以来已经有几十年了,但是有没有人列出可以与 VPN 相关的CFNetworkCopySystemProxySettings() 的变量?谢谢
【解决方案2】:

您可以对上述问题使用简单的解决方法。

只需使用苹果可达性来检查 ios 设备是否连接到互联网。如果没有抛出没有互联网连接错误。如果是,请尝试使用 NSURLConnection 访问您的 VPN 相关 URL。如果您获得成功 200,即您已连接到 VPN。如果此请求返回未找到主机或任何错误,如 -1001 表示你没有连接到 VPN。然后你可以向用户抛出相应的 VPN 连接错误。快乐编码.... Arun kumar

更多信息请参考我的博客 http://aruntheiphonedeveloper.blogspot.in

【讨论】:

  • 您的博客对所有人都是有限的!
【解决方案3】:
let connect=ConnectVPN()
        connect.loadFromPreference()
        DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
            let status=NEVPNManager.shared().connection.status
            print(status)
        }

负载偏好在哪里

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

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

然后在状态中,您会获得已断开、无效和已连接等 vpn 状态,您可以从此链接 https://developer.apple.com/documentation/networkextension/nevpnstatus 阅读有关它的信息 希望这个能对您有所帮助 快乐编码:)

【讨论】:

  • 目标 C 是否支持 NEVPNManager?你能在目标 C 中显示一些代码来检测是否连接在 vpn 中吗?
【解决方案4】:

使用这个方法很简单就可以实现。 自 iOS 12 和 iOS 13 起,按键列表已更改

已添加 2 个键

utun1 和 utun2

所以函数应该是:

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

}

【讨论】:

    猜你喜欢
    • 2011-12-29
    • 1970-01-01
    • 2015-10-22
    • 2012-07-30
    • 1970-01-01
    • 2011-03-12
    • 2022-11-09
    • 2019-07-08
    • 2017-12-25
    相关资源
    最近更新 更多