PacketTunnelProvider refactoring
- removing unnecessary dispatchQueue - removing lazy initiation for wg and ovpn - fix memory leaks
This commit is contained in:
parent
2254bfc128
commit
9be13ea465
4 changed files with 481 additions and 528 deletions
|
|
@ -22,8 +22,6 @@ extension PacketTunnelProvider {
|
|||
}
|
||||
|
||||
do {
|
||||
// ovpnLog(.info, message: "providerConfiguration: \(String(decoding: openVPNConfigData, as: UTF8.self))")
|
||||
|
||||
let openVPNConfig = try JSONDecoder().decode(OpenVPNConfig.self, from: openVPNConfigData)
|
||||
ovpnLog(.info, title: "config: ", message: openVPNConfig.str)
|
||||
let ovpnConfiguration = Data(openVPNConfig.config.utf8)
|
||||
|
|
@ -52,38 +50,39 @@ extension PacketTunnelProvider {
|
|||
configuration.setPTCloak()
|
||||
}
|
||||
|
||||
let evaluation: OpenVPNConfigurationEvaluation
|
||||
let evaluation: OpenVPNConfigurationEvaluation?
|
||||
do {
|
||||
evaluation = try ovpnAdapter.apply(configuration: configuration)
|
||||
ovpnAdapter = OpenVPNAdapter()
|
||||
ovpnAdapter?.delegate = self
|
||||
evaluation = try ovpnAdapter?.apply(configuration: configuration)
|
||||
|
||||
} catch {
|
||||
completionHandler(error)
|
||||
return
|
||||
}
|
||||
|
||||
if !evaluation.autologin {
|
||||
if evaluation?.autologin == false {
|
||||
ovpnLog(.info, message: "Implement login with user credentials")
|
||||
}
|
||||
|
||||
vpnReachability.startTracking { [weak self] status in
|
||||
guard status == .reachableViaWiFi else { return }
|
||||
self?.ovpnAdapter.reconnect(afterTimeInterval: 5)
|
||||
self?.ovpnAdapter?.reconnect(afterTimeInterval: 5)
|
||||
}
|
||||
|
||||
startHandler = completionHandler
|
||||
ovpnAdapter.connect(using: packetFlow)
|
||||
|
||||
// let ifaces = Interface.allInterfaces()
|
||||
// .filter { $0.family == .ipv4 }
|
||||
// .map { iface in iface.name }
|
||||
|
||||
// ovpn_log(.error, message: "Available TUN Interfaces: \(ifaces)")
|
||||
ovpnAdapter?.connect(using: packetFlow)
|
||||
}
|
||||
|
||||
func handleOpenVPNStatusMessage(_ messageData: Data, completionHandler: ((Data?) -> Void)? = nil) {
|
||||
guard let completionHandler = completionHandler else { return }
|
||||
let bytesin = ovpnAdapter.transportStatistics.bytesIn
|
||||
let bytesout = ovpnAdapter.transportStatistics.bytesOut
|
||||
let bytesin = ovpnAdapter?.transportStatistics.bytesIn
|
||||
let bytesout = ovpnAdapter?.transportStatistics.bytesOut
|
||||
|
||||
guard let bytesin, let bytesout else {
|
||||
completionHandler(nil)
|
||||
return
|
||||
}
|
||||
|
||||
let response: [String: Any] = [
|
||||
"rx_bytes": bytesin,
|
||||
|
|
@ -100,7 +99,7 @@ extension PacketTunnelProvider {
|
|||
if vpnReachability.isTracking {
|
||||
vpnReachability.stopTracking()
|
||||
}
|
||||
ovpnAdapter.disconnect()
|
||||
ovpnAdapter?.disconnect()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -123,6 +122,11 @@ extension PacketTunnelProvider: OpenVPNAdapterDelegate {
|
|||
if splitTunnelType == 1 {
|
||||
var ipv4IncludedRoutes = [NEIPv4Route]()
|
||||
|
||||
guard let splitTunnelSites else {
|
||||
completionHandler(NSError(domain: "Split tunnel sited not setted up", code: 0))
|
||||
return
|
||||
}
|
||||
|
||||
for allowedIPString in splitTunnelSites {
|
||||
if let allowedIP = IPAddressRange(from: allowedIPString) {
|
||||
ipv4IncludedRoutes.append(NEIPv4Route(
|
||||
|
|
@ -138,6 +142,11 @@ extension PacketTunnelProvider: OpenVPNAdapterDelegate {
|
|||
var ipv4IncludedRoutes = [NEIPv4Route]()
|
||||
var ipv6IncludedRoutes = [NEIPv6Route]()
|
||||
|
||||
guard let splitTunnelSites else {
|
||||
completionHandler(NSError(domain: "Split tunnel sited not setted up", code: 0))
|
||||
return
|
||||
}
|
||||
|
||||
for excludeIPString in splitTunnelSites {
|
||||
if let excludeIP = IPAddressRange(from: excludeIPString) {
|
||||
ipv4ExcludedRoutes.append(NEIPv4Route(
|
||||
|
|
|
|||
|
|
@ -55,9 +55,13 @@ extension PacketTunnelProvider {
|
|||
(activationAttemptId == nil ? "OS directly, rather than the app" : "app"))
|
||||
|
||||
// Start the tunnel
|
||||
wgAdapter.start(tunnelConfiguration: tunnelConfiguration) { adapterError in
|
||||
wgAdapter = WireGuardAdapter(with: self) { logLevel, message in
|
||||
wg_log(logLevel.osLogLevel, message: message)
|
||||
}
|
||||
|
||||
wgAdapter?.start(tunnelConfiguration: tunnelConfiguration) { [weak self] adapterError in
|
||||
guard let adapterError else {
|
||||
let interfaceName = self.wgAdapter.interfaceName ?? "unknown"
|
||||
let interfaceName = self?.wgAdapter?.interfaceName ?? "unknown"
|
||||
wg_log(.info, message: "Tunnel interface is \(interfaceName)")
|
||||
completionHandler(nil)
|
||||
return
|
||||
|
|
@ -97,12 +101,7 @@ extension PacketTunnelProvider {
|
|||
|
||||
func handleWireguardStatusMessage(_ messageData: Data, completionHandler: ((Data?) -> Void)? = nil) {
|
||||
guard let completionHandler = completionHandler else { return }
|
||||
wgAdapter.getRuntimeConfiguration { settings in
|
||||
var data: Data?
|
||||
if let settings {
|
||||
data = settings.data(using: .utf8)!
|
||||
}
|
||||
|
||||
wgAdapter?.getRuntimeConfiguration { settings in
|
||||
let components = settings!.components(separatedBy: "\n")
|
||||
|
||||
var settingsDictionary: [String: String] = [:]
|
||||
|
|
@ -125,7 +124,7 @@ extension PacketTunnelProvider {
|
|||
private func handleWireguardAppMessage(_ messageData: Data, completionHandler: ((Data?) -> Void)? = nil) {
|
||||
guard let completionHandler = completionHandler else { return }
|
||||
if messageData.count == 1 && messageData[0] == 0 {
|
||||
wgAdapter.getRuntimeConfiguration { settings in
|
||||
wgAdapter?.getRuntimeConfiguration { settings in
|
||||
var data: Data?
|
||||
if let settings {
|
||||
data = settings.data(using: .utf8)!
|
||||
|
|
@ -143,14 +142,14 @@ extension PacketTunnelProvider {
|
|||
|
||||
do {
|
||||
let tunnelConfiguration = try TunnelConfiguration(fromWgQuickConfig: configString)
|
||||
wgAdapter.update(tunnelConfiguration: tunnelConfiguration) { error in
|
||||
wgAdapter?.update(tunnelConfiguration: tunnelConfiguration) { [weak self] error in
|
||||
if let error {
|
||||
wg_log(.error, message: "Failed to switch tunnel configuration: \(error.localizedDescription)")
|
||||
completionHandler(nil)
|
||||
return
|
||||
}
|
||||
|
||||
self.wgAdapter.getRuntimeConfiguration { settings in
|
||||
self?.wgAdapter?.getRuntimeConfiguration { settings in
|
||||
var data: Data?
|
||||
if let settings {
|
||||
data = settings.data(using: .utf8)!
|
||||
|
|
@ -166,43 +165,10 @@ extension PacketTunnelProvider {
|
|||
}
|
||||
}
|
||||
|
||||
// private func startEmptyTunnel(completionHandler: @escaping (Error?) -> Void) {
|
||||
// dispatchPrecondition(condition: .onQueue(dispatchQueue))
|
||||
//
|
||||
// let emptyTunnelConfiguration = TunnelConfiguration(
|
||||
// name: nil,
|
||||
// interface: InterfaceConfiguration(privateKey: PrivateKey()),
|
||||
// peers: []
|
||||
// )
|
||||
//
|
||||
// wgAdapter.start(tunnelConfiguration: emptyTunnelConfiguration) { error in
|
||||
// self.dispatchQueue.async {
|
||||
// if let error {
|
||||
// wg_log(.error, message: "Failed to start an empty tunnel")
|
||||
// completionHandler(error)
|
||||
// } else {
|
||||
// wg_log(.info, message: "Started an empty tunnel")
|
||||
// self.tunnelAdapterDidStart()
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// let settings = NETunnelNetworkSettings(tunnelRemoteAddress: "1.1.1.1")
|
||||
//
|
||||
// self.setTunnelNetworkSettings(settings) { error in
|
||||
// completionHandler(error)
|
||||
// }
|
||||
// }
|
||||
|
||||
// private func tunnelAdapterDidStart() {
|
||||
// dispatchPrecondition(condition: .onQueue(dispatchQueue))
|
||||
// // ...
|
||||
// }
|
||||
|
||||
func stopWireguard(with reason: NEProviderStopReason, completionHandler: @escaping () -> Void) {
|
||||
wg_log(.info, message: "Stopping tunnel: reason: \(reason.description)")
|
||||
|
||||
wgAdapter.stop { error in
|
||||
wgAdapter?.stop { error in
|
||||
ErrorNotifier.removeLastErrorFile()
|
||||
|
||||
if let error {
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import Darwin
|
|||
import OpenVPNAdapter
|
||||
|
||||
enum TunnelProtoType: String {
|
||||
case wireguard, openvpn, shadowsocks, none
|
||||
case wireguard, openvpn
|
||||
}
|
||||
|
||||
struct Constants {
|
||||
|
|
@ -34,29 +34,17 @@ struct Constants {
|
|||
}
|
||||
|
||||
class PacketTunnelProvider: NEPacketTunnelProvider {
|
||||
lazy var wgAdapter = {
|
||||
WireGuardAdapter(with: self) { logLevel, message in
|
||||
wg_log(logLevel.osLogLevel, message: message)
|
||||
}
|
||||
}()
|
||||
var wgAdapter: WireGuardAdapter?
|
||||
var ovpnAdapter: OpenVPNAdapter?
|
||||
|
||||
lazy var ovpnAdapter: OpenVPNAdapter = {
|
||||
let adapter = OpenVPNAdapter()
|
||||
adapter.delegate = self
|
||||
return adapter
|
||||
}()
|
||||
|
||||
/// Internal queue.
|
||||
private let dispatchQueue = DispatchQueue(label: "PacketTunnel", qos: .utility)
|
||||
|
||||
var splitTunnelType: Int!
|
||||
var splitTunnelSites: [String]!
|
||||
var splitTunnelType: Int?
|
||||
var splitTunnelSites: [String]?
|
||||
|
||||
let vpnReachability = OpenVPNReachability()
|
||||
|
||||
var startHandler: ((Error?) -> Void)?
|
||||
var stopHandler: (() -> Void)?
|
||||
var protoType: TunnelProtoType = .none
|
||||
var protoType: TunnelProtoType?
|
||||
|
||||
override func handleAppMessage(_ messageData: Data, completionHandler: ((Data?) -> Void)? = nil) {
|
||||
guard let message = String(data: messageData, encoding: .utf8) else {
|
||||
|
|
@ -85,85 +73,75 @@ class PacketTunnelProvider: NEPacketTunnelProvider {
|
|||
}
|
||||
|
||||
if action == Constants.kActionStatus {
|
||||
handleStatusAppMessage(messageData, completionHandler: completionHandler)
|
||||
handleStatusAppMessage(messageData,
|
||||
completionHandler: completionHandler)
|
||||
}
|
||||
}
|
||||
|
||||
override func startTunnel(options: [String: NSObject]?, completionHandler: @escaping (Error?) -> Void) {
|
||||
dispatchQueue.async {
|
||||
override func startTunnel(options: [String : NSObject]? = nil,
|
||||
completionHandler: @escaping ((any Error)?) -> Void) {
|
||||
let activationAttemptId = options?[Constants.kActivationAttemptId] as? String
|
||||
let errorNotifier = ErrorNotifier(activationAttemptId: activationAttemptId)
|
||||
|
||||
neLog(.info, message: "Start tunnel")
|
||||
|
||||
if let protocolConfiguration = self.protocolConfiguration as? NETunnelProviderProtocol {
|
||||
if let protocolConfiguration = protocolConfiguration as? NETunnelProviderProtocol {
|
||||
let providerConfiguration = protocolConfiguration.providerConfiguration
|
||||
if (providerConfiguration?[Constants.ovpnConfigKey] as? Data) != nil {
|
||||
self.protoType = .openvpn
|
||||
protoType = .openvpn
|
||||
} else if (providerConfiguration?[Constants.wireGuardConfigKey] as? Data) != nil {
|
||||
self.protoType = .wireguard
|
||||
protoType = .wireguard
|
||||
}
|
||||
} else {
|
||||
self.protoType = .none
|
||||
}
|
||||
|
||||
switch self.protoType {
|
||||
guard let protoType else {
|
||||
let error = NSError(domain: "Protocol is not selected", code: 0)
|
||||
completionHandler(error)
|
||||
return
|
||||
}
|
||||
|
||||
switch protoType {
|
||||
case .wireguard:
|
||||
self.startWireguard(activationAttemptId: activationAttemptId,
|
||||
startWireguard(activationAttemptId: activationAttemptId,
|
||||
errorNotifier: errorNotifier,
|
||||
completionHandler: completionHandler)
|
||||
case .openvpn:
|
||||
self.startOpenVPN(completionHandler: completionHandler)
|
||||
case .shadowsocks:
|
||||
break
|
||||
// startShadowSocks(completionHandler: completionHandler)
|
||||
case .none:
|
||||
break
|
||||
}
|
||||
startOpenVPN(completionHandler: completionHandler)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
override func stopTunnel(with reason: NEProviderStopReason, completionHandler: @escaping () -> Void) {
|
||||
dispatchQueue.async {
|
||||
switch self.protoType {
|
||||
case .wireguard:
|
||||
self.stopWireguard(with: reason, completionHandler: completionHandler)
|
||||
case .openvpn:
|
||||
self.stopOpenVPN(with: reason, completionHandler: completionHandler)
|
||||
case .shadowsocks:
|
||||
break
|
||||
// stopShadowSocks(with: reason, completionHandler: completionHandler)
|
||||
case .none:
|
||||
break
|
||||
guard let protoType else {
|
||||
completionHandler()
|
||||
return
|
||||
}
|
||||
|
||||
switch protoType {
|
||||
case .wireguard:
|
||||
stopWireguard(with: reason,
|
||||
completionHandler: completionHandler)
|
||||
case .openvpn:
|
||||
stopOpenVPN(with: reason,
|
||||
completionHandler: completionHandler)
|
||||
}
|
||||
}
|
||||
|
||||
func handleStatusAppMessage(_ messageData: Data, completionHandler: ((Data?) -> Void)? = nil) {
|
||||
guard let protoType else {
|
||||
completionHandler?(nil)
|
||||
return
|
||||
}
|
||||
|
||||
switch protoType {
|
||||
case .wireguard:
|
||||
handleWireguardStatusMessage(messageData, completionHandler: completionHandler)
|
||||
case .openvpn:
|
||||
handleOpenVPNStatusMessage(messageData, completionHandler: completionHandler)
|
||||
case .shadowsocks:
|
||||
break
|
||||
// handleShadowSocksAppMessage(messageData, completionHandler: completionHandler)
|
||||
case .none:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: Network observing methods
|
||||
|
||||
private func startListeningForNetworkChanges() {
|
||||
stopListeningForNetworkChanges()
|
||||
addObserver(self, forKeyPath: Constants.kDefaultPathKey, options: .old, context: nil)
|
||||
}
|
||||
|
||||
private func stopListeningForNetworkChanges() {
|
||||
removeObserver(self, forKeyPath: Constants.kDefaultPathKey)
|
||||
}
|
||||
|
||||
override func observeValue(forKeyPath keyPath: String?,
|
||||
of object: Any?,
|
||||
change: [NSKeyValueChangeKey: Any]?,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue