强化dns客户端
This commit is contained in:
parent
f72f6dea78
commit
ad51a0a572
@ -2,13 +2,16 @@
|
|||||||
using DNS.Client.RequestResolver;
|
using DNS.Client.RequestResolver;
|
||||||
using DNS.Protocol;
|
using DNS.Protocol;
|
||||||
using DNS.Protocol.ResourceRecords;
|
using DNS.Protocol.ResourceRecords;
|
||||||
|
using FastGithub.Configuration;
|
||||||
using Microsoft.Extensions.Caching.Memory;
|
using Microsoft.Extensions.Caching.Memory;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
@ -21,6 +24,9 @@ namespace FastGithub.DomainResolve
|
|||||||
{
|
{
|
||||||
private const int DNS_PORT = 53;
|
private const int DNS_PORT = 53;
|
||||||
private const string LOCALHOST = "localhost";
|
private const string LOCALHOST = "localhost";
|
||||||
|
|
||||||
|
private readonly DnscryptProxy dnscryptProxy;
|
||||||
|
private readonly FastGithubConfig fastGithubConfig;
|
||||||
private readonly ILogger<DnsClient> logger;
|
private readonly ILogger<DnsClient> logger;
|
||||||
|
|
||||||
private readonly ConcurrentDictionary<string, SemaphoreSlim> semaphoreSlims = new();
|
private readonly ConcurrentDictionary<string, SemaphoreSlim> semaphoreSlims = new();
|
||||||
@ -30,13 +36,60 @@ namespace FastGithub.DomainResolve
|
|||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// DNS客户端
|
/// DNS客户端
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <param name="dnscryptProxy"></param>
|
||||||
|
/// <param name="fastGithubConfig"></param>
|
||||||
/// <param name="logger"></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;
|
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>
|
||||||
/// 解析域名
|
/// 解析域名
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -44,7 +97,7 @@ namespace FastGithub.DomainResolve
|
|||||||
/// <param name="domain"></param>
|
/// <param name="domain"></param>
|
||||||
/// <param name="cancellationToken"></param>
|
/// <param name="cancellationToken"></param>
|
||||||
/// <returns></returns>
|
/// <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 key = $"{dns}:{domain}";
|
||||||
var semaphore = this.semaphoreSlims.GetOrAdd(key, _ => new SemaphoreSlim(1, 1));
|
var semaphore = this.semaphoreSlims.GetOrAdd(key, _ => new SemaphoreSlim(1, 1));
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
using FastGithub.Configuration;
|
using FastGithub.Configuration;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
@ -12,23 +11,14 @@ namespace FastGithub.DomainResolve
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
sealed class DomainResolver : IDomainResolver
|
sealed class DomainResolver : IDomainResolver
|
||||||
{
|
{
|
||||||
private readonly DnscryptProxy dnscryptProxy;
|
|
||||||
private readonly FastGithubConfig fastGithubConfig;
|
|
||||||
private readonly DnsClient dnsClient;
|
private readonly DnsClient dnsClient;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 域名解析器
|
/// 域名解析器
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="dnscryptProxy"></param>
|
|
||||||
/// <param name="fastGithubConfig"></param>
|
|
||||||
/// <param name="dnsClient"></param>
|
/// <param name="dnsClient"></param>
|
||||||
public DomainResolver(
|
public DomainResolver(DnsClient dnsClient)
|
||||||
DnscryptProxy dnscryptProxy,
|
|
||||||
FastGithubConfig fastGithubConfig,
|
|
||||||
DnsClient dnsClient)
|
|
||||||
{
|
{
|
||||||
this.dnscryptProxy = dnscryptProxy;
|
|
||||||
this.fastGithubConfig = fastGithubConfig;
|
|
||||||
this.dnsClient = dnsClient;
|
this.dnsClient = dnsClient;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -53,38 +43,9 @@ namespace FastGithub.DomainResolve
|
|||||||
/// <param name="domain">域名</param>
|
/// <param name="domain">域名</param>
|
||||||
/// <param name="cancellationToken"></param>
|
/// <param name="cancellationToken"></param>
|
||||||
/// <returns></returns>
|
/// <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>();
|
return this.dnsClient.ResolveAsync(domain, cancellationToken);
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
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