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
Code Block 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") |
} |
} |
} |
|
Code Block 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:
Code Block 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.