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; namespace FastGithub.Dns { /// /// dns后台服务 /// sealed class DnsServerHostedService : BackgroundService { private const int SIO_UDP_CONNRESET = unchecked((int)0x9800000C); private readonly FastGihubResolver fastGihubResolver; 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后台服务 /// /// /// /// public DnsServerHostedService( FastGihubResolver fastGihubResolver, IOptions options, ILogger logger) { this.fastGihubResolver = fastGihubResolver; this.options = options; this.logger = logger; } /// /// 启动dns /// /// /// public override Task StartAsync(CancellationToken cancellationToken) { this.socket.Bind(new IPEndPoint(IPAddress.Any, 53)); if (OperatingSystem.IsWindows()) { this.socket.IOControl(SIO_UDP_CONNRESET, new byte[4], new byte[4]); } this.logger.LogInformation("dns服务启动成功"); var upStream = IPAddress.Parse(options.Value.UntrustedDns.Address); this.dnsAddresses = this.SetNameServers(IPAddress.Loopback, 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 { var request = Request.FromArray(datas); var remoteRequest = new RemoteRequest(request, remoteEndPoint); var response = await this.fastGihubResolver.Resolve(remoteRequest, cancellationToken); await this.socket.SendToAsync(response.ToArray(), SocketFlags.None, remoteEndPoint); } catch (Exception ex) { this.logger.LogTrace($"处理dns异常:{ex.Message}"); } } /// /// 停止dns服务 /// /// /// public override Task StopAsync(CancellationToken cancellationToken) { this.socket.Dispose(); this.logger.LogInformation("dns服务已终止"); if (this.dnsAddresses != null) { this.SetNameServers(this.dnsAddresses); } return base.StopAsync(cancellationToken); } /// /// 设置dns /// /// /// private IPAddress[]? SetNameServers(params IPAddress[] nameServers) { if (OperatingSystem.IsWindows()) { try { var results = NameServiceUtil.SetNameServers(nameServers); this.logger.LogInformation($"设置本机dns成功"); return results; } catch (Exception ex) { this.logger.LogWarning($"设置本机dns失败:{ex.Message}"); } } else { this.logger.LogError("不支持自动为本机设备设置dns值"); } return default; } } }