121 lines
4.2 KiB
Swift
121 lines
4.2 KiB
Swift
import Foundation
|
|
import NetworkExtension
|
|
import OpenVPNAdapter
|
|
|
|
extension PacketTunnelProvider: OpenVPNAdapterDelegate {
|
|
// OpenVPNAdapter calls this delegate method to configure a VPN tunnel.
|
|
// `completionHandler` callback requires an object conforming to `OpenVPNAdapterPacketFlow`
|
|
// protocol if the tunnel is configured without errors. Otherwise send nil.
|
|
// `OpenVPNAdapterPacketFlow` method signatures are similar to `NEPacketTunnelFlow` so
|
|
// you can just extend that class to adopt `OpenVPNAdapterPacketFlow` protocol and
|
|
// send `self.packetFlow` to `completionHandler` callback.
|
|
func openVPNAdapter(
|
|
_ openVPNAdapter: OpenVPNAdapter,
|
|
configureTunnelWithNetworkSettings networkSettings: NEPacketTunnelNetworkSettings?,
|
|
completionHandler: @escaping (Error?) -> Void
|
|
) {
|
|
// In order to direct all DNS queries first to the VPN DNS servers before the primary DNS servers
|
|
// send empty string to NEDNSSettings.matchDomains
|
|
networkSettings?.dnsSettings?.matchDomains = [""]
|
|
|
|
if splitTunnelType == 1 {
|
|
var ipv4IncludedRoutes = [NEIPv4Route]()
|
|
|
|
for allowedIPString in splitTunnelSites {
|
|
if let allowedIP = IPAddressRange(from: allowedIPString) {
|
|
ipv4IncludedRoutes.append(NEIPv4Route(
|
|
destinationAddress: "\(allowedIP.address)",
|
|
subnetMask: "\(allowedIP.subnetMask())"))
|
|
}
|
|
}
|
|
|
|
networkSettings?.ipv4Settings?.includedRoutes = ipv4IncludedRoutes
|
|
} else {
|
|
if splitTunnelType == 2 {
|
|
var ipv4ExcludedRoutes = [NEIPv4Route]()
|
|
var ipv4IncludedRoutes = [NEIPv4Route]()
|
|
var ipv6IncludedRoutes = [NEIPv6Route]()
|
|
|
|
for excludeIPString in splitTunnelSites {
|
|
if let excludeIP = IPAddressRange(from: excludeIPString) {
|
|
ipv4ExcludedRoutes.append(NEIPv4Route(
|
|
destinationAddress: "\(excludeIP.address)",
|
|
subnetMask: "\(excludeIP.subnetMask())"))
|
|
}
|
|
}
|
|
|
|
if let allIPv4 = IPAddressRange(from: "0.0.0.0/0") {
|
|
ipv4IncludedRoutes.append(NEIPv4Route(
|
|
destinationAddress: "\(allIPv4.address)",
|
|
subnetMask: "\(allIPv4.subnetMask())"))
|
|
}
|
|
if let allIPv6 = IPAddressRange(from: "::/0") {
|
|
ipv6IncludedRoutes.append(NEIPv6Route(
|
|
destinationAddress: "\(allIPv6.address)",
|
|
networkPrefixLength: NSNumber(value: allIPv6.networkPrefixLength)))
|
|
}
|
|
networkSettings?.ipv4Settings?.includedRoutes = ipv4IncludedRoutes
|
|
networkSettings?.ipv6Settings?.includedRoutes = ipv6IncludedRoutes
|
|
networkSettings?.ipv4Settings?.excludedRoutes = ipv4ExcludedRoutes
|
|
}
|
|
}
|
|
|
|
// Set the network settings for the current tunneling session.
|
|
setTunnelNetworkSettings(networkSettings, completionHandler: completionHandler)
|
|
}
|
|
|
|
// Process events returned by the OpenVPN library
|
|
func openVPNAdapter(
|
|
_ openVPNAdapter: OpenVPNAdapter,
|
|
handleEvent event: OpenVPNAdapterEvent,
|
|
message: String?) {
|
|
switch event {
|
|
case .connected:
|
|
if reasserting {
|
|
reasserting = false
|
|
}
|
|
|
|
guard let startHandler = startHandler else { return }
|
|
|
|
startHandler(nil)
|
|
self.startHandler = nil
|
|
case .disconnected:
|
|
guard let stopHandler = stopHandler else { return }
|
|
|
|
if vpnReachability.isTracking {
|
|
vpnReachability.stopTracking()
|
|
}
|
|
|
|
stopHandler()
|
|
self.stopHandler = nil
|
|
case .reconnecting:
|
|
reasserting = true
|
|
default:
|
|
break
|
|
}
|
|
}
|
|
|
|
// Handle errors thrown by the OpenVPN library
|
|
func openVPNAdapter(_ openVPNAdapter: OpenVPNAdapter, handleError error: Error) {
|
|
// Handle only fatal errors
|
|
guard let fatal = (error as NSError).userInfo[OpenVPNAdapterErrorFatalKey] as? Bool,
|
|
fatal == true else { return }
|
|
|
|
if vpnReachability.isTracking {
|
|
vpnReachability.stopTracking()
|
|
}
|
|
|
|
if let startHandler {
|
|
startHandler(error)
|
|
self.startHandler = nil
|
|
} else {
|
|
cancelTunnelWithError(error)
|
|
}
|
|
}
|
|
|
|
// Use this method to process any log message returned by OpenVPN library.
|
|
func openVPNAdapter(_ openVPNAdapter: OpenVPNAdapter, handleLogMessage logMessage: String) {
|
|
// Handle log messages
|
|
wg_log(.info, message: logMessage)
|
|
}
|
|
}
|