Hello!
I created a simple DNS filter application for iOS but the extension is not launching. I am getting this log message in the console.
Failed to start extension edu.stanford.stilakid.testDnsFilter.DNSFiltering: Error Domain=NSCocoaErrorDomain Code=4097 "connection to service named edu.stanford.stilakid.testDnsFilter.DNSFiltering.apple-extension-service" UserInfo={NSDebugDescription=connection to service named edu.stanford.stilakid.testDnsFilter.DNSFiltering.apple-extension-service}
For another project with the same code for dns filtering but different bundleID, I also got the following log message.
Failed to start extension edu.stanford.sml.rdahlke.controlShift.DNSProxy: Error Domain=PlugInKit Code=4 "RBSLaunchRequest error trying to launch plugin edu.stanford.sml.rdahlke.controlShift.DNSProxy(D26CD63C-4656-4A30-99A0-7C867265DD75): Error Domain=RBSRequestErrorDomain Code=5 "Launch failed." UserInfo={NSLocalizedFailureReason=Launch failed., NSUnderlyingError=0xc62b8c0d0 {Error Domain=NSPOSIXErrorDomain Code=111 "Unknown error: 111" UserInfo={NSLocalizedDescription=Launchd job spawn failed}}}" UserInfo={NSLocalizedDescription=RBSLaunchRequest error trying to launch plugin edu.stanford.sml.rdahlke.controlShift.DNSProxy(D26CD63C-4656-4A30-99A0-7C867265DD75): Error Domain=RBSRequestErrorDomain Code=5 "Launch failed." UserInfo={NSLocalizedFailureReason=Launch failed., NSUnderlyingError=0xc62b8c0d0 {Error Domain=NSPOSIXErrorDomain Code=111 "Unknown error: 111" UserInfo={NSLocalizedDescription=Launchd job spawn failed}}}}
Also, the log messages I have defined inside the constructor of the dns proxy extension is nowhere to be found in the logs, so I am pretty sure the extension is failing to launch.
The debugger attached to the main target app shows no errors as well, so it is able to load and update dnsProtocol.
Here is the code:
// DNSProxyProvider.swift
// DNSFiltering
//
// Created by Juben Rana on 2/20/24.
//
import NetworkExtension
import os.log
class DNSProxyProvider: NEDNSProxyProvider {
// MARK: - Logger
static let logger = Logger(subsystem: "edu.stanford.sml.rdahlke.controlShift", category: "dns-filter")
override init() {
Self.logger.log(level: .debug, "TestDns: dns proxy provider will init")
self.logger = Self.logger
super.init()
}
let logger: Logger
override func startProxy(options:[String: Any]? = nil, completionHandler: @escaping (Error?) -> Void) {
// Add code here to start the DNS proxy.
logger.log(level: .debug, "TestDns: proxy will start")
completionHandler(nil)
}
override func stopProxy(with reason: NEProviderStopReason, completionHandler: @escaping () -> Void) {
// Add code here to stop the DNS proxy.
logger.log(level: .debug, "TestDns: proxy will stop")
completionHandler()
}
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.
logger.log(level: .debug, "TestDns: proxy is handling flow")
return false
}
}
// ContentView.swift
// testDnsFilter
//
// Created by Juben Rana on 2/20/24.
//
import SwiftUI
struct ContentView: View {
var body: some View {
VStack {
// LoginScreen()
// .onOpenURL { url in
// GIDSignIn.sharedInstance.handle(url)
// }
Spacer()
#if os(macOS)
Text("I'm running on macOS")
#else
Text("I'm running on iOS")
#endif
Spacer()
Button("Activate") {
#if os(macOS)
ContentFilterMac.shared.activate()
#elseif os(iOS)
ContentFilter.shared.enable()
#endif
}
Spacer()
Button("Deactivate") {
#if os(macOS)
ContentFilterMac.shared.deactivate()
#elseif os(iOS)
ContentFilter.shared.disable()
#endif
}
Spacer()
Spacer()
}
.padding()
}
}
#Preview {
ContentView()
}
//
// ContentFilter.swift
// controlShift
//
// Created by Juben Rana on 9/28/23.
//
// This is only for macOS
import Foundation
import NetworkExtension
import os.log
// MARK: - Content Filter
class ContentFilter {
// MARK: - Set Up
static let shared = ContentFilter()
private init() {
Self.logger.log(level: .debug, "content filter will init")
self.logger = Self.logger
}
// MARK: - Logger
static let logger = Logger(subsystem: "edu.stanford.stilakid.testDnsFilter", category: "content-filter")
let logger: Logger
// MARK: - DNS Filter
private let manager = NEDNSProxyManager.shared()
func enable() {
loadAndUpdatePreferences {
self.manager.localizedDescription = "DNSProxySample"
let dnsProtocol = NEDNSProxyProviderProtocol()
dnsProtocol.providerBundleIdentifier = "edu.stanford.stilakid.testDnsFilter.DNSFiltering"
self.manager.providerProtocol = dnsProtocol
self.manager.isEnabled = true
}
}
func disable() {
loadAndUpdatePreferences {
self.manager.isEnabled = false
}
}
private func loadAndUpdatePreferences(_ completion: @escaping () -> Void) {
manager.loadFromPreferences { error in
guard error == nil else {
debugPrint("DNSProxySample.App: load error")
return
}
completion()
self.manager.saveToPreferences { (error) in
guard error == nil else {
debugPrint("DNSProxySample.App: save error")
return
}
debugPrint("DNSProxySample.App: saved")
}
}
}
}