ios - 如何以编程方式在 iOS 中为连接的 WiFi 更改/添加 DNS 服务器?

标签 ios dns

我想在 iOS 中以编程方式为我的 iPhone 设备连接的 WiFi 更改/添加 DNS 服务器?

Google 公共(public) DNS IP 地址 (IPv4) 如下: 8.8.8.8 8.8.4.4

我想以编程方式更改/添加它,就像附加的屏幕截图中一样。

请帮忙。我可以管理它是在 Objective-c 还是 Swift 中。这对我在 Objective-c 中更有帮助。 提前致谢。

已连接 Wi-Fi 的虚拟/旧 DNS 服务器:-

enter image description here

所连接 Wi-Fi 所需的 DNS 服务器:-

enter image description here

最佳答案

查看网络扩展类。随着NETunnelProviderManager类你可以设置 onDemandRulesNEEvaluateConnectionRule . NEEvaluateConnectionRule constructor可以使用顶级域(即 ["*.com", "*.net", "*.org", "*.io"])作为域的通配符列表,并使用 NEEvaluateConnectionRuleAction.connectIfNeeded作为行动。设置 onDemandRulesNEEvaluateConnectionRule您使用所有 tld 作为域创建。然后创建一个NEOnDemandRuleEvaluateConnection并设置它的 connectionRulesNEEvaluateConnectionRule使用所有顶级域创建,并设置其 interfaceTypeMatchNEOnDemandRuleInterfaceType.any .设置 NETunnelProviderManager.onDemandRulesNEOnDemandRuleEvaluateConnection以这种方式创建。如果你创建一个 NETunnelProviderManagerload itsave it如上所述,您可以使用 NETunnelProviderManager.isEnabled 打开和关闭它。和 NETunnelProviderManager.isOnDemandEnabled属性。

下面是一个示例类,正是这样做的。

import Foundation
import NetworkExtension

public class VPNConnect {
    private static let vpnDescription = "DNS OnDemand to GoogleDNS"
    private static let vpnServerDescription = "OnDemand DNS to GoogleDNS"

    public var manager:NETunnelProviderManager = NETunnelProviderManager()
    public var dnsEndpoint1:String = "8.8.8.8"
    public var dnsEndpoint2:String = "8.8.4.4"

    public var connected:Bool {
        get {
            return self.manager.isOnDemandEnabled
        }
        set {
            if newValue != self.connected {
                update(
                    body: {
                        self.manager.isEnabled = newValue
                        self.manager.isOnDemandEnabled = newValue

                    },
                    complete: {
                        if newValue {
                            do {
                                try (self.manager.connection as? NETunnelProviderSession)?.startVPNTunnel(options: nil)
                            } catch let err as NSError {
                                NSLog("\(err.localizedDescription)")
                            }
                        } else {
                            (self.manager.connection as? NETunnelProviderSession)?.stopVPNTunnel()
                        }
                    }
                )
            }
        }
    }

    public init() {
        refreshManager()
    }
    
    public func refreshManager() -> Void {
        NETunnelProviderManager.loadAllFromPreferences(completionHandler: { (managers, error) in
            if nil == error {
                if let managers = managers {
                    for manager in managers {
                        if manager.localizedDescription == VPNConnect.vpnDescription {
                            self.manager = manager
                            return
                        }
                    }
                }
            }
            self.setPreferences()
        })
    }
    
    private func update(body: @escaping ()->Void, complete: @escaping ()->Void) {
        manager.loadFromPreferences { error in
            if (error != nil) {
                NSLog("Load error: \(String(describing: error?.localizedDescription))")
                return
            }            
            body()
            self.manager.saveToPreferences { (error) in
                if nil != error {
                    NSLog("vpn_connect: save error \(error!)")
                } else {
                    complete()
                }
            }
        }
    }
    
    private func setPreferences() {
        self.manager.localizedDescription = VPNConnect.vpnDescription        
        let proto = NETunnelProviderProtocol()
        proto.providerBundleIdentifier = "com.popmedic.vpntunnel.provider"
        proto.serverAddress = VPNConnect.vpnServerDescription
        self.manager.protocolConfiguration = proto
        // TLDList is a struct I created in its own swift file that has an array of all top level domains
        let evaluationRule = NEEvaluateConnectionRule(matchDomains: TLDList.tlds, 
                                                         andAction: NEEvaluateConnectionRuleAction.connectIfNeeded)
        evaluationRule.useDNSServers = [self.dnsEndpoint1, self.dnsEndpoint2]
        let onDemandRule = NEOnDemandRuleEvaluateConnection()
        onDemandRule.connectionRules = [evaluationRule]
        onDemandRule.interfaceTypeMatch = NEOnDemandRuleInterfaceType.any
        self.manager.onDemandRules = [onDemandRule]
    }
}

请注意,您必须打开网络扩展功能,并且会出现一个对话框,告诉用户您正在打开 VPN 连接,但是当您打开时,状态栏中不会显示 [VPN] 图标连接已打开,因为我们没有设置 vpn,只是使用按需规则。

Here is the TLDList class I used.

和我一样讨厌谷歌,也许将它用于你设置的 DNS... Quad9

iOS 14 更新

在 iOS 14 中,他们添加了一个 NEDNSSettingsManager这将允许设置 DNS。

关于ios - 如何以编程方式在 iOS 中为连接的 WiFi 更改/添加 DNS 服务器?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45025200/

相关文章:

ios - 重复图像下载过程

ios - 在 iOS Swift 中使用正则表达式提取值

java - JVM是否因为networkaddress.cache.ttl设置而缓存url?

dns - 自定义域的记录与 CNAME 记录

azure - Azure 上的 IPv6 DNS 查询

ios - Swift 2 获得任何对象游戏、协议(protocol)级别的正确方法?结构?扩大?

ios - iTunes 没有显示 React Native App 支持的语言

ios - 当经/纬度接近时显示警报

azure - 迁移到 Cloudflare 后网站关闭

具有自定义域的 Azure 应用服务租户