123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199 |
- //
- // PacketTunnelProvider.swift
- // neiyoujsql
- //
- // Created by C Auto on 2021/6/29.
- //
- import NetworkExtension
- //let appGroup = "group.com.naiaaa.calska2"
- class PacketTunnelProvider: NEPacketTunnelProvider {
- var message: PacketTunnelMessage? = nil
- var tunFd : Int32?
- var conf : String = ""
- var lastPath : NWPath?
- var appGroup : String = ""
- override func startTunnel(options: [String : NSObject]?, completionHandler: @escaping (Error?) -> Void) {
- // Add code here to start the process of connecting the tunnel.
-
- //tunFd = self.packetFlow.value(forKeyPath: "socket.fileDescriptor") as! Int16
- tunFd = getFD()
- if let appgroup = message?.appGroup {
- appGroup = appgroup
- }
- else {
- completionHandler(NSError(domain: "PacketTunnel", code: -1, userInfo: ["error" : "读取不到配置"]))
- return
- }
- // guard let appgroup = message?.appGroup else {
- //
- // }
- //
-
-
- // 启动Tun2scoks
- if let configData = message?.configData {
-
- conf = String(decoding: configData, as: UTF8.self)
-
- } else {
- completionHandler(NSError(domain: "PacketTunnel", code: -1, userInfo: ["error" : "读取不到配置"]))
- return
- }
-
- // 配置PacketTunel
- self.setupTunnel(message: message!) {[weak self] (error) in
- //self?.proxyPackets()
- let confWithFd = self?.conf.replacingOccurrences(of: "REPLACE-ME-WITH-THE-FD", with: String(self?.tunFd ?? 0))
- // let url = FileManager().containerURL(forSecurityApplicationGroupIdentifier: self?.appGroup ?? "")!.appendingPathComponent("running_config.conf")
- let msg = confWithFd ?? ""
- let fileName = "/running_config.conf"
- // let fileManager = FileManager.default
- let file = NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.documentDirectory, FileManager.SearchPathDomainMask.userDomainMask, true).first
- let path = file! + fileName
- if !FileManager.default.fileExists(atPath: path) {
- FileManager.default.createFile(atPath: path, contents: nil, attributes: nil)
-
- } else {
- do{
- //删除指定位置的内容
- try FileManager.default.removeItem(atPath: path)
- print("Success to remove folder.")
- }catch{
- print("Failder to remove folder")
- }
- FileManager.default.createFile(atPath: path, contents: nil, attributes: nil)
- }
- let handle = FileHandle(forWritingAtPath:path)
-
- handle?.write(msg.data(using: String.Encoding.utf8)!)
- try? handle?.close()
-
- // let status = leaf_test_config(String(path))
- //
- // print(status)
-
-
- // let path = path.absoluteString
- // let start = path.index(path.startIndex, offsetBy: 7)
- // let subpath = path[start..<path.endIndex]
- DispatchQueue.global(qos: .userInteractive).async {
- signal(SIGPIPE, SIG_IGN)
- leaf_run(UInt16(self!.tunFd ?? 0),String(path))
- }
-
-
- completionHandler(error)
- }
-
- }
-
- override func stopTunnel(with reason: NEProviderStopReason, completionHandler: @escaping () -> Void) {
- // Add code here to start the process of stopping the tunnel.
-
- leaf_shutdown(UInt16(self.tunFd ?? 0))
-
- completionHandler()
- }
-
- override func handleAppMessage(_ messageData: Data, completionHandler: ((Data?) -> Void)?) {
- message = try? JSONDecoder().decode(PacketTunnelMessage.self, from: messageData)
- if let handler = completionHandler {
- handler(messageData)
- }
- }
-
- override func sleep(completionHandler: @escaping () -> Void) {
- // Add code here to get ready to sleep.
- completionHandler()
- }
-
- override func wake() {
- // Add code here to wake up.
- }
- }
- extension PacketTunnelProvider {
-
-
-
-
- func getFD() -> Int32? {
- if #available(iOS 15, *) {
- var buf = [CChar](repeating: 0, count: Int(IFNAMSIZ))
- let utunPrefix = "utun".utf8CString.dropLast()
- return (0...1024).first { (_ fd: Int32) -> Bool in
- var len = socklen_t(buf.count)
- return getsockopt(fd, 2, 2, &buf, &len) == 0 && buf.starts(with: utunPrefix)
- }
- } else {
- return self.packetFlow.value(forKeyPath: "socket.fileDescriptor") as? Int32
- }
- }
-
-
- func setupTunnel(message: PacketTunnelMessage, _ completion: @escaping((_ error: Error?) -> Void)) {
- guard let serverIP = message.serverIP else {
- completion(NSError(domain: "PacketTunnel", code: -1, userInfo: ["error" : "没有IP地址"]))
- return
- }
-
- let networkSettings = NEPacketTunnelNetworkSettings(tunnelRemoteAddress: serverIP)
- networkSettings.mtu = 1500
-
- let ipv4Settings = NEIPv4Settings(addresses: [serverIP], subnetMasks: ["255.255.255.0"])
- var includeRoutes: Array<NEIPv4Route> = []
- for route in message.ipv4IncludedRoutes {
- includeRoutes.append(NEIPv4Route(destinationAddress: route.0, subnetMask: route.1))
- }
- var excludeRoutes: Array<NEIPv4Route> = []
- for route in message.ipv4ExcludedRoutes {
- excludeRoutes.append(NEIPv4Route(destinationAddress: route.0, subnetMask: route.1))
- }
- ipv4Settings.includedRoutes = includeRoutes.count == 0 ? [NEIPv4Route.default()] : includeRoutes
- ipv4Settings.excludedRoutes = excludeRoutes
- networkSettings.ipv4Settings = ipv4Settings
- networkSettings.dnsSettings = NEDNSSettings(servers: message.dnsServers)
-
- let proxySettings = NEProxySettings()
- proxySettings.httpEnabled = true
- proxySettings.httpsEnabled = true
- proxySettings.autoProxyConfigurationEnabled = true
- // let httpsServer = NEProxyServer(address: "127.0.0.1", port: 1087)
- // httpsServer.authenticationRequired = false
- // proxySettings.httpsServer = httpsServer
- // proxySettings.httpServer = httpsServer
- proxySettings.exceptionList = message.proxyExeptionList
- proxySettings.matchDomains = message.proxyMatchDomains
- networkSettings.proxySettings = proxySettings
-
- self.setTunnelNetworkSettings(networkSettings) {error in
- completion(error)
- }
- }
- }
- extension PacketTunnelProvider {
- /// 监听网络状态,切换不同的网络的时候,需要重新连接vpn
- override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
- if keyPath == "defaultPath" {
- if self.defaultPath?.status == .satisfied && self.defaultPath != self.lastPath {
- if (self.lastPath == nil) {
- self.lastPath = self.defaultPath
- } else {
- NSLog("received network change notifcation")
- let xSeconds = 1.0
- DispatchQueue.main.asyncAfter(deadline: .now() + xSeconds) {
- self.startTunnel(options: nil){ _ in }
- }
- }
- } else {
- self.lastPath = defaultPath
- }
- }
-
- }
- }
|