From 4ae101a76f977517060fc8a5758d7fd259c5979c Mon Sep 17 00:00:00 2001 From: xljiulang <366193849@qq.com> Date: Tue, 20 Jul 2021 20:25:14 +0800 Subject: [PATCH] =?UTF-8?q?=E5=90=91=E7=B3=BB=E7=BB=9F=E6=8F=92=E5=85=A5?= =?UTF-8?q?=E8=87=AA=E8=BA=AB=E5=81=9A=E4=B8=BA=E4=B8=BBDNS?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- FastGithub.Dns/DnsServerHostedService.cs | 117 ++++++++++------------- FastGithub.Dns/SystemDnsUtil.cs | 97 ++++++++++++------- 2 files changed, 115 insertions(+), 99 deletions(-) diff --git a/FastGithub.Dns/DnsServerHostedService.cs b/FastGithub.Dns/DnsServerHostedService.cs index 4218d0b..eae4c47 100644 --- a/FastGithub.Dns/DnsServerHostedService.cs +++ b/FastGithub.Dns/DnsServerHostedService.cs @@ -6,8 +6,6 @@ using System; using System.Diagnostics; using System.Net; using System.Net.Sockets; -using System.Runtime.InteropServices; -using System.Runtime.Versioning; using System.Threading; using System.Threading.Tasks; @@ -19,50 +17,37 @@ namespace FastGithub.Dns sealed class DnsServerHostedService : BackgroundService { private readonly RequestResolver requestResolver; - private readonly FastGithubConfig fastGithubConfig; private readonly HostsValidator hostsValidator; 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; - [SupportedOSPlatform("windows")] - [DllImport("dnsapi.dll", EntryPoint = "DnsFlushResolverCache", SetLastError = true)] - private static extern void DnsFlushResolverCache(); /// /// dns后台服务 /// /// - /// + /// /// /// public DnsServerHostedService( RequestResolver requestResolver, - FastGithubConfig fastGithubConfig, HostsValidator hostsValidator, IOptionsMonitor options, ILogger logger) { this.requestResolver = requestResolver; - this.fastGithubConfig = fastGithubConfig; this.hostsValidator = hostsValidator; this.logger = logger; - options.OnChange(opt => FlushResolverCache()); - } - /// - /// 刷新dns缓存 - /// - private static void FlushResolverCache() - { if (OperatingSystem.IsWindows()) { - DnsFlushResolverCache(); + options.OnChange(opt => SystemDnsUtil.DnsFlushResolverCache()); } } + /// /// 启动dns /// @@ -70,57 +55,75 @@ namespace FastGithub.Dns /// public override async Task StartAsync(CancellationToken cancellationToken) { - const int DNS_PORT = 53; - if (OperatingSystem.IsWindows() && UdpTable.TryGetOwnerProcessId(DNS_PORT, out var processId)) - { - Process.GetProcessById(processId).Kill(); - } - - await BindAsync(this.socket, new IPEndPoint(IPAddress.Any, DNS_PORT), cancellationToken); - if (OperatingSystem.IsWindows()) - { - const int SIO_UDP_CONNRESET = unchecked((int)0x9800000C); - this.socket.IOControl(SIO_UDP_CONNRESET, new byte[4], new byte[4]); - } - - // 验证host文件 + await this.BindAsync(cancellationToken); await this.hostsValidator.ValidateAsync(); - - // 设置网关的dns - var secondary = this.fastGithubConfig.FastDns.Address; - this.dnsAddresses = this.SetNameServers(IPAddress.Loopback, secondary); - FlushResolverCache(); - + this.SetAsPrimitiveNameServer(); this.logger.LogInformation("dns服务启动成功"); + await base.StartAsync(cancellationToken); } /// /// 尝试多次绑定 /// - /// - /// /// /// - private static async Task BindAsync(Socket socket, IPEndPoint localEndPoint, CancellationToken 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 { - socket.Bind(localEndPoint); + this.socket.Bind(localEndPoint); break; } catch (Exception) { if (i == 0) { - throw new FastGithubException($"无法监听{localEndPoint},{localEndPoint.Port}的udp端口已被其它程序占用"); + 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"); + } } /// @@ -178,40 +181,20 @@ namespace FastGithub.Dns this.socket.Dispose(); this.logger.LogInformation("dns服务已终止"); - if (this.dnsAddresses != null) - { - this.SetNameServers(this.dnsAddresses); - } - FlushResolverCache(); - return base.StopAsync(cancellationToken); - } - - /// - /// 设置dns - /// - /// - /// - private IPAddress[]? SetNameServers(params IPAddress[] nameServers) - { if (OperatingSystem.IsWindows()) { try { - var results = SystemDnsUtil.SetNameServers(nameServers); - this.logger.LogInformation($"设置本机dns成功"); - return results; + SystemDnsUtil.DnsFlushResolverCache(); + SystemDnsUtil.DnsRemovePrimitive(IPAddress.Loopback); } catch (Exception ex) { - this.logger.LogWarning($"设置本机dns失败:{ex.Message}"); + this.logger.LogWarning($"恢复DNS记录失败:{ex.Message}"); } } - else - { - this.logger.LogWarning("不支持自动设置dns,请手动设置网卡的dns为127.0.0.1"); - } - return default; + return base.StopAsync(cancellationToken); } } } diff --git a/FastGithub.Dns/SystemDnsUtil.cs b/FastGithub.Dns/SystemDnsUtil.cs index 1b2dce3..fa8aa5b 100644 --- a/FastGithub.Dns/SystemDnsUtil.cs +++ b/FastGithub.Dns/SystemDnsUtil.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Net; @@ -22,64 +23,96 @@ namespace FastGithub.Dns [DllImport("iphlpapi")] private static extern int GetBestInterface(uint dwDestAddr, ref uint pdwBestIfIndex); + /// + /// 刷新DNS缓存 + /// + [DllImport("dnsapi.dll", EntryPoint = "DnsFlushResolverCache", SetLastError = true)] + public static extern void DnsFlushResolverCache(); + + /// /// 通过远程地址查找匹配的网络适接口 /// /// /// - private static NetworkInterface? GetBestNetworkInterface(IPAddress remoteAddress) + private static NetworkInterface GetBestNetworkInterface(IPAddress remoteAddress) { var dwBestIfIndex = 0u; var dwDestAddr = BitConverter.ToUInt32(remoteAddress.GetAddressBytes()); var errorCode = GetBestInterface(dwDestAddr, ref dwBestIfIndex); - return errorCode != 0 - ? throw new NetworkInformationException(errorCode) - : NetworkInterface + if (errorCode != 0) + { + throw new NetworkInformationException(errorCode); + } + + var @interface = NetworkInterface .GetAllNetworkInterfaces() .Where(item => item.GetIPProperties().GetIPv4Properties().Index == dwBestIfIndex) .FirstOrDefault(); + + return @interface ?? throw new NotSupportedException("找不到网络适配器用来设置dns"); + } + + + /// + /// 设置主dns + /// + /// + /// + /// + public static void DnsSetPrimitive(IPAddress primitive) + { + var @interface = GetBestNetworkInterface(www_baidu_com); + var dnsAddresses = @interface.GetIPProperties().DnsAddresses; + if (primitive.Equals(dnsAddresses.FirstOrDefault()) == false) + { + var nameServers = dnsAddresses.Prepend(primitive); + SetNameServers(@interface, nameServers); + } } /// - /// 设置域名服务 + /// 移除主dns /// - /// + /// /// - /// - /// 未设置之前的记录 - public static IPAddress[] SetNameServers(params IPAddress[] nameServers) + /// + public static void DnsRemovePrimitive(IPAddress primitive) { - var networkInterface = GetBestNetworkInterface(www_baidu_com); - if (networkInterface == null) + var @interface = GetBestNetworkInterface(www_baidu_com); + var dnsAddresses = @interface.GetIPProperties().DnsAddresses; + if (primitive.Equals(dnsAddresses.FirstOrDefault())) { - throw new NotSupportedException("找不到网络适配器用来设置dns"); + var nameServers = dnsAddresses.Skip(1); + SetNameServers(@interface, nameServers); } - var dnsAddresses = networkInterface.GetIPProperties().DnsAddresses.ToArray(); + } - Netsh($@"interface ipv4 delete dns ""{networkInterface.Name}"" all"); + /// + /// 设置网口的dns + /// + /// + /// + private static void SetNameServers(NetworkInterface @interface, IEnumerable nameServers) + { + Netsh($@"interface ipv4 delete dns ""{@interface.Name}"" all"); foreach (var address in nameServers) { - Netsh($@"interface ipv4 add dns ""{networkInterface.Name}"" {address} validate=no"); + Netsh($@"interface ipv4 add dns ""{@interface.Name}"" {address} validate=no"); } - return dnsAddresses; - } - - /// - /// 执行Netsh - /// - /// - private static void Netsh(string arguments) - { - var netsh = new ProcessStartInfo + static void Netsh(string arguments) { - FileName = "netsh.exe", - Arguments = arguments, - CreateNoWindow = true, - UseShellExecute = false, - WindowStyle = ProcessWindowStyle.Hidden - }; - Process.Start(netsh)?.WaitForExit(); + var netsh = new ProcessStartInfo + { + FileName = "netsh.exe", + Arguments = arguments, + CreateNoWindow = true, + UseShellExecute = false, + WindowStyle = ProcessWindowStyle.Hidden + }; + Process.Start(netsh)?.WaitForExit(); + } } } }