PacketTunnelProvider.swift 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. //
  2. // PacketTunnelProvider.swift
  3. // neiyoujsql
  4. //
  5. // Created by C Auto on 2021/6/29.
  6. //
  7. import NetworkExtension
  8. //let appGroup = "group.com.naiaaa.calska2"
  9. class PacketTunnelProvider: NEPacketTunnelProvider {
  10. var message: PacketTunnelMessage? = nil
  11. var tunFd : Int32?
  12. var conf : String = ""
  13. var lastPath : NWPath?
  14. var appGroup : String = ""
  15. override func startTunnel(options: [String : NSObject]?, completionHandler: @escaping (Error?) -> Void) {
  16. // Add code here to start the process of connecting the tunnel.
  17. //tunFd = self.packetFlow.value(forKeyPath: "socket.fileDescriptor") as! Int16
  18. tunFd = getFD()
  19. if let appgroup = message?.appGroup {
  20. appGroup = appgroup
  21. }
  22. else {
  23. completionHandler(NSError(domain: "PacketTunnel", code: -1, userInfo: ["error" : "读取不到配置"]))
  24. return
  25. }
  26. // guard let appgroup = message?.appGroup else {
  27. //
  28. // }
  29. //
  30. // 启动Tun2scoks
  31. if let configData = message?.configData {
  32. conf = String(decoding: configData, as: UTF8.self)
  33. } else {
  34. completionHandler(NSError(domain: "PacketTunnel", code: -1, userInfo: ["error" : "读取不到配置"]))
  35. return
  36. }
  37. // 配置PacketTunel
  38. self.setupTunnel(message: message!) {[weak self] (error) in
  39. //self?.proxyPackets()
  40. let confWithFd = self?.conf.replacingOccurrences(of: "REPLACE-ME-WITH-THE-FD", with: String(self?.tunFd ?? 0))
  41. // let url = FileManager().containerURL(forSecurityApplicationGroupIdentifier: self?.appGroup ?? "")!.appendingPathComponent("running_config.conf")
  42. let msg = confWithFd ?? ""
  43. let fileName = "/running_config.conf"
  44. // let fileManager = FileManager.default
  45. let file = NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.documentDirectory, FileManager.SearchPathDomainMask.userDomainMask, true).first
  46. let path = file! + fileName
  47. if !FileManager.default.fileExists(atPath: path) {
  48. FileManager.default.createFile(atPath: path, contents: nil, attributes: nil)
  49. } else {
  50. do{
  51. //删除指定位置的内容
  52. try FileManager.default.removeItem(atPath: path)
  53. print("Success to remove folder.")
  54. }catch{
  55. print("Failder to remove folder")
  56. }
  57. FileManager.default.createFile(atPath: path, contents: nil, attributes: nil)
  58. }
  59. let handle = FileHandle(forWritingAtPath:path)
  60. handle?.write(msg.data(using: String.Encoding.utf8)!)
  61. try? handle?.close()
  62. // let status = leaf_test_config(String(path))
  63. //
  64. // print(status)
  65. // let path = path.absoluteString
  66. // let start = path.index(path.startIndex, offsetBy: 7)
  67. // let subpath = path[start..<path.endIndex]
  68. DispatchQueue.global(qos: .userInteractive).async {
  69. signal(SIGPIPE, SIG_IGN)
  70. leaf_run(UInt16(self!.tunFd ?? 0),String(path))
  71. }
  72. completionHandler(error)
  73. }
  74. }
  75. override func stopTunnel(with reason: NEProviderStopReason, completionHandler: @escaping () -> Void) {
  76. // Add code here to start the process of stopping the tunnel.
  77. leaf_shutdown(UInt16(self.tunFd ?? 0))
  78. completionHandler()
  79. }
  80. override func handleAppMessage(_ messageData: Data, completionHandler: ((Data?) -> Void)?) {
  81. message = try? JSONDecoder().decode(PacketTunnelMessage.self, from: messageData)
  82. if let handler = completionHandler {
  83. handler(messageData)
  84. }
  85. }
  86. override func sleep(completionHandler: @escaping () -> Void) {
  87. // Add code here to get ready to sleep.
  88. completionHandler()
  89. }
  90. override func wake() {
  91. // Add code here to wake up.
  92. }
  93. }
  94. extension PacketTunnelProvider {
  95. func getFD() -> Int32? {
  96. if #available(iOS 15, *) {
  97. var buf = [CChar](repeating: 0, count: Int(IFNAMSIZ))
  98. let utunPrefix = "utun".utf8CString.dropLast()
  99. return (0...1024).first { (_ fd: Int32) -> Bool in
  100. var len = socklen_t(buf.count)
  101. return getsockopt(fd, 2, 2, &buf, &len) == 0 && buf.starts(with: utunPrefix)
  102. }
  103. } else {
  104. return self.packetFlow.value(forKeyPath: "socket.fileDescriptor") as? Int32
  105. }
  106. }
  107. func setupTunnel(message: PacketTunnelMessage, _ completion: @escaping((_ error: Error?) -> Void)) {
  108. guard let serverIP = message.serverIP else {
  109. completion(NSError(domain: "PacketTunnel", code: -1, userInfo: ["error" : "没有IP地址"]))
  110. return
  111. }
  112. let networkSettings = NEPacketTunnelNetworkSettings(tunnelRemoteAddress: serverIP)
  113. networkSettings.mtu = 1500
  114. let ipv4Settings = NEIPv4Settings(addresses: [serverIP], subnetMasks: ["255.255.255.0"])
  115. var includeRoutes: Array<NEIPv4Route> = []
  116. for route in message.ipv4IncludedRoutes {
  117. includeRoutes.append(NEIPv4Route(destinationAddress: route.0, subnetMask: route.1))
  118. }
  119. var excludeRoutes: Array<NEIPv4Route> = []
  120. for route in message.ipv4ExcludedRoutes {
  121. excludeRoutes.append(NEIPv4Route(destinationAddress: route.0, subnetMask: route.1))
  122. }
  123. ipv4Settings.includedRoutes = includeRoutes.count == 0 ? [NEIPv4Route.default()] : includeRoutes
  124. ipv4Settings.excludedRoutes = excludeRoutes
  125. networkSettings.ipv4Settings = ipv4Settings
  126. networkSettings.dnsSettings = NEDNSSettings(servers: message.dnsServers)
  127. let proxySettings = NEProxySettings()
  128. proxySettings.httpEnabled = true
  129. proxySettings.httpsEnabled = true
  130. proxySettings.autoProxyConfigurationEnabled = true
  131. // let httpsServer = NEProxyServer(address: "127.0.0.1", port: 1087)
  132. // httpsServer.authenticationRequired = false
  133. // proxySettings.httpsServer = httpsServer
  134. // proxySettings.httpServer = httpsServer
  135. proxySettings.exceptionList = message.proxyExeptionList
  136. proxySettings.matchDomains = message.proxyMatchDomains
  137. networkSettings.proxySettings = proxySettings
  138. self.setTunnelNetworkSettings(networkSettings) {error in
  139. completion(error)
  140. }
  141. }
  142. }
  143. extension PacketTunnelProvider {
  144. /// 监听网络状态,切换不同的网络的时候,需要重新连接vpn
  145. override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
  146. if keyPath == "defaultPath" {
  147. if self.defaultPath?.status == .satisfied && self.defaultPath != self.lastPath {
  148. if (self.lastPath == nil) {
  149. self.lastPath = self.defaultPath
  150. } else {
  151. NSLog("received network change notifcation")
  152. let xSeconds = 1.0
  153. DispatchQueue.main.asyncAfter(deadline: .now() + xSeconds) {
  154. self.startTunnel(options: nil){ _ in }
  155. }
  156. }
  157. } else {
  158. self.lastPath = defaultPath
  159. }
  160. }
  161. }
  162. }