AppProxy/AppProxyProvider.swift
/* |
Copyright (C) 2016 Apple Inc. All Rights Reserved. |
See LICENSE.txt for this sample’s licensing information |
Abstract: |
This file contains the AppProxyProvider class. The AppProxyProvider class is a sub-class of NEAppProxyProvider, and is the integration point between the Network Extension framework and the SimpleTunnel tunneling protocol. |
*/ |
import NetworkExtension |
import SimpleTunnelServices |
/// A NEAppProxyProvider sub-class that implements the client side of the SimpleTunnel tunneling protocol. |
class AppProxyProvider: NEAppProxyProvider, TunnelDelegate { |
// MARK: Properties |
/// A reference to the tunnel object. |
var tunnel: ClientTunnel? |
/// The completion handler to call when the tunnel is fully established. |
var pendingStartCompletion: ((NSError?) -> Void)? |
/// The completion handler to call when the tunnel is fully disconnected. |
var pendingStopCompletion: ((Void) -> Void)? |
// MARK: NEAppProxyProvider |
/// Begin the process of establishing the tunnel. |
override func startProxy(options: [String : Any]?, completionHandler: @escaping (Error?) -> Void) { |
let newTunnel = ClientTunnel() |
newTunnel.delegate = self |
if let error = newTunnel.startTunnel(self) { |
completionHandler(error as NSError) |
return |
} |
pendingStartCompletion = completionHandler |
tunnel = newTunnel |
} |
/// Begin the process of stopping the tunnel. |
override func stopProxy(with reason: NEProviderStopReason, completionHandler: @escaping () -> Void) { |
// Clear out any pending start completion handler. |
pendingStartCompletion = nil |
pendingStopCompletion = completionHandler |
tunnel?.closeTunnel() |
} |
/// Handle a new flow of network data created by an application. |
override func handleNewFlow(_ flow: (NEAppProxyFlow?)) -> Bool { |
var newConnection: ClientAppProxyConnection? |
guard let clientTunnel = tunnel else { return false } |
if let TCPFlow = flow as? NEAppProxyTCPFlow { |
newConnection = ClientAppProxyTCPConnection(tunnel: clientTunnel, newTCPFlow: TCPFlow) |
} |
else if let UDPFlow = flow as? NEAppProxyUDPFlow { |
newConnection = ClientAppProxyUDPConnection(tunnel: clientTunnel, newUDPFlow: UDPFlow) |
} |
guard newConnection != nil else { return false } |
newConnection!.open() |
return true |
} |
// MARK: TunnelDelegate |
/// Handle the event of the tunnel being fully established. |
func tunnelDidOpen(_ targetTunnel: Tunnel) { |
guard let clientTunnel = targetTunnel as? ClientTunnel else { |
pendingStartCompletion?(SimpleTunnelError.internalError as NSError) |
pendingStartCompletion = nil |
return |
} |
simpleTunnelLog("Tunnel opened, fetching configuration") |
clientTunnel.sendFetchConfiguation() |
} |
/// Handle the event of the tunnel being fully disconnected. |
func tunnelDidClose(_ targetTunnel: Tunnel) { |
// Call the appropriate completion handler depending on the current pending tunnel operation. |
if pendingStartCompletion != nil { |
pendingStartCompletion?(tunnel?.lastError) |
pendingStartCompletion = nil |
} |
else if pendingStopCompletion != nil { |
pendingStopCompletion?() |
pendingStopCompletion = nil |
} |
else { |
// No completion handler, so cancel the proxy. |
cancelProxyWithError(tunnel?.lastError) |
} |
tunnel = nil |
} |
/// Handle the server sending a configuration. |
func tunnelDidSendConfiguration(_ targetTunnel: Tunnel, configuration: [String : AnyObject]) { |
simpleTunnelLog("Server sent configuration: \(configuration)") |
guard let tunnelAddress = tunnel?.remoteHost else { |
let error = SimpleTunnelError.badConnection |
pendingStartCompletion?(error as NSError) |
pendingStartCompletion = nil |
return |
} |
guard let DNSDictionary = configuration[SettingsKey.DNS.rawValue] as? [String: AnyObject], let DNSServers = DNSDictionary[SettingsKey.Servers.rawValue] as? [String] else { |
self.pendingStartCompletion?(nil) |
self.pendingStartCompletion = nil |
return |
} |
let newSettings = NETunnelNetworkSettings(tunnelRemoteAddress: tunnelAddress) |
newSettings.dnsSettings = NEDNSSettings(servers: DNSServers) |
if let DNSSearchDomains = DNSDictionary[SettingsKey.SearchDomains.rawValue] as? [String] { |
newSettings.dnsSettings?.searchDomains = DNSSearchDomains |
} |
simpleTunnelLog("Calling setTunnelNetworkSettings") |
self.setTunnelNetworkSettings(newSettings) { error in |
if error != nil { |
let startError = SimpleTunnelError.badConfiguration |
self.pendingStartCompletion?(startError as NSError) |
self.pendingStartCompletion = nil |
} |
else { |
self.pendingStartCompletion?(nil) |
self.pendingStartCompletion = nil |
} |
} |
} |
} |
Copyright © 2016 Apple Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2016-10-04