// // PacketTunnelProvider.swift // punchnet // // Created by 安礼成 on 2025/8/3. // import Foundation import NetworkExtension enum TunnelError: Error { case invalidConfiguration case invalidContext } class PacketTunnelProvider: NEPacketTunnelProvider { private var runtimeEnv: SDLRuntimeEnvironment? override func startTunnel(options: [String: NSObject]?, completionHandler: @escaping (Error?) -> Void) { // 如果当前在运行状态,不允许重复请求 guard self.runtimeEnv == nil else { completionHandler(TunnelError.invalidContext) return } guard let options, let config = SDLConfiguration.parse(options: options) else { completionHandler(TunnelError.invalidConfiguration) return } if self.runtimeEnv == nil { let rsaCipher = try! CCRSACipher(keySize: 1024) self.runtimeEnv = SDLRuntimeEnvironment(config: config, rsaCipher: rsaCipher, provider: self) self.runtimeEnv?.run() } self.runtimeEnv?.submitCommand(command: .start(completion: { err in completionHandler(err) })) } override func stopTunnel(with reason: NEProviderStopReason, completionHandler: @escaping () -> Void) { // Add code here to start the process of stopping the tunnel. self.runtimeEnv?.submitCommand(command: .stop(completion: { completionHandler() })) } override func handleAppMessage(_ messageData: Data, completionHandler: ((Data?) -> Void)?) { // Add code here to handle the message. Task { do { let message = try AppRequest(serializedBytes: messageData) let replyData = try await self.handleAppRequest(message: message) completionHandler?(replyData) } catch let err { var reply = TunnelResponse() reply.code = 1 reply.message = err.localizedDescription let errorReplyData = try? reply.serializedData() completionHandler?(errorReplyData) } } } override func sleep(completionHandler: @escaping () -> Void) { // Add code here to get ready to sleep. guard let runtimeEnv else { completionHandler() return } runtimeEnv.submitCommand(command: .stop(completion: { SDLLogger.log("[PacketTunnelProvider] sleep") completionHandler() })) } override func wake() { SDLLogger.log("[PacketTunnelProvider] wake up!!!!!!!") // Add code here to wake up. // 重新启动 self.runtimeEnv?.submitCommand(command: .start(completion: { err in SDLLogger.log("[PacketTunnelProvider] wakeup and try start") })) } private func handleAppRequest(message: AppRequest) async throws -> Data? { guard let contextActor = self.runtimeEnv?.getContextActor() else { throw TunnelError.invalidContext } switch message.command { case .changeExitNode(let changeExitNode): let exitNodeIp = changeExitNode.ip do { try await contextActor.updateExitNode(exitNodeIp: exitNodeIp) var reply = TunnelResponse() reply.code = 0 reply.message = "操作成功" return try reply.serializedData() } catch let err { var reply = TunnelResponse() reply.code = 1 reply.message = err.localizedDescription return try reply.serializedData() } case .none: var reply = TunnelResponse() reply.code = 1 reply.message = "无效请求" return try reply.serializedData() } } }