🎨 IDnsAnalysisService

This commit is contained in:
Aigio Liu
2023-09-16 12:20:45 +08:00
parent d00572d97d
commit f6554a3b21
5 changed files with 75 additions and 229 deletions
@@ -5,9 +5,9 @@ using static BD.WTTS.Services.IDnsAnalysisService;
// ReSharper disable once CheckNamespace
namespace BD.WTTS.Services.Implementation;
sealed class DnsAnalysisServiceImpl : IDnsAnalysisService
sealed class DnsAnalysisServiceImpl
{
static readonly LookupClient lookupClient = new();
readonly LookupClient lookupClient = new();
public async Task<int> AnalysisHostnameTimeAsync(string url, CancellationToken cancellationToken = default)
{
@@ -24,7 +24,7 @@ sealed class DnsAnalysisServiceImpl : IDnsAnalysisService
return 0;
}
public static IEnumerable<ARecord>? GetPingHostNameData(string url)
public IEnumerable<ARecord>? GetPingHostNameData(string url)
{
if (!string.IsNullOrEmpty(url))
{
@@ -119,11 +119,18 @@ sealed class DnsAnalysisServiceImpl : IDnsAnalysisService
{
Retries = 1,
Timeout = TimeSpan.FromSeconds(1),
UseCache = false
UseCache = false,
};
var client = new LookupClient(options);
var response = await client.QueryServerAsync(new[] { IPAddress.Parse(PrimaryDNS_IPV6_Ali) }, IPV6_TESTDOMAIN, QueryType.AAAA, QueryClass.IN);
if (response.Answers.AaaaRecords().Any(s => s.Address.Equals(IPAddress.Parse(IPV6_TESTDOMAIN_SUCCESS))))
var response = await client.QueryServerAsync(
new[] {
IPAddress.Parse(PrimaryDNS_IPV6_Ali),
},
IPV6_TESTDOMAIN,
QueryType.AAAA,
QueryClass.IN);
if (response.Answers.AaaaRecords().Any(s =>
s.Address.Equals(IPAddress.Parse(IPV6_TESTDOMAIN_SUCCESS))))
{
return true;
}
@@ -133,9 +140,4 @@ sealed class DnsAnalysisServiceImpl : IDnsAnalysisService
}
return false;
}
public Task<IPAddress?> GetHostIpv6AddresAsync()
{
return Task.FromResult<IPAddress?>(null);
}
}
@@ -3,8 +3,8 @@ namespace BD.WTTS.Services.Implementation;
sealed class DnsAnalysisServiceSwitchImpl : IDnsAnalysisService
{
readonly IDnsAnalysisService dnsAnalysisServiceImpl;
readonly IDnsAnalysisService dnsDohAnalysisService;
readonly DnsAnalysisServiceImpl dnsAnalysisServiceImpl;
readonly DnsDohAnalysisService dnsDohAnalysisService;
readonly IReverseProxySettings settings;
public DnsAnalysisServiceSwitchImpl(
@@ -17,94 +17,17 @@ sealed class DnsAnalysisServiceSwitchImpl : IDnsAnalysisService
this.dnsDohAnalysisService = dnsDohAnalysisService;
}
public async Task<long> PingHostnameAsync(string url)
{
long r;
if (settings.UseDoh)
{
r = await dnsAnalysisServiceImpl.PingHostnameAsync(url);
}
else
{
r = await dnsDohAnalysisService.PingHostnameAsync(url);
}
return r;
}
public async Task<int> AnalysisHostnameTimeAsync(string url, CancellationToken cancellationToken = default)
{
int r;
if (settings.UseDoh)
{
var dohAddres = settings.CustomDohAddres;
if (!string.IsNullOrWhiteSpace(dohAddres))
{
r = await dnsAnalysisServiceImpl.AnalysisHostnameTimeByDohAddresAsync(dohAddres, url, cancellationToken);
}
else
{
r = await dnsAnalysisServiceImpl.AnalysisHostnameTimeAsync(url, cancellationToken);
}
r = await dnsDohAnalysisService.DohAnalysisHostnameTimeAsync(
settings.CustomDohAddres, url, cancellationToken);
}
else
{
r = await dnsDohAnalysisService.AnalysisHostnameTimeAsync(url, cancellationToken);
}
return r;
}
public async Task<int> AnalysisHostnameTimeByDohAddresAsync(string dohAddres, string url, CancellationToken cancellationToken = default)
{
int r;
if (settings.UseDoh)
{
r = await dnsAnalysisServiceImpl.AnalysisHostnameTimeByDohAddresAsync(dohAddres, url, cancellationToken);
}
else
{
r = await dnsDohAnalysisService.AnalysisHostnameTimeByDohAddresAsync(dohAddres, url, cancellationToken);
}
return r;
}
public IAsyncEnumerable<IPAddress> AnalysisDomainIpAsync(string hostNameOrAddress, bool isIPv6, CancellationToken cancellationToken = default)
{
IAsyncEnumerable<IPAddress> r;
if (settings.UseDoh)
{
r = dnsAnalysisServiceImpl.AnalysisDomainIpAsync(hostNameOrAddress, isIPv6, cancellationToken);
}
else
{
r = dnsDohAnalysisService.AnalysisDomainIpAsync(hostNameOrAddress, isIPv6, cancellationToken);
}
return r;
}
public IAsyncEnumerable<IPAddress> AnalysisDomainIpAsync(string hostNameOrAddress, CancellationToken cancellationToken = default)
{
IAsyncEnumerable<IPAddress> r;
if (settings.UseDoh)
{
r = dnsAnalysisServiceImpl.AnalysisDomainIpAsync(hostNameOrAddress, cancellationToken);
}
else
{
r = dnsDohAnalysisService.AnalysisDomainIpAsync(hostNameOrAddress, cancellationToken);
}
return r;
}
public IAsyncEnumerable<IPAddress> AnalysisDomainIpAsync(string hostNameOrAddress, IPAddress[]? dnsServers, CancellationToken cancellationToken = default)
{
IAsyncEnumerable<IPAddress> r;
if (settings.UseDoh)
{
r = dnsAnalysisServiceImpl.AnalysisDomainIpAsync(hostNameOrAddress, dnsServers, cancellationToken);
}
else
{
r = dnsDohAnalysisService.AnalysisDomainIpAsync(hostNameOrAddress, dnsServers, cancellationToken);
r = await dnsAnalysisServiceImpl.AnalysisHostnameTimeAsync(url, cancellationToken);
}
return r;
}
@@ -114,68 +37,25 @@ sealed class DnsAnalysisServiceSwitchImpl : IDnsAnalysisService
IAsyncEnumerable<IPAddress> r;
if (settings.UseDoh)
{
r = dnsAnalysisServiceImpl.AnalysisDomainIpAsync(hostNameOrAddress, dnsServers, isIPv6, cancellationToken);
r = dnsDohAnalysisService.DohAnalysisDomainIpAsync(settings.CustomDohAddres, hostNameOrAddress, isIPv6, true, cancellationToken);
}
else
{
r = dnsDohAnalysisService.AnalysisDomainIpAsync(hostNameOrAddress, dnsServers, isIPv6, cancellationToken);
}
return r;
}
public IAsyncEnumerable<IPAddress>? DohAnalysisDomainIpAsync(string hostNameOrAddress, string? dnsServers, bool isIPv6, CancellationToken cancellationToken = default)
{
IAsyncEnumerable<IPAddress>? r;
if (settings.UseDoh)
{
r = dnsAnalysisServiceImpl.DohAnalysisDomainIpAsync(hostNameOrAddress, dnsServers, isIPv6, cancellationToken);
}
else
{
r = dnsDohAnalysisService.DohAnalysisDomainIpAsync(hostNameOrAddress, dnsServers, isIPv6, cancellationToken);
r = dnsAnalysisServiceImpl.AnalysisDomainIpAsync(hostNameOrAddress, dnsServers, isIPv6, cancellationToken);
}
return r;
}
public async Task<string?> GetHostByIPAddressAsync(IPAddress ip)
{
string? r;
if (settings.UseDoh)
{
r = await dnsAnalysisServiceImpl.GetHostByIPAddressAsync(ip);
}
else
{
r = await dnsDohAnalysisService.GetHostByIPAddressAsync(ip);
}
var r = await dnsAnalysisServiceImpl.GetHostByIPAddressAsync(ip);
return r;
}
public async Task<bool> GetIsIpv6SupportAsync()
{
bool r;
if (settings.UseDoh)
{
r = await dnsAnalysisServiceImpl.GetIsIpv6SupportAsync();
}
else
{
r = await dnsDohAnalysisService.GetIsIpv6SupportAsync();
}
return r;
}
public async Task<IPAddress?> GetHostIpv6AddresAsync()
{
IPAddress? r;
if (settings.UseDoh)
{
r = await dnsAnalysisServiceImpl.GetHostIpv6AddresAsync();
}
else
{
r = await dnsDohAnalysisService.GetHostIpv6AddresAsync();
}
var r = await dnsAnalysisServiceImpl.GetIsIpv6SupportAsync();
return r;
}
}
@@ -7,13 +7,13 @@ using DnsQueryType = Ae.Dns.Protocol.Enums.DnsQueryType;
// ReSharper disable once CheckNamespace
namespace BD.WTTS.Services.Implementation;
sealed class DnsDohAnalysisService : GeneralHttpClientFactory, IDnsAnalysisService
sealed class DnsDohAnalysisService : GeneralHttpClientFactory
{
const string TAG = "DnsDohAnalysisS";
protected override string? DefaultClientName => TAG;
private readonly ConcurrentDictionary<string, List<DnsResourceRecord>> Cache = new();
private readonly ConcurrentDictionary<(Uri dohAddresUri, string hostNameOrAddressWithQueryType), List<DnsResourceRecord>> Cache = new();
public DnsDohAnalysisService(
ILoggerFactory loggerFactory,
@@ -23,28 +23,32 @@ sealed class DnsDohAnalysisService : GeneralHttpClientFactory, IDnsAnalysisServi
{
}
const string DefaultDohAddres = Dnspod_DohAddres;
public const string DefaultDohAddres = Dnspod_DohAddres;
public async Task<int> AnalysisHostnameTimeAsync(string url, CancellationToken cancellationToken = default)
static Uri GetDohAddres(string? dohAddres)
{
var r = await AnalysisHostnameTimeByDohAddresAsync(DefaultDohAddres, url, cancellationToken);
return r;
if (string.IsNullOrWhiteSpace(dohAddres))
return new Uri(DefaultDohAddres);
Uri dohAddresUri;
try
{
dohAddresUri = new Uri(dohAddres);
}
catch
{
dohAddresUri = new Uri(DefaultDohAddres);
}
return dohAddresUri;
}
public async Task<int> AnalysisHostnameTimeByDohAddresAsync(string dohAddres, string url, CancellationToken cancellationToken = default)
public async Task<int> DohAnalysisHostnameTimeAsync(string? dohAddres, string url, CancellationToken cancellationToken = default)
{
if (!string.IsNullOrEmpty(url))
{
const string clientName = TAG + "_" + nameof(AnalysisHostnameTimeAsync);
const string clientName = TAG + "_" + nameof(DohAnalysisHostnameTimeAsync);
var client = CreateClient(clientName, HttpHandlerCategory.Default);
try
{
client.BaseAddress = new Uri(dohAddres);
}
catch
{
client.BaseAddress = new Uri(DefaultDohAddres);
}
client.BaseAddress = GetDohAddres(dohAddres);
IDnsClient dnsClient = new DnsHttpClient(client);
var queryType = DnsQueryType.A;
@@ -57,55 +61,33 @@ sealed class DnsDohAnalysisService : GeneralHttpClientFactory, IDnsAnalysisServi
return 0;
}
/// <summary>
/// 解析域名 IP 地址
/// </summary>
/// <param name="hostNameOrAddress">要解析的主机名或 IP 地址</param>
/// <param name="isIPv6"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public IAsyncEnumerable<IPAddress> AnalysisDomainIpAsync(string hostNameOrAddress, bool isIPv6, bool useCache = true, CancellationToken cancellationToken = default)
=> DohAnalysisDomainIpAsync(hostNameOrAddress, default, isIPv6, useCache, cancellationToken);
/// <summary>
/// 解析域名 IP 地址
/// </summary>
/// <param name="hostNameOrAddress">要解析的主机名或 IP 地址</param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public IAsyncEnumerable<IPAddress> AnalysisDomainIpAsync(string hostNameOrAddress, bool useCache = true, CancellationToken cancellationToken = default)
=> DohAnalysisDomainIpAsync(hostNameOrAddress, default, default, useCache, cancellationToken);
/// <summary>
/// 解析域名 IP 地址
/// </summary>
/// <param name="hostNameOrAddress">要解析的主机名或 IP 地址</param>
/// <param name="dnsServers">自定义 DNS 服务器,可选的值有 <see cref="DNS_Alis"/>, <see cref="DNS_114s"/>, <see cref="DNS_Cloudflares"/>, <see cref="DNS_Dnspods"/>, <see cref="DNS_Googles"/></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public IAsyncEnumerable<IPAddress> AnalysisDomainIpAsync(string hostNameOrAddress, Uri[]? dnsServers, bool useCache = true, CancellationToken cancellationToken = default)
=> DohAnalysisDomainIpAsync(hostNameOrAddress, dnsServers, default, useCache, cancellationToken);
/// <summary>
/// DOH 解析域名 IP 地址
/// </summary>
/// <param name="hostNameOrAddress">要解析的主机名或 IP 地址</param>
/// <param name="dnsServers">自定义 DNS 服务器,可选的值有 <see cref="DNS_Alis"/>, <see cref="DNS_114s"/>, <see cref="DNS_Cloudflares"/>, <see cref="DNS_Dnspods"/>, <see cref="DNS_Googles"/></param>
/// <param name="isIPv6"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public async IAsyncEnumerable<IPAddress> DohAnalysisDomainIpAsync(string hostNameOrAddress, Uri[]? dotServers, bool isIPv6, bool useCache = true, [EnumeratorCancellation] CancellationToken cancellationToken = default)
public async IAsyncEnumerable<IPAddress> DohAnalysisDomainIpAsync(string? dohAddres, string hostNameOrAddress, bool isIPv6, bool useCache = true, [EnumeratorCancellation] CancellationToken cancellationToken = default)
{
var queryType = isIPv6 ? DnsQueryType.AAAA : DnsQueryType.A;
var dohAddresUri = GetDohAddres(dohAddres);
var current_dns_list = Enumerable.Empty<DnsResourceRecord>();
(Uri dohAddresUri, string hostNameOrAddressWithQueryType) cacheKey = useCache ? GetCacheKey() : default;
(Uri dohAddresUri, string hostNameOrAddressWithQueryType) GetCacheKey()
{
var hostNameOrAddressWithQueryType = string.Concat(hostNameOrAddress, ":", (short)queryType);
var cacheKey = (dohAddresUri, hostNameOrAddressWithQueryType);
return cacheKey;
}
var current_dns_list = new List<DnsResourceRecord>();
if (useCache)
{
var cacheKey = string.Concat(hostNameOrAddress, ":", (short)queryType);
if (Cache.TryGetValue(cacheKey, out var dns_list))
{
current_dns_list = dns_list.Where(x => x.TimeToLive > DateTime.Now.ToUnixTimeSeconds()).ToList();
Cache[cacheKey] = current_dns_list.ToList();
Cache[cacheKey] = current_dns_list;
foreach (var x in current_dns_list)
{
if (x.Resource is DnsIpAddressResource ipAddressResource)
@@ -118,41 +100,38 @@ sealed class DnsDohAnalysisService : GeneralHttpClientFactory, IDnsAnalysisServi
if (!current_dns_list.Any())
{
if (dotServers == null || dotServers.Length <= 0)
dotServers = new Uri[] { new Uri(DNS_Ali_DohAddres) };
try
{
var query = DnsQueryFactory.CreateQuery(hostNameOrAddress, queryType);
IDnsClient dnsClient;
HttpClient httpClient;
foreach (var dot_server in dotServers)
{
const string clientName = TAG + "_" + nameof(DohAnalysisDomainIpAsync);
httpClient = CreateClient(clientName, HttpHandlerCategory.Default);
httpClient.BaseAddress = dot_server;
dnsClient = new DnsHttpClient(httpClient);
const string clientName = TAG + "_" + nameof(DohAnalysisDomainIpAsync);
httpClient = CreateClient(clientName, HttpHandlerCategory.Default);
httpClient.BaseAddress = dohAddresUri;
using var dnsClient = new DnsHttpClient(httpClient);
var answer = await dnsClient.Query(query, cancellationToken);
if (useCache)
current_dns_list = current_dns_list.Concat(answer.Answers);
foreach (var x in answer.Answers)
var answer = await dnsClient.Query(query, cancellationToken);
if (useCache)
{
current_dns_list.AddRange(answer.Answers);
}
foreach (var x in answer.Answers)
{
if (x.Resource is DnsIpAddressResource ipAddressResource)
{
if (x.Resource is DnsIpAddressResource ipAddressResource)
{
yield return ipAddressResource.IPAddress;
}
yield return ipAddressResource.IPAddress;
}
dnsClient.Dispose();
}
}
finally
{
if (useCache)
{
var cacheKey = string.Concat(hostNameOrAddress, ":", (short)queryType);
Cache[cacheKey] = current_dns_list
.Select(item => { item.TimeToLive += (uint)DateTime.Now.ToUnixTimeSeconds(); return item; })
.Select(item =>
{
item.TimeToLive += (uint)DateTime.Now.ToUnixTimeSeconds();
return item;
})
.ToList();
}
}
@@ -21,7 +21,7 @@ public partial interface IDnsAnalysisService // 公共常量定义
const string DohAddres_360 = "https://doh.360.cn/dns-query";
const string TUNA_DohAddres = "https://101.6.6.6:8443/dns-query";
protected const string PrimaryDNS_IPV6_Ali = "2400:3200::1";
const string PrimaryDNS_IPV6_Ali = "2400:3200::1";
const string PrimaryDNS_Ali = "223.5.5.5";
const string SecondaryDNS_Ali = "223.6.6.6";
@@ -7,8 +7,8 @@ partial interface IDnsAnalysisService // 服务函数与 protected 定义
{
protected const string TAG = "DnsAnalysisS";
protected const string IPV6_TESTDOMAIN = "ipv6.rmbgame.net";
protected const string IPV6_TESTDOMAIN_SUCCESS = PrimaryDNS_IPV6_Ali;
const string IPV6_TESTDOMAIN = "ipv6.rmbgame.net";
const string IPV6_TESTDOMAIN_SUCCESS = PrimaryDNS_IPV6_Ali;
async Task<long> PingHostnameAsync(string url)
{
@@ -23,8 +23,6 @@ partial interface IDnsAnalysisService // 服务函数与 protected 定义
Task<int> AnalysisHostnameTimeAsync(string url, CancellationToken cancellationToken = default);
Task<int> AnalysisHostnameTimeByDohAddresAsync(string dohAddres, string url, CancellationToken cancellationToken = default) => AnalysisHostnameTimeAsync(url, cancellationToken);
/// <summary>
/// 解析域名 IP 地址
/// </summary>
@@ -76,19 +74,6 @@ partial interface IDnsAnalysisService // 服务函数与 protected 定义
}
}
/// <summary>
/// DOH 解析域名 IP 地址
/// </summary>
/// <param name="hostNameOrAddress">要解析的主机名或 IP 地址</param>
/// <param name="dnsServers">自定义 DNS 服务器,可选的值有 <see cref="DNS_Alis"/>, <see cref="DNS_114s"/>, <see cref="DNS_Cloudflares"/>, <see cref="DNS_Dnspods"/>, <see cref="DNS_Googles"/></param>
/// <param name="isIPv6"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
IAsyncEnumerable<IPAddress>? DohAnalysisDomainIpAsync(string hostNameOrAddress, string? dnsServers, bool isIPv6, CancellationToken cancellationToken = default)
{
return null;
}
async Task<string?> GetHostByIPAddressAsync(IPAddress ip)
{
var hostEntry = await Dns.GetHostEntryAsync(ip);