106 lines
3.4 KiB
Swift
106 lines
3.4 KiB
Swift
//
|
||
// SDLDNSClient 2.swift
|
||
// punchnet
|
||
//
|
||
// Created by 安礼成 on 2026/4/9.
|
||
//
|
||
import Foundation
|
||
import Network
|
||
|
||
final class DNSCloudClient {
|
||
private var connection: NWConnection?
|
||
private let dnsServerAddress: NWEndpoint
|
||
|
||
// 用于对外输出收到的 DNS 响应包
|
||
public let packetFlow: AsyncStream<Data>
|
||
private let packetContinuation: AsyncStream<Data>.Continuation
|
||
|
||
// 用来处理关闭事件
|
||
private let (closeStream, closeContinuation) = AsyncStream.makeStream(of: Void.self)
|
||
|
||
/// - 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 (stream, continuation) = AsyncStream.makeStream(of: Data.self, bufferingPolicy: .unbounded)
|
||
self.packetFlow = stream
|
||
self.packetContinuation = continuation
|
||
}
|
||
|
||
func start() {
|
||
// 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)
|
||
self.connection = connection
|
||
|
||
connection.stateUpdateHandler = { [weak self] state in
|
||
switch state {
|
||
case .ready:
|
||
SDLLogger.log("[DNSClient] Connection ready", for: .debug)
|
||
self?.receiveLoop() // 开始循环接收数据
|
||
case .failed(let error):
|
||
SDLLogger.log("[DNSClient] Connection failed: \(error)", for: .debug)
|
||
self?.stop()
|
||
case .cancelled:
|
||
self?.packetContinuation.finish()
|
||
self?.closeContinuation.finish()
|
||
default:
|
||
break
|
||
}
|
||
}
|
||
|
||
// 启动连接队列
|
||
connection.start(queue: .global())
|
||
}
|
||
|
||
public func waitClose() async {
|
||
for await _ in closeStream { }
|
||
}
|
||
|
||
/// 接收数据的递归循环
|
||
private func receiveLoop() {
|
||
connection?.receiveMessage { [weak self] content, _, isComplete, error in
|
||
if let data = content, !data.isEmpty {
|
||
// 将收到的 DNS 响应写回 AsyncStream
|
||
self?.packetContinuation.yield(data)
|
||
}
|
||
|
||
if error == nil && self?.connection?.state == .ready {
|
||
self?.receiveLoop() // 继续监听下一个包
|
||
}
|
||
}
|
||
}
|
||
|
||
/// 发送 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 {
|
||
SDLLogger.log("[DNSClient] Send error: \(error)", for: .debug)
|
||
}
|
||
})
|
||
}
|
||
|
||
func stop() {
|
||
connection?.cancel()
|
||
connection = nil
|
||
}
|
||
|
||
deinit {
|
||
stop()
|
||
}
|
||
|
||
}
|
||
|