From 288c58d1a7b883c4ade333cd93e4c773d90033c1 Mon Sep 17 00:00:00 2001 From: anlicheng <244108715@qq.com> Date: Mon, 4 May 2026 21:12:22 +0800 Subject: [PATCH] fix dnsClient --- Tun/Punchnet/Actors/SDLContextActor.swift | 73 ++++++-- Tun/Punchnet/DNS/DNSCloudClient.swift | 214 ++++++++-------------- 2 files changed, 135 insertions(+), 152 deletions(-) diff --git a/Tun/Punchnet/Actors/SDLContextActor.swift b/Tun/Punchnet/Actors/SDLContextActor.swift index f9cbd04..901c397 100644 --- a/Tun/Punchnet/Actors/SDLContextActor.swift +++ b/Tun/Punchnet/Actors/SDLContextActor.swift @@ -56,7 +56,6 @@ actor SDLContextActor { // dns的client对象 private var dnsClient: DNSCloudClient? - private var dnsWorker: Task? // Localdns的client对象 private var dnsLocalClient: DNSLocalClient? @@ -124,10 +123,20 @@ actor SDLContextActor { // 启动arp的定时清理任务 await self.puncherActor.start() await self.arpServer.start() - await self.startDnsClient() - await self.startDnsLocalClient() - // 先启动udp + await self.supervisor.addWorker(name: "dnsClient") { + SDLLogger.log("[SDLContext] dnsClient running!!!!") + try await self.startDnsClient() + SDLLogger.log("[SDLContext] dnsClient closed!!!!") + } + + await self.supervisor.addWorker(name: "dnsLocalClient") { + SDLLogger.log("[SDLContext] dnsLocalClient running!!!!") + try await self.startDnsLocalClient() + SDLLogger.log("[SDLContext] dnsLocalClient closed!!!!") + } + + // 启动udp await self.supervisor.addWorker(name: "udpHole") { SDLLogger.log("[SDLContext] udp running!!!!") try await self.startUDPHole() @@ -294,26 +303,52 @@ actor SDLContextActor { SDLLogger.log("[SDLContext] tunnelAppNotifier ready") } - private func startDnsClient() async { - self.dnsWorker?.cancel() - self.dnsWorker = nil - + private func startDnsClient() async throws { // 启动dns服务 let dnsClient = DNSCloudClient(host: self.config.serverHost, port: 15353) - await dnsClient.start() + dnsClient.start() SDLLogger.log("[SDLContext] dnsClient started") self.dnsClient = dnsClient - let packetFlow = dnsClient.packetFlow - self.dnsWorker = Task.detached { - // 处理事件流 - for await packet in packetFlow { - if Task.isCancelled { - break - } - let nePacket = NEPacket(data: packet, protocolFamily: 2) - self.provider.packetFlow.writePacketObjects([nePacket]) - } + + defer { + self.dnsClient?.stop() + self.dnsClient = nil } + + try await withThrowingTaskGroup { group in + defer { + group.cancelAll() + } + + group.addTask { + for await packet in dnsClient.packetFlow { + try Task.checkCancellation() + + let nePacket = NEPacket(data: packet, protocolFamily: 2) + self.provider.packetFlow.writePacketObjects([nePacket]) + } + } + + group.addTask { + for await event in dnsClient.eventStream { + try Task.checkCancellation() + switch event { + case .failed(let error): + SDLLogger.log("[SDLContext] dnsClient failed with error: \(error)") + throw error + case .cancelled: + SDLLogger.log("[SDLContext] dnsClient cancelled") + return + case .sendFailed(let error): + SDLLogger.log("[SDLContext] dnsClient sendFailed with error: \(error)") + throw error + } + } + } + + try await group.next() + } + } private func startDnsLocalClient() async { diff --git a/Tun/Punchnet/DNS/DNSCloudClient.swift b/Tun/Punchnet/DNS/DNSCloudClient.swift index 4465abc..9ab242a 100644 --- a/Tun/Punchnet/DNS/DNSCloudClient.swift +++ b/Tun/Punchnet/DNS/DNSCloudClient.swift @@ -7,7 +7,14 @@ import Foundation import Network -actor DNSCloudClient { +final class DNSCloudClient { + + enum Event { + case failed(Error) + case cancelled + case sendFailed(Error) + } + private enum State { case idle case running @@ -15,6 +22,7 @@ actor DNSCloudClient { } private var state: State = .idle + private var connection: NWConnection? private var receiveTask: Task? private let dnsServerAddress: NWEndpoint @@ -22,37 +30,28 @@ actor DNSCloudClient { // 用于对外输出收到的 DNS 响应包 public let packetFlow: AsyncStream private let packetContinuation: AsyncStream.Continuation - private var didFinishPacketFlow = false - - // 用来处理关闭事件 - private let closeStream: AsyncStream - private let closeContinuation: AsyncStream.Continuation - private var didFinishCloseStream = false + // 处理Connection的事件 + public let eventStream: AsyncStream + private let eventContinuation: AsyncStream.Continuation + /// - Parameter host: 你的 sn-server 地址 (如 "8.8.8.8") /// - Parameter port: 端口 (如 53) init(host: String, port: UInt16 ) { self.dnsServerAddress = .hostPort(host: NWEndpoint.Host(host), port: NWEndpoint.Port(integerLiteral: port)) - let (packetStream, packetContinuation) = AsyncStream.makeStream(of: Data.self, bufferingPolicy: .bufferingNewest(256)) - self.packetFlow = packetStream - self.packetContinuation = packetContinuation + let packetPair = AsyncStream.makeStream(of: Data.self, bufferingPolicy: .bufferingNewest(256)) + self.packetFlow = packetPair.stream + self.packetContinuation = packetPair.continuation - let (closeStream, closeContinuation) = AsyncStream.makeStream(of: Void.self, bufferingPolicy: .bufferingNewest(1)) - self.closeStream = closeStream - self.closeContinuation = closeContinuation + let eventPair = AsyncStream.makeStream(of: Event.self) + self.eventStream = eventPair.stream + self.eventContinuation = eventPair.continuation } func start() { - guard case .idle = self.state else { - return - } - - self.state = .running - // 1. 配置参数:这是解决环路的关键 let parameters = NWParameters.udp - // 禁止此连接走 TUN 网卡(在 NE 中 TUN 通常被归类为 .other) parameters.prohibitedInterfaceTypes = [.other] // 2. 增强健壮性:启用多路径切换(替代 pathSelectionOptions 的意图) @@ -60,20 +59,74 @@ actor DNSCloudClient { // 2. 创建连接 let connection = NWConnection(to: self.dnsServerAddress, using: parameters) - self.connection = connection - connection.stateUpdateHandler = { [weak self] state in - Task { - await self?.handleConnectionStateUpdate(state, for: connection) - } + self?.handleConnectionStateUpdate(state, for: connection) } - // 启动连接队列 connection.start(queue: .global()) + + self.connection = connection } - public func waitClose() async { - for await _ in self.closeStream { } + /// 发送 DNS 查询包(由 TUN 拦截到的原始 IP 包数据) + func forward(ipPacketData: Data) { + guard let connection = self.connection, connection.state == .ready else { + return + } + + connection.send(content: ipPacketData, completion: .contentProcessed { error in + if let error = error { + self.eventContinuation.yield(.sendFailed(error)) + } + }) + } + + func stop() { + guard self.state != .stopped else { + return + } + + self.state = .stopped + + self.receiveTask?.cancel() + self.receiveTask = nil + + self.connection?.cancel() + self.connection = nil + + self.packetContinuation.finish() + self.eventContinuation.finish() + } + + private func handleConnectionStateUpdate(_ state: NWConnection.State, for connection: NWConnection) { + switch state { + case .ready: + SDLLogger.log("[DNSClient] Connection ready", for: .debug) + self.startReceiveTask(for: connection) + self.state = .running + case .failed(let error): + self.eventContinuation.yield(.failed(error)) + case .cancelled: + self.eventContinuation.yield(.cancelled) + default: + break + } + } + + private func startReceiveTask(for connection: NWConnection) { + guard self.receiveTask == nil else { + return + } + + let stream = Self.makeReceiveStream(for: connection) + self.receiveTask = Task { [weak self] in + for await data in stream { + if Task.isCancelled { + break + } + self?.packetContinuation.yield(data) + } + } } /// 接收数据的递归循环 @@ -98,109 +151,4 @@ actor DNSCloudClient { } } - /// 发送 DNS 查询包(由 TUN 拦截到的原始 IP 包数据) - func forward(ipPacketData: Data) { - guard case .running = self.state, let connection = self.connection, connection.state == .ready else { - return - } - - connection.send(content: ipPacketData, completion: .contentProcessed { error in - if let error = error { - SDLLogger.log("[DNSClient] Send error: \(error)", for: .debug) - } - }) - } - - func stop() { - guard self.state != .stopped else { - return - } - - self.state = .stopped - self.receiveTask?.cancel() - self.receiveTask = nil - self.connection?.cancel() - self.connection = nil - self.finishPacketFlowIfNeeded() - self.finishCloseStreamIfNeeded() - } - - private func handleConnectionStateUpdate(_ state: NWConnection.State, for connection: NWConnection) { - guard case .running = self.state else { - return - } - - switch state { - case .ready: - SDLLogger.log("[DNSClient] Connection ready", for: .debug) - self.startReceiveTask(for: connection) - case .failed(let error): - SDLLogger.log("[DNSClient] Connection failed: \(error)", for: .debug) - self.stop() - case .cancelled: - self.stop() - default: - break - } - } - - private func startReceiveTask(for connection: NWConnection) { - guard self.receiveTask == nil else { - return - } - - let stream = Self.makeReceiveStream(for: connection) - self.receiveTask = Task { [weak self] in - for await data in stream { - guard let self else { - break - } - await self.handleReceivedPacket(data) - } - - await self?.didFinishReceiving(for: connection) - } - } - - private func handleReceivedPacket(_ data: Data) { - guard case .running = self.state else { - return - } - - self.packetContinuation.yield(data) - } - - private func didFinishReceiving(for connection: NWConnection) { - guard case .running = self.state else { - return - } - - if self.connection === connection, connection.state != .ready { - self.stop() - } else { - self.receiveTask = nil - } - } - - private func finishPacketFlowIfNeeded() { - guard !self.didFinishPacketFlow else { - return - } - - self.didFinishPacketFlow = true - self.packetContinuation.finish() - } - - private func finishCloseStreamIfNeeded() { - guard !self.didFinishCloseStream else { - return - } - - self.didFinishCloseStream = true - self.closeContinuation.finish() - } - - deinit { - self.connection?.cancel() - } }