From 9d3a380063af94bbba181eb9b554c8e96ee005e3 Mon Sep 17 00:00:00 2001 From: anlicheng <244108715@qq.com> Date: Wed, 7 Jan 2026 17:42:27 +0800 Subject: [PATCH] fix punch --- Tun/Punchnet/Actors/SDLPuncherActor.swift | 89 +++++++++++++++++++++++ Tun/Punchnet/SDLContext.swift | 71 ++---------------- 2 files changed, 95 insertions(+), 65 deletions(-) create mode 100644 Tun/Punchnet/Actors/SDLPuncherActor.swift diff --git a/Tun/Punchnet/Actors/SDLPuncherActor.swift b/Tun/Punchnet/Actors/SDLPuncherActor.swift new file mode 100644 index 0000000..7118f2a --- /dev/null +++ b/Tun/Punchnet/Actors/SDLPuncherActor.swift @@ -0,0 +1,89 @@ +// +// SDLPuncherActor.swift +// Tun +// +// Created by 安礼成 on 2026/1/7. +// + +import Foundation + +actor SDLPuncherActor { + // dstMac + private var coolingDown: Set = [] + private let cooldown: Duration = .seconds(5) + + private var superClientActor: SDLSuperClientActor? + private var udpHoleActor: SDLUDPHoleActor? + + // 处理holer + private var logger: SDLLogger + + struct RegisterRequest { + let srcMac: Data + let dstMac: Data + let networkId: UInt32 + } + + init(logger: SDLLogger) { + self.logger = logger + } + + func setSuperClientActor(superClientActor: SDLSuperClientActor?) { + self.superClientActor = superClientActor + } + + func setUDPHoleActor(udpHoleActor: SDLUDPHoleActor?) { + self.udpHoleActor = udpHoleActor + } + + func submitRegisterRequest(request: RegisterRequest) { + let dstMac = request.dstMac + + guard !coolingDown.contains(dstMac) else { + return + } + + // 触发一次打洞 + coolingDown.insert(dstMac) + + Task { + await self.tryHole(request: request) + // 启动冷却期 + try? await Task.sleep(for: .seconds(5)) + self.endCooldown(for: dstMac) + } + } + + private func endCooldown(for key: Data) { + self.coolingDown.remove(key) + } + + private func tryHole(request: RegisterRequest) async { + var queryInfo = SDLQueryInfo() + queryInfo.dstMac = request.dstMac + guard let message = try? await self.superClientActor?.request(type: .queryInfo, data: try queryInfo.serializedData()).get() else { + return + } + + switch message.packet { + case .empty: + self.logger.log("[SDLContext] hole query_info get empty: \(message)", level: .debug) + case .peerInfo(let peerInfo): + if let remoteAddress = peerInfo.v4Info.socketAddress() { + self.logger.log("[SDLContext] hole sock address: \(remoteAddress)", level: .debug) + // 发送register包 + var register = SDLRegister() + register.networkID = request.networkId + register.srcMac = request.srcMac + register.dstMac = request.dstMac + + await self.udpHoleActor?.send(type: .register, data: try! register.serializedData(), remoteAddress: remoteAddress) + } else { + self.logger.log("[SDLContext] hole sock address is invalid: \(peerInfo.v4Info)", level: .warning) + } + default: + self.logger.log("[SDLContext] hole query_info is packet: \(message)", level: .warning) + } + } + +} diff --git a/Tun/Punchnet/SDLContext.swift b/Tun/Punchnet/SDLContext.swift index 10b37e6..13c314a 100644 --- a/Tun/Punchnet/SDLContext.swift +++ b/Tun/Punchnet/SDLContext.swift @@ -51,6 +51,7 @@ public class SDLContext { var udpHoleActor: SDLUDPHoleActor? var superClientActor: SDLSuperClientActor? var providerActor: SDLTunnelProviderActor + var puncherActor: SDLPuncherActor // dns的client对象 var dnsClient: DNSClient? @@ -74,20 +75,9 @@ public class SDLContext { private var flowTracer = SDLFlowTracerActor() private var flowTracerCancel: AnyCancellable? - // 处理holer - private var holerPublishers: [Data:PassthroughSubject] = [:] - private var bag = Set() - private var locker = NSLock() - private let logger: SDLLogger private var rootTask: Task? - struct RegisterRequest { - let srcMac: Data - let dstMac: Data - let networkId: UInt32 - } - public init(provider: NEPacketTunnelProvider, config: SDLConfiguration, rsaCipher: RSACipher, aesCipher: AESCipher, logger: SDLLogger) { self.logger = logger @@ -103,6 +93,7 @@ public class SDLContext { self.sessionManager = SessionManager() self.arpServer = ArpServer(known_macs: [:]) self.providerActor = SDLTunnelProviderActor(provider: provider, logger: logger) + self.puncherActor = SDLPuncherActor(logger: logger) } public func start() async throws { @@ -297,6 +288,8 @@ public class SDLContext { private func handleSuperEvent(event: SDLSuperClientActor.SuperEvent) async throws { switch event { case .ready: + await self.puncherActor.setSuperClientActor(superClientActor: self.superClientActor) + self.logger.log("[SDLContext] get registerSuper, mac address: \(SDLUtil.formatMacAddress(mac: self.devAddr.mac))", level: .debug) var registerSuper = SDLRegisterSuper() registerSuper.version = UInt32(self.config.version) @@ -413,6 +406,7 @@ public class SDLContext { private func handleUDPEvent(event: SDLUDPHoleActor.UDPEvent) async throws { switch event { case .ready: + await self.puncherActor.setUDPHoleActor(udpHoleActor: self.udpHoleActor) // 获取当前网络的类型 //self.natType = await SDLNatProber.getNatType(udpHole: self.udpHole, config: self.config) self.logger.log("[SDLContext] nat type is: \(self.natType)", level: .debug) @@ -602,60 +596,7 @@ public class SDLContext { await self.flowTracer.inc(num: data.count, type: .forward) // 尝试打洞 - let registerRequest = RegisterRequest(srcMac: self.devAddr.mac, dstMac: dstMac, networkId: self.devAddr.networkID) - self.submitRegisterRequest(request: registerRequest) - } - } - - private func submitRegisterRequest(request: RegisterRequest) { - self.locker.lock() - defer { - self.locker.unlock() - } - - let dstMac = request.dstMac - if let publisher = self.holerPublishers[dstMac] { - publisher.send(request) - } else { - let publisher = PassthroughSubject() - publisher.throttle(for: .seconds(5), scheduler: DispatchQueue.global(), latest: true) - .sink { request in - Task { - await self.tryHole(request: request) - } - } - .store(in: &self.bag) - - self.holerPublishers[dstMac] = publisher - } - } - - private func tryHole(request: RegisterRequest) async { - var queryInfo = SDLQueryInfo() - queryInfo.dstMac = request.dstMac - - guard let message = try? await self.superClientActor?.request(type: .queryInfo, data: try queryInfo.serializedData()).get() else { - return - } - - switch message.packet { - case .empty: - self.logger.log("[SDLContext] hole query_info get empty: \(message)", level: .debug) - case .peerInfo(let peerInfo): - if let remoteAddress = peerInfo.v4Info.socketAddress() { - self.logger.log("[SDLContext] hole sock address: \(remoteAddress)", level: .debug) - // 发送register包 - var register = SDLRegister() - register.networkID = request.networkId - register.srcMac = request.srcMac - register.dstMac = request.dstMac - - await self.udpHoleActor?.send(type: .register, data: try! register.serializedData(), remoteAddress: remoteAddress) - } else { - self.logger.log("[SDLContext] hole sock address is invalid: \(peerInfo.v4Info)", level: .warning) - } - default: - self.logger.log("[SDLContext] hole query_info is packet: \(message)", level: .warning) + await self.puncherActor.submitRegisterRequest(request: .init(srcMac: self.devAddr.mac, dstMac: dstMac, networkId: self.devAddr.networkID)) } }