完善反向代理功能
This commit is contained in:
parent
ae6b0d7260
commit
9a0c2aab5f
@ -23,5 +23,10 @@ namespace FastGithub.Dns
|
|||||||
/// 是否设置本机使用此dns
|
/// 是否设置本机使用此dns
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool SetToLocalMachine { get; set; } = true;
|
public bool SetToLocalMachine { get; set; } = true;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 是否启用反向代理
|
||||||
|
/// </summary>
|
||||||
|
public bool UseReverseProxy { get; set; } = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,7 +6,7 @@ using Microsoft.Extensions.DependencyInjection;
|
|||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net;
|
using System.Net.Sockets;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
@ -44,7 +44,7 @@ namespace FastGithub.Dns
|
|||||||
/// <param name="request"></param>
|
/// <param name="request"></param>
|
||||||
/// <param name="cancellationToken"></param>
|
/// <param name="cancellationToken"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public Task<IResponse> Resolve(IRequest request, CancellationToken cancellationToken = default)
|
public async Task<IResponse> Resolve(IRequest request, CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
var response = Response.FromRequest(request);
|
var response = Response.FromRequest(request);
|
||||||
var question = request.Questions.FirstOrDefault();
|
var question = request.Questions.FirstOrDefault();
|
||||||
@ -56,15 +56,31 @@ namespace FastGithub.Dns
|
|||||||
|
|
||||||
if (address != null)
|
if (address != null)
|
||||||
{
|
{
|
||||||
address = IPAddress.Loopback;
|
|
||||||
var ttl = this.options.CurrentValue.GithubTTL;
|
var ttl = this.options.CurrentValue.GithubTTL;
|
||||||
var record = new IPAddressResourceRecord(question.Name, address, ttl);
|
if (this.options.CurrentValue.UseReverseProxy == false)
|
||||||
response.AnswerRecords.Add(record);
|
{
|
||||||
this.logger.LogInformation(record.ToString());
|
var record = new IPAddressResourceRecord(question.Name, address, ttl);
|
||||||
|
response.AnswerRecords.Add(record);
|
||||||
|
this.logger.LogInformation(record.ToString());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var hostName = System.Net.Dns.GetHostName();
|
||||||
|
var addresses = await System.Net.Dns.GetHostAddressesAsync(hostName);
|
||||||
|
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());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return Task.FromResult<IResponse>(response);
|
return response;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -38,7 +38,7 @@ namespace FastGithub.ReverseProxy
|
|||||||
/// <param name="caPublicCerPath"></param>
|
/// <param name="caPublicCerPath"></param>
|
||||||
/// <param name="caPrivateKeyPath"></param>
|
/// <param name="caPrivateKeyPath"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static X509Certificate2 Generate(IEnumerable<string> domains, int keySizeBits, DateTime validFrom, DateTime validTo, string caPublicCerPath, string caPrivateKeyPath)
|
public static X509Certificate2 Generate(IEnumerable<string> domains, int keySizeBits, DateTime validFrom, DateTime validTo, string caPublicCerPath, string caPrivateKeyPath, string? password = default)
|
||||||
{
|
{
|
||||||
if (File.Exists(caPublicCerPath) == false)
|
if (File.Exists(caPublicCerPath) == false)
|
||||||
{
|
{
|
||||||
@ -61,7 +61,7 @@ namespace FastGithub.ReverseProxy
|
|||||||
var keys = GenerateRsaKeyPair(keySizeBits);
|
var keys = GenerateRsaKeyPair(keySizeBits);
|
||||||
var cert = GenerateCertificate(domains, keys.Public, validFrom, validTo, caSubjectName, caCert.GetPublicKey(), caPrivateKey, null);
|
var cert = GenerateCertificate(domains, keys.Public, validFrom, validTo, caSubjectName, caCert.GetPublicKey(), caPrivateKey, null);
|
||||||
|
|
||||||
return GeneratePfx(cert, keys.Private, password: null);
|
return GeneratePfx(cert, keys.Private, password);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@ -1,5 +1,4 @@
|
|||||||
using FastGithub.Scanner;
|
using FastGithub.Scanner;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
@ -10,7 +9,7 @@ namespace FastGithub.ReverseProxy
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Github的dns解析的httpHandler
|
/// Github的dns解析的httpHandler
|
||||||
/// 使扫描索结果作为github的https请求的域名解析
|
/// 使扫描索结果作为github的https请求的域名解析
|
||||||
/// </summary>
|
/// </summary>
|
||||||
sealed class GithubDnsHttpHandler : DelegatingHandler
|
sealed class GithubDnsHttpHandler : DelegatingHandler
|
||||||
{
|
{
|
||||||
private readonly IGithubScanResults scanResults;
|
private readonly IGithubScanResults scanResults;
|
||||||
@ -19,9 +18,9 @@ namespace FastGithub.ReverseProxy
|
|||||||
/// Github的dns解析的httpHandler
|
/// Github的dns解析的httpHandler
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="scanResults"></param>
|
/// <param name="scanResults"></param>
|
||||||
/// <param name="handler"></param>
|
/// <param name="innerHandler"></param>
|
||||||
public GithubDnsHttpHandler(IGithubScanResults scanResults, HttpMessageHandler handler)
|
public GithubDnsHttpHandler(IGithubScanResults scanResults, HttpMessageHandler innerHandler)
|
||||||
: base(handler)
|
: base(innerHandler)
|
||||||
{
|
{
|
||||||
this.scanResults = scanResults;
|
this.scanResults = scanResults;
|
||||||
}
|
}
|
||||||
|
|||||||
58
FastGithub.ReverseProxy/LifetimeHttpHandler.cs
Normal file
58
FastGithub.ReverseProxy/LifetimeHttpHandler.cs
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
using System;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
|
namespace FastGithub.ReverseProxy
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 表示自主管理生命周期的的HttpMessageHandler
|
||||||
|
/// </summary>
|
||||||
|
[DebuggerDisplay("LifeTime = {lifeTime}")]
|
||||||
|
sealed class LifetimeHttpHandler : DelegatingHandler
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 生命周期
|
||||||
|
/// </summary>
|
||||||
|
private readonly TimeSpan lifeTime;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Token取消源
|
||||||
|
/// </summary>
|
||||||
|
private readonly CancellationTokenSource tokenSource = new CancellationTokenSource();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 具有生命周期的HttpHandler
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="handler">HttpHandler</param>
|
||||||
|
/// <param name="lifeTime">拦截器的生命周期</param>
|
||||||
|
/// <param name="deactivateAction">失效回调</param>
|
||||||
|
/// <exception cref="ArgumentNullException"></exception>
|
||||||
|
public LifetimeHttpHandler(HttpMessageHandler handler, TimeSpan lifeTime, Action<LifetimeHttpHandler> deactivateAction)
|
||||||
|
: base(handler)
|
||||||
|
{
|
||||||
|
if (deactivateAction == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(deactivateAction));
|
||||||
|
}
|
||||||
|
|
||||||
|
this.lifeTime = lifeTime;
|
||||||
|
|
||||||
|
this.tokenSource.Token.Register(() =>
|
||||||
|
{
|
||||||
|
this.tokenSource.Dispose();
|
||||||
|
deactivateAction.Invoke(this);
|
||||||
|
}, useSynchronizationContext: false);
|
||||||
|
|
||||||
|
this.tokenSource.CancelAfter(lifeTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 这里不释放资源
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="disposing"></param>
|
||||||
|
protected override void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
144
FastGithub.ReverseProxy/LifetimeHttpHandlerCleaner.cs
Normal file
144
FastGithub.ReverseProxy/LifetimeHttpHandlerCleaner.cs
Normal file
@ -0,0 +1,144 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace FastGithub.ReverseProxy
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 表示LifetimeHttpHandler清理器
|
||||||
|
/// </summary>
|
||||||
|
sealed class LifetimeHttpHandlerCleaner
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 当前监视生命周期的记录的数量
|
||||||
|
/// </summary>
|
||||||
|
private int trackingEntryCount = 0;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 监视生命周期的记录队列
|
||||||
|
/// </summary>
|
||||||
|
private readonly ConcurrentQueue<TrackingEntry> trackingEntries = new();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取或设置清理的时间间隔
|
||||||
|
/// 默认10s
|
||||||
|
/// </summary>
|
||||||
|
public TimeSpan CleanupInterval { get; set; } = TimeSpan.FromSeconds(10d);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 添加要清除的httpHandler
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="handler">httpHandler</param>
|
||||||
|
public void Add(LifetimeHttpHandler handler)
|
||||||
|
{
|
||||||
|
var entry = new TrackingEntry(handler);
|
||||||
|
this.trackingEntries.Enqueue(entry);
|
||||||
|
|
||||||
|
// 从0变为1,要启动清理作业
|
||||||
|
if (Interlocked.Increment(ref this.trackingEntryCount) == 1)
|
||||||
|
{
|
||||||
|
this.StartCleanup();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 启动清理作业
|
||||||
|
/// </summary>
|
||||||
|
private async void StartCleanup()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
await Task
|
||||||
|
.Delay(this.CleanupInterval)
|
||||||
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
|
if (this.Cleanup() == true)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
// 这是应该不可能发生的
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 清理失效的拦截器
|
||||||
|
/// 返回是否完全清理
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
private bool Cleanup()
|
||||||
|
{
|
||||||
|
var cleanCount = this.trackingEntries.Count;
|
||||||
|
for (var i = 0; i < cleanCount; i++)
|
||||||
|
{
|
||||||
|
this.trackingEntries.TryDequeue(out var entry);
|
||||||
|
Debug.Assert(entry != null);
|
||||||
|
|
||||||
|
if (entry.CanDispose == false)
|
||||||
|
{
|
||||||
|
this.trackingEntries.Enqueue(entry);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
entry.Dispose();
|
||||||
|
if (Interlocked.Decrement(ref this.trackingEntryCount) == 0)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 表示监视生命周期的记录
|
||||||
|
/// </summary>
|
||||||
|
private class TrackingEntry : IDisposable
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 用于释放资源的对象
|
||||||
|
/// </summary>
|
||||||
|
private readonly IDisposable disposable;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 监视对象的弱引用
|
||||||
|
/// </summary>
|
||||||
|
private readonly WeakReference weakReference;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取是否可以释放资源
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
public bool CanDispose
|
||||||
|
{
|
||||||
|
get => this.weakReference.IsAlive == false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 监视生命周期的记录
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="handler">激活状态的httpHandler</param>
|
||||||
|
public TrackingEntry(LifetimeHttpHandler handler)
|
||||||
|
{
|
||||||
|
this.disposable = handler.InnerHandler!;
|
||||||
|
this.weakReference = new WeakReference(handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
this.disposable.Dispose();
|
||||||
|
}
|
||||||
|
catch (Exception) { }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -7,6 +7,9 @@ using System.Security.Cryptography.X509Certificates;
|
|||||||
|
|
||||||
namespace FastGithub
|
namespace FastGithub
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// ListenOptions扩展
|
||||||
|
/// </summary>
|
||||||
public static class ListenOptionsHttpsExtensions
|
public static class ListenOptionsHttpsExtensions
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -21,16 +24,16 @@ namespace FastGithub
|
|||||||
return listenOptions.UseHttps(https =>
|
return listenOptions.UseHttps(https =>
|
||||||
{
|
{
|
||||||
var certs = new ConcurrentDictionary<string, X509Certificate2>();
|
var certs = new ConcurrentDictionary<string, X509Certificate2>();
|
||||||
https.ServerCertificateSelector = (ctx, domain) =>
|
https.ServerCertificateSelector = (ctx, domain) => certs.GetOrAdd(domain, CreateCert);
|
||||||
certs.GetOrAdd(domain, d =>
|
|
||||||
CertGenerator.Generate(
|
|
||||||
new[] { d },
|
|
||||||
2048,
|
|
||||||
DateTime.Today.AddYears(-1),
|
|
||||||
DateTime.Today.AddYears(1),
|
|
||||||
caPublicCerPath,
|
|
||||||
caPrivateKeyPath));
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
X509Certificate2 CreateCert(string domain)
|
||||||
|
{
|
||||||
|
var domains = new[] { domain };
|
||||||
|
var validFrom = DateTime.Today.AddYears(-1);
|
||||||
|
var validTo = DateTime.Today.AddYears(10);
|
||||||
|
return CertGenerator.Generate(domains, 2048, validFrom, validTo, caPublicCerPath, caPrivateKeyPath);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,62 +0,0 @@
|
|||||||
using FastGithub.Scanner;
|
|
||||||
using System.IO;
|
|
||||||
using System.Net.Http;
|
|
||||||
using System.Net.Security;
|
|
||||||
using System.Net.Sockets;
|
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace FastGithub.ReverseProxy
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 去掉Sni的HttpClient
|
|
||||||
/// </summary>
|
|
||||||
sealed class NoneSniHttpClient : HttpMessageInvoker
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 去掉Sni的HttpClient
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="githubScanResults"></param>
|
|
||||||
public NoneSniHttpClient(IGithubScanResults githubScanResults)
|
|
||||||
: base(CreateNoneSniHttpHandler(githubScanResults), disposeHandler: false)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 去掉Sni的HttpHandler
|
|
||||||
/// </summary>
|
|
||||||
private static HttpMessageHandler CreateNoneSniHttpHandler(IGithubScanResults githubScanResults)
|
|
||||||
{
|
|
||||||
var httpHandler = new SocketsHttpHandler
|
|
||||||
{
|
|
||||||
AllowAutoRedirect = false,
|
|
||||||
UseCookies = false,
|
|
||||||
UseProxy = false,
|
|
||||||
ConnectCallback = ConnectCallback
|
|
||||||
};
|
|
||||||
|
|
||||||
return new GithubDnsHttpHandler(githubScanResults, httpHandler);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 连接回调
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="context"></param>
|
|
||||||
/// <param name="cancellationToken"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
private static async ValueTask<Stream> ConnectCallback(SocketsHttpConnectionContext context, CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
var socket = new Socket(SocketType.Stream, ProtocolType.Tcp);
|
|
||||||
await socket.ConnectAsync(context.DnsEndPoint, cancellationToken);
|
|
||||||
var stream = new NetworkStream(socket, ownsSocket: true);
|
|
||||||
if (context.InitialRequestMessage.Headers.Host == null)
|
|
||||||
{
|
|
||||||
return stream;
|
|
||||||
}
|
|
||||||
|
|
||||||
var sslStream = new SslStream(stream, leaveInnerStreamOpen: false, delegate { return true; });
|
|
||||||
await sslStream.AuthenticateAsClientAsync(string.Empty, null, false);
|
|
||||||
return sslStream;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
96
FastGithub.ReverseProxy/NoneSniHttpClientFactory.cs
Normal file
96
FastGithub.ReverseProxy/NoneSniHttpClientFactory.cs
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
using FastGithub.Scanner;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using System;
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Net.Security;
|
||||||
|
using System.Net.Sockets;
|
||||||
|
|
||||||
|
namespace FastGithub.ReverseProxy
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 禁用tls sni的HttpClient工厂
|
||||||
|
/// </summary>
|
||||||
|
[Service(ServiceLifetime.Singleton)]
|
||||||
|
sealed class NoneSniHttpClientFactory
|
||||||
|
{
|
||||||
|
private readonly IGithubScanResults githubScanResults;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 生命周期
|
||||||
|
/// </summary>
|
||||||
|
private readonly TimeSpan lifeTime = TimeSpan.FromMinutes(2d);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 具有生命周期的httpHandler延时创建对象
|
||||||
|
/// </summary>
|
||||||
|
private Lazy<LifetimeHttpHandler> lifeTimeHttpHandlerLazy;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// HttpHandler清理器
|
||||||
|
/// </summary>
|
||||||
|
private readonly LifetimeHttpHandlerCleaner httpHandlerCleaner = new LifetimeHttpHandlerCleaner();
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 禁用tls sni的HttpClient工厂
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="githubScanResults"></param>
|
||||||
|
public NoneSniHttpClientFactory(IGithubScanResults githubScanResults)
|
||||||
|
{
|
||||||
|
this.githubScanResults = githubScanResults;
|
||||||
|
this.lifeTimeHttpHandlerLazy = new Lazy<LifetimeHttpHandler>(this.CreateHttpHandler, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 创建HttpClient
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
public HttpMessageInvoker CreateHttpClient()
|
||||||
|
{
|
||||||
|
var handler = this.lifeTimeHttpHandlerLazy.Value;
|
||||||
|
return new HttpMessageInvoker(handler, disposeHandler: false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 创建具有生命周期控制的httpHandler
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
private LifetimeHttpHandler CreateHttpHandler()
|
||||||
|
{
|
||||||
|
var noneSniHandler = new SocketsHttpHandler
|
||||||
|
{
|
||||||
|
Proxy = null,
|
||||||
|
UseProxy = false,
|
||||||
|
AllowAutoRedirect = false,
|
||||||
|
ConnectCallback = async (ctx, ct) =>
|
||||||
|
{
|
||||||
|
var socket = new Socket(SocketType.Stream, ProtocolType.Tcp);
|
||||||
|
await socket.ConnectAsync(ctx.DnsEndPoint, ct);
|
||||||
|
var stream = new NetworkStream(socket, ownsSocket: true);
|
||||||
|
if (ctx.InitialRequestMessage.Headers.Host == null)
|
||||||
|
{
|
||||||
|
return stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
var sslStream = new SslStream(stream, leaveInnerStreamOpen: false, delegate { return true; });
|
||||||
|
await sslStream.AuthenticateAsClientAsync(string.Empty, null, false);
|
||||||
|
return sslStream;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var dnsHandler = new GithubDnsHttpHandler(this.githubScanResults, noneSniHandler);
|
||||||
|
return new LifetimeHttpHandler(dnsHandler, this.lifeTime, this.OnHttpHandlerDeactivate);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 当有httpHandler失效时
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="handler">httpHandler</param>
|
||||||
|
private void OnHttpHandlerDeactivate(LifetimeHttpHandler handler)
|
||||||
|
{
|
||||||
|
// 切换激活状态的记录的实例
|
||||||
|
this.lifeTimeHttpHandlerLazy = new Lazy<LifetimeHttpHandler>(this.CreateHttpHandler, true);
|
||||||
|
this.httpHandlerCleaner.Add(handler);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -18,13 +18,15 @@ namespace FastGithub
|
|||||||
public static IApplicationBuilder UseGithubReverseProxy(this IApplicationBuilder app)
|
public static IApplicationBuilder UseGithubReverseProxy(this IApplicationBuilder app)
|
||||||
{
|
{
|
||||||
var httpForwarder = app.ApplicationServices.GetRequiredService<IHttpForwarder>();
|
var httpForwarder = app.ApplicationServices.GetRequiredService<IHttpForwarder>();
|
||||||
var httpClient = app.ApplicationServices.GetRequiredService<NoneSniHttpClient>();
|
var httpClientFactory = app.ApplicationServices.GetRequiredService<NoneSniHttpClientFactory>();
|
||||||
|
|
||||||
app.Use(next => async context =>
|
app.Use(next => async context =>
|
||||||
{
|
{
|
||||||
var hostString = context.Request.Host;
|
var hostString = context.Request.Host;
|
||||||
var port = hostString.Port ?? 443;
|
var port = hostString.Port ?? 443;
|
||||||
var destinationPrefix = $"http://{hostString.Host}:{port}/";
|
var destinationPrefix = $"http://{hostString.Host}:{port}/";
|
||||||
|
|
||||||
|
var httpClient = httpClientFactory.CreateHttpClient();
|
||||||
await httpForwarder.SendAsync(context, destinationPrefix, httpClient);
|
await httpForwarder.SendAsync(context, destinationPrefix, httpClient);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,4 @@
|
|||||||
using FastGithub.ReverseProxy;
|
using Microsoft.Extensions.Configuration;
|
||||||
using Microsoft.Extensions.Configuration;
|
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
namespace FastGithub
|
namespace FastGithub
|
||||||
@ -12,13 +11,15 @@ namespace FastGithub
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// gitub反向代理
|
/// gitub反向代理
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="services"></param>
|
/// <param name="services"></param>
|
||||||
|
/// <param name="configuration"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static IServiceCollection AddGithubReverseProxy(this IServiceCollection services)
|
public static IServiceCollection AddGithubReverseProxy(this IServiceCollection services, IConfiguration configuration)
|
||||||
{
|
{
|
||||||
services.AddHttpForwarder();
|
var assembly = typeof(ReverseProxyServiceCollectionExtensions).Assembly;
|
||||||
services.AddSingleton<NoneSniHttpClient>();
|
return services
|
||||||
return services;
|
.AddServiceAndOptions(assembly, configuration)
|
||||||
|
.AddHttpForwarder();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -60,7 +60,7 @@ namespace FastGithub.Scanner.LookupProviders
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var httpClient = this.httpClientFactory.CreateClient(nameof(FastGithub));
|
var httpClient = this.httpClientFactory.CreateClient(nameof(Scanner));
|
||||||
var meta = await GetMetaAsync(httpClient, setting.MetaUri, cancellationToken);
|
var meta = await GetMetaAsync(httpClient, setting.MetaUri, cancellationToken);
|
||||||
if (meta != null)
|
if (meta != null)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -57,7 +57,7 @@ namespace FastGithub.Scanner.LookupProviders
|
|||||||
return Enumerable.Empty<DomainAddress>();
|
return Enumerable.Empty<DomainAddress>();
|
||||||
}
|
}
|
||||||
|
|
||||||
var httpClient = this.httpClientFactory.CreateClient(nameof(FastGithub));
|
var httpClient = this.httpClientFactory.CreateClient(nameof(Scanner));
|
||||||
var result = new HashSet<DomainAddress>();
|
var result = new HashSet<DomainAddress>();
|
||||||
foreach (var domain in domains)
|
foreach (var domain in domains)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -64,7 +64,7 @@ namespace FastGithub.Scanner.ScanMiddlewares
|
|||||||
using var timeoutTokenSource = new CancellationTokenSource(timeout);
|
using var timeoutTokenSource = new CancellationTokenSource(timeout);
|
||||||
using var linkedTokenSource = CancellationTokenSource.CreateLinkedTokenSource(timeoutTokenSource.Token, context.CancellationToken);
|
using var linkedTokenSource = CancellationTokenSource.CreateLinkedTokenSource(timeoutTokenSource.Token, context.CancellationToken);
|
||||||
|
|
||||||
var httpClient = this.httpClientFactory.CreateClient(nameof(FastGithub));
|
var httpClient = this.httpClientFactory.CreateClient(nameof(Scanner));
|
||||||
using var response = await httpClient.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, linkedTokenSource.Token);
|
using var response = await httpClient.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, linkedTokenSource.Token);
|
||||||
|
|
||||||
VerifyHttpsResponse(context.Domain, response);
|
VerifyHttpsResponse(context.Domain, response);
|
||||||
|
|||||||
@ -26,8 +26,9 @@ namespace FastGithub
|
|||||||
var defaultUserAgent = new ProductInfoHeaderValue(assembly.GetName().Name ?? nameof(FastGithub), assembly.GetName().Version?.ToString());
|
var defaultUserAgent = new ProductInfoHeaderValue(assembly.GetName().Name ?? nameof(FastGithub), assembly.GetName().Version?.ToString());
|
||||||
|
|
||||||
services
|
services
|
||||||
.AddHttpClient(nameof(FastGithub))
|
.AddHttpClient(nameof(Scanner))
|
||||||
.SetHandlerLifetime(TimeSpan.FromMinutes(5d))
|
.SetHandlerLifetime(TimeSpan.FromMinutes(5d))
|
||||||
|
.AddHttpMessageHandler<GithubDnsHttpHandler>()
|
||||||
.ConfigureHttpClient(httpClient =>
|
.ConfigureHttpClient(httpClient =>
|
||||||
{
|
{
|
||||||
httpClient.Timeout = TimeSpan.FromSeconds(10d);
|
httpClient.Timeout = TimeSpan.FromSeconds(10d);
|
||||||
@ -53,8 +54,7 @@ namespace FastGithub
|
|||||||
await sslStream.AuthenticateAsClientAsync(string.Empty, null, false);
|
await sslStream.AuthenticateAsClientAsync(string.Empty, null, false);
|
||||||
return sslStream;
|
return sslStream;
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
.AddHttpMessageHandler<GithubDnsHttpHandler>();
|
|
||||||
|
|
||||||
return services
|
return services
|
||||||
.AddMemoryCache()
|
.AddMemoryCache()
|
||||||
|
|||||||
@ -38,7 +38,7 @@ namespace FastGithub
|
|||||||
{
|
{
|
||||||
services.AddAppUpgrade();
|
services.AddAppUpgrade();
|
||||||
services.AddGithubDns(ctx.Configuration);
|
services.AddGithubDns(ctx.Configuration);
|
||||||
services.AddGithubReverseProxy();
|
services.AddGithubReverseProxy(ctx.Configuration);
|
||||||
services.AddGithubScanner(ctx.Configuration);
|
services.AddGithubScanner(ctx.Configuration);
|
||||||
})
|
})
|
||||||
.ConfigureWebHostDefaults(web =>
|
.ConfigureWebHostDefaults(web =>
|
||||||
@ -50,9 +50,7 @@ namespace FastGithub
|
|||||||
|
|
||||||
web.UseKestrel(kestrel =>
|
web.UseKestrel(kestrel =>
|
||||||
{
|
{
|
||||||
const string caPublicCerPath = "FastGithub_CA.cer";
|
kestrel.ListenAnyIP(443, listen => listen.UseGithubHttps("FastGithub_CA.cer", "FastGithub_CA.key"));
|
||||||
const string caPrivateKeyPath = "FastGithub_CA.key";
|
|
||||||
kestrel.ListenLocalhost(443, listen => listen.UseGithubHttps(caPublicCerPath, caPrivateKeyPath));
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,7 +2,8 @@
|
|||||||
"Dns": {
|
"Dns": {
|
||||||
"UpStream": "114.114.114.114", // 上游dns
|
"UpStream": "114.114.114.114", // 上游dns
|
||||||
"GithubTTL": "00:10:00", // github相关域名解析结果的存活时长
|
"GithubTTL": "00:10:00", // github相关域名解析结果的存活时长
|
||||||
"SetToLocalMachine": true // 是否设置本机使用此dns(仅支持windows)
|
"SetToLocalMachine": true, // 是否设置本机使用此dns(仅支持windows)
|
||||||
|
"UseReverseProxy": true // 是否使用反向代理访问github
|
||||||
},
|
},
|
||||||
"Lookup": { // ip查找
|
"Lookup": { // ip查找
|
||||||
"IPAddressComProvider": {
|
"IPAddressComProvider": {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user