Quellcode durchsuchen

非windows平台dns检测

陈国伟 vor 4 Jahren
Ursprung
Commit
8e8ad9f69e
2 geänderte Dateien mit 78 neuen und 66 gelöschten Zeilen
  1. 17 32
      FastGithub.Dns/DnsOverUdpHostedService.cs
  2. 61 34
      FastGithub.Dns/SystemDnsUtil.cs

+ 17 - 32
FastGithub.Dns/DnsOverUdpHostedService.cs

@@ -38,13 +38,7 @@ namespace FastGithub.Dns
             this.options = options;
             this.logger = logger;
 
-            options.OnChange(opt =>
-            {
-                if (OperatingSystem.IsWindows())
-                {
-                    SystemDnsUtil.DnsFlushResolverCache();
-                }
-            });
+            options.OnChange(opt => SystemDnsUtil.FlushResolverCache());
         }
 
         /// <summary>
@@ -58,31 +52,22 @@ namespace FastGithub.Dns
             this.dnsOverUdpServer.Bind(IPAddress.Any, dnsPort);
             this.logger.LogInformation("DNS服务启动成功");
 
-            const int DNS_PORT = 53;
-            if (dnsPort != DNS_PORT)
-            {
-                this.logger.LogWarning($"由于使用了非标准DNS端口{dnsPort},你需要将{nameof(FastGithub)}设置为标准DNS的上游");
-            }
-            else if (OperatingSystem.IsWindows())
+            const int STANDARD_DNS_PORT = 53;
+            if (dnsPort == STANDARD_DNS_PORT)
             {
                 try
                 {
-                    SystemDnsUtil.DnsSetPrimitive(IPAddress.Loopback);
-                    SystemDnsUtil.DnsFlushResolverCache();
-                    this.logger.LogInformation($"设置成本机主DNS成功");
+                    SystemDnsUtil.SetPrimitiveDns(IPAddress.Loopback);
+                    SystemDnsUtil.FlushResolverCache();
                 }
                 catch (Exception ex)
                 {
-                    this.logger.LogWarning($"设置成本机主DNS为{IPAddress.Loopback}失败:{ex.Message}");
+                    this.logger.LogWarning(ex.Message);
                 }
             }
-            else if (OperatingSystem.IsLinux())
-            {
-                this.logger.LogWarning($"不支持自动设置本机DNS,手工添加{IPAddress.Loopback}做为/etc/resolv.conf的第一条记录");
-            }
             else
             {
-                this.logger.LogWarning($"不支持自动设置本机DNS,请手工添加{IPAddress.Loopback}做为连接网络的DNS的第一条记录");
+                this.logger.LogWarning($"由于使用了非标准DNS端口{dnsPort},你需要将{nameof(FastGithub)}设置为标准DNS的上游");
             }
 
             foreach (var item in this.conflictValidators)
@@ -113,17 +98,17 @@ namespace FastGithub.Dns
             this.dnsOverUdpServer.Dispose();
             this.logger.LogInformation("DNS服务已停止");
 
-            if (OperatingSystem.IsWindows())
+            try
             {
-                try
-                {
-                    SystemDnsUtil.DnsFlushResolverCache();
-                    SystemDnsUtil.DnsRemovePrimitive(IPAddress.Loopback);
-                }
-                catch (Exception ex)
-                {
-                    this.logger.LogWarning($"恢复DNS记录失败:{ex.Message}");
-                }
+                SystemDnsUtil.RemovePrimitiveDns(IPAddress.Loopback);
+            }
+            catch (Exception ex)
+            {
+                this.logger.LogWarning(ex.Message);
+            }
+            finally
+            {
+                SystemDnsUtil.FlushResolverCache();
             }
 
             return base.StopAsync(cancellationToken);

+ 61 - 34
FastGithub.Dns/SystemDnsUtil.cs

