解决dns的问题
This commit is contained in:
parent
a1c42d8eef
commit
f22e962bd7
@ -23,12 +23,6 @@ class PacketTunnelProvider: NEPacketTunnelProvider {
|
|||||||
SDLLogger.shared.log("NE read message: \(msg ?? "failed")")
|
SDLLogger.shared.log("NE read message: \(msg ?? "failed")")
|
||||||
|
|
||||||
DarwinNotificationCenter.shared.post(.vpnStatusChanged)
|
DarwinNotificationCenter.shared.post(.vpnStatusChanged)
|
||||||
|
|
||||||
// host: "192.168.0.101", port: 1265
|
|
||||||
guard let options, let config = SDLConfiguration.parse(options: options) else {
|
|
||||||
completionHandler(TunnelError.invalidConfiguration)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// 如果当前在运行状态,不允许重复请求
|
// 如果当前在运行状态,不允许重复请求
|
||||||
guard self.contextActor == nil else {
|
guard self.contextActor == nil else {
|
||||||
@ -39,6 +33,12 @@ class PacketTunnelProvider: NEPacketTunnelProvider {
|
|||||||
// 加密算法
|
// 加密算法
|
||||||
let rsaCipher = try! CCRSACipher(keySize: 1024)
|
let rsaCipher = try! CCRSACipher(keySize: 1024)
|
||||||
self.rootTask = Task {
|
self.rootTask = Task {
|
||||||
|
// host: "192.168.0.101", port: 1265
|
||||||
|
guard let options, let config = await SDLConfiguration.parse(options: options) else {
|
||||||
|
completionHandler(TunnelError.invalidConfiguration)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
self.contextActor = SDLContextActor(provider: self, config: config, rsaCipher: rsaCipher)
|
self.contextActor = SDLContextActor(provider: self, config: config, rsaCipher: rsaCipher)
|
||||||
await self.contextActor?.start()
|
await self.contextActor?.start()
|
||||||
completionHandler(nil)
|
completionHandler(nil)
|
||||||
|
|||||||
@ -103,6 +103,7 @@ actor SDLContextActor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public func start() async {
|
public func start() async {
|
||||||
|
|
||||||
self.startMonitor()
|
self.startMonitor()
|
||||||
|
|
||||||
// 启动arp的定时清理任务
|
// 启动arp的定时清理任务
|
||||||
@ -233,7 +234,7 @@ actor SDLContextActor {
|
|||||||
self.dnsWorker = nil
|
self.dnsWorker = nil
|
||||||
|
|
||||||
// 启动dns服务
|
// 启动dns服务
|
||||||
let dnsClient = DNSCloudClient(host: self.config.serverHost, port: 15353, logger: SDLLogger.shared)
|
let dnsClient = DNSCloudClient(host: self.config.serverIp, port: 15353, logger: SDLLogger.shared)
|
||||||
dnsClient.start()
|
dnsClient.start()
|
||||||
SDLLogger.shared.log("[SDLContext] dnsClient started")
|
SDLLogger.shared.log("[SDLContext] dnsClient started")
|
||||||
self.dnsClient = dnsClient
|
self.dnsClient = dnsClient
|
||||||
@ -264,6 +265,8 @@ actor SDLContextActor {
|
|||||||
if Task.isCancelled {
|
if Task.isCancelled {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 要想办法构造一个完整的Ip包
|
||||||
let nePacket = NEPacket(data: packet, protocolFamily: 2)
|
let nePacket = NEPacket(data: packet, protocolFamily: 2)
|
||||||
self.provider.packetFlow.writePacketObjects([nePacket])
|
self.provider.packetFlow.writePacketObjects([nePacket])
|
||||||
}
|
}
|
||||||
@ -693,8 +696,31 @@ actor SDLContextActor {
|
|||||||
let networkAddr = self.config.networkAddress
|
let networkAddr = self.config.networkAddress
|
||||||
|
|
||||||
if DNSHelper.isDnsRequestPacket(ipPacket: packet) {
|
if DNSHelper.isDnsRequestPacket(ipPacket: packet) {
|
||||||
|
// 数据是通过offset解析的, dns查询必然是udp包
|
||||||
|
if case .udp(let udpPacket) = packet.transportPacket {
|
||||||
|
let payloadOffset = udpPacket.payloadOffset
|
||||||
|
let dnsParser = DNSParser(data: packet.data, offset: payloadOffset)
|
||||||
|
if let dnsMessage = dnsParser.parse(), let name = dnsMessage.questions.first?.name {
|
||||||
|
// 如果是内部域名,则转发整个ip包的内容到云端服务器
|
||||||
|
if name.contains(self.config.networkAddress.networkDomain) {
|
||||||
|
SDLLogger.shared.log("[Tun] get cloud dns request: \(name)")
|
||||||
|
self.dnsClient?.forward(ipPacketData: packet.data)
|
||||||
|
}
|
||||||
|
// 通过本地的dns解析,发送的是udp的payload部分
|
||||||
|
else if packet.data.count > payloadOffset {
|
||||||
|
// 尝试解析下对不对
|
||||||
|
let dnsPayload = Data(packet.data[payloadOffset..<packet.data.count])
|
||||||
|
SDLLogger.shared.log("[Tun] get local dns request: \(name)")
|
||||||
|
|
||||||
|
let tracker = DNSLocalClient.DNSTracker(transactionID: dnsMessage.transactionID, clientIP: packet.header.source, clientPort: udpPacket.srcPort, createdAt: Date())
|
||||||
|
self.dnsLocalClient?.query(tracker: tracker, dnsPayload: dnsPayload)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
self.dnsClient?.forward(ipPacketData: packet.data)
|
self.dnsClient?.forward(ipPacketData: packet.data)
|
||||||
return
|
return
|
||||||
|
} else {
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
let dstIp = packet.header.destination
|
let dstIp = packet.header.destination
|
||||||
@ -812,8 +838,8 @@ actor SDLContextActor {
|
|||||||
let dnsSettings = NEDNSSettings(servers: [dnsServer])
|
let dnsSettings = NEDNSSettings(servers: [dnsServer])
|
||||||
|
|
||||||
dnsSettings.searchDomains = [networkDomain]
|
dnsSettings.searchDomains = [networkDomain]
|
||||||
dnsSettings.matchDomains = [networkDomain]
|
dnsSettings.matchDomains = [networkDomain, ""]
|
||||||
// 必须设置为 false,否则它会尝试接管全局解析
|
// 设置为 false 允许系统在补全 Search Domain 时也能匹配到此设置
|
||||||
dnsSettings.matchDomainsNoSearch = false
|
dnsSettings.matchDomainsNoSearch = false
|
||||||
|
|
||||||
networkSettings.dnsSettings = dnsSettings
|
networkSettings.dnsSettings = dnsSettings
|
||||||
@ -822,12 +848,6 @@ actor SDLContextActor {
|
|||||||
// 设置路由表
|
// 设置路由表
|
||||||
ipv4Settings.includedRoutes = routes
|
ipv4Settings.includedRoutes = routes
|
||||||
|
|
||||||
let rs = self.getIpv4ExcludeRoutes()
|
|
||||||
|
|
||||||
rs.forEach { x in
|
|
||||||
SDLLogger.shared.log("excludsL: \(x.destinationAddress)")
|
|
||||||
}
|
|
||||||
|
|
||||||
// 配置要排除的路由
|
// 配置要排除的路由
|
||||||
ipv4Settings.excludedRoutes = self.getIpv4ExcludeRoutes()
|
ipv4Settings.excludedRoutes = self.getIpv4ExcludeRoutes()
|
||||||
|
|
||||||
|
|||||||
@ -2,6 +2,14 @@ import Foundation
|
|||||||
import Network
|
import Network
|
||||||
|
|
||||||
final class DNSLocalClient {
|
final class DNSLocalClient {
|
||||||
|
// 需要保存DNS请求的追踪信息
|
||||||
|
struct DNSTracker {
|
||||||
|
let transactionID: UInt16
|
||||||
|
let clientIP: UInt32 // 原始包的源 IP (大端序)
|
||||||
|
let clientPort: UInt16 // 原始包的源端口 (大端序)
|
||||||
|
let createdAt: Date // 用于超时清理
|
||||||
|
}
|
||||||
|
|
||||||
private var connections: [NWConnection] = []
|
private var connections: [NWConnection] = []
|
||||||
|
|
||||||
// 准备多个公共 DNS
|
// 准备多个公共 DNS
|
||||||
@ -9,6 +17,9 @@ final class DNSLocalClient {
|
|||||||
|
|
||||||
public let packetFlow: AsyncStream<Data>
|
public let packetFlow: AsyncStream<Data>
|
||||||
private let packetContinuation: AsyncStream<Data>.Continuation
|
private let packetContinuation: AsyncStream<Data>.Continuation
|
||||||
|
|
||||||
|
private let locker = NSLock()
|
||||||
|
private var trackers: [UInt16: [DNSTracker]] = [:]
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
let (stream, continuation) = AsyncStream.makeStream(of: Data.self, bufferingPolicy: .unbounded)
|
let (stream, continuation) = AsyncStream.makeStream(of: Data.self, bufferingPolicy: .unbounded)
|
||||||
@ -29,6 +40,7 @@ final class DNSLocalClient {
|
|||||||
case .ready:
|
case .ready:
|
||||||
self?.receiveLoop(for: conn)
|
self?.receiveLoop(for: conn)
|
||||||
case .failed(let error):
|
case .failed(let error):
|
||||||
|
SDLLogger.shared.log("[DNSLocalClient] failed with error: \(error.localizedDescription)")
|
||||||
self?.stop()
|
self?.stop()
|
||||||
case .cancelled:
|
case .cancelled:
|
||||||
self?.packetContinuation.finish()
|
self?.packetContinuation.finish()
|
||||||
@ -43,7 +55,11 @@ final class DNSLocalClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// 并发查询:对所有服务器广播
|
/// 并发查询:对所有服务器广播
|
||||||
func query(dnsPayload: Data) {
|
func query(tracker: DNSTracker, dnsPayload: Data) {
|
||||||
|
locker.lock()
|
||||||
|
self.trackers[tracker.transactionID, default: []].append(tracker)
|
||||||
|
locker.unlock()
|
||||||
|
|
||||||
for conn in connections where conn.state == .ready {
|
for conn in connections where conn.state == .ready {
|
||||||
conn.send(content: dnsPayload, completion: .contentProcessed({ _ in }))
|
conn.send(content: dnsPayload, completion: .contentProcessed({ _ in }))
|
||||||
}
|
}
|
||||||
@ -55,8 +71,7 @@ final class DNSLocalClient {
|
|||||||
// !!!核心:由于 AsyncStream 是流式的
|
// !!!核心:由于 AsyncStream 是流式的
|
||||||
// 谁先 yield,上层就先收到谁。
|
// 谁先 yield,上层就先收到谁。
|
||||||
// 只要上层收到了第一个有效响应并回填给系统,
|
// 只要上层收到了第一个有效响应并回填给系统,
|
||||||
// 后面迟到的重复响应会被系统协议栈自动忽略(因为 Transaction ID 已失效)
|
self?.handleResponse(data: data)
|
||||||
self?.packetContinuation.yield(data)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if error == nil && conn.state == .ready {
|
if error == nil && conn.state == .ready {
|
||||||
@ -65,6 +80,30 @@ final class DNSLocalClient {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private func handleResponse(data: Data) {
|
||||||
|
let dnsParser = DNSParser(data: data, offset: 0)
|
||||||
|
if let message = dnsParser.parse() {
|
||||||
|
let tranId = message.transactionID
|
||||||
|
|
||||||
|
locker.lock()
|
||||||
|
let items = self.trackers.removeValue(forKey: tranId)
|
||||||
|
locker.unlock()
|
||||||
|
|
||||||
|
if let items {
|
||||||
|
items.forEach { tracker in
|
||||||
|
let packet = Self.createDNSResponse(
|
||||||
|
payload: data,
|
||||||
|
srcIP: DNSHelper.dnsDestIpAddr,
|
||||||
|
srcPort: 53,
|
||||||
|
destIP: tracker.clientIP,
|
||||||
|
destPort: tracker.clientPort
|
||||||
|
)
|
||||||
|
self.packetContinuation.yield(packet)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func stop() {
|
func stop() {
|
||||||
connections.forEach { conn in
|
connections.forEach { conn in
|
||||||
conn.cancel()
|
conn.cancel()
|
||||||
@ -73,3 +112,77 @@ final class DNSLocalClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension DNSLocalClient {
|
||||||
|
/// 构造发回 TUN 的完整 UDP/IPv4 数据包
|
||||||
|
static func createDNSResponse(payload: Data, srcIP: UInt32, srcPort: UInt16, destIP: UInt32, destPort: UInt16) -> Data {
|
||||||
|
let udpLen = 8 + payload.count
|
||||||
|
let ipLen = 20 + udpLen
|
||||||
|
|
||||||
|
// --- 1. IPv4 Header (20 字节) ---
|
||||||
|
var ipHeader = Data(count: 20)
|
||||||
|
ipHeader[0] = 0x45 // Version 4, IHL 5
|
||||||
|
ipHeader[2...3] = withUnsafeBytes(of: UInt16(ipLen).bigEndian) { Data($0) }
|
||||||
|
ipHeader[8] = 64 // TTL
|
||||||
|
ipHeader[9] = 17 // Protocol UDP
|
||||||
|
|
||||||
|
// 填充 IP 地址
|
||||||
|
ipHeader[12...15] = withUnsafeBytes(of: srcIP.bigEndian) { Data($0) }
|
||||||
|
ipHeader[16...19] = withUnsafeBytes(of: destIP.bigEndian) { Data($0) }
|
||||||
|
|
||||||
|
// 计算 IP Checksum
|
||||||
|
let ipChecksum = calculateChecksum(data: ipHeader)
|
||||||
|
ipHeader[10...11] = withUnsafeBytes(of: ipChecksum.bigEndian) { Data($0) }
|
||||||
|
|
||||||
|
// --- 2. UDP Header (8 字节) ---
|
||||||
|
var udpHeader = Data(count: 8)
|
||||||
|
udpHeader[0...1] = withUnsafeBytes(of: srcPort.bigEndian) { Data($0) }
|
||||||
|
udpHeader[2...3] = withUnsafeBytes(of: destPort.bigEndian) { Data($0) }
|
||||||
|
udpHeader[4...5] = withUnsafeBytes(of: UInt16(udpLen).bigEndian) { Data($0) }
|
||||||
|
// UDP Checksum 在 IPv4 中可选,设为 0 可跳过计算(大部分系统接受)
|
||||||
|
udpHeader[6...7] = Data([0, 0])
|
||||||
|
|
||||||
|
// --- 3. 拼接 ---
|
||||||
|
var packet = Data(capacity: ipLen)
|
||||||
|
packet.append(ipHeader)
|
||||||
|
packet.append(udpHeader)
|
||||||
|
packet.append(payload)
|
||||||
|
|
||||||
|
return packet
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 经典的 Internet Checksum 算法
|
||||||
|
static func calculateChecksum(data: Data) -> UInt16 {
|
||||||
|
var sum: UInt32 = 0
|
||||||
|
let count = data.count
|
||||||
|
|
||||||
|
data.withUnsafeBytes { (ptr: UnsafeRawBufferPointer) in
|
||||||
|
guard let baseAddress = ptr.baseAddress else { return }
|
||||||
|
|
||||||
|
// 1. 处理成对的 16-bit 单词
|
||||||
|
let wordCount = count / 2
|
||||||
|
let words = baseAddress.bindMemory(to: UInt16.self, capacity: wordCount)
|
||||||
|
|
||||||
|
for i in 0..<wordCount {
|
||||||
|
// 使用 bigEndian: words[i] 是正确的,但要确保不越界
|
||||||
|
sum += UInt32(UInt16(bigEndian: words[i]))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 关键修复:处理奇数长度的最后一个字节
|
||||||
|
if count % 2 != 0 {
|
||||||
|
// 获取最后一个字节,并左移 8 位(作为 16-bit 的高位)
|
||||||
|
let lastByte = ptr[count - 1]
|
||||||
|
sum += UInt32(lastByte) << 8
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. 将进位加回低 16 位
|
||||||
|
while (sum >> 16) != 0 {
|
||||||
|
sum = (sum & 0xffff) + (sum >> 16)
|
||||||
|
}
|
||||||
|
|
||||||
|
return UInt16(~sum & 0xffff)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|||||||
@ -29,7 +29,9 @@ struct DNSMessage {
|
|||||||
var questions: [DNSQuestion] = []
|
var questions: [DNSQuestion] = []
|
||||||
var answers: [DNSResourceRecord] = []
|
var answers: [DNSResourceRecord] = []
|
||||||
|
|
||||||
var isResponse: Bool { (flags & 0x8000) != 0 }
|
var isResponse: Bool {
|
||||||
|
(flags & 0x8000) != 0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - DNS 完整解析器
|
// MARK: - DNS 完整解析器
|
||||||
@ -37,13 +39,15 @@ final class DNSParser {
|
|||||||
private let data: Data
|
private let data: Data
|
||||||
private var offset: Int = 0
|
private var offset: Int = 0
|
||||||
|
|
||||||
init(data: Data) {
|
init(data: Data, offset: Int) {
|
||||||
self.data = data
|
self.data = data
|
||||||
|
self.offset = offset
|
||||||
}
|
}
|
||||||
|
|
||||||
func parse() -> DNSMessage? {
|
func parse() -> DNSMessage? {
|
||||||
guard data.count >= 12 else { return nil }
|
guard data.count >= 12 + self.offset else {
|
||||||
offset = 0
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
let id = readUInt16()
|
let id = readUInt16()
|
||||||
let flags = readUInt16()
|
let flags = readUInt16()
|
||||||
@ -55,11 +59,17 @@ final class DNSParser {
|
|||||||
var message = DNSMessage(transactionID: id, flags: flags)
|
var message = DNSMessage(transactionID: id, flags: flags)
|
||||||
|
|
||||||
for _ in 0..<qdCount {
|
for _ in 0..<qdCount {
|
||||||
if let q = parseQuestion() { message.questions.append(q) }
|
if let q = parseQuestion() {
|
||||||
|
message.questions.append(q)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for _ in 0..<anCount {
|
for _ in 0..<anCount {
|
||||||
if let rr = parseRR() { message.answers.append(rr) }
|
if let rr = parseRR() {
|
||||||
|
message.answers.append(rr)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return message
|
return message
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -201,17 +201,20 @@ struct UDPPacket {
|
|||||||
let dstPort: UInt16
|
let dstPort: UInt16
|
||||||
let length: UInt16
|
let length: UInt16
|
||||||
let checksum: UInt16
|
let checksum: UInt16
|
||||||
|
let payloadOffset: Int
|
||||||
|
|
||||||
init?(_ data: Data, offset: Int) {
|
init?(_ data: Data, offset: Int) {
|
||||||
guard data.count >= offset + 8 else {
|
guard data.count >= offset + 8 else {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
self.srcPort = UInt16(bytes: (data[offset], data[offset + 1]))
|
self.srcPort = UInt16(bytes: (data[offset], data[offset + 1]))
|
||||||
self.dstPort = UInt16(bytes: (data[offset + 2], data[offset + 3]))
|
self.dstPort = UInt16(bytes: (data[offset + 2], data[offset + 3]))
|
||||||
self.length = UInt16(bytes: (data[offset + 4], data[offset + 5]))
|
self.length = UInt16(bytes: (data[offset + 4], data[offset + 5]))
|
||||||
self.checksum = UInt16(bytes: (data[offset + 6], data[offset + 7]))
|
self.checksum = UInt16(bytes: (data[offset + 6], data[offset + 7]))
|
||||||
|
self.payloadOffset = offset + 8
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - ICMP Packet
|
// MARK: - ICMP Packet
|
||||||
|
|||||||
@ -49,6 +49,7 @@ public class SDLConfiguration {
|
|||||||
let version: Int
|
let version: Int
|
||||||
|
|
||||||
let serverHost: String
|
let serverHost: String
|
||||||
|
let serverIp: String
|
||||||
let stunServers: [String]
|
let stunServers: [String]
|
||||||
|
|
||||||
let noticePort: Int
|
let noticePort: Int
|
||||||
@ -78,6 +79,7 @@ public class SDLConfiguration {
|
|||||||
|
|
||||||
public init(version: Int,
|
public init(version: Int,
|
||||||
serverHost: String,
|
serverHost: String,
|
||||||
|
serverIp: String,
|
||||||
stunServers: [String],
|
stunServers: [String],
|
||||||
clientId: String,
|
clientId: String,
|
||||||
networkAddress: NetworkAddress,
|
networkAddress: NetworkAddress,
|
||||||
@ -86,9 +88,9 @@ public class SDLConfiguration {
|
|||||||
accessToken: String,
|
accessToken: String,
|
||||||
identityId: UInt32,
|
identityId: UInt32,
|
||||||
exitNode: ExitNode?) {
|
exitNode: ExitNode?) {
|
||||||
|
|
||||||
self.version = version
|
self.version = version
|
||||||
self.serverHost = serverHost
|
self.serverHost = serverHost
|
||||||
|
self.serverIp = serverIp
|
||||||
self.stunServers = stunServers
|
self.stunServers = stunServers
|
||||||
self.clientId = clientId
|
self.clientId = clientId
|
||||||
self.networkAddress = networkAddress
|
self.networkAddress = networkAddress
|
||||||
@ -104,7 +106,7 @@ public class SDLConfiguration {
|
|||||||
// 解析配置文件
|
// 解析配置文件
|
||||||
extension SDLConfiguration {
|
extension SDLConfiguration {
|
||||||
|
|
||||||
static func parse(options: [String: NSObject]) -> SDLConfiguration? {
|
static func parse(options: [String: NSObject]) async -> SDLConfiguration? {
|
||||||
guard let version = options["version"] as? Int,
|
guard let version = options["version"] as? Int,
|
||||||
let serverHost = options["server_host"] as? String,
|
let serverHost = options["server_host"] as? String,
|
||||||
let stunAssistHost = options["stun_assist_host"] as? String,
|
let stunAssistHost = options["stun_assist_host"] as? String,
|
||||||
@ -121,6 +123,11 @@ extension SDLConfiguration {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 解析dns域名所在的服务器地址
|
||||||
|
guard let serverIp = await SDLUtil.resolveHostname(host: serverHost) else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// 网络出口配置是可选的
|
// 网络出口配置是可选的
|
||||||
var exitNode: ExitNode? = nil
|
var exitNode: ExitNode? = nil
|
||||||
if let exitNodeIpStr = options["exit_node_ip"] as? String, let exitNodeIp = SDLUtil.ipv4StrToInt32(exitNodeIpStr) {
|
if let exitNodeIpStr = options["exit_node_ip"] as? String, let exitNodeIp = SDLUtil.ipv4StrToInt32(exitNodeIpStr) {
|
||||||
@ -129,6 +136,7 @@ extension SDLConfiguration {
|
|||||||
|
|
||||||
return SDLConfiguration(version: version,
|
return SDLConfiguration(version: version,
|
||||||
serverHost: serverHost,
|
serverHost: serverHost,
|
||||||
|
serverIp: serverIp,
|
||||||
stunServers: [serverHost, stunAssistHost],
|
stunServers: [serverHost, stunAssistHost],
|
||||||
clientId: clientId,
|
clientId: clientId,
|
||||||
networkAddress: networkAddress,
|
networkAddress: networkAddress,
|
||||||
|
|||||||
@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
import SystemConfiguration
|
import SystemConfiguration
|
||||||
|
import Network
|
||||||
|
|
||||||
struct SDLUtil {
|
struct SDLUtil {
|
||||||
|
|
||||||
@ -76,5 +77,31 @@ struct SDLUtil {
|
|||||||
}
|
}
|
||||||
return results
|
return results
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 域名解析
|
||||||
|
static func resolveHostname(host: String) async -> String? {
|
||||||
|
let endpoint = NWEndpoint.hostPort(host: NWEndpoint.Host(host), port: 53)
|
||||||
|
let parameters = NWParameters.udp
|
||||||
|
// 即使还没正式开始,也加上这个,确保不会被残留的旧 utun 路由卡死
|
||||||
|
parameters.prohibitedInterfaceTypes = [.other]
|
||||||
|
|
||||||
|
let connection = NWConnection(to: endpoint, using: parameters)
|
||||||
|
|
||||||
|
return await withCheckedContinuation { continuation in
|
||||||
|
connection.stateUpdateHandler = { state in
|
||||||
|
if case .ready = state {
|
||||||
|
if let path = connection.currentPath,
|
||||||
|
case .hostPort(let resolvedHost, _) = path.remoteEndpoint {
|
||||||
|
let ip = String(describing: resolvedHost)
|
||||||
|
continuation.resume(returning: ip)
|
||||||
|
connection.cancel()
|
||||||
|
}
|
||||||
|
} else if case .failed = state {
|
||||||
|
continuation.resume(returning: nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
connection.start(queue: .global())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user