123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311 |
- //
- // VPNHelper.swift
- // SwiftV2Ray
- //
- // Created by David.Dai on 2019/12/27.
- // Copyright © 2019 david. All rights reserved.
- //
- import Foundation
- import NetworkExtension
- let kProxyServiceVPNStatusNotification = "kProxyServiceVPNStatusNotification"
- enum VPNStatus {
- case off
- case connecting
- case on
- case disconnecting
- }
- public enum VPNSTATUS {
- case connecting
- case connectd
- case close
- }
- class VPNHelper {
- static let `shared` = VPNHelper()
- var manager: NETunnelProviderManager? = nil
- private var openVPNClosure: ((_ error: Error?) -> Void)? = nil
- private var openStatusVPN: ((_ status: VPNSTATUS?) -> Void)? = nil
- private var closeVPNClosure: (() -> Void)? = nil
-
- var observerAdded: Bool = false
-
- fileprivate(set) var vpnStatus = VPNStatus.off {
- didSet {
- NotificationCenter.default.post(name: Notification.Name(rawValue: kProxyServiceVPNStatusNotification), object: nil)
- }
- }
-
- deinit {
- NotificationCenter.default.removeObserver(self)
- }
-
-
- init() {
- loadProviderManager{
- guard let manager = $0 else{return}
- self.updateVPNStatus(manager)
- self.manager = manager
- }
- addVPNStatusObserver()
- }
-
- func addVPNStatusObserver() {
- guard !observerAdded else{
- return
- }
- loadProviderManager { [unowned self] (manager) -> Void in
- if let manager = manager {
- self.observerAdded = true
- NotificationCenter.default.addObserver(forName: NSNotification.Name.NEVPNStatusDidChange, object: manager.connection, queue: OperationQueue.main, using: { [unowned self] (notification) -> Void in
- self.updateVPNStatus(manager)
- })
- }
- }
- }
-
- func updateVPNStatus(_ manager: NEVPNManager) {
- switch manager.connection.status {
- case .connected:
- self.vpnStatus = .on
- case .connecting, .reasserting:
- self.vpnStatus = .connecting
- case .disconnecting:
- self.vpnStatus = .disconnecting
- case .disconnected, .invalid:
- self.vpnStatus = .off
- @unknown default: break
-
- }
- print(self.vpnStatus)
- }
-
-
-
- func open(with message: PacketTunnelMessage, completion: @escaping((_ error: Error?) -> Void)) {
- // guard openVPNClosure == nil else {
- // completion(NSError(domain: "VPNHelper", code: -1, userInfo: ["error" : "正在处理中"]))
- // return
- // }
- //
- //// guard openStatusVPN == nil else {
- //// completion(NSError(domain: "VPNHelper", code: -1, userInfo: ["error" : "正在处理中"]))
- //// return
- //// }
- //
- //
- // self.openVPNClosure = completion
-
- let fetchClosure = {[weak self] (manager: NETunnelProviderManager?, error: Error?) in
- var openError = error
- guard let manager = manager else {
- completion(openError)
- return
- }
- if self?.manager == nil {
- self?.updateVPNStatus(manager)
- self?.addVPNStatusObserver()
- }
-
-
- guard manager.connection.status != .connected else {
- completion(nil)
- self?.openVPNClosure = nil
- self?.openStatusVPN = nil
- return
- }
-
- PacketTunnelMessage.messageTo(manager.connection as? NETunnelProviderSession, message) { (error, response) in
- guard error == nil else {
- completion(error)
- self?.stopObservingStatus(manager)
- return
- }
-
- //self?.observeStatus(manager)
- do {
- try manager.connection.startVPNTunnel(options: [:])
- } catch let starError {
- NSLog(starError.localizedDescription)
- openError = starError
- }
-
- guard openError == nil else {
- completion(openError)
- self?.stopObservingStatus(manager)
- return
- }
-
-
- if self?.manager == nil {
-
- self?.manager = manager
- }
-
- }
- }
-
-
-
- // 获取VPN配置
- NETunnelProviderManager.loadAllFromPreferences { (managers, error) in
- guard let vpnManagers = managers else {
- fetchClosure(nil, error)
- return
- }
- if vpnManagers.count > 0 {
- vpnManagers[0].isEnabled = true
- vpnManagers[0].saveToPreferences(completionHandler: { (error) in
- if error != nil {
- fetchClosure(nil, error)
- return
- }
- vpnManagers[0].loadFromPreferences(completionHandler: { (error) in
- fetchClosure(vpnManagers[0], error)
- })
- })
- return
- }
- let manager = NETunnelProviderManager()
- manager.protocolConfiguration = NETunnelProviderProtocol()
- manager.protocolConfiguration?.serverAddress = "127.0.0.1"
- manager.localizedDescription = "Naiyou"
- manager.isEnabled = true
- manager.saveToPreferences(completionHandler: { (error) in
- if error != nil {
- fetchClosure(nil, error)
- return
- }
- manager.loadFromPreferences(completionHandler: { (error) in
- fetchClosure(manager, error)
- })
- })
- }
- }
-
- func close(completion: @escaping(() -> Void)) {
- // guard self.closeVPNClosure == nil else {
- // completion()
- // return
- // }
-
- guard let manager = self.manager else {
- completion()
- return
- }
-
- self.closeVPNClosure = completion
- manager.connection.stopVPNTunnel()
- //self.stopObservingStatus(manager)
- }
-
- private func observeStatus(_ manager: NETunnelProviderManager) {
- NotificationCenter.default.removeObserver(self, name: NSNotification.Name.NEVPNStatusDidChange, object: manager.connection)
- NotificationCenter.default.addObserver(forName: NSNotification.Name.NEVPNStatusDidChange, object: manager.connection, queue: OperationQueue.main,using: {
- [weak self] notification in
- let connection = notification.object as? NEVPNConnection
- switch connection?.status {
- case .none:
- print("无")
-
- case .some(.invalid):
- print("无效")
- self?.openVPNClosure?(NSError(domain: "VPNHelper", code: (connection?.status)!.rawValue, userInfo: ["error" : "连接无效"]))
- self?.openVPNClosure = nil
- self?.closeVPNClosure?()
- self?.closeVPNClosure = nil
- self?.openStatusVPN?(VPNSTATUS.close)
- //self?.openStatusVPN = nil
- self?.vpnStatus = .off
-
- case .some(.connecting):
- print("VPN通道连接中")
- self?.openStatusVPN?(VPNSTATUS.connecting)
- //self?.openStatusVPN = nil
- self?.vpnStatus = .connecting
- case .some(.connected):
- print("VPN通道连接上了")
- self?.openVPNClosure?(nil)
- self?.openVPNClosure = nil
- self?.openStatusVPN?(VPNSTATUS.connectd)
- self?.openStatusVPN = nil
- self?.vpnStatus = .on
-
- case .some(.reasserting):
- print("断言")
- self?.openVPNClosure?(NSError(domain: "VPNHelper", code: (connection?.status)!.rawValue, userInfo: ["error" : "断言"]))
- self?.openVPNClosure = nil
- self?.closeVPNClosure?()
- self?.closeVPNClosure = nil
- self?.openStatusVPN?(VPNSTATUS.close)
- self?.openStatusVPN = nil
- self?.vpnStatus = .off
-
- case .some(.disconnecting):
- print("VPN通道断开连接中")
- self?.openVPNClosure?(NSError(domain: "VPNHelper", code: (connection?.status)!.rawValue, userInfo: ["error" : "断开连接"]))
- self?.openVPNClosure = nil
- self?.openStatusVPN?(VPNSTATUS.close)
- //self?.openStatusVPN = nil
- self?.vpnStatus = .disconnecting
-
- case .some(_):
- print("其他")
- self?.openVPNClosure?(NSError(domain: "VPNHelper", code: (connection?.status)!.rawValue, userInfo: ["error" : "其他"]))
- self?.openVPNClosure = nil
- self?.openStatusVPN?(VPNSTATUS.close)
- self?.vpnStatus = .off
- DispatchQueue.main.asyncAfter(deadline: .now() + 0.15) {
- self?.closeVPNClosure?()
- self?.closeVPNClosure = nil
- self?.openStatusVPN?(VPNSTATUS.close)
- self?.openStatusVPN = nil
- self?.vpnStatus = .off
- }
- }
- })
- }
- private func stopObservingStatus(_ manager: NETunnelProviderManager) {
- NotificationCenter.default.removeObserver(self, name: NSNotification.Name.NEVPNStatusDidChange, object: manager.connection)
- }
- }
- // load VPN Profiles
- extension VPNHelper{
-
- func loadProviderManager(_ complete: @escaping (NETunnelProviderManager?) -> Void){
- NETunnelProviderManager.loadAllFromPreferences { (managers, error) in
- if let managers = managers {
- if managers.count > 0 {
- let manager = managers[0]
- complete(manager)
- return
- }
- }
- complete(nil)
- }
- }
-
-
- func delDupConfig(_ arrays:[NETunnelProviderManager]){
- if (arrays.count)>1{
- for i in 0 ..< arrays.count{
- print("Del DUP Profiles")
- arrays[i].removeFromPreferences(completionHandler: { (error) in
- if(error != nil){print(error.debugDescription)}
- })
- }
- }
- }
- }
|