VPNHelper.swift 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311
  1. //
  2. // VPNHelper.swift
  3. // SwiftV2Ray
  4. //
  5. // Created by David.Dai on 2019/12/27.
  6. // Copyright © 2019 david. All rights reserved.
  7. //
  8. import Foundation
  9. import NetworkExtension
  10. let kProxyServiceVPNStatusNotification = "kProxyServiceVPNStatusNotification"
  11. enum VPNStatus {
  12. case off
  13. case connecting
  14. case on
  15. case disconnecting
  16. }
  17. public enum VPNSTATUS {
  18. case connecting
  19. case connectd
  20. case close
  21. }
  22. class VPNHelper {
  23. static let `shared` = VPNHelper()
  24. var manager: NETunnelProviderManager? = nil
  25. private var openVPNClosure: ((_ error: Error?) -> Void)? = nil
  26. private var openStatusVPN: ((_ status: VPNSTATUS?) -> Void)? = nil
  27. private var closeVPNClosure: (() -> Void)? = nil
  28. var observerAdded: Bool = false
  29. fileprivate(set) var vpnStatus = VPNStatus.off {
  30. didSet {
  31. NotificationCenter.default.post(name: Notification.Name(rawValue: kProxyServiceVPNStatusNotification), object: nil)
  32. }
  33. }
  34. deinit {
  35. NotificationCenter.default.removeObserver(self)
  36. }
  37. init() {
  38. loadProviderManager{
  39. guard let manager = $0 else{return}
  40. self.updateVPNStatus(manager)
  41. self.manager = manager
  42. }
  43. addVPNStatusObserver()
  44. }
  45. func addVPNStatusObserver() {
  46. guard !observerAdded else{
  47. return
  48. }
  49. loadProviderManager { [unowned self] (manager) -> Void in
  50. if let manager = manager {
  51. self.observerAdded = true
  52. NotificationCenter.default.addObserver(forName: NSNotification.Name.NEVPNStatusDidChange, object: manager.connection, queue: OperationQueue.main, using: { [unowned self] (notification) -> Void in
  53. self.updateVPNStatus(manager)
  54. })
  55. }
  56. }
  57. }
  58. func updateVPNStatus(_ manager: NEVPNManager) {
  59. switch manager.connection.status {
  60. case .connected:
  61. self.vpnStatus = .on
  62. case .connecting, .reasserting:
  63. self.vpnStatus = .connecting
  64. case .disconnecting:
  65. self.vpnStatus = .disconnecting
  66. case .disconnected, .invalid:
  67. self.vpnStatus = .off
  68. @unknown default: break
  69. }
  70. print(self.vpnStatus)
  71. }
  72. func open(with message: PacketTunnelMessage, completion: @escaping((_ error: Error?) -> Void)) {
  73. // guard openVPNClosure == nil else {
  74. // completion(NSError(domain: "VPNHelper", code: -1, userInfo: ["error" : "正在处理中"]))
  75. // return
  76. // }
  77. //
  78. //// guard openStatusVPN == nil else {
  79. //// completion(NSError(domain: "VPNHelper", code: -1, userInfo: ["error" : "正在处理中"]))
  80. //// return
  81. //// }
  82. //
  83. //
  84. // self.openVPNClosure = completion
  85. let fetchClosure = {[weak self] (manager: NETunnelProviderManager?, error: Error?) in
  86. var openError = error
  87. guard let manager = manager else {
  88. completion(openError)
  89. return
  90. }
  91. if self?.manager == nil {
  92. self?.updateVPNStatus(manager)
  93. self?.addVPNStatusObserver()
  94. }
  95. guard manager.connection.status != .connected else {
  96. completion(nil)
  97. self?.openVPNClosure = nil
  98. self?.openStatusVPN = nil
  99. return
  100. }
  101. PacketTunnelMessage.messageTo(manager.connection as? NETunnelProviderSession, message) { (error, response) in
  102. guard error == nil else {
  103. completion(error)
  104. self?.stopObservingStatus(manager)
  105. return
  106. }
  107. //self?.observeStatus(manager)
  108. do {
  109. try manager.connection.startVPNTunnel(options: [:])
  110. } catch let starError {
  111. NSLog(starError.localizedDescription)
  112. openError = starError
  113. }
  114. guard openError == nil else {
  115. completion(openError)
  116. self?.stopObservingStatus(manager)
  117. return
  118. }
  119. if self?.manager == nil {
  120. self?.manager = manager
  121. }
  122. }
  123. }
  124. // 获取VPN配置
  125. NETunnelProviderManager.loadAllFromPreferences { (managers, error) in
  126. guard let vpnManagers = managers else {
  127. fetchClosure(nil, error)
  128. return
  129. }
  130. if vpnManagers.count > 0 {
  131. vpnManagers[0].isEnabled = true
  132. vpnManagers[0].saveToPreferences(completionHandler: { (error) in
  133. if error != nil {
  134. fetchClosure(nil, error)
  135. return
  136. }
  137. vpnManagers[0].loadFromPreferences(completionHandler: { (error) in
  138. fetchClosure(vpnManagers[0], error)
  139. })
  140. })
  141. return
  142. }
  143. let manager = NETunnelProviderManager()
  144. manager.protocolConfiguration = NETunnelProviderProtocol()
  145. manager.protocolConfiguration?.serverAddress = "127.0.0.1"
  146. manager.localizedDescription = "Naiyou"
  147. manager.isEnabled = true
  148. manager.saveToPreferences(completionHandler: { (error) in
  149. if error != nil {
  150. fetchClosure(nil, error)
  151. return
  152. }
  153. manager.loadFromPreferences(completionHandler: { (error) in
  154. fetchClosure(manager, error)
  155. })
  156. })
  157. }
  158. }
  159. func close(completion: @escaping(() -> Void)) {
  160. // guard self.closeVPNClosure == nil else {
  161. // completion()
  162. // return
  163. // }
  164. guard let manager = self.manager else {
  165. completion()
  166. return
  167. }
  168. self.closeVPNClosure = completion
  169. manager.connection.stopVPNTunnel()
  170. //self.stopObservingStatus(manager)
  171. }
  172. private func observeStatus(_ manager: NETunnelProviderManager) {
  173. NotificationCenter.default.removeObserver(self, name: NSNotification.Name.NEVPNStatusDidChange, object: manager.connection)
  174. NotificationCenter.default.addObserver(forName: NSNotification.Name.NEVPNStatusDidChange, object: manager.connection, queue: OperationQueue.main,using: {
  175. [weak self] notification in
  176. let connection = notification.object as? NEVPNConnection
  177. switch connection?.status {
  178. case .none:
  179. print("无")
  180. case .some(.invalid):
  181. print("无效")
  182. self?.openVPNClosure?(NSError(domain: "VPNHelper", code: (connection?.status)!.rawValue, userInfo: ["error" : "连接无效"]))
  183. self?.openVPNClosure = nil
  184. self?.closeVPNClosure?()
  185. self?.closeVPNClosure = nil
  186. self?.openStatusVPN?(VPNSTATUS.close)
  187. //self?.openStatusVPN = nil
  188. self?.vpnStatus = .off
  189. case .some(.connecting):
  190. print("VPN通道连接中")
  191. self?.openStatusVPN?(VPNSTATUS.connecting)
  192. //self?.openStatusVPN = nil
  193. self?.vpnStatus = .connecting
  194. case .some(.connected):
  195. print("VPN通道连接上了")
  196. self?.openVPNClosure?(nil)
  197. self?.openVPNClosure = nil
  198. self?.openStatusVPN?(VPNSTATUS.connectd)
  199. self?.openStatusVPN = nil
  200. self?.vpnStatus = .on
  201. case .some(.reasserting):
  202. print("断言")
  203. self?.openVPNClosure?(NSError(domain: "VPNHelper", code: (connection?.status)!.rawValue, userInfo: ["error" : "断言"]))
  204. self?.openVPNClosure = nil
  205. self?.closeVPNClosure?()
  206. self?.closeVPNClosure = nil
  207. self?.openStatusVPN?(VPNSTATUS.close)
  208. self?.openStatusVPN = nil
  209. self?.vpnStatus = .off
  210. case .some(.disconnecting):
  211. print("VPN通道断开连接中")
  212. self?.openVPNClosure?(NSError(domain: "VPNHelper", code: (connection?.status)!.rawValue, userInfo: ["error" : "断开连接"]))
  213. self?.openVPNClosure = nil
  214. self?.openStatusVPN?(VPNSTATUS.close)
  215. //self?.openStatusVPN = nil
  216. self?.vpnStatus = .disconnecting
  217. case .some(_):
  218. print("其他")
  219. self?.openVPNClosure?(NSError(domain: "VPNHelper", code: (connection?.status)!.rawValue, userInfo: ["error" : "其他"]))
  220. self?.openVPNClosure = nil
  221. self?.openStatusVPN?(VPNSTATUS.close)
  222. self?.vpnStatus = .off
  223. DispatchQueue.main.asyncAfter(deadline: .now() + 0.15) {
  224. self?.closeVPNClosure?()
  225. self?.closeVPNClosure = nil
  226. self?.openStatusVPN?(VPNSTATUS.close)
  227. self?.openStatusVPN = nil
  228. self?.vpnStatus = .off
  229. }
  230. }
  231. })
  232. }
  233. private func stopObservingStatus(_ manager: NETunnelProviderManager) {
  234. NotificationCenter.default.removeObserver(self, name: NSNotification.Name.NEVPNStatusDidChange, object: manager.connection)
  235. }
  236. }
  237. // load VPN Profiles
  238. extension VPNHelper{
  239. func loadProviderManager(_ complete: @escaping (NETunnelProviderManager?) -> Void){
  240. NETunnelProviderManager.loadAllFromPreferences { (managers, error) in
  241. if let managers = managers {
  242. if managers.count > 0 {
  243. let manager = managers[0]
  244. complete(manager)
  245. return
  246. }
  247. }
  248. complete(nil)
  249. }
  250. }
  251. func delDupConfig(_ arrays:[NETunnelProviderManager]){
  252. if (arrays.count)>1{
  253. for i in 0 ..< arrays.count{
  254. print("Del DUP Profiles")
  255. arrays[i].removeFromPreferences(completionHandler: { (error) in
  256. if(error != nil){print(error.debugDescription)}
  257. })
  258. }
  259. }
  260. }
  261. }