fix dns client

This commit is contained in:
anlicheng 2025-12-12 15:05:36 +08:00
parent 0df890a699
commit 7ca620eca7
3 changed files with 212 additions and 59 deletions

View File

@ -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<ByteBuffer>, AddressedEnvelope<ByteBuffer>>
private let (writeStream, writeContinuation) = AsyncStream.makeStream(of: Data.self, bufferingPolicy: .unbounded)
private let logger: SDLLogger
private let dnsServerAddress: SocketAddress
public let packetFlow: AsyncStream<Data>
private let packetContinuation: AsyncStream<Data>.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<ByteBuffer>.self,
outboundType: AddressedEnvelope<ByteBuffer>.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<ByteBuffer>(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()
}
}

View File

@ -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..<offset+2]
// return subdata.withUnsafeBytes { $0.load(as: UInt16.self).bigEndian }
// }
//}
}
// Helper
private extension Data {
func uint16(at offset: Int) -> UInt16 {
let subdata = self[offset..<offset+2]
return subdata.withUnsafeBytes { $0.load(as: UInt16.self).bigEndian }
}
}

View File

@ -51,6 +51,9 @@ public class SDLContext: @unchecked Sendable {
var udpHole: SDLUDPHole?
var superClient: SDLSuperClient?
// dnsclient
var dnsClient: DNSClient?
//
private var readTask: Task<(), Never>?
@ -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
}
// arpmac
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
}
// arpmac
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