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": {