diff --git a/FastGithub.Dns/DnsOptions.cs b/FastGithub.Dns/DnsOptions.cs index 39ef373..2718086 100644 --- a/FastGithub.Dns/DnsOptions.cs +++ b/FastGithub.Dns/DnsOptions.cs @@ -1,4 +1,5 @@ -using System.Net; +using System; +using System.Net; namespace FastGithub.Dns { @@ -6,5 +7,7 @@ namespace FastGithub.Dns sealed class DnsOptions { public IPAddress UpStream { get; set; } = IPAddress.Parse("114.114.114.114"); + + public TimeSpan GithubTTL { get; set; } = TimeSpan.FromMinutes(10d); } } diff --git a/FastGithub.Dns/DnsServiceCollectionExtensions.cs b/FastGithub.Dns/DnsServiceCollectionExtensions.cs index d0d9385..48ccd0f 100644 --- a/FastGithub.Dns/DnsServiceCollectionExtensions.cs +++ b/FastGithub.Dns/DnsServiceCollectionExtensions.cs @@ -18,8 +18,7 @@ namespace FastGithub public static IServiceCollection AddGithubDns(this IServiceCollection services, IConfiguration configuration) { var assembly = typeof(DnsServiceCollectionExtensions).Assembly; - return services - .AddMemoryCache() + return services .AddServiceAndOptions(assembly, configuration) .AddHostedService() .AddGithubScanner(configuration); diff --git a/FastGithub.Dns/FastGithub.Dns.csproj b/FastGithub.Dns/FastGithub.Dns.csproj index ffa588f..a399977 100644 --- a/FastGithub.Dns/FastGithub.Dns.csproj +++ b/FastGithub.Dns/FastGithub.Dns.csproj @@ -6,8 +6,7 @@ - - + diff --git a/FastGithub.Dns/GithubRequestResolver.cs b/FastGithub.Dns/GithubRequestResolver.cs index a3c1543..c54201e 100644 --- a/FastGithub.Dns/GithubRequestResolver.cs +++ b/FastGithub.Dns/GithubRequestResolver.cs @@ -2,12 +2,11 @@ using DNS.Protocol; using DNS.Protocol.ResourceRecords; using FastGithub.Scanner; -using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; using System; using System.Linq; -using System.Net; using System.Threading; using System.Threading.Tasks; @@ -17,17 +16,16 @@ namespace FastGithub.Dns sealed class GithubRequestResolver : IRequestResolver { private readonly IGithubScanResults githubScanResults; - private readonly IMemoryCache memoryCache; - private readonly ILogger logger; - private readonly TimeSpan TTL = TimeSpan.FromMinutes(10d); + private readonly IOptionsMonitor options; + private readonly ILogger logger; public GithubRequestResolver( IGithubScanResults githubScanResults, - IMemoryCache memoryCache, + IOptionsMonitor options, ILogger logger) { this.githubScanResults = githubScanResults; - this.memoryCache = memoryCache; + this.options = options; this.logger = logger; } @@ -39,11 +37,12 @@ namespace FastGithub.Dns if (question != null && question.Type == RecordType.A) { var domain = question.Name.ToString(); - var address = this.GetGithubAddress(domain, TTL); + var address = this.githubScanResults.FindBestAddress(domain); if (address != null) { - var record = new IPAddressResourceRecord(question.Name, address); + var ttl = this.options.CurrentValue.GithubTTL; + var record = new IPAddressResourceRecord(question.Name, address, ttl); response.AnswerRecords.Add(record); this.logger.LogInformation(record.ToString()); } @@ -51,37 +50,5 @@ namespace FastGithub.Dns return Task.FromResult(response); } - - /// - /// 模拟TTL - /// 如果ip可用,则10分钟内返回缓存的ip,防止客户端ip频繁切换 - /// - /// - /// - /// - private IPAddress? GetGithubAddress(string domain, TimeSpan ttl) - { - if (domain.Contains("github", StringComparison.OrdinalIgnoreCase) == false) - { - return default; - } - - var key = $"ttl:{domain}"; - if (this.memoryCache.TryGetValue(key, out var address)) - { - if (this.githubScanResults.IsAvailable(domain, address)) - { - return address; - } - this.memoryCache.Remove(key); - } - - address = this.githubScanResults.FindBestAddress(domain); - if (address != null) - { - this.memoryCache.Set(key, address, ttl); - } - return address; - } } } diff --git a/FastGithub.Scanner/GithubContext.cs b/FastGithub.Scanner/GithubContext.cs index e70356e..b073645 100644 --- a/FastGithub.Scanner/GithubContext.cs +++ b/FastGithub.Scanner/GithubContext.cs @@ -8,7 +8,8 @@ namespace FastGithub.Scanner private record Github( string Domain, IPAddress Address, - double SuccessRate, + bool Available, + double AvailableRate, TimeSpan AvgElapsed); /// @@ -58,8 +59,9 @@ namespace FastGithub.Scanner return new Github( this.Domain, this.Address, - this.History.GetSuccessRate(), - this.History.GetAvgElapsed() + this.Available, + this.History.AvailableRate, + this.History.AvgElapsed ).ToString(); } } diff --git a/FastGithub.Scanner/GithubContextCollection.cs b/FastGithub.Scanner/GithubContextCollection.cs index a968643..b04cbe3 100644 --- a/FastGithub.Scanner/GithubContextCollection.cs +++ b/FastGithub.Scanner/GithubContextCollection.cs @@ -54,9 +54,9 @@ namespace FastGithub.Scanner lock (this.syncRoot) { return this.contextList - .Where(item => item.Available && item.Domain == domain) - .OrderByDescending(item => item.History.GetSuccessRate()) - .ThenBy(item => item.History.GetAvgElapsed()) + .Where(item => item.Domain == domain && item.History.AvailableRate > 0d) + .OrderByDescending(item => item.History.AvailableRate) + .ThenBy(item => item.History.AvgElapsed) .Select(item => item.Address) .FirstOrDefault(); } diff --git a/FastGithub.Scanner/GithubContextHistory.cs b/FastGithub.Scanner/GithubContextHistory.cs index 228be76..aec2095 100644 --- a/FastGithub.Scanner/GithubContextHistory.cs +++ b/FastGithub.Scanner/GithubContextHistory.cs @@ -1,74 +1,66 @@ using System; using System.Collections.Generic; +using System.Linq; namespace FastGithub.Scanner { sealed class GithubContextHistory { - private record ScanLog(DateTime ScanTime, TimeSpan Elapsed); + private const int MAX_LOG_COUNT = 10; + private record ScanLog(bool Available, TimeSpan Elapsed); - private readonly Queue successLogs = new(); + private readonly Queue scanLogs = new(); - private readonly Queue failureLogs = new(); - - private static readonly TimeSpan keepLogsTimeSpan = TimeSpan.FromHours(2d); - - - public void AddSuccess(TimeSpan elapsed) + /// + /// 获取可用率 + /// + /// + public double AvailableRate { - ClearStaleData(this.successLogs, keepLogsTimeSpan); - this.successLogs.Enqueue(new ScanLog(DateTime.Now, elapsed)); - } - - public void AddFailure() - { - ClearStaleData(this.failureLogs, keepLogsTimeSpan); - this.failureLogs.Enqueue(new ScanLog(DateTime.Now, TimeSpan.Zero)); - } - - static void ClearStaleData(Queue logs, TimeSpan timeSpan) - { - var time = DateTime.Now.Subtract(timeSpan); - while (logs.TryPeek(out var log)) + get { - if (log.ScanTime < time) + if (this.scanLogs.Count == 0) { - logs.TryDequeue(out _); + return 0d; } - break; + + var availableCount = this.scanLogs.Count(item => item.Available); + return (double)availableCount / this.scanLogs.Count; } } - /// - /// 获取成功率 - /// - /// - public double GetSuccessRate() - { - var successCount = this.successLogs.Count; - var totalScanCount = successCount + this.failureLogs.Count; - return totalScanCount == 0 ? 0d : (double)successCount / totalScanCount; - } /// /// 获取平均耗时 /// /// - public TimeSpan GetAvgElapsed() + public TimeSpan AvgElapsed { - var totalScanCount = this.successLogs.Count + this.failureLogs.Count; - if (totalScanCount == 0) + get { - return TimeSpan.MaxValue; - } + var availableCount = 0; + var availableElapsed = TimeSpan.Zero; - var totalSuccessElapsed = TimeSpan.Zero; - foreach (var item in this.successLogs) + foreach (var item in this.scanLogs) + { + if (item.Available == true) + { + availableCount += 1; + availableElapsed = availableElapsed.Add(item.Elapsed); + } + } + + return availableCount == 0 ? TimeSpan.MaxValue : availableElapsed / availableCount; + } + } + + public void Add(bool available, TimeSpan elapsed) + { + this.scanLogs.Enqueue(new ScanLog(available, elapsed)); + while (this.scanLogs.Count > MAX_LOG_COUNT) { - totalSuccessElapsed = totalSuccessElapsed.Add(item.Elapsed); + this.scanLogs.Dequeue(); } - - return totalSuccessElapsed / totalScanCount; } } } diff --git a/FastGithub.Scanner/Middlewares/StatisticsMiddleware.cs b/FastGithub.Scanner/Middlewares/StatisticsMiddleware.cs index b70db7f..ca8a67c 100644 --- a/FastGithub.Scanner/Middlewares/StatisticsMiddleware.cs +++ b/FastGithub.Scanner/Middlewares/StatisticsMiddleware.cs @@ -28,16 +28,12 @@ namespace FastGithub.Scanner.Middlewares finally { stopwatch.Stop(); + context.History.Add(context.Available, stopwatch.Elapsed); - if (context.Available) + if (context.History.AvailableRate > 0d) { - context.History.AddSuccess(stopwatch.Elapsed); this.logger.LogInformation(context.ToString()); } - else - { - context.History.AddFailure(); - } } } } diff --git a/FastGithub/appsettings.json b/FastGithub/appsettings.json index 13581ab..5172bd6 100644 --- a/FastGithub/appsettings.json +++ b/FastGithub/appsettings.json @@ -1,6 +1,7 @@ { "Dns": { - "UpStream": "114.114.114.114" + "UpStream": "114.114.114.114", + "GithubTTL": "00.10.00" }, "Github": { "ScanAllInterval": "02:00:00", // ɨʱ diff --git a/README.md b/README.md index 456424f..b08521e 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ github定制版的dns服务,解析访问github最快的ip ### 加速原理 * 使用github公开的ip范围,扫描所有可用的ip; * 轮询检测并统计可用ip的访问成功率与访问耗时; -* 拦截dns,访问github时,服务端模拟TTL,返回最优ip; +* 拦截dns,访问github时返回最优ip; ### 使用说明 在局域网服务器(没有就使用本机)运行本程序,将网络连接的dns设置为程序运行的机器的ip。