From 30382becd7da3a5fdce26a502293a376dde899ed Mon Sep 17 00:00:00 2001
From: xljiulang <366193849@qq.com>
Date: Sat, 24 Jul 2021 20:45:56 +0800
Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96dns=E6=9C=8D=E5=8A=A1?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
FastGithub.Dns/DnsHostedService.cs | 114 ++++++++++
FastGithub.Dns/DnsServer.cs | 111 ++++++++++
FastGithub.Dns/DnsServerHostedService.cs | 203 ------------------
...s.cs => DnsServiceCollectionExtensions.cs} | 5 +-
4 files changed, 228 insertions(+), 205 deletions(-)
create mode 100644 FastGithub.Dns/DnsHostedService.cs
create mode 100644 FastGithub.Dns/DnsServer.cs
delete mode 100644 FastGithub.Dns/DnsServerHostedService.cs
rename FastGithub.Dns/{DnsServerServiceCollectionExtensions.cs => DnsServiceCollectionExtensions.cs} (78%)
diff --git a/FastGithub.Dns/DnsHostedService.cs b/FastGithub.Dns/DnsHostedService.cs
new file mode 100644
index 0000000..37083c7
--- /dev/null
+++ b/FastGithub.Dns/DnsHostedService.cs
@@ -0,0 +1,114 @@
+using Microsoft.Extensions.Hosting;
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Options;
+using System;
+using System.Net;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace FastGithub.Dns
+{
+ ///
+ /// dns后台服务
+ ///
+ sealed class DnsHostedService : BackgroundService
+ {
+ private readonly DnsServer dnsServer;
+ private readonly HostsFileValidator hostsValidator;
+ private readonly ILogger logger;
+
+ ///
+ /// dns后台服务
+ ///
+ ///
+ ///
+ ///
+ ///
+ public DnsHostedService(
+ DnsServer dnsServer,
+ HostsFileValidator hostsValidator,
+ IOptionsMonitor options,
+ ILogger logger)
+ {
+ this.dnsServer = dnsServer;
+ this.hostsValidator = hostsValidator;
+ this.logger = logger;
+
+ options.OnChange(opt =>
+ {
+ if (OperatingSystem.IsWindows())
+ {
+ SystemDnsUtil.DnsFlushResolverCache();
+ }
+ });
+ }
+
+ ///
+ /// 启动dns
+ ///
+ ///
+ ///
+ public override async Task StartAsync(CancellationToken cancellationToken)
+ {
+ this.dnsServer.Bind(IPAddress.Any, 53);
+ this.logger.LogInformation("DNS服务启动成功");
+
+ if (OperatingSystem.IsWindows())
+ {
+ try
+ {
+ SystemDnsUtil.DnsSetPrimitive(IPAddress.Loopback);
+ SystemDnsUtil.DnsFlushResolverCache();
+ this.logger.LogInformation($"设置为本机主DNS成功");
+ }
+ catch (Exception ex)
+ {
+ this.logger.LogWarning($"设置为本机主DNS失败:{ex.Message}");
+ }
+ }
+ else
+ {
+ this.logger.LogWarning("平台不支持自动设置DNS,请手动设置网卡的主DNS为127.0.0.1");
+ }
+
+ await this.hostsValidator.ValidateAsync();
+ await base.StartAsync(cancellationToken);
+ }
+
+ ///
+ /// dns后台
+ ///
+ ///
+ ///
+ protected override Task ExecuteAsync(CancellationToken stoppingToken)
+ {
+ return this.dnsServer.ListenAsync(stoppingToken);
+ }
+
+ ///
+ /// 停止dns服务
+ ///
+ ///
+ ///
+ public override Task StopAsync(CancellationToken cancellationToken)
+ {
+ this.dnsServer.Dispose();
+ this.logger.LogInformation("DNS服务已停止");
+
+ if (OperatingSystem.IsWindows())
+ {
+ try
+ {
+ SystemDnsUtil.DnsFlushResolverCache();
+ SystemDnsUtil.DnsRemovePrimitive(IPAddress.Loopback);
+ }
+ catch (Exception ex)
+ {
+ this.logger.LogWarning($"恢复DNS记录失败:{ex.Message}");
+ }
+ }
+
+ return base.StopAsync(cancellationToken);
+ }
+ }
+}
diff --git a/FastGithub.Dns/DnsServer.cs b/FastGithub.Dns/DnsServer.cs
new file mode 100644
index 0000000..a7c5650
--- /dev/null
+++ b/FastGithub.Dns/DnsServer.cs
@@ -0,0 +1,111 @@
+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);
+ this.socket.Bind(new IPEndPoint(address, port));
+ }
+
+ ///
+ /// 监听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();
+ }
+ }
+}
diff --git a/FastGithub.Dns/DnsServerHostedService.cs b/FastGithub.Dns/DnsServerHostedService.cs
deleted file mode 100644
index ede083a..0000000
--- a/FastGithub.Dns/DnsServerHostedService.cs
+++ /dev/null
@@ -1,203 +0,0 @@
-using DNS.Protocol;
-using Microsoft.Extensions.Hosting;
-using Microsoft.Extensions.Logging;
-using Microsoft.Extensions.Options;
-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 DnsServerHostedService : BackgroundService
- {
- private readonly RequestResolver requestResolver;
- private readonly HostsFileValidator hostsValidator;
- 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 DnsServerHostedService(
- RequestResolver requestResolver,
- HostsFileValidator hostsValidator,
- IOptionsMonitor options,
- ILogger logger)
- {
- this.requestResolver = requestResolver;
- this.hostsValidator = hostsValidator;
- this.logger = logger;
-
- options.OnChange(opt =>
- {
- if (OperatingSystem.IsWindows())
- {
- SystemDnsUtil.DnsFlushResolverCache();
- }
- });
- }
-
- ///
- /// 启动dns
- ///
- ///
- ///
- public override async Task StartAsync(CancellationToken cancellationToken)
- {
- await this.BindAsync(cancellationToken);
- this.logger.LogInformation("DNS服务启动成功");
-
- this.SetAsPrimitiveNameServer();
- await this.hostsValidator.ValidateAsync();
-
- await base.StartAsync(cancellationToken);
- }
-
- ///
- /// 尝试多次绑定
- ///
- ///
- ///
- private async Task BindAsync(CancellationToken cancellationToken)
- {
- const int DNS_PORT = 53;
- if (OperatingSystem.IsWindows() && UdpTable.TryGetOwnerProcessId(DNS_PORT, out var processId))
- {
- Process.GetProcessById(processId).Kill();
- }
-
- var localEndPoint = new IPEndPoint(IPAddress.Any, DNS_PORT);
- var delay = TimeSpan.FromMilliseconds(100d);
- for (var i = 10; i >= 0; i--)
- {
- try
- {
- this.socket.Bind(localEndPoint);
- break;
- }
- catch (Exception)
- {
- if (i == 0)
- {
- throw new FastGithubException($"无法监听{localEndPoint},udp端口已被其它程序占用");
- }
- await Task.Delay(delay, cancellationToken);
- }
- }
-
- if (OperatingSystem.IsWindows())
- {
- const int SIO_UDP_CONNRESET = unchecked((int)0x9800000C);
- this.socket.IOControl(SIO_UDP_CONNRESET, new byte[4], new byte[4]);
- }
- }
-
- ///
- /// 设置自身为主dns
- ///
- private void SetAsPrimitiveNameServer()
- {
- if (OperatingSystem.IsWindows())
- {
- try
- {
- SystemDnsUtil.DnsSetPrimitive(IPAddress.Loopback);
- SystemDnsUtil.DnsFlushResolverCache();
- this.logger.LogInformation($"设置为本机主DNS成功");
- }
- catch (Exception ex)
- {
- this.logger.LogWarning($"设置为本机主DNS失败:{ex.Message}");
- }
- }
- else
- {
- this.logger.LogWarning("平台不支持自动设置DNS,请手动设置网卡的主DNS为127.0.0.1");
- }
- }
-
- ///
- /// dns后台
- ///
- ///
- ///
- protected async override Task ExecuteAsync(CancellationToken stoppingToken)
- {
- var remoteEndPoint = new IPEndPoint(IPAddress.Any, 0);
- while (stoppingToken.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, stoppingToken);
- }
- 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}");
- }
- }
-
- ///
- /// 停止dns服务
- ///
- ///
- ///
- public override Task StopAsync(CancellationToken cancellationToken)
- {
- this.socket.Dispose();
- this.logger.LogInformation("DNS服务已停止");
-
- if (OperatingSystem.IsWindows())
- {
- try
- {
- SystemDnsUtil.DnsFlushResolverCache();
- SystemDnsUtil.DnsRemovePrimitive(IPAddress.Loopback);
- }
- catch (Exception ex)
- {
- this.logger.LogWarning($"恢复DNS记录失败:{ex.Message}");
- }
- }
-
- return base.StopAsync(cancellationToken);
- }
- }
-}
diff --git a/FastGithub.Dns/DnsServerServiceCollectionExtensions.cs b/FastGithub.Dns/DnsServiceCollectionExtensions.cs
similarity index 78%
rename from FastGithub.Dns/DnsServerServiceCollectionExtensions.cs
rename to FastGithub.Dns/DnsServiceCollectionExtensions.cs
index 6dad648..b80527f 100644
--- a/FastGithub.Dns/DnsServerServiceCollectionExtensions.cs
+++ b/FastGithub.Dns/DnsServiceCollectionExtensions.cs
@@ -6,7 +6,7 @@ namespace FastGithub
///
/// dns服务注册扩展
///
- public static class DnsServerServiceCollectionExtensions
+ public static class DnsServiceCollectionExtensions
{
///
/// 注册dns服务
@@ -17,8 +17,9 @@ namespace FastGithub
{
return services
.AddSingleton()
+ .AddSingleton()
.AddSingleton()
- .AddHostedService();
+ .AddHostedService();
}
}
}