Title: DNS Proxy Not Capturing Traffic When Public DNS Is Set in WiFi Settings

I'm working on a Network Extension using NEDNSProxyProvider to inspect DNS traffic. However, I've run into a couple of issues:

DNS Proxy is not capturing traffic when a public DNS (like 8.8.8.8 or 1.1.1.1) is manually configured in the WiFi settings. It seems like the system bypasses the proxy in this case. Is this expected behavior? Is there a way to force DNS traffic through the proxy even if a public DNS is set?

Using DNS Proxy and DNS Settings simultaneously doesn't work. Is there a known limitation or a correct way to combine these?

How to set DNS or DNSSettings using DNSProxy?

import NetworkExtension
import SystemExtensions
import SwiftUI
protocol DNSProxyManagerDelegate {
func managerStateDidChange(_ manager: DNSProxyManager)
}
class DNSProxyManager: NSObject {
private let manager = NEDNSProxyManager.shared()
var delegate: DNSProxyManagerDelegate?
private(set) var isEnabled: Bool = false {
didSet {
delegate?.managerStateDidChange(self)
}
}
var completion: (() -> Void)?
override init() {
super.init()
self.load()
}
func toggle() {
isEnabled ? disable() : start()
}
private func start() {
let request = OSSystemExtensionRequest
.activationRequest(forExtensionWithIdentifier: Constants.extensionBundleID,
queue: DispatchQueue.main)
request.delegate = self
OSSystemExtensionManager.shared.submitRequest(request)
log.info("Submitted extension activation request")
}
private func enable() {
update {
self.manager.localizedDescription = "DNS Proxy"
let proto = NEDNSProxyProviderProtocol()
proto.providerBundleIdentifier = Constants.extensionBundleID
self.manager.providerProtocol = proto
self.manager.isEnabled = true
}
}
private func disable() {
update {
self.manager.isEnabled = false
}
}
private func remove() {
update {
self.manager.removeFromPreferences { _ in
self.isEnabled = self.manager.isEnabled
}
}
}
private func update(_ body: @escaping () -> Void) {
self.manager.loadFromPreferences { (error) in
if let error = error {
log.error("Failed to load DNS manager: \(error)")
return
}
self.manager.saveToPreferences { (error) in
if let error = error {
return
}
log.info("Saved DNS manager")
self.isEnabled = self.manager.isEnabled
}
}
}
private func load() {
manager.loadFromPreferences { error in
guard error == nil else { return }
self.isEnabled = self.manager.isEnabled
}
}
}
extension DNSProxyManager: OSSystemExtensionRequestDelegate {
func requestNeedsUserApproval(_ request: OSSystemExtensionRequest) {
log.info("Extension activation request needs user approval")
}
func request(_ request: OSSystemExtensionRequest, didFailWithError error: Error) {
log.error("Extension activation request failed: \(error)")
}
func request(_ request: OSSystemExtensionRequest, foundProperties properties: [OSSystemExtensionProperties]) {
log.info("Extension activation request found properties: \(properties)")
}
func request(_ request: OSSystemExtensionRequest, didFinishWithResult result: OSSystemExtensionRequest.Result) {
guard result == .completed else {
log.error("Unexpected result \(result.description) for system extension request")
return
}
log.info("Extension activation request did finish with result: \(result.description)")
enable()
}
func request(_ request: OSSystemExtensionRequest, actionForReplacingExtension existing: OSSystemExtensionProperties, withExtension ext: OSSystemExtensionProperties) -> OSSystemExtensionRequest.ReplacementAction {
log.info("Existing extension willt be replaced: \(existing.bundleIdentifier) -> \(ext.bundleIdentifier)")
return .replace
}
}
import NetworkExtension
class DNSProxyProvider: NEDNSProxyProvider {
var handlers: [String: FlowHandler] = [:]
var isReady = false
let queue = DispatchQueue(label: "DNSProxyProvider")
override func startProxy(options:[String: Any]? = nil, completionHandler: @escaping (Error?) -> Void) {
completionHandler(nil)
}
override func stopProxy(with reason: NEProviderStopReason, completionHandler: @escaping () -> Void) {
completionHandler()
}
override func handleNewUDPFlow(_ flow: NEAppProxyUDPFlow, initialRemoteEndpoint remoteEndpoint: NWEndpoint) -> Bool {
let id = shortUUID()
handlers[id] = FlowHandler(flow: flow, remoteEndpoint: remoteEndpoint, id: id, delegate: self)
return true
}
override func handleNewFlow(_ flow: NEAppProxyFlow) -> Bool {
return false
}
}
class FlowHandler {
let id: String
let flow: NEAppProxyUDPFlow
let remoteEndpoint: NWHostEndpoint
let delegate: FlowHandlerDelegate
private var connections: [String: RemoteConnection] = [:]
private var pendingPacketsByDomain: [String: [(packet: Data, endpoint: NWEndpoint, uniqueID: String, timestamp: Date)]] = [:]
private let packetQueue = DispatchQueue(label: "com.flowhandler.packetQueue")
init(flow: NEAppProxyUDPFlow, remoteEndpoint: NWEndpoint, id: String, delegate: FlowHandlerDelegate) {
log.info("Flow received for \(id) flow: \(String(describing: flow))")
self.flow = flow
self.remoteEndpoint = remoteEndpoint as! NWHostEndpoint
self.id = id
self.delegate = delegate
defer { start() }
}
deinit {
closeAll(nil)
}
func start() {
flow.open(withLocalEndpoint: flow.localEndpoint as? NWHostEndpoint) { error in
if let error = error {
self.delegate.flowClosed(self)
return
}
self.readFromFlow()
}
}
func readFromFlow() {
self.flow.readDatagrams { packets, endpoint, error in
if let error = error {
self.closeAll(error)
return
}
guard let packets = packets, let endpoints = endpoint, !packets.isEmpty, !endpoints.isEmpty else {
self.closeAll(nil)
return
}
self.processFlowPackets(packets, endpoints)
self.readFromFlow()
}
}
}

Any insights or suggestions would be greatly appreciated. Thanks!

Answered by DTS Engineer in 835399022
Written by dhanraj_kawade in 781143021
Is this expected behavior?

Yes. The system has a bias towards using secure DNS where possible, and those services provide secure DNS. I touch on this in this thread, with its reference to RFC 9462.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Written by dhanraj_kawade in 781143021
Is this expected behavior?

Yes. The system has a bias towards using secure DNS where possible, and those services provide secure DNS. I touch on this in this thread, with its reference to RFC 9462.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Thank you for the clarification! If we set Public DNS in WiFi settings we can not capture network traffic in NEDNSProxyProvider.

Title: DNS Proxy Not Capturing Traffic When Public DNS Is Set in WiFi Settings
 
 
Q