diff --git a/FastGithub.Dns/DnsHostedService.cs b/FastGithub.Dns/DnsHostedService.cs index 88393ff..33eda8a 100644 --- a/FastGithub.Dns/DnsHostedService.cs +++ b/FastGithub.Dns/DnsHostedService.cs @@ -1,9 +1,11 @@ -using DNS.Server; +using DNS.Client.RequestResolver; +using DNS.Protocol; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using System; using System.Net; +using System.Net.Sockets; using System.Threading; using System.Threading.Tasks; @@ -14,11 +16,17 @@ namespace FastGithub.Dns /// sealed class DnsHostedService : BackgroundService { - private readonly DnsServer dnsServer; + private const int SIO_UDP_CONNRESET = unchecked((int)0x9800000C); + + private readonly IRequestResolver requestResolver; private readonly IOptions options; private readonly ILogger logger; + + private readonly Socket socket = new(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); + private readonly byte[] buffer = new byte[ushort.MaxValue]; private IPAddress[]? dnsAddresses; + /// /// dns后台服务 /// @@ -30,51 +38,63 @@ namespace FastGithub.Dns IOptions options, ILogger logger) { - this.dnsServer = new DnsServer(githubRequestResolver, options.Value.UpStream); - this.dnsServer.Listening += DnsServer_Listening; - this.dnsServer.Errored += DnsServer_Errored; this.options = options; this.logger = logger; - } - - /// - /// 监听后 - /// - /// - /// - private void DnsServer_Listening(object? sender, EventArgs e) - { - this.logger.LogInformation("dns服务启动成功"); - this.dnsAddresses = this.SetNameServers(IPAddress.Loopback, this.options.Value.UpStream); - } - - /// - /// dns异常 - /// - /// - /// - private void DnsServer_Errored(object? sender, DnsServer.ErroredEventArgs e) - { - if (e.Exception is not OperationCanceledException) - { - this.logger.LogError($"dns服务异常:{e.Exception.Message}"); - } + this.requestResolver = new CompositeRequestResolver(options.Value.UpStream, githubRequestResolver); } /// /// 启动dns /// + /// + /// + public override Task StartAsync(CancellationToken cancellationToken) + { + this.socket.Bind(new IPEndPoint(IPAddress.Loopback, 53)); + if (OperatingSystem.IsWindows()) + { + this.socket.IOControl(SIO_UDP_CONNRESET, new byte[4], new byte[4]); + } + + this.logger.LogInformation("dns服务启动成功"); + this.dnsAddresses = this.SetNameServers(IPAddress.Loopback, this.options.Value.UpStream); + return base.StartAsync(cancellationToken); + } + + /// + /// dns后台 + /// /// /// protected async override Task ExecuteAsync(CancellationToken stoppingToken) + { + var remoteEndPoint = new IPEndPoint(IPAddress.Any, 0); + while (stoppingToken.IsCancellationRequested == false) + { + 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, stoppingToken); + } + } + + /// + /// 处理dns请求 + /// + /// + /// + /// + private async void HandleRequestAsync(byte[] datas, EndPoint remoteEndPoint, CancellationToken cancellationToken) { try { - await this.dnsServer.Listen(); + var request = Request.FromArray(datas); + var response = await this.requestResolver.Resolve(request, cancellationToken); + await this.socket.SendToAsync(response.ToArray(), SocketFlags.None, remoteEndPoint); } catch (Exception ex) { - this.logger.LogWarning($"dns服务启动失败:{ex.Message}"); + this.logger.LogTrace($"处理dns异常:{ex.Message}"); } } @@ -85,15 +105,14 @@ namespace FastGithub.Dns /// public override Task StopAsync(CancellationToken cancellationToken) { - this.dnsServer.Dispose(); + this.socket.Dispose(); this.logger.LogInformation("dns服务已终止"); if (this.dnsAddresses != null) { this.SetNameServers(this.dnsAddresses); } - - return Task.CompletedTask; + return base.StopAsync(cancellationToken); } /// @@ -120,5 +139,31 @@ namespace FastGithub.Dns return default; } + + private class CompositeRequestResolver : IRequestResolver + { + private readonly IRequestResolver upStreamResolver; + private readonly IRequestResolver[] customResolvers; + + public CompositeRequestResolver(IPAddress upStream, params IRequestResolver[] customResolvers) + { + this.upStreamResolver = new UdpRequestResolver(new IPEndPoint(upStream, 53)); + this.customResolvers = customResolvers; + } + + public async Task Resolve(IRequest request, CancellationToken cancellationToken = default) + { + foreach (IRequestResolver resolver in customResolvers) + { + var response = await resolver.Resolve(request, cancellationToken); + if (response.AnswerRecords.Count > 0) + { + return response; + } + } + + return await this.upStreamResolver.Resolve(request, cancellationToken); + } + } } }