From 8aeb543b17c9c24a974bd917f2b5ee374a523fb6 Mon Sep 17 00:00:00 2001 From: anlicheng <244108715@qq.com> Date: Thu, 28 May 2026 14:15:26 +0800 Subject: [PATCH] fix dns --- Tun/DNS/DNSCloudClient.swift | 110 ++++++++++++++-------------------- Tun/DNS/DNSCloudService.swift | 52 ++++++++-------- 2 files changed, 70 insertions(+), 92 deletions(-) diff --git a/Tun/DNS/DNSCloudClient.swift b/Tun/DNS/DNSCloudClient.swift index bd5053d..721fdbf 100644 --- a/Tun/DNS/DNSCloudClient.swift +++ b/Tun/DNS/DNSCloudClient.swift @@ -16,33 +16,36 @@ actor DNSCloudClient { case invalidData } - private enum State { - case idle - case starting - case running - case stopped - } - - private var state: State = .idle private let queue = DispatchQueue(label: "com.sdl.DNSCloudClient.queue") - - private var connection: NWConnection? - private let dnsServerAddress: NWEndpoint + private let connection: NWConnection // 用于对外输出收到的 DNS 响应包 nonisolated let packetFlow: AsyncThrowingStream private let packetContinuation: AsyncThrowingStream.Continuation - private var isPacketContinuationFinished: Bool = false + private let readySignal = AsyncOneShot() + private var isStopped: Bool = false + private var isPacketContinuationFinished: Bool = false + /// - Parameter serverIP: 你的 sn-server IP 地址 (如 "8.8.8.8") /// - Parameter port: 端口 (如 53) init(serverIP: String, port: UInt16) { - self.dnsServerAddress = .hostPort(host: Self.makeEndpointHost(address: serverIP), port: NWEndpoint.Port(integerLiteral: port)) + let dnsServerAddress = NWEndpoint.hostPort(host: Self.makeEndpointHost(address: serverIP), port: NWEndpoint.Port(integerLiteral: port)) let packetPair = AsyncThrowingStream.makeStream(of: Data.self) self.packetFlow = packetPair.stream self.packetContinuation = packetPair.continuation + + // 1. 配置参数:这是解决环路的关键 + let parameters = NWParameters.udp + // 禁止此连接走 TUN 网卡(在 NE 中 TUN 通常被归类为 .other) + parameters.prohibitedInterfaceTypes = [.other] + // 2. 增强健壮性:启用多路径切换(替代 pathSelectionOptions 的意图) + parameters.multipathServiceType = .handover + + // 2. 创建连接 + self.connection = NWConnection(to: dnsServerAddress, using: parameters) } private static func makeEndpointHost(address ip: String) -> NWEndpoint.Host { @@ -58,46 +61,29 @@ actor DNSCloudClient { } func run() async throws { - guard self.state == .idle else { - return - } - self.state = .starting - - // 1. 配置参数:这是解决环路的关键 - let parameters = NWParameters.udp - // 禁止此连接走 TUN 网卡(在 NE 中 TUN 通常被归类为 .other) - parameters.prohibitedInterfaceTypes = [.other] - // 2. 增强健壮性:启用多路径切换(替代 pathSelectionOptions 的意图) - parameters.multipathServiceType = .handover - - // 2. 创建连接 - let connection = NWConnection(to: self.dnsServerAddress, using: parameters) - connection.stateUpdateHandler = { [weak self] state in + self.connection.stateUpdateHandler = { [weak self] state in Task { - await self?.handleConnectionStateUpdate(state, for: connection) + await self?.handleConnectionStateUpdate(state) } } - self.connection = connection - - // 启动连接队列 - connection.start(queue: self.queue) - + self.connection.start(queue: self.queue) + try await withTaskCancellationHandler { try await self.readySignal.wait() + while true { try Task.checkCancellation() let data = try await self.readOnce() self.packetContinuation.yield(data) } } onCancel: { - connection.cancel() + self.connection.cancel() } } /// 发送 DNS 查询包(由 TUN 拦截到的原始 IP 包数据) func forward(ipPacketData: Data) { - guard self.state == .running, - let connection = self.connection, connection.state == .ready else { + guard connection.state == .ready else { return } @@ -111,30 +97,25 @@ actor DNSCloudClient { } func stop() async { - guard self.state != .stopped else { + guard !self.isStopped else { return } + self.isStopped = true - self.state = .stopped - - let connection = self.connection - self.connection = nil - - connection?.cancel() + self.connection.cancel() await self.readySignal.fail(DNSCloudError.cancelled) self.finishPacketContinuationIfNeed(throwing: nil) SDLLogger.log("[SDLCloudClient] stopped") } - private func handleConnectionStateUpdate(_ state: NWConnection.State, for connection: NWConnection) async { + private func handleConnectionStateUpdate(_ state: NWConnection.State) async { switch state { case .ready: - guard self.state != .stopped, self.isCurrentConnection(connection) else { + guard !self.isStopped else { return } - self.state = .running SDLLogger.log("[DNSClient] Connection ready", for: .debug) await self.readySignal.succeed(()) case .failed(let error): @@ -148,20 +129,13 @@ actor DNSCloudClient { } } - private func isCurrentConnection(_ connection: NWConnection) -> Bool { - guard let currentConnection = self.connection else { - return false - } - - return currentConnection === connection - } - private func finishPacketContinuationIfNeed(throwing error: DNSCloudError?) { guard !self.isPacketContinuationFinished else { return } - + self.isPacketContinuationFinished = true + if let error { self.packetContinuation.finish(throwing: error) } else { @@ -170,20 +144,26 @@ actor DNSCloudClient { } private func readOnce() async throws -> Data { - guard let connection = self.connection, connection.state == .ready else { + guard self.connection.state == .ready else { throw DNSCloudError.cancelled } - return try await withCheckedThrowingContinuation { continuation in - connection.receiveMessage { content, _, _, error in - if let error { - continuation.resume(throwing: error) - } else if let data = content, !data.isEmpty { - continuation.resume(returning: data) - } else { - continuation.resume(throwing: DNSCloudError.invalidData) + let readContinuation = OnceContinuation() + return try await withTaskCancellationHandler { + try await withCheckedThrowingContinuation { cont in + readContinuation.set(cont) + self.connection.receiveMessage { content, _, _, error in + if let error { + readContinuation.resume(throwing: error) + } else if let data = content, !data.isEmpty { + readContinuation.resume(returning: data) + } else { + readContinuation.resume(throwing: DNSCloudError.invalidData) + } } } + } onCancel: { + readContinuation.resume(throwing: CancellationError()) } } diff --git a/Tun/DNS/DNSCloudService.swift b/Tun/DNS/DNSCloudService.swift index 8632fcf..b0266ad 100644 --- a/Tun/DNS/DNSCloudService.swift +++ b/Tun/DNS/DNSCloudService.swift @@ -20,16 +20,37 @@ actor DNSCloudService { let client = DNSCloudClient(serverIP: self.serverIP, port: 15353) self.currentClient = client - do { - try await self.run(client: client) + defer { self.clearCurrent(client, generation: generation) + } + + do { + let onEvent = self.onEvent + + try await withThrowingTaskGroup(of: Void.self) { group in + defer { + group.cancelAll() + } + + group.addTask { + try await client.run() + } + + group.addTask { + for try await packet in client.packetFlow { + try Task.checkCancellation() + await onEvent(.packet(packet)) + } + } + + _ = try await group.next() + } + await client.stop() } catch is CancellationError { - self.clearCurrent(client, generation: generation) await client.stop() throw CancellationError() } catch { - self.clearCurrent(client, generation: generation) await client.stop() throw error } @@ -48,29 +69,6 @@ actor DNSCloudService { await self.currentClient?.forward(ipPacketData: ipPacketData) } - private func run(client: DNSCloudClient) async throws { - let onEvent = self.onEvent - - try await withThrowingTaskGroup(of: Void.self) { group in - defer { - group.cancelAll() - } - - group.addTask { - try await client.run() - } - - group.addTask { - for try await packet in client.packetFlow { - try Task.checkCancellation() - await onEvent(.packet(packet)) - } - } - - _ = try await group.next() - } - } - private func nextGeneration() -> UInt64 { self.generation &+= 1 return self.generation