fix dns
This commit is contained in:
parent
831a86947e
commit
eb2b4e7167
@ -1,89 +1,58 @@
|
|||||||
//
|
|
||||||
// SDLLocalDNSClient.swift
|
|
||||||
// punchnet
|
|
||||||
//
|
|
||||||
// Created by 安礼成 on 2026/4/10.
|
|
||||||
//
|
|
||||||
import Foundation
|
import Foundation
|
||||||
import Network
|
import Network
|
||||||
|
|
||||||
/// 纯粹的本地 DNS 解析器:负责将 DNS 载荷绕过 TUN 发送到公网 DNS
|
final class SDLLocalDNSClient {
|
||||||
final class DNSLocalClient {
|
private var connections: [NWConnection] = []
|
||||||
private var connection: NWConnection?
|
|
||||||
private let logger: SDLLogger
|
private let logger: SDLLogger
|
||||||
private let remoteEndpoint: NWEndpoint
|
|
||||||
|
|
||||||
// 用于对外输出收到的原始 DNS 载荷 (注意:这里只输出 UDP 载荷,不带 IP 头)
|
// 准备多个公共 DNS
|
||||||
|
private let dnsServers = ["114.114.114.114", "223.5.5.5", "8.8.8.8"]
|
||||||
|
|
||||||
public let payloadFlow: AsyncStream<Data>
|
public let payloadFlow: AsyncStream<Data>
|
||||||
private let payloadContinuation: AsyncStream<Data>.Continuation
|
private let payloadContinuation: AsyncStream<Data>.Continuation
|
||||||
|
|
||||||
private let (closeStream, closeContinuation) = AsyncStream.makeStream(of: Void.self)
|
init(logger: SDLLogger) {
|
||||||
|
|
||||||
/// - Parameter dnsServer: 物理 DNS 地址,例如 "114.114.114.114"
|
|
||||||
init(dnsServer: String, logger: SDLLogger) {
|
|
||||||
self.logger = logger
|
self.logger = logger
|
||||||
self.remoteEndpoint = .hostPort(host: NWEndpoint.Host(dnsServer), port: 53)
|
|
||||||
|
|
||||||
let (stream, continuation) = AsyncStream.makeStream(of: Data.self, bufferingPolicy: .unbounded)
|
let (stream, continuation) = AsyncStream.makeStream(of: Data.self, bufferingPolicy: .unbounded)
|
||||||
self.payloadFlow = stream
|
self.payloadFlow = stream
|
||||||
self.payloadContinuation = continuation
|
self.payloadContinuation = continuation
|
||||||
}
|
}
|
||||||
|
|
||||||
func start() {
|
func start() {
|
||||||
let parameters = NWParameters.udp
|
for server in dnsServers {
|
||||||
// 关键:强制绕过 TUN 网卡
|
let endpoint = NWEndpoint.hostPort(host: NWEndpoint.Host(server), port: 53)
|
||||||
parameters.prohibitedInterfaceTypes = [.other]
|
let parameters = NWParameters.udp
|
||||||
parameters.multipathServiceType = .handover
|
parameters.prohibitedInterfaceTypes = [.other]
|
||||||
|
|
||||||
let connection = NWConnection(to: self.remoteEndpoint, using: parameters)
|
let conn = NWConnection(to: endpoint, using: parameters)
|
||||||
self.connection = connection
|
|
||||||
|
conn.stateUpdateHandler = { [weak self] state in
|
||||||
connection.stateUpdateHandler = { [weak self] state in
|
if case .ready = state { self?.receiveLoop(for: conn) }
|
||||||
switch state {
|
|
||||||
case .ready:
|
|
||||||
self?.logger.log("[LocalDNS] Path ready", level: .debug)
|
|
||||||
self?.receiveLoop()
|
|
||||||
case .failed(let error):
|
|
||||||
self?.logger.log("[LocalDNS] Failed: \(error)", level: .error)
|
|
||||||
self?.closeContinuation.finish()
|
|
||||||
case .cancelled:
|
|
||||||
self?.payloadContinuation.finish()
|
|
||||||
self?.closeContinuation.finish()
|
|
||||||
default: break
|
|
||||||
}
|
}
|
||||||
|
conn.start(queue: .global())
|
||||||
|
connections.append(conn)
|
||||||
}
|
}
|
||||||
connection.start(queue: .global())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 发送 DNS 载荷(由上层剥离 IP/UDP 头后的 Data)
|
/// 并发查询:对所有服务器广播
|
||||||
func query(dnsPayload: Data) {
|
func query(dnsPayload: Data) {
|
||||||
guard let connection = self.connection, connection.state == .ready else { return }
|
for conn in connections where conn.state == .ready {
|
||||||
|
conn.send(content: dnsPayload, completion: .contentProcessed({ _ in }))
|
||||||
connection.send(content: dnsPayload, completion: .contentProcessed { [weak self] error in
|
}
|
||||||
if let error = error {
|
|
||||||
self?.logger.log("[LocalDNS] Send error: \(error)", level: .error)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private func receiveLoop() {
|
private func receiveLoop(for conn: NWConnection) {
|
||||||
connection?.receiveMessage { [weak self] content, _, _, error in
|
conn.receiveMessage { [weak self] content, _, _, error in
|
||||||
if let data = content, !data.isEmpty {
|
if let data = content {
|
||||||
// 直接输出收到的 DNS 响应载荷
|
// !!!核心:由于 AsyncStream 是流式的
|
||||||
|
// 谁先 yield,上层就先收到谁。
|
||||||
|
// 只要上层收到了第一个有效响应并回填给系统,
|
||||||
|
// 后面迟到的重复响应会被系统协议栈自动忽略(因为 Transaction ID 已失效)
|
||||||
self?.payloadContinuation.yield(data)
|
self?.payloadContinuation.yield(data)
|
||||||
}
|
}
|
||||||
if error == nil && self?.connection?.state == .ready {
|
if error == nil && conn.state == .ready {
|
||||||
self?.receiveLoop()
|
self?.receiveLoop(for: conn)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func stop() {
|
|
||||||
connection?.cancel()
|
|
||||||
}
|
|
||||||
|
|
||||||
public func waitClose() async {
|
|
||||||
for await _ in closeStream { }
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user