From eca022cae0d1de99249bdc52bc343675533521f4 Mon Sep 17 00:00:00 2001 From: anlicheng <244108715@qq.com> Date: Thu, 28 May 2026 00:59:08 +0800 Subject: [PATCH] fix superControlPlane --- Tun/Context/SDLContextActor.swift | 248 ++++++----------------- Tun/Context/SDLSuperControlPlane.swift | 210 +++++++++++++++++++ Tun/Context/SDLSuperEventProcessor.swift | 78 ------- 3 files changed, 273 insertions(+), 263 deletions(-) create mode 100644 Tun/Context/SDLSuperControlPlane.swift delete mode 100644 Tun/Context/SDLSuperEventProcessor.swift diff --git a/Tun/Context/SDLContextActor.swift b/Tun/Context/SDLContextActor.swift index ad7462c..1a66866 100644 --- a/Tun/Context/SDLContextActor.swift +++ b/Tun/Context/SDLContextActor.swift @@ -22,9 +22,6 @@ actor SDLContextActor { // AES加密,授权通过后,对象才会被创建 private var dataCipher: CCDataCipher? - // session token - private var sessionToken: Data? - // rsa的相关配置, public_key是本地生成的 // 加密算法相关 nonisolated let rsaCipher: RSACipher @@ -32,6 +29,7 @@ actor SDLContextActor { private let dnsCloudService: DNSCloudService private let dnsLocalService: DNSLocalService private let superService: SDLSuperService + private let superControlPlane: SDLSuperControlPlane private let udpHoleService: SDLUDPHoleService private let udpHoleV6Service: SDLUDPHoleV6Service private let packetOutboundActor: PacketOutboundActor @@ -77,6 +75,7 @@ actor SDLContextActor { let udpHoleV6Service = SDLUDPHoleV6Service() let dnsCloudService = DNSCloudService(serverIP: config.serverEndpoint.ip) let dnsLocalService = DNSLocalService(publicDnsServers: Self.publicDnsServers) + let superControlPlane = SDLSuperControlPlane(config: config, rsaCipher: rsaCipher) let tunNetworkManager = SDLTunNetworkManager(provider: provider) let ipv6AssistPair = AsyncStream.makeStream(of: Optional.self, bufferingPolicy: .bufferingNewest(1)) let packetOutboundActor = PacketOutboundActor( @@ -122,6 +121,7 @@ actor SDLContextActor { self.dnsCloudService = dnsCloudService self.dnsLocalService = dnsLocalService self.superService = superService + self.superControlPlane = superControlPlane self.udpHoleService = udpHoleService self.udpHoleV6Service = udpHoleV6Service self.packetOutboundActor = packetOutboundActor @@ -138,7 +138,17 @@ actor SDLContextActor { } let rootTask = Task { - try await self.runRoot() + do { + try await self.runRootBody() + await self.cleanupRoot() + } catch is CancellationError { + await self.cleanupRoot() + throw CancellationError() + } catch { + await self.readySignal.fail(error) + await self.cleanupRoot() + throw error + } } self.rootTask = rootTask @@ -163,20 +173,6 @@ actor SDLContextActor { await self.cleanupRoot() } - private func runRoot() async throws { - do { - try await self.runRootBody() - await self.cleanupRoot() - } catch is CancellationError { - await self.cleanupRoot() - throw CancellationError() - } catch { - await self.readySignal.fail(error) - await self.cleanupRoot() - throw error - } - } - private func runRootBody() async throws { self.prepareTunnelNotifier() @@ -188,8 +184,13 @@ actor SDLContextActor { await self?.handleDNSEvent(event) } - await self.superService.updateMessageHandler { [weak self] message in - await self?.handleSuperMessage(message: message) + await self.superControlPlane.updateDecisionHandler { [weak self] decision in + await self?.handleSuperDecision(decision) + } + + let superControlPlane = self.superControlPlane + await self.superService.updateMessageHandler { message in + await superControlPlane.handle(message) } let packetInboundActor = self.packetInboundActor @@ -392,8 +393,8 @@ actor SDLContextActor { await self.dnsLocalService.stop() await self.superService.stop() + await self.superControlPlane.reset() - self.sessionToken = nil self.dataCipher = nil self.natType = .blocked await self.packetOutboundActor.updateRuntime(config: self.config, dataCipher: nil) @@ -436,11 +437,6 @@ extension SDLContextActor { // MARK: 数据发送 extension SDLContextActor { - // 发送给super/stun节点的数据 - private func sendSuperPacket(type: SDLPacketType, data: Data) async { - await self.sendPacket(type: type, data: data, remoteAddress: self.config.stunSocketAddress) - } - // 发送给peer的数据 private func sendPeerPacket(type: SDLPacketType, data: Data, remoteAddress: SocketAddress) async { await self.sendPacket(type: type, data: data, remoteAddress: remoteAddress) @@ -460,160 +456,64 @@ extension SDLContextActor { // MARK: 处理和Super之间的通讯 extension SDLContextActor { - - private func handleSuperMessage(message: SDLSuperMessage) async { - switch message { - case .welcome(let welcome): - SDLLogger.log("[SDLContext] quic welcome: \(welcome)") - + + private func handleSuperDecision(_ decision: SuperDecision) async { + switch decision { + case .updateIPv6Assist(let assistInfo): await self.stopCurrentIPv6AssistClient() - // 尝试创建v6地址的辅助探测器 - if welcome.hasIpv6Assist { - self.ipv6AssistContinuation.yield(welcome.ipv6Assist) - } else { - self.ipv6AssistContinuation.yield(nil) - } - - // 注册 - await self.doRegisterSuper() - SDLLogger.log("[SDLContext] quic doRegisterSuper") - case .pong: - //SDLLogger.shared.log("[SDLContext] quic pong") - () - case .registerSuperAck(let registerSuperAck): - await self.handleRegisterSuperAck(registerSuperAck: registerSuperAck) - case .registerSuperNak(let registerSuperNak): - await self.handleRegisterSuperNak(nakPacket: registerSuperNak) - case .peerInfo(let peerInfo): - SDLLogger.log("[SDLContext] peer message: \(peerInfo)") + self.ipv6AssistContinuation.yield(assistInfo) + case .completeRegistration(let cipher): + await self.completeSuperRegistration(cipher: cipher) + case .failTunnel(let error): + await self.failTunnel(error) + case .publishTunnelEvent(let code, let message): + self.publishTunnelEvent(code: code, message: message) + case .sendSuper(let type, let data): + await self.superService.send(type: type, data: data) + case .sendPacket(let type, let data, let remoteAddress): + await self.sendPacket(type: type, data: data, remoteAddress: remoteAddress) + case .resolvePeerInfo(let peerInfo): let packets = await self.puncherActor.makeRegisterPackets(peerInfo: peerInfo) for packet in packets { await self.sendPacket(type: .register, data: packet.data, remoteAddress: packet.remoteAddress) } - case .event(let event): - await self.handleEvent(event: event) - case .policyReponse(let policyResponse): - // 处理权限的请求问题 - await self.policyService.applyPolicyResponse(policyResponse) - case .exposedServiceResponse(let response): - await self.applyExposedServiceResponse(response) - case .arpResponse(let arpResponse): - SDLLogger.log("[SDLContext] get arp response: \(arpResponse)") - await self.arpResolver.handleArpResponse(arpResponse: arpResponse) - } - } - - private func makeSuperEventProcessor() -> SDLSuperEventProcessor { - return .init(networkAddress: self.config.networkAddress) - } - - private func handleRegisterSuperAck(registerSuperAck: SDLRegisterSuperAck) async { - // 需要对数据通过rsa的私钥解码 - guard let key = try? self.rsaCipher.decode(data: Data(registerSuperAck.key)) else { - SDLLogger.log("[SDLContext] registerSuperAck invalid key") - let error = SDLError.invalidKey - await self.readySignal.fail(error) - self.provider.cancelTunnelWithError(error) - return - } - - let algorithm = registerSuperAck.algorithm.lowercased() - let regionId = registerSuperAck.regionID - self.sessionToken = registerSuperAck.sessionToken - - switch algorithm { - case "aes": - self.dataCipher = CCAESChiper(key: key) - case "chacha20": - self.dataCipher = CCChaCha20Cipher(regionId: regionId, keyData: key) - default: - SDLLogger.log("[SDLContext] registerSuperAck invalid algorithm \(algorithm)") - let error = SDLError.unsupportedAlgorithm(algorithm: algorithm) - await self.readySignal.fail(error) - self.provider.cancelTunnelWithError(error) - return - } - - await self.packetOutboundActor.updateRuntime(config: self.config, dataCipher: self.dataCipher) - await self.packetInboundActor.updateRuntime(config: self.config, dataCipher: self.dataCipher) - SDLLogger.log("[SDLContext] registerSuperAck, use algorithm \(algorithm), key len: \(key.count)") - // 服务器分配的tun网卡信息 - do { - try await self.tunNetworkManager.apply(settings: .init(config: self.config), dnsServer: DNSHelper.dnsServer) - SDLLogger.log("[SDLContext] setNetworkSettings successed") - await self.readySignal.succeed(()) - } catch let err { - SDLLogger.log("[SDLContext] setTunnelNetworkSettings get error: \(err)") - await self.readySignal.fail(err) - self.provider.cancelTunnelWithError(err) - } - } - - private func handleRegisterSuperNak(nakPacket: SDLRegisterSuperNak) async { - let errorMessage = nakPacket.errorMessage - guard let errorCode = SDLNAKErrorCode(rawValue: UInt8(nakPacket.errorCode)) else { - return - } - - switch errorCode { - case .invalidToken, .nodeDisabled: - self.publishTunnelEvent(code: Int(errorCode.rawValue), message: errorMessage) - // 报告错误并退出 - let error = NSError(domain: "com.jihe.punchnet.tun", code: -1) - await self.readySignal.fail(error) - self.provider.cancelTunnelWithError(error) - - case .noIpAddress, .networkFault, .internalFault: - self.publishTunnelEvent(code: Int(errorCode.rawValue), message: errorMessage) - } - SDLLogger.log("[SDLContext] Get a SuperNak message exit") - } - - private func handleEvent(event: SDLEvent) async { - let processor = self.makeSuperEventProcessor() - let plan = await processor.makeProcessingPlan(event: event) - if let logMessage = plan.logMessage { - SDLLogger.log(logMessage) - } - - switch plan.action { case .removeSession(let dstMac): await self.sessionManager.removeSession(dstMac: dstMac) - case .sendRegister(let registerData, let remoteAddresses): - for remoteAddress in remoteAddresses { - await self.sendPeerPacket(type: .register, data: registerData, remoteAddress: remoteAddress) - } case .requestExposedService: await self.requestExposedService() case .shutdown(let message): self.publishTunnelEvent(message: message) - - // 报告错误并退出 let error = NSError(domain: "com.jihe.punchnet.tun", code: -2) self.provider.cancelTunnelWithError(error) - case .none: - () + case .applyPolicyResponse(let policyResponse): + await self.policyService.applyPolicyResponse(policyResponse) + case .applyExposedServiceResponse(let response): + await self.applyExposedServiceResponse(response) + case .handleARPResponse(let arpResponse): + await self.arpResolver.handleArpResponse(arpResponse: arpResponse) } } - - private func doRegisterSuper() async { - // 注册 - var registerSuper = SDLRegisterSuper() - registerSuper.clientID = self.config.clientId - registerSuper.networkID = self.config.networkAddress.networkId - registerSuper.mac = self.config.networkAddress.mac - registerSuper.ip = self.config.networkAddress.ip - registerSuper.maskLen = UInt32(self.config.networkAddress.maskLen) - registerSuper.hostname = self.config.hostname - registerSuper.pubKey = self.rsaCipher.pubKey - registerSuper.accessToken = self.config.accessToken - - if let registerSuperData = try? registerSuper.serializedData() { - SDLLogger.log("[SDLContext] will send register super") - await self.superService.send(type: .registerSuper, data: registerSuperData) + + private func completeSuperRegistration(cipher: CCDataCipher) async { + self.dataCipher = cipher + await self.packetOutboundActor.updateRuntime(config: self.config, dataCipher: cipher) + await self.packetInboundActor.updateRuntime(config: self.config, dataCipher: cipher) + + do { + try await self.tunNetworkManager.apply(settings: .init(config: self.config), dnsServer: DNSHelper.dnsServer) + SDLLogger.log("[SDLContext] setNetworkSettings successed") + await self.readySignal.succeed(()) + } catch { + SDLLogger.log("[SDLContext] setTunnelNetworkSettings get error: \(error)") + await self.failTunnel(error) } } + private func failTunnel(_ error: Error) async { + await self.readySignal.fail(error) + self.provider.cancelTunnelWithError(error) + } + private func requestExposedService() async { guard let requestData = await self.policyService.makeExposedServiceRequest() else { return @@ -735,29 +635,7 @@ extension SDLContextActor { SDLLogger.log("[SDLContext] probe ipv6 address: empty") } - await self.sendStunRequest(v6Info: probeReply?.v6Info) - } - - private func sendStunRequest(v6Info: SDLV6Info?) async { - guard let sessionToken = self.sessionToken else { - return - } - - var stunRequest = SDLStunRequest() - stunRequest.clientID = self.config.clientId - stunRequest.networkID = self.config.networkAddress.networkId - stunRequest.ip = self.config.networkAddress.ip - stunRequest.mac = self.config.networkAddress.mac - stunRequest.natType = UInt32(self.natType.rawValue) - stunRequest.sessionToken = sessionToken - - if let v6Info { - stunRequest.v6Info = v6Info - } - - if let stunData = try? stunRequest.serializedData() { - await self.sendSuperPacket(type: .stunRequest, data: stunData) - } + await self.superControlPlane.sendStunRequest(natType: self.natType, v6Info: probeReply?.v6Info) } } diff --git a/Tun/Context/SDLSuperControlPlane.swift b/Tun/Context/SDLSuperControlPlane.swift new file mode 100644 index 0000000..c773e67 --- /dev/null +++ b/Tun/Context/SDLSuperControlPlane.swift @@ -0,0 +1,210 @@ +// +// SDLSuperControlPlane.swift +// Tun +// +// Created by Codex on 2026/5/28. +// + +import Foundation +import NIOCore + +enum SuperDecision { + case updateIPv6Assist(SDLV6Info?) + case completeRegistration(cipher: CCDataCipher) + case failTunnel(Error) + case publishTunnelEvent(code: Int?, message: String) + case sendSuper(type: SDLPacketType, data: Data) + case sendPacket(type: SDLPacketType, data: Data, remoteAddress: SocketAddress) + case resolvePeerInfo(SDLPeerInfo) + case removeSession(dstMac: Data) + case requestExposedService + case shutdown(message: String) + case applyPolicyResponse(SDLPolicyResponse) + case applyExposedServiceResponse(SDLExposedServiceResponse) + case handleARPResponse(SDLArpResponse) +} + +actor SDLSuperControlPlane { + typealias DecisionHandler = @Sendable (SuperDecision) async -> Void + + private let config: SDLConfiguration + private let rsaCipher: RSACipher + private var sessionToken: Data? + private var onDecision: DecisionHandler = { _ in } + + init(config: SDLConfiguration, rsaCipher: RSACipher) { + self.config = config + self.rsaCipher = rsaCipher + } + + func updateDecisionHandler(_ onDecision: @escaping DecisionHandler) { + self.onDecision = onDecision + } + + func reset() { + self.sessionToken = nil + } + + func handle(_ message: SDLSuperMessage) async { + switch message { + case .welcome(let welcome): + await self.handleWelcome(welcome) + case .pong: + () + case .registerSuperAck(let registerSuperAck): + await self.handleRegisterSuperAck(registerSuperAck) + case .registerSuperNak(let registerSuperNak): + await self.handleRegisterSuperNak(registerSuperNak) + case .peerInfo(let peerInfo): + SDLLogger.log("[SDLContext] peer message: \(peerInfo)") + await self.onDecision(.resolvePeerInfo(peerInfo)) + case .event(let event): + await self.handleEvent(event) + case .policyReponse(let policyResponse): + await self.onDecision(.applyPolicyResponse(policyResponse)) + case .exposedServiceResponse(let response): + await self.onDecision(.applyExposedServiceResponse(response)) + case .arpResponse(let arpResponse): + SDLLogger.log("[SDLContext] get arp response: \(arpResponse)") + await self.onDecision(.handleARPResponse(arpResponse)) + } + } + + func sendStunRequest(natType: SDLNATProberActor.NatType, v6Info: SDLV6Info?) async { + guard let sessionToken else { + return + } + + var stunRequest = SDLStunRequest() + stunRequest.clientID = self.config.clientId + stunRequest.networkID = self.config.networkAddress.networkId + stunRequest.ip = self.config.networkAddress.ip + stunRequest.mac = self.config.networkAddress.mac + stunRequest.natType = UInt32(natType.rawValue) + stunRequest.sessionToken = sessionToken + + if let v6Info { + stunRequest.v6Info = v6Info + } + + if let stunData = try? stunRequest.serializedData() { + await self.onDecision(.sendPacket(type: .stunRequest, data: stunData, remoteAddress: self.config.stunSocketAddress)) + } + } + + private func handleWelcome(_ welcome: SDLWelcome) async { + SDLLogger.log("[SDLContext] quic welcome: \(welcome)") + + if welcome.hasIpv6Assist { + await self.onDecision(.updateIPv6Assist(welcome.ipv6Assist)) + } else { + await self.onDecision(.updateIPv6Assist(nil)) + } + + await self.doRegisterSuper() + SDLLogger.log("[SDLContext] quic doRegisterSuper") + } + + private func handleRegisterSuperAck(_ registerSuperAck: SDLRegisterSuperAck) async { + guard let key = try? self.rsaCipher.decode(data: Data(registerSuperAck.key)) else { + SDLLogger.log("[SDLContext] registerSuperAck invalid key") + await self.onDecision(.failTunnel(SDLError.invalidKey)) + return + } + + let algorithm = registerSuperAck.algorithm.lowercased() + let regionId = registerSuperAck.regionID + self.sessionToken = registerSuperAck.sessionToken + + let cipher: CCDataCipher + switch algorithm { + case "aes": + cipher = CCAESChiper(key: key) + case "chacha20": + cipher = CCChaCha20Cipher(regionId: regionId, keyData: key) + default: + SDLLogger.log("[SDLContext] registerSuperAck invalid algorithm \(algorithm)") + await self.onDecision(.failTunnel(SDLError.unsupportedAlgorithm(algorithm: algorithm))) + return + } + + SDLLogger.log("[SDLContext] registerSuperAck, use algorithm \(algorithm), key len: \(key.count)") + await self.onDecision(.completeRegistration(cipher: cipher)) + } + + private func handleRegisterSuperNak(_ nakPacket: SDLRegisterSuperNak) async { + let errorMessage = nakPacket.errorMessage + guard let errorCode = SDLNAKErrorCode(rawValue: UInt8(nakPacket.errorCode)) else { + return + } + + switch errorCode { + case .invalidToken, .nodeDisabled: + await self.onDecision(.publishTunnelEvent(code: Int(errorCode.rawValue), message: errorMessage)) + await self.onDecision(.failTunnel(NSError(domain: "com.jihe.punchnet.tun", code: -1))) + case .noIpAddress, .networkFault, .internalFault: + await self.onDecision(.publishTunnelEvent(code: Int(errorCode.rawValue), message: errorMessage)) + } + + SDLLogger.log("[SDLContext] Get a SuperNak message exit") + } + + private func handleEvent(_ event: SDLEvent) async { + switch event.event { + case .natChanged(let natChangedEvent): + let dstMac = natChangedEvent.mac + SDLLogger.log("[SDLContext] natChangedEvent, dstMac: \(dstMac)") + await self.onDecision(.removeSession(dstMac: dstMac)) + case .sendRegister(let sendRegisterEvent): + await self.handleSendRegisterEvent(sendRegisterEvent) + case .exposedServiceChanged: + SDLLogger.log("[SDLContext] exposedServiceChanged event") + await self.onDecision(.requestExposedService) + case .shutdown(let shutdownEvent): + await self.onDecision(.shutdown(message: shutdownEvent.message)) + case .none: + () + } + } + + private func handleSendRegisterEvent(_ event: SDLEvent.SendRegister) async { + var register = SDLRegister() + register.networkID = self.config.networkAddress.networkId + register.srcMac = self.config.networkAddress.mac + register.dstMac = event.dstMac + + guard let registerData = try? register.serializedData() else { + return + } + + SDLLogger.log("[SDLContext] sendRegisterEvent, ip: \(event)") + + if event.natIp > 0 && event.natPort > 0 { + let address = SDLUtil.int32ToIp(event.natIp) + if let remoteAddress = try? SocketAddress(ipAddress: address, port: Int(event.natPort)) { + await self.onDecision(.sendPacket(type: .register, data: registerData, remoteAddress: remoteAddress)) + } + } + + if event.hasV6Info, let remoteAddress = try? await event.v6Info.socketAddress() { + await self.onDecision(.sendPacket(type: .register, data: registerData, remoteAddress: remoteAddress)) + } + } + + private func doRegisterSuper() async { + var registerSuper = SDLRegisterSuper() + registerSuper.clientID = self.config.clientId + registerSuper.networkID = self.config.networkAddress.networkId + registerSuper.mac = self.config.networkAddress.mac + registerSuper.ip = self.config.networkAddress.ip + registerSuper.maskLen = UInt32(self.config.networkAddress.maskLen) + registerSuper.hostname = self.config.hostname + registerSuper.pubKey = self.rsaCipher.pubKey + registerSuper.accessToken = self.config.accessToken + + if let registerSuperData = try? registerSuper.serializedData() { + SDLLogger.log("[SDLContext] will send register super") + await self.onDecision(.sendSuper(type: .registerSuper, data: registerSuperData)) + } + } +} diff --git a/Tun/Context/SDLSuperEventProcessor.swift b/Tun/Context/SDLSuperEventProcessor.swift deleted file mode 100644 index 5fb0b11..0000000 --- a/Tun/Context/SDLSuperEventProcessor.swift +++ /dev/null @@ -1,78 +0,0 @@ -// -// SDLSuperEventProcessor.swift -// Tun -// -// Created by 安礼成 on 2026/4/15. -// - -import Foundation -import NIOCore - -final class SDLSuperEventProcessor { - enum ProcessingAction { - case removeSession(dstMac: Data) - case sendRegister(data: Data, remoteAddresses: [SocketAddress]) - case requestExposedService - case shutdown(message: String) - case none - } - - struct ProcessingPlan { - let logMessage: String? - let action: ProcessingAction - } - - private let networkAddress: SDLConfiguration.NetworkAddress - - init(networkAddress: SDLConfiguration.NetworkAddress) { - self.networkAddress = networkAddress - } - - func makeProcessingPlan(event: SDLEvent) async -> ProcessingPlan { - switch event.event { - case .natChanged(let natChangedEvent): - let dstMac = natChangedEvent.mac - return .init( - logMessage: "[SDLContext] natChangedEvent, dstMac: \(dstMac)", - action: .removeSession(dstMac: dstMac) - ) - case .sendRegister(let sendRegisterEvent): - return await self.makeSendRegisterPlan(sendRegisterEvent) - case .exposedServiceChanged: - return .init( - logMessage: "[SDLContext] exposedServiceChanged event", - action: .requestExposedService - ) - case .shutdown(let shutdownEvent): - return .init(logMessage: nil, action: .shutdown(message: shutdownEvent.message)) - case .none: - return .init(logMessage: nil, action: .none) - } - } - - private func makeSendRegisterPlan(_ event: SDLEvent.SendRegister) async -> ProcessingPlan { - // 发送register包 - var register = SDLRegister() - register.networkID = self.networkAddress.networkId - register.srcMac = self.networkAddress.mac - register.dstMac = event.dstMac - let registerData = try! register.serializedData() - - var remoteAddresses: [SocketAddress] = [] - if event.natIp > 0 && event.natPort > 0 { - let address = SDLUtil.int32ToIp(event.natIp) - if let remoteAddress = try? SocketAddress(ipAddress: address, port: Int(event.natPort)) { - remoteAddresses.append(remoteAddress) - } - } - - if event.hasV6Info, let remoteAddress = try? await event.v6Info.socketAddress() { - remoteAddresses.append(remoteAddress) - } - - return .init( - logMessage: "[SDLContext] sendRegisterEvent, ip: \(event)", - action: .sendRegister(data: registerData, remoteAddresses: remoteAddresses) - ) - } -}