//===----------------------------------------------------------------------===// // Copyright © 2025 Apple Inc. and the container project authors. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //===----------------------------------------------------------------------===// import Foundation import Logging import NIOCore import NIOPosix /// Provides a DNS server. /// - Parameters: /// - host: The host address on which to listen. /// - port: The port for the server to listen. public struct DNSServer { public var handler: DNSHandler let log: Logger? public init( handler: DNSHandler, log: Logger? = nil ) { self.handler = handler self.log = log } public func run(host: String, port: Int) async throws { // TODO: TCP server let srv = try await DatagramBootstrap(group: NIOSingletons.posixEventLoopGroup) .channelOption(.socketOption(.so_reuseaddr), value: 1) .bind(host: host, port: port) .flatMapThrowing { channel in try NIOAsyncChannel( wrappingChannelSynchronously: channel, configuration: NIOAsyncChannel.Configuration( inboundType: AddressedEnvelope.self, outboundType: AddressedEnvelope.self ) ) } .get() try await srv.executeThenClose { inbound, outbound in for try await var packet in inbound { try await self.handle(outbound: outbound, packet: &packet) } } } public func run(socketPath: String) async throws { // TODO: TCP server let srv = try await DatagramBootstrap(group: NIOSingletons.posixEventLoopGroup) .bind(unixDomainSocketPath: socketPath, cleanupExistingSocketFile: true) .flatMapThrowing { channel in try NIOAsyncChannel( wrappingChannelSynchronously: channel, configuration: NIOAsyncChannel.Configuration( inboundType: AddressedEnvelope.self, outboundType: AddressedEnvelope.self ) ) } .get() try await srv.executeThenClose { inbound, outbound in for try await var packet in inbound { log?.debug("received packet from \(packet.remoteAddress)") try await self.handle(outbound: outbound, packet: &packet) log?.debug("sent packet") } } } public func stop() async throws {} }