From ad51a0a572441dd7c584d2f98feceb0defbdfb32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E5=9B=BD=E4=BC=9F?= <366193849@qq.com> Date: Tue, 28 Sep 2021 08:47:06 +0800 Subject: [PATCH] =?UTF-8?q?=E5=BC=BA=E5=8C=96dns=E5=AE=A2=E6=88=B7?= =?UTF-8?q?=E7=AB=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- FastGithub.DomainResolve/DnsClient.cs | 59 ++++++++++++++++++- FastGithub.DomainResolve/DomainResolver.cs | 47 ++------------- FastGithub.DomainResolve/IPAddressItem.cs | 50 ++++++++++++++++ .../IPAddressItemHashSet.cs | 48 +++++++++++++++ 4 files changed, 158 insertions(+), 46 deletions(-) create mode 100644 FastGithub.DomainResolve/IPAddressItem.cs create mode 100644 FastGithub.DomainResolve/IPAddressItemHashSet.cs diff --git a/FastGithub.DomainResolve/DnsClient.cs b/FastGithub.DomainResolve/DnsClient.cs index e60f20a..4d1f03f 100644 --- a/FastGithub.DomainResolve/DnsClient.cs +++ b/FastGithub.DomainResolve/DnsClient.cs @@ -2,13 +2,16 @@ using DNS.Client.RequestResolver; using DNS.Protocol; using DNS.Protocol.ResourceRecords; +using FastGithub.Configuration; using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using System; using System.Collections.Concurrent; +using System.Collections.Generic; using System.Linq; using System.Net; +using System.Runtime.CompilerServices; using System.Threading; using System.Threading.Tasks; @@ -21,6 +24,9 @@ namespace FastGithub.DomainResolve { private const int DNS_PORT = 53; private const string LOCALHOST = "localhost"; + + private readonly DnscryptProxy dnscryptProxy; + private readonly FastGithubConfig fastGithubConfig; private readonly ILogger logger; private readonly ConcurrentDictionary semaphoreSlims = new(); @@ -30,13 +36,60 @@ namespace FastGithub.DomainResolve /// /// DNS客户端 - /// + /// + /// + /// /// - public DnsClient(ILogger logger) + public DnsClient( + DnscryptProxy dnscryptProxy, + FastGithubConfig fastGithubConfig, + ILogger logger) { + this.dnscryptProxy = dnscryptProxy; + this.fastGithubConfig = fastGithubConfig; this.logger = logger; } + /// + /// 解析域名 + /// + /// 域名 + /// + /// + public async IAsyncEnumerable ResolveAsync(string domain, [EnumeratorCancellation] CancellationToken cancellationToken) + { + var hashSet = new HashSet(); + foreach (var dns in this.GetDnsServers()) + { + foreach (var address in await this.LookupAsync(dns, domain, cancellationToken)) + { + if (hashSet.Add(address) == true) + { + yield return address; + } + } + } + } + + /// + /// 获取dns服务 + /// + /// + private IEnumerable GetDnsServers() + { + var cryptDns = this.dnscryptProxy.LocalEndPoint; + if (cryptDns != null) + { + yield return cryptDns; + yield return cryptDns; + } + + foreach (var fallbackDns in this.fastGithubConfig.FallbackDns) + { + yield return fallbackDns; + } + } + /// /// 解析域名 /// @@ -44,7 +97,7 @@ namespace FastGithub.DomainResolve /// /// /// - public async Task LookupAsync(IPEndPoint dns, string domain, CancellationToken cancellationToken = default) + private async Task LookupAsync(IPEndPoint dns, string domain, CancellationToken cancellationToken = default) { var key = $"{dns}:{domain}"; var semaphore = this.semaphoreSlims.GetOrAdd(key, _ => new SemaphoreSlim(1, 1)); diff --git a/FastGithub.DomainResolve/DomainResolver.cs b/FastGithub.DomainResolve/DomainResolver.cs index fa88a8a..e44ef41 100644 --- a/FastGithub.DomainResolve/DomainResolver.cs +++ b/FastGithub.DomainResolve/DomainResolver.cs @@ -1,7 +1,6 @@ using FastGithub.Configuration; using System.Collections.Generic; using System.Net; -using System.Runtime.CompilerServices; using System.Threading; using System.Threading.Tasks; @@ -12,23 +11,14 @@ namespace FastGithub.DomainResolve /// sealed class DomainResolver : IDomainResolver { - private readonly DnscryptProxy dnscryptProxy; - private readonly FastGithubConfig fastGithubConfig; private readonly DnsClient dnsClient; /// /// 域名解析器 - /// - /// - /// + /// /// - public DomainResolver( - DnscryptProxy dnscryptProxy, - FastGithubConfig fastGithubConfig, - DnsClient dnsClient) + public DomainResolver(DnsClient dnsClient) { - this.dnscryptProxy = dnscryptProxy; - this.fastGithubConfig = fastGithubConfig; this.dnsClient = dnsClient; } @@ -53,38 +43,9 @@ namespace FastGithub.DomainResolve /// 域名 /// /// - public async IAsyncEnumerable ResolveAllAsync(string domain, [EnumeratorCancellation] CancellationToken cancellationToken) + public IAsyncEnumerable ResolveAllAsync(string domain, CancellationToken cancellationToken) { - var hashSet = new HashSet(); - foreach (var dns in this.GetDnsServers()) - { - foreach (var address in await this.dnsClient.LookupAsync(dns, domain, cancellationToken)) - { - if (hashSet.Add(address) == true) - { - yield return address; - } - } - } - } - - /// - /// 获取dns服务 - /// - /// - private IEnumerable GetDnsServers() - { - var cryptDns = this.dnscryptProxy.LocalEndPoint; - if (cryptDns != null) - { - yield return cryptDns; - yield return cryptDns; - } - - foreach (var fallbackDns in this.fastGithubConfig.FallbackDns) - { - yield return fallbackDns; - } + return this.dnsClient.ResolveAsync(domain, cancellationToken); } } } diff --git a/FastGithub.DomainResolve/IPAddressItem.cs b/FastGithub.DomainResolve/IPAddressItem.cs new file mode 100644 index 0000000..189bf1b --- /dev/null +++ b/FastGithub.DomainResolve/IPAddressItem.cs @@ -0,0 +1,50 @@ +using System; +using System.Net; +using System.Net.NetworkInformation; +using System.Threading.Tasks; + +namespace FastGithub.DomainResolve +{ + sealed class IPAddressItem : IEquatable + { + public IPAddress Address { get; } + + public TimeSpan Elapsed { get; private set; } = TimeSpan.MaxValue; + + public IPAddressItem(IPAddress address) + { + this.Address = address; + } + + public async Task TestSpeedAsync() + { + try + { + using var ping = new Ping(); + var reply = await ping.SendPingAsync(this.Address); + this.Elapsed = reply.Status == IPStatus.Success + ? TimeSpan.FromMilliseconds(reply.RoundtripTime) + : TimeSpan.MaxValue; + } + catch (Exception) + { + this.Elapsed = TimeSpan.MaxValue; + } + } + + public bool Equals(IPAddressItem? other) + { + return other != null && other.Address.Equals(this.Address); + } + + public override bool Equals(object? obj) + { + return obj is IPAddressItem other && this.Equals(other); + } + + public override int GetHashCode() + { + return this.Address.GetHashCode(); + } + } +} diff --git a/FastGithub.DomainResolve/IPAddressItemHashSet.cs b/FastGithub.DomainResolve/IPAddressItemHashSet.cs new file mode 100644 index 0000000..c98b2da --- /dev/null +++ b/FastGithub.DomainResolve/IPAddressItemHashSet.cs @@ -0,0 +1,48 @@ +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace FastGithub.DomainResolve +{ + sealed class IPAddressItemHashSet + { + private readonly object syncRoot = new(); + + private readonly HashSet hashSet = new(); + + public int Count => this.hashSet.Count; + + public bool Add(IPAddressItem item) + { + lock (this.syncRoot) + { + return this.hashSet.Add(item); + } + } + + public void AddRange(IEnumerable items) + { + lock (this.syncRoot) + { + foreach (var item in items) + { + this.hashSet.Add(item); + } + } + } + + public IPAddressItem[] ToArray() + { + lock (this.syncRoot) + { + return this.hashSet.ToArray(); + } + } + + public Task TestSpeedAsync() + { + var tasks = this.ToArray().Select(item => item.TestSpeedAsync()); + return Task.WhenAll(tasks); + } + } +}