增强dns返回的ip的稳定性

This commit is contained in:
陈国伟 2021-06-16 13:14:02 +08:00
parent 3d20996d4b
commit 42458fd25a
7 changed files with 122 additions and 39 deletions

View File

@ -5,11 +5,26 @@ namespace FastGithub.Scanner
{ {
sealed class GithubContext : IEquatable<GithubContext> sealed class GithubContext : IEquatable<GithubContext>
{ {
/// <summary>
/// 获取域名
/// </summary>
public string Domain { get; } public string Domain { get; }
/// <summary>
/// 获取ip
/// </summary>
public IPAddress Address { get; } public IPAddress Address { get; }
public TimeSpan? HttpElapsed { get; set; } /// <summary>
/// 获取或设置是否可用
/// </summary>
public bool Available { get; set; } = false;
/// <summary>
/// 获取或设置扫描总耗时
/// </summary>
public TimeSpan Elapsed { get; set; } = TimeSpan.MaxValue;
public GithubContext(string domain, IPAddress address) public GithubContext(string domain, IPAddress address)
{ {
@ -19,7 +34,7 @@ namespace FastGithub.Scanner
public override string ToString() public override string ToString()
{ {
return $"{Address}\t{Domain}\t# {HttpElapsed}"; return $"{Address}\t{Domain}\t# {Elapsed}";
} }
public override bool Equals(object? obj) public override bool Equals(object? obj)

View File

@ -0,0 +1,66 @@
using System.Collections.Generic;
using System.Linq;
using System.Net;
namespace FastGithub.Scanner
{
sealed class GithubContextCollection
{
private readonly object syncRoot = new();
private readonly HashSet<GithubContext> contextHashSet = new();
private readonly Dictionary<string, IPAddress> domainAdressCache = new();
public bool Add(GithubContext context)
{
lock (this.syncRoot)
{
return this.contextHashSet.Add(context);
}
}
public GithubContext[] ToArray()
{
lock (this.syncRoot)
{
return this.contextHashSet.ToArray();
}
}
/// <summary>
/// 查找又稳又快的ip
/// </summary>
/// <param name="domain"></param>
/// <returns></returns>
public IPAddress? FindFastAddress(string domain)
{
lock (this.syncRoot)
{
// 如果上一次的ip可以使用就返回上一次的ip
if (this.domainAdressCache.TryGetValue(domain, out var address))
{
var key = new GithubContext(domain, address);
if (this.contextHashSet.TryGetValue(key, out var context) && context.Available)
{
return address;
}
}
var fastAddress = this.contextHashSet
.Where(item => item.Available && item.Domain == domain)
.OrderBy(item => item.Elapsed)
.Select(item => item.Address)
.FirstOrDefault();
if (fastAddress != null)
{
this.domainAdressCache[domain] = fastAddress;
}
else
{
this.domainAdressCache.Remove(domain);
}
return fastAddress;
}
}
}
}

View File

@ -1,9 +0,0 @@
using System.Collections.Generic;
namespace FastGithub.Scanner
{
sealed class GithubContextHashSet : HashSet<GithubContext>
{
public readonly object SyncRoot = new();
}
}

View File

@ -14,7 +14,7 @@ namespace FastGithub.Scanner
{ {
private readonly GithubMetaService metaService; private readonly GithubMetaService metaService;
private readonly ILogger<GithubScanService> logger; private readonly ILogger<GithubScanService> logger;
private readonly GithubContextHashSet results = new(); private readonly GithubContextCollection results = new();
private readonly InvokeDelegate<GithubContext> fullScanDelegate; private readonly InvokeDelegate<GithubContext> fullScanDelegate;
private readonly InvokeDelegate<GithubContext> resultScanDelegate; private readonly InvokeDelegate<GithubContext> resultScanDelegate;
@ -30,6 +30,7 @@ namespace FastGithub.Scanner
this.fullScanDelegate = pipelineBuilder this.fullScanDelegate = pipelineBuilder
.New() .New()
.Use<ConcurrentMiddleware>() .Use<ConcurrentMiddleware>()
.Use<ScanElapsedMiddleware>()
.Use<PortScanMiddleware>() .Use<PortScanMiddleware>()
.Use<HttpsScanMiddleware>() .Use<HttpsScanMiddleware>()
.Use<ScanOkLogMiddleware>() .Use<ScanOkLogMiddleware>()
@ -37,6 +38,7 @@ namespace FastGithub.Scanner
this.resultScanDelegate = pipelineBuilder this.resultScanDelegate = pipelineBuilder
.New() .New()
.Use<ScanElapsedMiddleware>()
.Use<PortScanMiddleware>() .Use<PortScanMiddleware>()
.Use<HttpsScanMiddleware>() .Use<HttpsScanMiddleware>()
.Use<ScanOkLogMiddleware>() .Use<ScanOkLogMiddleware>()
@ -58,12 +60,9 @@ namespace FastGithub.Scanner
async Task ScanAsync(GithubContext context) async Task ScanAsync(GithubContext context)
{ {
await this.fullScanDelegate(context); await this.fullScanDelegate(context);
if (context.HttpElapsed != null) if (context.Available == true)
{ {
lock (this.results.SyncRoot) this.results.Add(context);
{
this.results.Add(context);
}
} }
} }
} }
@ -71,15 +70,10 @@ namespace FastGithub.Scanner
public async Task ScanResultAsync() public async Task ScanResultAsync()
{ {
this.logger.LogInformation("结果扫描开始"); this.logger.LogInformation("结果扫描开始");
GithubContext[] contexts;
lock (this.results.SyncRoot)
{
contexts = this.results.ToArray();
}
var contexts = this.results.ToArray();
foreach (var context in contexts) foreach (var context in contexts)
{ {
context.HttpElapsed = null;
await this.resultScanDelegate(context); await this.resultScanDelegate(context);
} }
@ -88,19 +82,9 @@ namespace FastGithub.Scanner
public IPAddress? FindFastAddress(string domain) public IPAddress? FindFastAddress(string domain)
{ {
if (domain.Contains("github", StringComparison.OrdinalIgnoreCase)) return domain.Contains("github", StringComparison.OrdinalIgnoreCase)
{ ? this.results.FindFastAddress(domain)
lock (this.results.SyncRoot) : default;
{
return this.results
.Where(item => item.Domain == domain && item.HttpElapsed != null)
.OrderBy(item => item.HttpElapsed)
.Select(item => item.Address)
.FirstOrDefault();
}
}
return default;
} }
} }
} }

View File

@ -27,6 +27,8 @@ namespace FastGithub.Scanner.Middlewares
{ {
try try
{ {
context.Available = false;
var request = new HttpRequestMessage var request = new HttpRequestMessage
{ {
Method = HttpMethod.Get, Method = HttpMethod.Get,
@ -40,13 +42,12 @@ namespace FastGithub.Scanner.Middlewares
UseProxy = false, UseProxy = false,
}); });
var startTime = DateTime.Now;
using var cancellationTokenSource = new CancellationTokenSource(this.options.CurrentValue.HttpsScanTimeout); using var cancellationTokenSource = new CancellationTokenSource(this.options.CurrentValue.HttpsScanTimeout);
var response = await httpClient.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, cancellationTokenSource.Token); var response = await httpClient.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, cancellationTokenSource.Token);
var server = response.EnsureSuccessStatusCode().Headers.Server; var server = response.EnsureSuccessStatusCode().Headers.Server;
if (server.Any(s => string.Equals("GitHub.com", s.Product?.Name, StringComparison.OrdinalIgnoreCase))) if (server.Any(s => string.Equals("GitHub.com", s.Product?.Name, StringComparison.OrdinalIgnoreCase)))
{ {
context.HttpElapsed = DateTime.Now.Subtract(startTime); context.Available = true;
await next(); await next();
} }
} }

View File

@ -0,0 +1,26 @@
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Diagnostics;
using System.Threading.Tasks;
namespace FastGithub.Scanner.Middlewares
{
[Service(ServiceLifetime.Singleton)]
sealed class ScanElapsedMiddleware : IMiddleware<GithubContext>
{
public async Task InvokeAsync(GithubContext context, Func<Task> next)
{
var stopwatch = new Stopwatch();
try
{
stopwatch.Start();
await next();
}
finally
{
stopwatch.Stop();
context.Elapsed = stopwatch.Elapsed;
}
}
}
}

View File

@ -17,7 +17,7 @@ namespace FastGithub.Scanner.Middlewares
public Task InvokeAsync(GithubContext context, Func<Task> next) public Task InvokeAsync(GithubContext context, Func<Task> next)
{ {
if (context.HttpElapsed != null) if (context.Available)
{ {
this.logger.LogInformation(context.ToString()); this.logger.LogInformation(context.ToString());
} }