【问题标题】:How can I change wifi DNS setting iOS using swift如何使用 swift 更改 wifi DNS 设置 iOS
【发布时间】:2016-06-02 20:47:30
【问题描述】:

我正在尽我最大的努力来完成这项工作。

我有一个 DNS 服务器供我的客户使用,有时我会向他们发送电子邮件以更改他们的 DNS 设置。但现在我想通过一个 ios 应用程序来做到这一点。 有没有办法让他们下载应用程序并单击应用程序上的一个按钮来更改它?

我看过这个 https://developer.apple.com/library/ios/documentation/NetworkExtension/Reference/NEDNSSettingsClassRef/index.html#//apple_ref/occ/cl/NEDNSSettings

但不确定

谢谢

【问题讨论】:

标签: ios swift networking dns settings


【解决方案1】:

查看网络扩展类。使用NETunnelProviderManager 类,您可以将onDemandRules 设置为NEEvaluateConnectionRuleNEEvaluateConnectionRule constructor 可以将带有顶级域(即["*.com", "*.net", "*.org", "*.io"])的通配符列表作为域,并使用NEEvaluateConnectionRuleAction.connectIfNeeded 作为操作。将您创建的NEEvaluateConnectionRule 中的onDemandRules 设置为所有tld 作为域。然后创建一个NEOnDemandRuleEvaluateConnection 并将其connectionRules 设置为使用所有顶级域创建的NEEvaluateConnectionRule,并将其interfaceTypeMatch 设置为NEOnDemandRuleInterfaceType.any。将NETunnelProviderManager.onDemandRules 设置为以这种方式创建的NEOnDemandRuleEvaluateConnection。如果您如上所述创建 NETunnelProviderManagerload itsave it,则可以使用 NETunnelProviderManager.isEnabledNETunnelProviderManager.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] 图标连接已打开,因为我们没有设置 vpn,只是使用按需规则。

和我一样讨厌 Google,也许将它用于您设置的 DNS... Quad9

【讨论】:

  • 谢谢。使用所有内容的 matchDomains 规则是什么?
  • 不幸的是,没有办法为 matchDomains 使用 *.* 通配符,所以我为所有顶级域创建了一个包含 *.<tld> 的数组 (TLDList.tlds),然后将其传入。
  • 嘿,感谢您的代码,但我收到此错误:vpn_connect: save error Error Domain=NEVPNErrorDomain Code=1 "Missing protocol or protocol has invalid type" UserInfo={NSLocalizedDescription=Missing protocol or protocol has invalid type} 如何解决此问题?
  • 请注意,您必须打开网络扩展功能。你打开它们了吗?
【解决方案2】:

请考虑构建 DNSProxy 扩展(网络扩展之一)来拦截设备上生成的所有 DNS 流量并使用自定义/内部 DNS 服务器。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-11-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-07-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多