Thanks for your assistance but I am still having issues and will continue to investigate with SIP enabled as you suggested. In the meantime this is what I have.
ViewController.swift
import Cocoa
import os
import NetworkExtension
import SystemExtensions
class ViewController: NSViewController {
override func viewDidLoad() {
super.viewDidLoad()
os_log("DNSFILTER: viewDidLoad")
installSystemExtension()
configureProxy()
}
override var representedObject: Any? {
didSet {
// Update the view, if already loaded.
}
}
var manager: NEDNSProxyManager?
private func installSystemExtension() {
os_log("DNSFILTER: installing system extension")
let request = OSSystemExtensionRequest.activationRequest(
forExtensionWithIdentifier: "com.blob.macappproxy.dns",
queue: .main
)
request.delegate = self
OSSystemExtensionManager.shared.submitRequest(request)
}
private func configureProxy() {
os_log("DNSFILTER: configuring proxy")
guard let dnsManager = manager else { return }
dnsManager.loadFromPreferences { error in
precondition(Thread.isMainThread)
if let nsError = error as NSError? {
os_log("DNSFILTER: Failed to load the filter configuration: %@", nsError.localizedDescription)
return
}
let proto = NEDNSProxyProviderProtocol()
proto.serverAddress = "localhost" /* Just for testing purposes */
proto.providerBundleIdentifier = "com.blob.macappproxy.dns"
dnsManager.providerProtocol = proto
dnsManager.isEnabled = true
dnsManager.localizedDescription = "Testing DNS Proxy"
dnsManager.saveToPreferences { saveError in
if let nsError = saveError as NSError? {
os_log("DNSFILTER: Failed to disable the filter configuration: %@", nsError.localizedDescription)
return
}
/* Handle Success Case */
os_log("DNSFILTER: dns proxy configured")
}
}
}
}
extension ViewController: OSSystemExtensionRequestDelegate {
func request(_ request: OSSystemExtensionRequest, actionForReplacingExtension existing: OSSystemExtensionProperties, withExtension ext: OSSystemExtensionProperties) - OSSystemExtensionRequest.ReplacementAction {
os_log("DNSFILTER: Replacing extension %@ version %@ with version %@", request.identifier, existing.bundleShortVersion, ext.bundleShortVersion)
return .replace
}
func requestNeedsUserApproval(_ request: OSSystemExtensionRequest) {
os_log("DNSFILTER: Extension %@ requires user approval", request.identifier)
}
func request(_ request: OSSystemExtensionRequest, didFailWithError error: Error) {
os_log("DNSFILTER: System extension request failed: %@", error.localizedDescription)
}
/* Other delegate methods here */
func request(_ request: OSSystemExtensionRequest, didFinishWithResult result: OSSystemExtensionRequest.Result) {
switch result {
case .completed:
manager = NEDNSProxyManager.shared()
case .willCompleteAfterReboot:
os_log("DNSFILTER: willCompleteAfterReboot")
@unknown default:
os_log("DNSFILTER: default")
}
}
}
2021-03-18 17:09:27.676100+1100 macappproxy[1142:14431] DNSFILTER: viewDidLoad
2021-03-18 17:09:27.676187+1100 macappproxy[1142:14431] DNSFILTER: installing system extension
2021-03-18 17:09:27.678794+1100 macappproxy[1142:14431] DNSFILTER: configuring proxy
2021-03-18 17:09:27.922090+1100 macappproxy[1142:14431] DNSFILTER: System extension request failed: The operation couldn’t be completed. (OSSystemExtensionErrorDomain error 1.)
When configureProxy() is invoked it doesn't get past line 36 in ViewController.swift, which I guess is understandable if the extension hasn't started.
My DNSProxyProvider.swift is barebones:
import NetworkExtension
import os
class DNSProxyProvider: NEAppProxyProvider {
override func startProxy(options: [String : Any]?, completionHandler: @escaping (Error?) - Void) {
// Add code here to start the process of connecting the tunnel.
os_log("DNSFILTER: provider started")
completionHandler(nil)
}
override func stopProxy(with reason: NEProviderStopReason, completionHandler: @escaping () - Void) {
// Add code here to start the process of stopping the tunnel.
completionHandler()
}
override func handleAppMessage(_ messageData: Data, completionHandler: ((Data?) - Void)?) {
// Add code here to handle the message.
if let handler = completionHandler {
handler(messageData)
}
}
override func sleep(completionHandler: @escaping () - Void) {
// Add code here to get ready to sleep.
completionHandler()
}
override func wake() {
// Add code here to wake up.
}
override func handleNewFlow(_ flow: NEAppProxyFlow) - Bool {
// Add code here to handle the incoming flow.
return false
}
}
Let me know if anything looks awry. Thanks. I will continue to trawl through the console logs for any clues.