@@ -12,8 +12,7 @@ namespace FastGithub.Dns
 {
     /// <summary>
     /// 系统域名服务工具
-    /// </summary>
-    [SupportedOSPlatform("windows")]
+    /// </summary> 
     static class SystemDnsUtil
     {
         /// <summary>
@@ -21,54 +20,53 @@ namespace FastGithub.Dns
         /// </summary>
         private static readonly IPAddress www_baidu_com = IPAddress.Parse("183.232.231.172");
 
-        [DllImport("iphlpapi")]
-        private static extern int GetBestInterface(uint dwDestAddr, ref uint pdwBestIfIndex);
-
         /// <summary>
         /// 刷新DNS缓存
         /// </summary>
+        [SupportedOSPlatform("windows")]
         [DllImport("dnsapi.dll", EntryPoint = "DnsFlushResolverCache", SetLastError = true)]
-        public static extern void DnsFlushResolverCache();
-
+        private static extern void DnsFlushResolverCache();
 
         /// <summary>
-        /// 通过远程地址查找匹配的网络适接口
+        /// 刷新DNS缓存
         /// </summary>
-        /// <param name="remoteAddress"></param>
-        /// <returns></returns>
-        private static NetworkInterface GetBestNetworkInterface(IPAddress remoteAddress)
+        public static void FlushResolverCache()
         {
-            var dwBestIfIndex = 0u;
-            var dwDestAddr = BitConverter.ToUInt32(remoteAddress.GetAddressBytes());
-            var errorCode = GetBestInterface(dwDestAddr, ref dwBestIfIndex);
-            if (errorCode != 0)
+            if (OperatingSystem.IsWindows())
             {
-                throw new NetworkInformationException(errorCode);
+                DnsFlushResolverCache();
             }
-
-            var @interface = NetworkInterface
-                .GetAllNetworkInterfaces()
-                .Where(item => item.GetIPProperties().GetIPv4Properties().Index == dwBestIfIndex)
-                .FirstOrDefault();
-
-            return @interface ?? throw new FastGithubException("找不到网络适配器用来设置dns");
         }
 
-
         /// <summary>
         /// 设置主dns
         /// </summary>
         /// <param name="primitive"></param>
-        /// <exception cref="NetworkInformationException"></exception>
-        /// <exception cref="NotSupportedException"></exception> 
-        public static void DnsSetPrimitive(IPAddress primitive)
+        /// <exception cref="FastGithubException"></exception> 
+        public static void SetPrimitiveDns(IPAddress primitive)
         {
-            var @interface = GetBestNetworkInterface(www_baidu_com);
+            var @interface = GetOutboundNetworkInterface();
+            if (@interface == null)
+            {
+                throw new FastGithubException($"找不到匹配的网络适配器来设置主DNS值:{primitive}");
+            }
+
             var dnsAddresses = @interface.GetIPProperties().DnsAddresses;
             if (primitive.Equals(dnsAddresses.FirstOrDefault()) == false)
             {
                 var nameServers = dnsAddresses.Prepend(primitive);
-                SetNameServers(@interface, nameServers);
+                if (OperatingSystem.IsWindows())
+                {
+                    SetNameServers(@interface, nameServers);
+                }
+                else if (OperatingSystem.IsLinux())
+                {
+                    throw new FastGithubException($"不支持自动设置本机DNS,请手工添加{primitive}做为/etc/resolv.conf的第一条记录");
+                }
+                else if (OperatingSystem.IsMacOS())
+                {
+                    throw new FastGithubException($"不支持自动设置本机DNS,请手工添加{primitive}做为连接网络的DNS的第一条记录");
+                }
             }
         }
 
@@ -76,24 +74,53 @@ namespace FastGithub.Dns
         /// 移除主dns
         /// </summary>
         /// <param name="primitive"></param>
-        /// <exception cref="NetworkInformationException"></exception>
-        /// <exception cref="NotSupportedException"></exception> 
-        public static void DnsRemovePrimitive(IPAddress primitive)
+        /// <exception cref="FastGithubException"></exception> 
+        public static void RemovePrimitiveDns(IPAddress primitive)
         {
-            var @interface = GetBestNetworkInterface(www_baidu_com);
+            var @interface = GetOutboundNetworkInterface();
+            if (@interface == null)
+            {
+                throw new FastGithubException($"找不到匹配的网络适配器来移除主DNS值:{primitive}");
+            }
+
             var dnsAddresses = @interface.GetIPProperties().DnsAddresses;
             if (primitive.Equals(dnsAddresses.FirstOrDefault()))
             {
                 var nameServers = dnsAddresses.Skip(1);
-                SetNameServers(@interface, nameServers);
+                if (OperatingSystem.IsWindows())
+                {
+                    SetNameServers(@interface, nameServers);
+                }
+            }
+        }
+
+
+        /// <summary>
+        /// 查找出口的网络适器
+        /// </summary> 
+        /// <returns></returns> 
+        private static NetworkInterface? GetOutboundNetworkInterface()
+        {
+            var remoteEndPoint = new IPEndPoint(www_baidu_com, 443);
+            var address = LocalMachine.GetLocalIPAddress(remoteEndPoint);
+            if (address == null)
+            {
+                return default;
             }
+
+            return NetworkInterface
+                .GetAllNetworkInterfaces()
+                .Where(item => item.GetIPProperties().UnicastAddresses.Any(a => a.Address.Equals(address)))
+                .FirstOrDefault();
         }
 
+
         /// <summary>
         /// 设置网口的dns
         /// </summary>
         /// <param name="interface"></param>
         /// <param name="nameServers"></param>
+        [SupportedOSPlatform("windows")]
         private static void SetNameServers(NetworkInterface @interface, IEnumerable<IPAddress> nameServers)
         {
             Netsh($@"interface ipv4 delete dns ""{@interface.Name}"" all");