如何在iOS 11中使用NEDNSProxyProvider

16

在网络方面,DNS代理是iOS 11最重要的功能之一。但是关于它们并没有提供太多的文档或示例。有一个讲座也提到了它,但他们只是描述了DNS代理的可能性。

我想创建一个可工作的样例,但直到现在都没有成功。所以我创建了一个带有DNS代理权限的网络扩展并添加了DNS代理提供者。以下是代码:

class DNSProxyProvider: NEDNSProxyProvider {
    let defaults = UserDefaults(suiteName: "group.com.securly.dnsProxy")

    override init() {
        NSLog("QNEDNSProxy.Provider: init")
        super.init()
        // +++ might want to set up KVO on `systemDNSSettings`
    }

    override func startProxy(options:[String: Any]? = nil, completionHandler: @escaping (Error?) -> Void) {
        NSLog("QNEDNSProxy.Provider: start")
        // self.defaults?.set("DidStart", forKey: "DidStart")
        completionHandler(nil)
    }

    override func stopProxy(with reason: NEProviderStopReason, completionHandler: @escaping () -> Void) {
        NSLog("QNEDNSProxy.Provider: stop")
        completionHandler()
    }

    override func handleNewFlow(_ flow: NEAppProxyFlow) -> Bool {
        NSLog("QNEDNSProxy.Provider: new flow (denied)")
        // self.defaults?.set("DidHandleNewFlow", forKey: "DidHandleNewFlow")
        return true
    }

}

然后在AppDelegate中,我声明了一个NEDNSProxyManager并将其用作:

class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?
    let manager = NEDNSProxyManager.shared()

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {

        self.enable()
        return true
    }

    private func enable() {
        self.update {
            self.manager.localizedDescription = "DNSProxySample"
            let proto = NEDNSProxyProviderProtocol()
            // proto.providerConfiguration = +++
            proto.providerBundleIdentifier = "com.securly.dnsProxy"
            self.manager.providerProtocol = proto
            self.manager.isEnabled = true
        }
    }

    private func disable() {
        self.update {
            self.manager.isEnabled = false
        }
    }

    private func update(_ body: @escaping () -> Void) {
        self.manager.loadFromPreferences { (error) in
            guard error == nil else {
                NSLog("DNSProxySample.App: load error")
                return
            }
            body()
            self.manager.saveToPreferences { (error) in
                guard error == nil else {
                    NSLog("DNSProxySample.App: save error")
                    return
                }
                NSLog("DNSProxySample.App: saved")
            }
        }
    }
}

问题/问题:

  1. 为什么没有调用startProxy或者handleNewFlow?设置有什么问题吗?
  2. 我该如何提及自定义DNS地址?

Questions/Issues:

  1. 为什么没有调用startProxyhandleNewFlow?设置有什么问题吗?
  2. 如何提及自定义DNS地址?
1个回答

7

我成功地通过系统触发了DNSProxyProvider上的startProxyhandleFlow。我的配置如下:

  1. Entitlements on app target enter image description here
  2. Entitlements on DNSProxy Extension enter image description here Red line is something similar to: group.com.xzy.project_name

  3. Info.plist file on Extension enter image description here

  4. AppDelegate

    import UIKit
    import NetworkExtension
    
    @UIApplicationMain
    class AppDelegate: UIResponder, UIApplicationDelegate {
    
        var window: UIWindow?
        let manager = NEDNSProxyManager.shared()
    
        func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
            self.enable()
            return true
        }
    
        private func enable() {
            self.update {
                self.manager.localizedDescription = "DNS"
                let proto = NEDNSProxyProviderProtocol()
                proto.providerBundleIdentifier = "EXTENSION_BUNDLE_IDENTIFIER_WHICH_HAS_DNS_PROXY"
                self.manager.providerProtocol = proto
                self.manager.isEnabled = true
            }
        }
    
        private func disable() {
            self.update {
                self.manager.isEnabled = false
            }
        }
    
        private func update(_ body: @escaping () -> Void) {
            self.manager.loadFromPreferences { (error) in
                guard error == nil else {
                    NSLog("DNS Test App: load error")
                    return
                }
                body()
                self.manager.saveToPreferences { (error) in
                    guard error == nil else {
                        NSLog("DNS Test App: save error")
                        return
                    }
                    NSLog("DNS Test App: saved")
                }
            }
        }
    }
    

