From 4d181e413cda1dd50dc7ce7ec3710c9c879f13fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E5=9B=BD=E4=BC=9F?= <366193849@qq.com> Date: Wed, 14 Jul 2021 12:36:36 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0GithubReverseProxyOptions?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- FastGithub.Dns/DnsOptions.cs | 7 +-- FastGithub.Dns/FastGithub.Dns.csproj | 1 + FastGithub.Dns/GithubRequestResolver.cs | 57 ++++++++++++------- .../GithubReverseProxyOptions.cs | 26 +++++++++ .../LifetimeHttpHandler.cs | 2 +- .../LifetimeHttpHandlerCleaner.cs | 34 +++++++---- .../NoneSniHttpClientFactory.cs | 20 +++++-- ...everseProxyApplicationBuilderExtensions.cs | 8 ++- FastGithub.Scanner/GithubDnsHttpHandler.cs | 4 +- .../GithubLookupFactoryOptions.cs | 4 +- .../ScannerServiceCollectionExtensions.cs | 8 ++- FastGithub/appsettings.json | 10 +++- 12 files changed, 127 insertions(+), 54 deletions(-) create mode 100644 FastGithub.ReverseProxy/GithubReverseProxyOptions.cs diff --git a/FastGithub.Dns/DnsOptions.cs b/FastGithub.Dns/DnsOptions.cs index 45d5eea..6fcf7ed 100644 --- a/FastGithub.Dns/DnsOptions.cs +++ b/FastGithub.Dns/DnsOptions.cs @@ -22,11 +22,6 @@ namespace FastGithub.Dns /// /// 是否设置本机使用此dns /// - public bool SetToLocalMachine { get; set; } = true; - - /// - /// 是否启用反向代理 - /// - public bool UseReverseProxy { get; set; } = true; + public bool SetToLocalMachine { get; set; } = true; } } diff --git a/FastGithub.Dns/FastGithub.Dns.csproj b/FastGithub.Dns/FastGithub.Dns.csproj index a21c360..e2d2214 100644 --- a/FastGithub.Dns/FastGithub.Dns.csproj +++ b/FastGithub.Dns/FastGithub.Dns.csproj @@ -5,6 +5,7 @@ + diff --git a/FastGithub.Dns/GithubRequestResolver.cs b/FastGithub.Dns/GithubRequestResolver.cs index e7d36f0..653abd5 100644 --- a/FastGithub.Dns/GithubRequestResolver.cs +++ b/FastGithub.Dns/GithubRequestResolver.cs @@ -1,6 +1,7 @@ using DNS.Client.RequestResolver; using DNS.Protocol; using DNS.Protocol.ResourceRecords; +using FastGithub.ReverseProxy; using FastGithub.Scanner; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; @@ -21,6 +22,8 @@ namespace FastGithub.Dns { private readonly IGithubScanResults githubScanResults; private readonly IOptionsMonitor options; + private readonly IOptionsMonitor lookupOptions; + private readonly IOptionsMonitor reverseProxyOptions; private readonly ILogger logger; /// @@ -32,10 +35,14 @@ namespace FastGithub.Dns public GithubRequestResolver( IGithubScanResults githubScanResults, IOptionsMonitor options, + IOptionsMonitor lookupOptions, + IOptionsMonitor reverseProxyOptions, ILogger logger) { this.githubScanResults = githubScanResults; this.options = options; + this.lookupOptions = lookupOptions; + this.reverseProxyOptions = reverseProxyOptions; this.logger = logger; } @@ -50,36 +57,42 @@ namespace FastGithub.Dns var response = Response.FromRequest(request); var question = request.Questions.FirstOrDefault(); - if (question != null && question.Type == RecordType.A) + if (question == null || question.Type != RecordType.A) { - var domain = question.Name.ToString(); - var address = this.githubScanResults.FindBestAddress(domain); + return response; + } + var domain = question.Name.ToString(); + if (this.lookupOptions.CurrentValue.Domains.Contains(domain) == false) + { + return response; + } + + if (this.reverseProxyOptions.CurrentValue.Enable == false) + { + var address = this.githubScanResults.FindBestAddress(domain); if (address != null) { - if (this.options.CurrentValue.UseReverseProxy == false) + var ttl = this.options.CurrentValue.GithubTTL; + var record = new IPAddressResourceRecord(question.Name, address, ttl); + response.AnswerRecords.Add(record); + this.logger.LogInformation(record.ToString()); + } + } + else + { + var localhost = System.Net.Dns.GetHostName(); + var addresses = await System.Net.Dns.GetHostAddressesAsync(localhost); + var ttl = TimeSpan.FromMinutes(1d); + + foreach (var item in addresses) + { + if (item.AddressFamily == AddressFamily.InterNetwork) { - var ttl = this.options.CurrentValue.GithubTTL; - var record = new IPAddressResourceRecord(question.Name, address, ttl); + var record = new IPAddressResourceRecord(question.Name, item, ttl); response.AnswerRecords.Add(record); this.logger.LogInformation(record.ToString()); } - else - { - var localhost = System.Net.Dns.GetHostName(); - var addresses = await System.Net.Dns.GetHostAddressesAsync(localhost); - var ttl = TimeSpan.FromMinutes(1d); - - foreach (var item in addresses) - { - if (item.AddressFamily == AddressFamily.InterNetwork) - { - var record = new IPAddressResourceRecord(question.Name, item, ttl); - response.AnswerRecords.Add(record); - this.logger.LogInformation(record.ToString()); - } - } - } } } diff --git a/FastGithub.ReverseProxy/GithubReverseProxyOptions.cs b/FastGithub.ReverseProxy/GithubReverseProxyOptions.cs new file mode 100644 index 0000000..8608d2b --- /dev/null +++ b/FastGithub.ReverseProxy/GithubReverseProxyOptions.cs @@ -0,0 +1,26 @@ +using Yarp.ReverseProxy.Forwarder; + +namespace FastGithub.ReverseProxy +{ + /// + /// 反向代理选项 + /// + [Options("ReverseProxy")] + public class GithubReverseProxyOptions + { + /// + /// 是否启用 + /// + public bool Enable { get; set; } = true; + + /// + /// 每个服务的最大代理连接数 + /// + public int MaxConnectionsPerServer { get; set; } = int.MaxValue; + + /// + /// 请求配置 + /// + public ForwarderRequestConfig ForwarderRequestConfig { get; set; } = new(); + } +} diff --git a/FastGithub.ReverseProxy/LifetimeHttpHandler.cs b/FastGithub.ReverseProxy/LifetimeHttpHandler.cs index 14837cb..932309f 100644 --- a/FastGithub.ReverseProxy/LifetimeHttpHandler.cs +++ b/FastGithub.ReverseProxy/LifetimeHttpHandler.cs @@ -19,7 +19,7 @@ namespace FastGithub.ReverseProxy /// /// Token取消源 /// - private readonly CancellationTokenSource tokenSource = new CancellationTokenSource(); + private readonly CancellationTokenSource tokenSource = new(); /// /// 具有生命周期的HttpHandler diff --git a/FastGithub.ReverseProxy/LifetimeHttpHandlerCleaner.cs b/FastGithub.ReverseProxy/LifetimeHttpHandlerCleaner.cs index 35c01cb..bd1ca86 100644 --- a/FastGithub.ReverseProxy/LifetimeHttpHandlerCleaner.cs +++ b/FastGithub.ReverseProxy/LifetimeHttpHandlerCleaner.cs @@ -1,4 +1,5 @@ -using System; +using Microsoft.Extensions.Logging; +using System; using System.Collections.Concurrent; using System.Diagnostics; using System.Threading; @@ -11,6 +12,8 @@ namespace FastGithub.ReverseProxy /// sealed class LifetimeHttpHandlerCleaner { + private readonly ILogger logger; + /// /// 当前监视生命周期的记录的数量 /// @@ -27,6 +30,15 @@ namespace FastGithub.ReverseProxy /// public TimeSpan CleanupInterval { get; set; } = TimeSpan.FromSeconds(10d); + /// + /// LifetimeHttpHandler清理器 + /// + /// + public LifetimeHttpHandlerCleaner(ILogger logger) + { + this.logger = logger; + } + /// /// 添加要清除的httpHandler /// @@ -52,18 +64,16 @@ namespace FastGithub.ReverseProxy { while (true) { - await Task - .Delay(this.CleanupInterval) - .ConfigureAwait(false); - + await Task.Delay(this.CleanupInterval); if (this.Cleanup() == true) { break; } } } - catch (Exception) + catch (Exception ex) { + this.logger.LogError(ex, "清理HttpMessageHandler出现不可预期的异常"); // 这是应该不可能发生的 } } @@ -76,6 +86,8 @@ namespace FastGithub.ReverseProxy private bool Cleanup() { var cleanCount = this.trackingEntries.Count; + this.logger.LogTrace($"尝试清理{cleanCount}条HttpMessageHandler"); + for (var i = 0; i < cleanCount; i++) { this.trackingEntries.TryDequeue(out var entry); @@ -87,12 +99,14 @@ namespace FastGithub.ReverseProxy continue; } + this.logger.LogTrace($"释放了{entry.GetHashCode()}@HttpMessageHandler"); entry.Dispose(); if (Interlocked.Decrement(ref this.trackingEntryCount) == 0) { return true; } } + return false; } @@ -116,10 +130,7 @@ namespace FastGithub.ReverseProxy /// 获取是否可以释放资源 /// /// - public bool CanDispose - { - get => this.weakReference.IsAlive == false; - } + public bool CanDispose => this.weakReference.IsAlive == false; /// /// 监视生命周期的记录 @@ -131,6 +142,9 @@ namespace FastGithub.ReverseProxy this.weakReference = new WeakReference(handler); } + /// + /// 释放资源 + /// public void Dispose() { try diff --git a/FastGithub.ReverseProxy/NoneSniHttpClientFactory.cs b/FastGithub.ReverseProxy/NoneSniHttpClientFactory.cs index 59ab8cd..16ca0dd 100644 --- a/FastGithub.ReverseProxy/NoneSniHttpClientFactory.cs +++ b/FastGithub.ReverseProxy/NoneSniHttpClientFactory.cs @@ -1,6 +1,7 @@ using FastGithub.Scanner; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; using System; using System.Net.Http; using System.Net.Security; @@ -15,6 +16,7 @@ namespace FastGithub.ReverseProxy sealed class NoneSniHttpClientFactory { private readonly IGithubScanResults githubScanResults; + private readonly IOptionsMonitor options; private readonly ILogger logger; /// @@ -25,12 +27,12 @@ namespace FastGithub.ReverseProxy /// /// 具有生命周期的httpHandler延时创建对象 /// - private Lazy lifeTimeHttpHandlerLazy; + private volatile Lazy lifeTimeHttpHandlerLazy; /// /// HttpHandler清理器 /// - private readonly LifetimeHttpHandlerCleaner httpHandlerCleaner = new LifetimeHttpHandlerCleaner(); + private readonly LifetimeHttpHandlerCleaner httpHandlerCleaner; /// @@ -39,11 +41,14 @@ namespace FastGithub.ReverseProxy /// public NoneSniHttpClientFactory( IGithubScanResults githubScanResults, + IOptionsMonitor options, ILogger logger) { this.githubScanResults = githubScanResults; + this.options = options; this.logger = logger; this.lifeTimeHttpHandlerLazy = new Lazy(this.CreateHttpHandler, true); + this.httpHandlerCleaner = new LifetimeHttpHandlerCleaner(logger); } /// @@ -53,7 +58,7 @@ namespace FastGithub.ReverseProxy public HttpMessageInvoker CreateHttpClient() { var handler = this.lifeTimeHttpHandlerLazy.Value; - return new HttpMessageInvoker(handler, disposeHandler: false); + return new HttpMessageInvoker(handler); } /// @@ -67,6 +72,7 @@ namespace FastGithub.ReverseProxy Proxy = null, UseProxy = false, AllowAutoRedirect = false, + MaxConnectionsPerServer = this.options.CurrentValue.MaxConnectionsPerServer, ConnectCallback = async (ctx, ct) => { var socket = new Socket(SocketType.Stream, ProtocolType.Tcp); @@ -77,8 +83,12 @@ namespace FastGithub.ReverseProxy return stream; } - var sslStream = new SslStream(stream, leaveInnerStreamOpen: false, delegate { return true; }); - await sslStream.AuthenticateAsClientAsync(string.Empty, null, false); + var sslStream = new SslStream(stream, leaveInnerStreamOpen: false); + await sslStream.AuthenticateAsClientAsync(new SslClientAuthenticationOptions + { + TargetHost = string.Empty, + RemoteCertificateValidationCallback = delegate { return true; } + }, ct); return sslStream; } }; diff --git a/FastGithub.ReverseProxy/ReverseProxyApplicationBuilderExtensions.cs b/FastGithub.ReverseProxy/ReverseProxyApplicationBuilderExtensions.cs index 5bc71cd..62dfff0 100644 --- a/FastGithub.ReverseProxy/ReverseProxyApplicationBuilderExtensions.cs +++ b/FastGithub.ReverseProxy/ReverseProxyApplicationBuilderExtensions.cs @@ -24,12 +24,13 @@ namespace FastGithub { var httpForwarder = app.ApplicationServices.GetRequiredService(); var httpClientFactory = app.ApplicationServices.GetRequiredService(); - var options = app.ApplicationServices.GetRequiredService>(); + var lookupOptions = app.ApplicationServices.GetRequiredService>(); + var options = app.ApplicationServices.GetRequiredService>(); app.Use(next => async context => { var host = context.Request.Host.Host; - if (options.CurrentValue.Domains.Contains(host) == false) + if (lookupOptions.CurrentValue.Domains.Contains(host) == false) { await context.Response.WriteAsJsonAsync(new { message = $"不支持以{host}访问" }); } @@ -38,7 +39,8 @@ namespace FastGithub var port = context.Request.Host.Port ?? 443; var destinationPrefix = $"http://{host}:{port}/"; var httpClient = httpClientFactory.CreateHttpClient(); - await httpForwarder.SendAsync(context, destinationPrefix, httpClient); + var requestConfig = options.CurrentValue.ForwarderRequestConfig; + await httpForwarder.SendAsync(context, destinationPrefix, httpClient, requestConfig); } }); diff --git a/FastGithub.Scanner/GithubDnsHttpHandler.cs b/FastGithub.Scanner/GithubDnsHttpHandler.cs index b349e44..69b2033 100644 --- a/FastGithub.Scanner/GithubDnsHttpHandler.cs +++ b/FastGithub.Scanner/GithubDnsHttpHandler.cs @@ -39,7 +39,9 @@ namespace FastGithub.Scanner { var builder = new UriBuilder(uri) { - Host = address.ToString() + Scheme = Uri.UriSchemeHttp, + Host = address.ToString(), + Port = 443 }; request.RequestUri = builder.Uri; request.Headers.Host = uri.Host; diff --git a/FastGithub.Scanner/GithubLookupFactoryOptions.cs b/FastGithub.Scanner/GithubLookupFactoryOptions.cs index 298c4f7..da8e753 100644 --- a/FastGithub.Scanner/GithubLookupFactoryOptions.cs +++ b/FastGithub.Scanner/GithubLookupFactoryOptions.cs @@ -1,4 +1,4 @@ -using System; +using System.Collections.Generic; namespace FastGithub.Scanner { @@ -11,6 +11,6 @@ namespace FastGithub.Scanner /// /// 反查的域名 /// - public string[] Domains { get; set; } = Array.Empty(); + public HashSet Domains { get; set; } = new(); } } diff --git a/FastGithub.Scanner/ScannerServiceCollectionExtensions.cs b/FastGithub.Scanner/ScannerServiceCollectionExtensions.cs index 5ef2164..d8fa143 100644 --- a/FastGithub.Scanner/ScannerServiceCollectionExtensions.cs +++ b/FastGithub.Scanner/ScannerServiceCollectionExtensions.cs @@ -50,8 +50,12 @@ namespace FastGithub return stream; } - var sslStream = new SslStream(stream, leaveInnerStreamOpen: false, delegate { return true; }); - await sslStream.AuthenticateAsClientAsync(string.Empty, null, false); + var sslStream = new SslStream(stream, leaveInnerStreamOpen: false); + await sslStream.AuthenticateAsClientAsync(new SslClientAuthenticationOptions + { + TargetHost = string.Empty, + RemoteCertificateValidationCallback = delegate { return true; } + }, ct); return sslStream; } }); diff --git a/FastGithub/appsettings.json b/FastGithub/appsettings.json index 0341e50..f4581d5 100644 --- a/FastGithub/appsettings.json +++ b/FastGithub/appsettings.json @@ -2,8 +2,14 @@ "Dns": { "UpStream": "114.114.114.114", // dns "GithubTTL": "00:10:00", // githubĴʱ - "SetToLocalMachine": true, // Ƿñʹôdns(֧windows) - "UseReverseProxy": true // Ƿʹ÷github + "SetToLocalMachine": true // Ƿñʹôdns(֧windows) + }, + "ReverseProxy": { + "Enable": true, // Ƿʹ÷github, + "MaxConnectionsPerServer": 100, // + "ForwarderRequestConfig": { + "Timeout": "00:02:00" // ʱʱ + } }, "Lookup": { // ip "IPAddressComProvider": {