@meaton
Thank you for quick response and detailed explanation!
Currently I am also struggled with launching extension that use Packet Tunnel Provider. I have been trying to make an app without GUI that just launch the extension. To check that tunnel started I want to log some message from startTunnel() and see it in Console:
swift
override func startTunnel(options: [String : NSObject]?, completionHandler: @escaping (Error?) - Void)
{
os_log(.default, "Tunnel started successfuly")
let settings = NETunnelNetworkSettings(tunnelRemoteAddress: "some address")
setTunnelNetworkSettings(settings) { error in
completionHandler(error)
}
}
Currently when I launch the app, dialog appears with message which says that application trying to install system extension. After opening "Security and Privacy" option in System Preferences and allowing installation I can found in systemextensionctl list that the extension has status "activated enabled". But there is no messages in Console about tunnel start.
To achieve 'no GUI' goal I removed ViewController from project and modified AppDelegate::applicationDidFinishLaunching():
swift
func applicationDidFinishLaunching(_ aNotification: Notification)
{
guard let extensionIdentifier = self.extensionBundle.bundleIdentifier else
{
os_log(.default, "Problems with extension bundle ID")
return
}
os_log(.default, "SE activation request")
let activationRequest = OSSystemExtensionRequest.activationRequest(forExtensionWithIdentifier: extensionIdentifier, queue: .main)
activationRequest.delegate = self
OSSystemExtensionManager.shared.submitRequest(activationRequest)
}
To handle activation request result I have also added next thing:
swift
extension AppDelegate: OSSystemExtensionRequestDelegate
{
func request(_ request: OSSystemExtensionRequest, didFinishWithResult result: OSSystemExtensionRequest.Result)
{
guard result == .completed else
{
os_log(.default, "Unexpected result for SystemExtension activation request: %@", result.rawValue)
return
}
enableTunnelConfiguration()
}
}
enableTunnelConfiguration:
swift
func enableTunnelConfiguration()
{
NETunnelProviderManager.loadAllFromPreferences { managers, error in
if let loadError = error
{
os_log("Error while loading from preferences: %@", loadError.localizedDescription)
}
let managersList = managers ?? []
if managersList.count 0
{
self.tunnelManager = managersList.first!
}
else
{
self.tunnelManager = self.makeManager()
}
self.tunnelManager.saveToPreferences { error in
if let saveError = error
{
os_log("Error while saving to prefs: %@", saveError.localizedDescription)
return
}
os_log("Successfuly saved")
}
}
do
{
try self.tunnelManager.connection.startVPNTunnel()
}
catch
{
os_log("Failed to start tunnel")
}
}
and makeManager():
swift
private func makeManager() - NETunnelProviderManager {
let manager = NETunnelProviderManager()
manager.localizedDescription = "CustomVPN"
let proto = NETunnelProviderProtocol()
proto.providerBundleIdentifier = "extension bundle id"
proto.serverAddress = "same as address in startTunnel()"
proto.providerConfiguration = [:]
manager.protocolConfiguration = proto
manager.isEnabled = true
return manager
}
Also I'm getting log "Failed to start tunnel" after startVPNTunnel() call. Should I call this method to start tunnel and see desired message. Or extension is always launch automatically when app starts. Could it be issue with entitlements or code signing? Is it mandatory to use NETunnelManagerProvider to successfully launch extension? I save only one configuration in app, so managers list will contain only one element always? Would be glad if you provide explanation one more time. Sorry if my questions sounds dumb