不要忘记更改捆绑标识符 在这里 proto.providerBundleIdentifier = "具有DNS代理的扩展束标识符"

  1. DNSProxyProvider

    import NetworkExtension
    
    class DNSProxyProvider: NEDNSProxyProvider {
    
        override init() {
            NSLog("DNSProxyProvider: init")
            super.init()
        }
    
        override func startProxy(options:[String: Any]? = nil, completionHandler: @escaping (Error?) -> Void) {
            NSLog("DNSProxyProvider: startProxy")
            completionHandler(nil)
        }
    
        override func stopProxy(with reason: NEProviderStopReason, completionHandler: @escaping () -> Void) {
            NSLog("DNSProxyProvider: stopProxy")
            completionHandler()
        }
    
        override func sleep(completionHandler: @escaping () -> Void) {
            NSLog("DNSProxyProvider: sleep")
            completionHandler()
        }
    
        override func wake() {
            NSLog("DNSProxyProvider: wake")
        }
    
        override func handleNewFlow(_ flow: NEAppProxyFlow) -> Bool {
            NSLog("DNSProxyProvider: handleFlow")
            if let tcpFlow = flow as? NEAppProxyTCPFlow {
                let remoteHost = (tcpFlow.remoteEndpoint as! NWHostEndpoint).hostname
                let remotePort = (tcpFlow.remoteEndpoint as! NWHostEndpoint).port
                NSLog("DNSProxyProvider TCP HOST : \(remoteHost)")
                NSLog("DNSProxyProvider TCP PORT : \(remotePort)")
            } else if let udpFlow = flow as? NEAppProxyUDPFlow {
                let localHost = (udpFlow.localEndpoint as! NWHostEndpoint).hostname
                let localPort = (udpFlow.localEndpoint as! NWHostEndpoint).port
                NSLog("DNSProxyProvider UDP HOST : \(localHost)")
                NSLog("DNSProxyProvider UDP PORT : \(localPort)")
            }
            return true
        }
    
    }
    
  2. As a last step run the app on a real iOS Device.

  3. If you want to display extension logs open Console.app from your Mac.

  4. To debug the extension: Your main app should be selected from run menu. Select Attach to Process by PID or Name... from Xcode's Debug menu and then type your extension's name, press Attach button. After you see the Waiting to attach to EXTENSION_NAME on XYZ's iPhone. Run your app target on a iOS device.


你是在使用带有主管或管理模式的实际设备吗? 您的指示在我的实际iPhone上不起作用,我在控制台中看到这个“警告:允许在非受监控设备上创建/修改DNS代理配置,因为请求应用程序(XXXX)是开发版本。这将不会允许生产版本的XXXX”。无论如何,即使有了那个,它也应该在开发模式下工作,但是没有。感谢您的帮助。 - Ricardo
1
您可以在真实设备上使用Debug构建来执行这些指令,而无需管理该设备。如果您想要使用Managed设备,则需要安装一个特定于您的应用程序的.mobileconfig文件。 - abdullahselek
我应该如何配置handleNewFlow函数?我想要能够看到哪个URL被处理。在这个函数中是否可能实现? - Robert Veringa
你好@abdullahselek,感谢您的回答。我可以在控制台应用程序中看到日志,但我只能看到IP地址。是否也可以看到网站(如www.stackoverflow.com)?此外,当我浏览网站时,如果扩展正在运行,则无法加载。 - Robert Veringa
要获取URL,您需要创建一个UDP会话,在此会话中,您可以编写以继续流程并从流中读取数据包详细信息。您可以从这个存储库中获得灵感。 - abdullahselek
我们在哪里添加自定义的DNSEndpoints? - Sidharth J Dev

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接