Hello there, I am new in swift development. I want to create a mac app with native support for DOH/DOT. I found it can be done by using NEPacketTunnelProvider. I have started my code and I am currently stuck at a bug where dnsleaktest.com shows my doh or dot server in safari and firefox but not in chrome and brave.
this is a function to load and create a provider manager
This is my code for network extension
this is a function to load and create a provider manager
Code Block func loadAndCreateProviderManager(_ completion: @escaping (NETunnelProviderManager?, Error?) -> ()) { NETunnelProviderManager.loadAllFromPreferences { managers, error in guard let managers = managers else { return completion(nil, error) } let manager = managers.first ?? NETunnelProviderManager() manager.protocolConfiguration = NETunnelProviderProtocol() var appRules = [NEAppRule]() // let appRule = NEAppRule() let chromeRule = NEAppRule.init(signingIdentifier: "com.google.Chrome", designatedRequirement: "(identifier \"com.google.Chrome\" or identifier \"com.google.Chrome.beta\" or identifier \"com.google.Chrome.dev\" or identifier \"com.google.Chrome.canary\") and certificate leaf = H\"c9a99324ca3fcb23dbcc36bd5fd4f9753305130a\"") appRules.append(chromeRule) print("App Rules: ") print(appRules) manager.isEnabled = true let domainArr : [String] = ["*.com","*.net","*.org","*.int","*.edu","*.gov","*.mil","*.au","*.us","*.br","*.in","*.co.nz","*.nz","*.co",".sex",".sexy",".xxx",".sex",".xyz",".online",".adult","*.box","*.buzz","*.book","*.chat"] let connectionRule : NEEvaluateConnectionRule = NEEvaluateConnectionRule.init(matchDomains: domainArr , andAction: .connectIfNeeded) connectionRule.useDNSServers = ["104.155.237.225"] let rulesArr : [NEEvaluateConnectionRule] = [connectionRule] let demandRuleConnection : NEOnDemandRuleEvaluateConnection = NEOnDemandRuleEvaluateConnection() demandRuleConnection.interfaceTypeMatch = .any demandRuleConnection.connectionRules = rulesArr manager.onDemandRules = [demandRuleConnection] manager.isOnDemandEnabled = true manager.appRules = appRules manager.localizedDescription = "vpn_subtitle".localized let tunnel = NETunnelProviderProtocol() tunnel.providerBundleIdentifier = "com.Manish.DOH-app.VPN-Tunnel"; tunnel.providerConfiguration = [: ] tunnel.serverAddress = "127.0.0.1" tunnel.disconnectOnSleep = false manager.protocolConfiguration = tunnel self.isConfigured = true self.reloadManager(manager, completion: completion) } } func reloadManager(_ manager: NETunnelProviderManager, completion: @escaping (NETunnelProviderManager?, Error?) -> ()) { manager.saveToPreferences(completionHandler: { (error) -> Void in if let error = error { completion(nil, error) } else { manager.loadFromPreferences(completionHandler: { (error) -> Void in if let error = error { completion(nil, error) }else{ completion(manager, nil) } }) } }) }
This is my code for network extension
Code Block import NetworkExtension @available(OSXApplicationExtension 11.0, *) class PacketTunnelProvider: NEPacketTunnelProvider { override func startTunnel(options: [String : NSObject]?, completionHandler: @escaping (Error?) -> Void) { NSLog("Starting tunnel, options: %{private}@", "\(String(describing: options))") if let options = options { NSLog("PacketTunnelProvider > startTunnel with options: \(options)") } else { NSLog("PacketTunnelProvider > startTunnel") } configureAndStartTunnel(completionHandler: completionHandler) } @available(OSXApplicationExtension 11.0, *) func configureAndStartTunnel(completionHandler: @escaping (Error?) -> Void) { let dnsSettings: NEDNSSettings let servers = ["104.155.237.225","104.197.28.121"] if #available(OSXApplicationExtension 11.0, *) { let dataProvider = PacketTunnelDataProvider() switch dataProvider.mode { case let .doh(url): let settings = NEDNSOverHTTPSSettings(servers: []) settings.serverURL = url NSLog("PacketTunnelProvider > start doh: \(url)") dnsSettings = settings case let .dot(serverName): let settings = NEDNSOverTLSSettings(servers: []) settings.serverName = serverName NSLog("PacketTunnelProvider > start dot: \(serverName)") dnsSettings = settings case .regular: NSLog("PacketTunnelProvider > start regular") dnsSettings = NEDNSSettings(servers: servers) } } else { NSLog("PacketTunnelProvider > start regular") dnsSettings = NEDNSSettings(servers: servers) } let matchDomains : [String] = [""] dnsSettings.matchDomains = matchDomains let tunnelSettings = NEPacketTunnelNetworkSettings(tunnelRemoteAddress: "127.0.0.1") tunnelSettings.dnsSettings = dnsSettings setTunnelNetworkSettings(tunnelSettings, completionHandler: { error in if let error = error { NSLog("PacketTunnelProvider > error tunnel settings: \(error)") } completionHandler(error) }) } override func stopTunnel(with reason: NEProviderStopReason, completionHandler: @escaping () -> Void) { NSLog("PacketTunnelProvider > stopTunnel") completionHandler() } override func handleAppMessage(_ messageData: Data, completionHandler: ((Data?) -> Void)?) { NSLog("PacketTunnelProvider > handle messageData") if messageData.isDNSSettingsChangedData { NSLog("PacketTunnelProvider > DNS Settings changed") configureAndStartTunnel { error in if let error = error { NSLog("PacketTunnelProvider > error configuring and starting tunnel: \(error)") } completionHandler?(nil) } } else { completionHandler?(nil) } } override func sleep(completionHandler: @escaping () -> Void) { NSLog("PacketTunnelProvider > sleep") completionHandler() } override func wake() { NSLog("PacketTunnelProvider > wake") } }