using DNS.Protocol; using Microsoft.Extensions.Logging; using System; using System.Diagnostics; using System.Net; using System.Net.Sockets; using System.Threading; using System.Threading.Tasks; namespace FastGithub.Dns { /// /// dns服务器 /// sealed class DnsServer : IDisposable { private readonly RequestResolver requestResolver; private readonly ILogger logger; private readonly Socket socket = new(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); private readonly byte[] buffer = new byte[ushort.MaxValue]; /// /// dns服务器 /// /// /// public DnsServer( RequestResolver requestResolver, ILogger logger) { this.requestResolver = requestResolver; this.logger = logger; } /// /// 绑定地址和端口 /// /// /// /// public void Bind(IPAddress address, int port) { if (OperatingSystem.IsWindows() && UdpTable.TryGetOwnerProcessId(port, out var processId)) { Process.GetProcessById(processId).Kill(); } if (OperatingSystem.IsWindows()) { const int SIO_UDP_CONNRESET = unchecked((int)0x9800000C); this.socket.IOControl(SIO_UDP_CONNRESET, new byte[4], new byte[4]); } this.socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); var maxSpinCount = 100; var spinWait = new SpinWait(); var localEndPoint = new IPEndPoint(address, port); for (var i = 0; i < maxSpinCount; i++) { try { this.socket.Bind(localEndPoint); break; } catch (SocketException ex) when (ex.SocketErrorCode == SocketError.AccessDenied) { spinWait.SpinOnce(); } } } /// /// 监听dns请求 /// /// /// public async Task ListenAsync(CancellationToken cancellationToken) { var remoteEndPoint = new IPEndPoint(IPAddress.Any, 0); while (cancellationToken.IsCancellationRequested == false) { try { var result = await this.socket.ReceiveFromAsync(this.buffer, SocketFlags.None, remoteEndPoint); var datas = new byte[result.ReceivedBytes]; this.buffer.AsSpan(0, datas.Length).CopyTo(datas); this.HandleRequestAsync(datas, result.RemoteEndPoint, cancellationToken); } catch (SocketException ex) when (ex.SocketErrorCode == SocketError.OperationAborted) { break; } } } /// /// 处理dns请求 /// /// /// /// private async void HandleRequestAsync(byte[] datas, EndPoint remoteEndPoint, CancellationToken cancellationToken) { try { var request = Request.FromArray(datas); var remoteEndPointRequest = new RemoteEndPointRequest(request, remoteEndPoint); var response = await this.requestResolver.Resolve(remoteEndPointRequest, cancellationToken); await this.socket.SendToAsync(response.ToArray(), SocketFlags.None, remoteEndPoint); } catch (Exception ex) { this.logger.LogTrace($"处理DNS异常:{ex.Message}"); } } /// /// 释放资源 /// public void Dispose() { this.socket.Dispose(); } } }