强化dns客户端
This commit is contained in:
parent
f72f6dea78
commit
ad51a0a572
@ -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<DnsClient> logger;
|
||||
|
||||
private readonly ConcurrentDictionary<string, SemaphoreSlim> semaphoreSlims = new();
|
||||
@ -31,12 +37,59 @@ namespace FastGithub.DomainResolve
|
||||
/// <summary>
|
||||
/// DNS客户端
|
||||
/// </summary>
|
||||
/// <param name="dnscryptProxy"></param>
|
||||
/// <param name="fastGithubConfig"></param>
|
||||
/// <param name="logger"></param>
|
||||
public DnsClient(ILogger<DnsClient> logger)
|
||||
public DnsClient(
|
||||
DnscryptProxy dnscryptProxy,
|
||||
FastGithubConfig fastGithubConfig,
|
||||
ILogger<DnsClient> logger)
|
||||
{
|
||||
this.dnscryptProxy = dnscryptProxy;
|
||||
this.fastGithubConfig = fastGithubConfig;
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 解析域名
|
||||
/// </summary>
|
||||
/// <param name="domain">域名</param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
public async IAsyncEnumerable<IPAddress> ResolveAsync(string domain, [EnumeratorCancellation] CancellationToken cancellationToken)
|
||||
{
|
||||
var hashSet = new HashSet<IPAddress>();
|
||||
foreach (var dns in this.GetDnsServers())
|
||||
{
|
||||
foreach (var address in await this.LookupAsync(dns, domain, cancellationToken))
|
||||
{
|
||||
if (hashSet.Add(address) == true)
|
||||
{
|
||||
yield return address;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取dns服务
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private IEnumerable<IPEndPoint> 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;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 解析域名
|
||||
/// </summary>
|
||||
@ -44,7 +97,7 @@ namespace FastGithub.DomainResolve
|
||||
/// <param name="domain"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<IPAddress[]> LookupAsync(IPEndPoint dns, string domain, CancellationToken cancellationToken = default)
|
||||
private async Task<IPAddress[]> LookupAsync(IPEndPoint dns, string domain, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var key = $"{dns}:{domain}";
|
||||
var semaphore = this.semaphoreSlims.GetOrAdd(key, _ => new SemaphoreSlim(1, 1));
|
||||
|
||||
@ -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
|
||||
/// </summary>
|
||||
sealed class DomainResolver : IDomainResolver
|
||||
{
|
||||
private readonly DnscryptProxy dnscryptProxy;
|
||||
private readonly FastGithubConfig fastGithubConfig;
|
||||
private readonly DnsClient dnsClient;
|
||||
|
||||
/// <summary>
|
||||
/// 域名解析器
|
||||
/// </summary>
|
||||
/// <param name="dnscryptProxy"></param>
|
||||
/// <param name="fastGithubConfig"></param>
|
||||
/// <param name="dnsClient"></param>
|
||||
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
|
||||
/// <param name="domain">域名</param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
public async IAsyncEnumerable<IPAddress> ResolveAllAsync(string domain, [EnumeratorCancellation] CancellationToken cancellationToken)
|
||||
public IAsyncEnumerable<IPAddress> ResolveAllAsync(string domain, CancellationToken cancellationToken)
|
||||
{
|
||||
var hashSet = new HashSet<IPAddress>();
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取dns服务
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private IEnumerable<IPEndPoint> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
50
FastGithub.DomainResolve/IPAddressItem.cs
Normal file
50
FastGithub.DomainResolve/IPAddressItem.cs
Normal file
@ -0,0 +1,50 @@
|
||||
using System;
|
||||
using System.Net;
|
||||
using System.Net.NetworkInformation;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace FastGithub.DomainResolve
|
||||
{
|
||||
sealed class IPAddressItem : IEquatable<IPAddressItem>
|
||||
{
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
48
FastGithub.DomainResolve/IPAddressItemHashSet.cs
Normal file
48
FastGithub.DomainResolve/IPAddressItemHashSet.cs
Normal file
@ -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<IPAddressItem> 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<IPAddressItem> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user