From 9516a22c26b9a84db69cca47763ea02f71e0c64b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E5=9B=BD=E4=BC=9F?= <366193849@qq.com> Date: Sun, 26 Sep 2021 16:02:30 +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 | 76 ++++++++++++++----- FastGithub.DomainResolve/DomainResolver.cs | 68 +++++------------ FastGithub.DomainResolve/IDomainResolver.cs | 8 +- .../ServiceCollectionExtensions.cs | 3 +- .../Dns/DnsInterceptor.cs | 1 - 5 files changed, 81 insertions(+), 75 deletions(-) diff --git a/FastGithub.DomainResolve/DnsClient.cs b/FastGithub.DomainResolve/DnsClient.cs index 305987d..a5bc044 100644 --- a/FastGithub.DomainResolve/DnsClient.cs +++ b/FastGithub.DomainResolve/DnsClient.cs @@ -2,6 +2,9 @@ using DNS.Client.RequestResolver; using DNS.Protocol; using DNS.Protocol.ResourceRecords; +using Microsoft.Extensions.Caching.Memory; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; using System; using System.Linq; using System.Net; @@ -15,48 +18,79 @@ namespace FastGithub.DomainResolve /// sealed class DnsClient { - private readonly IPEndPoint dns; - private readonly IRequestResolver resolver; - private readonly int timeout = (int)TimeSpan.FromSeconds(2d).TotalMilliseconds; + private readonly ILogger logger; + + private readonly int resolveTimeout = (int)TimeSpan.FromSeconds(2d).TotalMilliseconds; + private readonly IMemoryCache dnsCache = new MemoryCache(Options.Create(new MemoryCacheOptions())); + private readonly TimeSpan dnsExpiration = TimeSpan.FromMinutes(2d); /// /// DNS客户端 - /// - /// - public DnsClient(IPEndPoint dns) + /// + /// + public DnsClient(ILogger logger) { - this.dns = dns; - this.resolver = dns.Port == 53 - ? new TcpRequestResolver(dns) - : new UdpRequestResolver(dns, new TcpRequestResolver(dns), this.timeout); + this.logger = logger; } /// /// 解析域名 /// + /// /// /// /// - public async Task LookupAsync(string domain, CancellationToken cancellationToken = default) + public async Task LookupAsync(IPEndPoint dns, string domain, CancellationToken cancellationToken = default) { + var key = $"{dns}:{domain}"; + if (this.dnsCache.TryGetValue(key, out var value)) + { + return value; + } + + try + { + value = await this.LookupCoreAsync(dns, domain, cancellationToken); + this.dnsCache.Set(key, value, this.dnsExpiration); + + var items = string.Join(", ", value.Select(item => item.ToString())); + this.logger.LogInformation($"{dns}:{domain}->[{items}]"); + return value; + } + catch (Exception ex) + { + this.logger.LogWarning($"{dns}无法解析{domain}:{ex.Message}"); + return Array.Empty(); + } + } + + /// + /// 解析域名 + /// + /// + /// + /// + /// + private async Task LookupCoreAsync(IPEndPoint dns, string domain, CancellationToken cancellationToken = default) + { + if (domain == "localhost") + { + return new[] { IPAddress.Loopback }; + } + + var resolver = dns.Port == 53 + ? (IRequestResolver)new TcpRequestResolver(dns) + : new UdpRequestResolver(dns, new TcpRequestResolver(dns), this.resolveTimeout); + var request = new Request { RecursionDesired = true, OperationCode = OperationCode.Query }; request.Questions.Add(new Question(new Domain(domain), RecordType.A)); - var clientRequest = new ClientRequest(this.resolver, request); + var clientRequest = new ClientRequest(resolver, request); var response = await clientRequest.Resolve(cancellationToken); return response.AnswerRecords.OfType().Select(item => item.IPAddress).ToArray(); } - - /// - /// 转换为文本 - /// - /// - public override string ToString() - { - return $"dns://{this.dns}"; - } } } diff --git a/FastGithub.DomainResolve/DomainResolver.cs b/FastGithub.DomainResolve/DomainResolver.cs index 6d376d8..7baef65 100644 --- a/FastGithub.DomainResolve/DomainResolver.cs +++ b/FastGithub.DomainResolve/DomainResolver.cs @@ -1,11 +1,9 @@ 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.Net.Sockets; using System.Runtime.CompilerServices; @@ -21,7 +19,7 @@ namespace FastGithub.DomainResolve { private readonly DnscryptProxy dnscryptProxy; private readonly FastGithubConfig fastGithubConfig; - private readonly ILogger logger; + private readonly DnsClient dnsClient; private readonly ConcurrentDictionary semaphoreSlims = new(); private readonly IMemoryCache ipEndPointAvailableCache = new MemoryCache(Options.Create(new MemoryCacheOptions())); @@ -33,33 +31,33 @@ namespace FastGithub.DomainResolve /// /// /// - /// + /// public DomainResolver( DnscryptProxy dnscryptProxy, FastGithubConfig fastGithubConfig, - ILogger logger) + DnsClient dnsClient) { this.dnscryptProxy = dnscryptProxy; this.fastGithubConfig = fastGithubConfig; - this.logger = logger; + this.dnsClient = dnsClient; } /// - /// 解析域名 + /// 解析可用的ip /// - /// + /// 远程节点 /// /// - public async Task ResolveAsync(DnsEndPoint domain, CancellationToken cancellationToken) + public async Task ResolveAsync(DnsEndPoint endPoint, CancellationToken cancellationToken = default) { - await foreach (var address in this.ResolveAsync(domain.Host, cancellationToken)) + await foreach (var address in this.ResolveAsync(endPoint.Host, cancellationToken)) { - if (await this.IsAvailableAsync(new IPEndPoint(address, domain.Port), cancellationToken)) + if (await this.IsAvailableAsync(new IPEndPoint(address, endPoint.Port), cancellationToken)) { return address; } } - throw new FastGithubException($"解析不到{domain.Host}可用的IP"); + throw new FastGithubException($"解析不到{endPoint.Host}可用的IP"); } /// @@ -112,30 +110,10 @@ namespace FastGithub.DomainResolve /// public async IAsyncEnumerable ResolveAsync(string domain, [EnumeratorCancellation] CancellationToken cancellationToken) { - if (domain == "localhost") - { - yield return IPAddress.Loopback; - yield break; - } - var hashSet = new HashSet(); - var cryptDns = this.dnscryptProxy.LocalEndPoint; - if (cryptDns != null) + foreach (var dns in this.GetDnsServers()) { - var dnsClient = new DnsClient(cryptDns); - foreach (var address in await this.LookupAsync(dnsClient, domain, cancellationToken)) - { - if (hashSet.Add(address) == true) - { - yield return address; - } - } - } - - foreach (var fallbackDns in this.fastGithubConfig.FallbackDns) - { - var dnsClient = new DnsClient(fallbackDns); - foreach (var address in await this.LookupAsync(dnsClient, domain, cancellationToken)) + foreach (var address in await this.dnsClient.LookupAsync(dns, domain, cancellationToken)) { if (hashSet.Add(address) == true) { @@ -146,26 +124,20 @@ namespace FastGithub.DomainResolve } /// - /// 查找ip + /// 获取dns服务 /// - /// - /// - /// /// - private async Task LookupAsync(DnsClient dnsClient, string domain, CancellationToken cancellationToken) + private IEnumerable GetDnsServers() { - try + var cryptDns = this.dnscryptProxy.LocalEndPoint; + if (cryptDns != null) { - var addresses = await dnsClient.LookupAsync(domain, cancellationToken); - var items = string.Join(", ", addresses.Select(item => item.ToString())); - this.logger.LogInformation($"{dnsClient}:{domain}->[{items}]"); - return addresses; + yield return cryptDns; } - catch (Exception ex) + + foreach (var fallbackDns in this.fastGithubConfig.FallbackDns) { - cancellationToken.ThrowIfCancellationRequested(); - this.logger.LogWarning($"{dnsClient}无法解析{domain}:{ex.Message}"); - return Array.Empty(); + yield return fallbackDns; } } } diff --git a/FastGithub.DomainResolve/IDomainResolver.cs b/FastGithub.DomainResolve/IDomainResolver.cs index fd063ed..47b7319 100644 --- a/FastGithub.DomainResolve/IDomainResolver.cs +++ b/FastGithub.DomainResolve/IDomainResolver.cs @@ -11,15 +11,15 @@ namespace FastGithub.DomainResolve public interface IDomainResolver { /// - /// 解析域名 + /// 解析可用的ip /// - /// + /// 远程节点 /// /// - Task ResolveAsync(DnsEndPoint domain, CancellationToken cancellationToken = default); + Task ResolveAsync(DnsEndPoint endPoint, CancellationToken cancellationToken = default); /// - /// 解析域名 + /// 解析所有ip /// /// 域名 /// diff --git a/FastGithub.DomainResolve/ServiceCollectionExtensions.cs b/FastGithub.DomainResolve/ServiceCollectionExtensions.cs index deccdd2..c35acc7 100644 --- a/FastGithub.DomainResolve/ServiceCollectionExtensions.cs +++ b/FastGithub.DomainResolve/ServiceCollectionExtensions.cs @@ -15,7 +15,8 @@ namespace FastGithub /// /// public static IServiceCollection AddDomainResolve(this IServiceCollection services) - { + { + services.TryAddSingleton(); services.TryAddSingleton(); services.TryAddSingleton(); return services.AddHostedService(); diff --git a/FastGithub.PacketIntercept/Dns/DnsInterceptor.cs b/FastGithub.PacketIntercept/Dns/DnsInterceptor.cs index 46801a7..9716180 100644 --- a/FastGithub.PacketIntercept/Dns/DnsInterceptor.cs +++ b/FastGithub.PacketIntercept/Dns/DnsInterceptor.cs @@ -164,7 +164,6 @@ namespace FastGithub.PacketIntercept.Dns winDivertAddress.Impostor = true; WinDivert.WinDivertHelperCalcChecksums(winDivertBuffer, packetLength, ref winDivertAddress, WinDivertChecksumHelperParam.All); - this.logger.LogInformation($"{domain} => {IPAddress.Loopback}"); }