diff --git a/Tun/Punchnet/DNSClient.swift b/Tun/Punchnet/DNSClient.swift new file mode 100644 index 0000000..9e60ef1 --- /dev/null +++ b/Tun/Punchnet/DNSClient.swift @@ -0,0 +1,102 @@ +// +// DNSClient.swift +// Tun +// +// Created by 安礼成 on 2025/12/10. +// + +import Foundation +import NIOCore +import NIOPosix + +// 处理和sn-server服务器之间的通讯 +@available(macOS 14, *) +actor DNSClient { + private let group = MultiThreadedEventLoopGroup(numberOfThreads: 1) + private let asyncChannel: NIOAsyncChannel, AddressedEnvelope> + private let (writeStream, writeContinuation) = AsyncStream.makeStream(of: Data.self, bufferingPolicy: .unbounded) + + private let logger: SDLLogger + private let dnsServerAddress: SocketAddress + + public let packetFlow: AsyncStream + private let packetContinuation: AsyncStream.Continuation + + // 启动函数 + init(dnsServerAddress: SocketAddress, logger: SDLLogger) async throws { + self.dnsServerAddress = dnsServerAddress + self.logger = logger + + (self.packetFlow, self.packetContinuation) = AsyncStream.makeStream(of: Data.self, bufferingPolicy: .unbounded) + + let bootstrap = DatagramBootstrap(group: group) + .channelOption(ChannelOptions.socketOption(.so_reuseaddr), value: 1) + + self.asyncChannel = try await bootstrap.bind(host: "0.0.0.0", port: 0) + .flatMapThrowing { channel in + return try NIOAsyncChannel(wrappingChannelSynchronously: channel, configuration: .init( + inboundType: AddressedEnvelope.self, + outboundType: AddressedEnvelope.self + )) + } + .get() + } + + func start() async throws { + try await withTaskCancellationHandler { + try await self.asyncChannel.executeThenClose {inbound, outbound in + try await withThrowingTaskGroup(of: Void.self) { group in + group.addTask { + defer { + self.logger.log("[DNSClient] inbound closed", level: .warning) + } + + for try await envelope in inbound { + try Task.checkCancellation() + var buffer = envelope.data + let remoteAddress = envelope.remoteAddress + self.logger.log("[DNSClient] read data: \(buffer), from: \(remoteAddress)", level: .debug) + + let len = buffer.readableBytes + if let bytes = buffer.readBytes(length: len) { + self.packetContinuation.yield(Data(bytes)) + } + } + } + + group.addTask { + defer { + self.logger.log("[DNSClient] outbound closed", level: .warning) + } + + for await message in self.writeStream { + try Task.checkCancellation() + + let buffer = self.asyncChannel.channel.allocator.buffer(bytes: message) + let envelope = AddressedEnvelope(remoteAddress: self.dnsServerAddress, data: buffer) + try await outbound.write(envelope) + } + } + + if let _ = try await group.next() { + group.cancelAll() + } + } + } + } onCancel: { + self.writeContinuation.finish() + self.packetContinuation.finish() + self.logger.log("[DNSClient] withTaskCancellationHandler cancel") + } + } + + func forward(ipPacket: IPPacket) { + self.writeContinuation.yield(ipPacket.data) + } + + deinit { + try? self.group.syncShutdownGracefully() + self.writeContinuation.finish() + } + +} diff --git a/Tun/Punchnet/DNSUtil.swift b/Tun/Punchnet/DNSUtil.swift index e2a89b0..0b83333 100644 --- a/Tun/Punchnet/DNSUtil.swift +++ b/Tun/Punchnet/DNSUtil.swift @@ -1,23 +1,23 @@ -//// -//// DNSUtil.swift -//// punchnet -//// -//// Created by 安礼成 on 2025/12/9. -//// // -//import Foundation -//import Network +// DNSUtil.swift +// punchnet // -//struct DNSUtil { -// static let dnsServers: [String] = ["100.100.100.100"] -// // dns请求包的目标地址 -// static let dnsDestIpAddr: UInt32 = 1684300900 -// -// // 判断是否是dns请求的数据包 -// static func isDnsRequestPacket(ipPacket: IPPacket) -> Bool { -// return ipPacket.header.destination == dnsDestIpAddr -// } -// +// Created by 安礼成 on 2025/12/9. +// + +import Foundation +import Network + +struct DNSUtil { + static let dnsServers: [String] = ["100.100.100.100"] + // dns请求包的目标地址 + static let dnsDestIpAddr: UInt32 = 1684300900 + + // 判断是否是dns请求的数据包 + static func isDnsRequestPacket(ipPacket: IPPacket) -> Bool { + return ipPacket.header.destination == dnsDestIpAddr + } + // // DNS Header 结构 // struct DNSHeader { // var id: UInt16 @@ -35,8 +35,6 @@ // var qclass: UInt16 // } // -// -// // // 解析域名(DNS Label 格式) // func parseName(from data: Data, offset: inout Int) -> String { // var labels: [String] = [] @@ -109,13 +107,13 @@ // print("Question: \(q.name), type: \(q.type), class: \(q.qclass)") // } // } -// -//} -// -//// Helper 扩展:读取整数类型 -//private extension Data { -// func uint16(at offset: Int) -> UInt16 { -// let subdata = self[offset.. UInt16 { + let subdata = self[offset..? @@ -107,6 +110,18 @@ public class SDLContext: @unchecked Sendable { public func start() async throws { self.rootTask = Task { try await withThrowingTaskGroup(of: Void.self) { group in + + group.addTask { + while !Task.isCancelled { + do { + try await self.startDnsClient() + } catch let err { + self.logger.log("[SDLContext] UDPHole get err: \(err)", level: .warning) + try await Task.sleep(for: .seconds(2)) + } + } + } + group.addTask { while !Task.isCancelled { do { @@ -235,6 +250,35 @@ public class SDLContext: @unchecked Sendable { } } + private func startDnsClient() async throws { + let dnsSocketAddress = try SocketAddress.makeAddressResolvingHost("127.0.0.1", port: 15353) + self.dnsClient = try await DNSClient(dnsServerAddress: dnsSocketAddress, logger: self.logger) + + try await withThrowingTaskGroup(of: Void.self) { group in + defer { + self.logger.log("[SDLContext] dns client task cancel", level: .warning) + } + + group.addTask { + try await self.dnsClient?.start() + } + + group.addTask { + if let packetFlow = self.dnsClient?.packetFlow { + for await packet in packetFlow { + let nePacket = NEPacket(data: packet, protocolFamily: 2) + self.provider.packetFlow.writePacketObjects([nePacket]) + } + } + + } + + if let _ = try await group.next() { + group.cancelAll() + } + } + } + private func handleSuperEvent(event: SDLSuperClient.SuperEvent) async throws { switch event { case .ready: @@ -485,39 +529,47 @@ public class SDLContext: @unchecked Sendable { repeat { let (packets, numbers) = await self.provider.packetFlow.readPackets() for (data, number) in zip(packets, numbers) where number == 2 { - if let packet = IPPacket(data) { - let destIp = packet.header.destination_ip - NSLog("destIp: \(destIp), int: \(packet.header.destination)") - - - Task.detached { - let dstIp = packet.header.destination - // 本地通讯, 目标地址是本地服务器的ip地址 - if dstIp == self.devAddr.netAddr { - let nePacket = NEPacket(data: packet.data, protocolFamily: 2) - self.provider.packetFlow.writePacketObjects([nePacket]) - return - } - - // 查找arp缓存中是否有目标mac地址 - if let dstMac = await self.arpServer.query(ip: dstIp) { - await self.routeLayerPacket(dstMac: dstMac, type: .ipv4, data: packet.data) - } - else { - // 构造arp请求 - let broadcastMac = Data([0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]) - let arpReqeust = ARPPacket.arpRequest(senderIP: self.devAddr.netAddr, senderMAC: self.devAddr.mac, targetIP: dstIp) - await self.routeLayerPacket(dstMac: broadcastMac, type: .arp, data: arpReqeust.marshal()) - - self.logger.log("[SDLContext] dstIp: \(dstIp) arp query not found", level: .debug) - } - } - } + await self.dealPacket(data: data) } - } while true } + } + + // 处理读取的每个数据包 + private func dealPacket(data: Data) async { + guard let packet = IPPacket(data) else { + return + } + if DNSUtil.isDnsRequestPacket(ipPacket: packet) { + let destIp = packet.header.destination_ip + NSLog("destIp: \(destIp), int: \(packet.header.destination)") + await self.dnsClient?.forward(ipPacket: packet) + } + else { + Task.detached { + let dstIp = packet.header.destination + // 本地通讯, 目标地址是本地服务器的ip地址 + if dstIp == self.devAddr.netAddr { + let nePacket = NEPacket(data: packet.data, protocolFamily: 2) + self.provider.packetFlow.writePacketObjects([nePacket]) + return + } + + // 查找arp缓存中是否有目标mac地址 + if let dstMac = await self.arpServer.query(ip: dstIp) { + await self.routeLayerPacket(dstMac: dstMac, type: .ipv4, data: packet.data) + } + else { + // 构造arp请求 + let broadcastMac = Data([0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]) + let arpReqeust = ARPPacket.arpRequest(senderIP: self.devAddr.netAddr, senderMAC: self.devAddr.mac, targetIP: dstIp) + await self.routeLayerPacket(dstMac: broadcastMac, type: .arp, data: arpReqeust.marshal()) + + self.logger.log("[SDLContext] dstIp: \(dstIp) arp query not found", level: .debug) + } + } + } } private func routeLayerPacket(dstMac: Data, type: LayerPacket.PacketType, data: Data) async { @@ -594,6 +646,7 @@ public class SDLContext: @unchecked Sendable { self.rootTask?.cancel() self.udpHole = nil self.superClient = nil + self.dnsClient = nil } // 获取mac地址