diff --git a/src/BD.WTTS.Client.Plugins.Accelerator.ReverseProxy/Extensions/ListenOptionsExtensions.cs b/src/BD.WTTS.Client.Plugins.Accelerator.ReverseProxy/Extensions/ListenOptionsExtensions.cs index b6e625ade..f33075b35 100644 --- a/src/BD.WTTS.Client.Plugins.Accelerator.ReverseProxy/Extensions/ListenOptionsExtensions.cs +++ b/src/BD.WTTS.Client.Plugins.Accelerator.ReverseProxy/Extensions/ListenOptionsExtensions.cs @@ -1,4 +1,6 @@ // ReSharper disable once CheckNamespace +using System.Security.Authentication; + namespace Microsoft.Extensions.DependencyInjection; static partial class ListenOptionsExtensions @@ -38,33 +40,35 @@ static partial class ListenOptionsExtensions public static ListenOptions UseTls(this ListenOptions listen) { var certService = listen.ApplicationServices.GetRequiredService(); - //certService.CreateCaCertIfNotExists(); - //certService.InstallAndTrustCaCert(); - return listen.UseTls(https => + listen.Use(next => context => TlsInvadeMiddleware.InvokeAsync(next, context)); + listen.UseHttps(new TlsHandshakeCallbackOptions { - https.ServerCertificateSelector = (ctx, domain) => + OnConnection = ctx => { - var cert = certService.GetOrCreateServerCert(domain); - return cert; - }; + var domain = ctx.ClientHelloInfo.ServerName; + var o = new SslServerAuthenticationOptions + { + ServerCertificate = certService.GetOrCreateServerCert(domain), + }; + return ValueTask.FromResult(o); + }, }); - } - - /// - /// 使用 Tls 中间件 - /// - /// - /// https配置 - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - static ListenOptions UseTls(this ListenOptions listen, Action configureOptions) - { - var invadeMiddleware = listen.ApplicationServices.GetRequiredService(); - var restoreMiddleware = listen.ApplicationServices.GetRequiredService(); - - listen.Use(next => context => invadeMiddleware.InvokeAsync(next, context)); - listen.UseHttps(configureOptions); - listen.Use(next => context => restoreMiddleware.InvokeAsync(next, context)); + listen.Use(next => context => TlsRestoreMiddleware.InvokeAsync(next, context)); return listen; } + + ///// + ///// 使用 Tls 中间件 + ///// + ///// + ///// https配置 + ///// + //[MethodImpl(MethodImplOptions.AggressiveInlining)] + //static ListenOptions UseTls(this ListenOptions listen, Action configureOptions) + //{ + // listen.Use(next => context => TlsInvadeMiddleware.InvokeAsync(next, context)); + // listen.UseHttps(configureOptions); + // listen.Use(next => context => TlsRestoreMiddleware.InvokeAsync(next, context)); + // return listen; + //} } diff --git a/src/BD.WTTS.Client.Plugins.Accelerator.ReverseProxy/Extensions/ServiceCollectionExtensions.cs b/src/BD.WTTS.Client.Plugins.Accelerator.ReverseProxy/Extensions/ServiceCollectionExtensions.cs index 99b4d8c45..01dd3e197 100644 --- a/src/BD.WTTS.Client.Plugins.Accelerator.ReverseProxy/Extensions/ServiceCollectionExtensions.cs +++ b/src/BD.WTTS.Client.Plugins.Accelerator.ReverseProxy/Extensions/ServiceCollectionExtensions.cs @@ -124,8 +124,8 @@ public static partial class ServiceCollectionExtensions .AddSingleton() // tls - .AddSingleton() - .AddSingleton() + //.AddSingleton() + //.AddSingleton() //http .AddSingleton() diff --git a/src/BD.WTTS.Client.Plugins.Accelerator.ReverseProxy/Services.Implementation/HttpServer/Certificates/CertService.cs b/src/BD.WTTS.Client.Plugins.Accelerator.ReverseProxy/Services.Implementation/HttpServer/Certificates/CertService.cs index 2d3b73053..ada4a0bc6 100644 --- a/src/BD.WTTS.Client.Plugins.Accelerator.ReverseProxy/Services.Implementation/HttpServer/Certificates/CertService.cs +++ b/src/BD.WTTS.Client.Plugins.Accelerator.ReverseProxy/Services.Implementation/HttpServer/Certificates/CertService.cs @@ -69,15 +69,19 @@ sealed class CertService var key = $"{nameof(CertService)}:{domain}"; return serverCertCache.GetOrCreate(key, GetOrCreateCert); - // 生成域名的1年证书 + // 生成域名的 1 年证书 X509Certificate2 GetOrCreateCert(ICacheEntry entry) { var domains = GetDomains(domain).Distinct(); - var validFrom = DateTime.Today.AddDays(-1); - var validTo = DateTime.Today.AddYears(1); + DateTimeOffset today = DateTime.Today; + var validFrom = today.AddDays(-1); + var validTo = today.AddYears(1); entry.SetAbsoluteExpiration(validTo); - return CertGenerator.GenerateByCaPfx(domains, validFrom, validTo, CaPfxFilePath); + using var serverCert = CertGenerator.GenerateByCaPfx(domains, validFrom, validTo, CaPfxFilePath); + var serverCertPfx = serverCert.Export(X509ContentType.Pfx); + // 将生成的证书导出后重新创建一个 + return new X509Certificate2(serverCertPfx); } } diff --git a/src/BD.WTTS.Client.Plugins.Accelerator.ReverseProxy/Services.Implementation/HttpServer/Middleware/FakeTlsConnectionFeature.cs b/src/BD.WTTS.Client.Plugins.Accelerator.ReverseProxy/Services.Implementation/HttpServer/Middleware/FakeTlsConnectionFeature.cs index 3a66ba69b..770dfc6ce 100644 --- a/src/BD.WTTS.Client.Plugins.Accelerator.ReverseProxy/Services.Implementation/HttpServer/Middleware/FakeTlsConnectionFeature.cs +++ b/src/BD.WTTS.Client.Plugins.Accelerator.ReverseProxy/Services.Implementation/HttpServer/Middleware/FakeTlsConnectionFeature.cs @@ -9,12 +9,12 @@ sealed class FakeTlsConnectionFeature : ITlsConnectionFeature public X509Certificate2? ClientCertificate { - get => throw new NotImplementedException(); - set => throw new NotImplementedException(); + get => default; + set { } } public Task GetClientCertificateAsync(CancellationToken cancellationToken) { - throw new NotImplementedException(); + return Task.FromResult(default); } } \ No newline at end of file diff --git a/src/BD.WTTS.Client.Plugins.Accelerator.ReverseProxy/Services.Implementation/HttpServer/Middleware/HttpProxyMiddleware.cs b/src/BD.WTTS.Client.Plugins.Accelerator.ReverseProxy/Services.Implementation/HttpServer/Middleware/HttpProxyMiddleware.cs index f15f8503b..4a70946be 100644 --- a/src/BD.WTTS.Client.Plugins.Accelerator.ReverseProxy/Services.Implementation/HttpServer/Middleware/HttpProxyMiddleware.cs +++ b/src/BD.WTTS.Client.Plugins.Accelerator.ReverseProxy/Services.Implementation/HttpServer/Middleware/HttpProxyMiddleware.cs @@ -9,8 +9,6 @@ namespace BD.WTTS.Services.Implementation; sealed class HttpProxyMiddleware { readonly HttpParser httpParser = new(); - readonly byte[] http200 = Encoding.ASCII.GetBytes("HTTP/1.1 200 Connection Established\r\n\r\n"); - readonly byte[] http400 = Encoding.ASCII.GetBytes("HTTP/1.1 400 Bad Request\r\n\r\n"); /// /// 执行中间件 @@ -20,55 +18,79 @@ sealed class HttpProxyMiddleware /// public async Task InvokeAsync(ConnectionDelegate next, ConnectionContext context) { - var result = await context.Transport.Input.ReadAsync(); - var httpRequest = GetHttpRequestHandler(result, out var consumed); - - // 协议错误 - if (consumed == 0L) + var input = context.Transport.Input; + var output = context.Transport.Output; + var request = new HttpRequestHandler(); + while (context.ConnectionClosed.IsCancellationRequested == false) { - await context.Transport.Output.WriteAsync(http400, context.ConnectionClosed); - } - else - { - // 隧道代理连接请求 - if (httpRequest.ProxyProtocol == ProxyProtocol.TunnelProxy) + var result = await input.ReadAsync(); + if (result.IsCanceled) { - var position = result.Buffer.GetPosition(consumed); - context.Transport.Input.AdvanceTo(position); - await context.Transport.Output.WriteAsync(http200, context.ConnectionClosed); - } - else - { - var position = result.Buffer.Start; - context.Transport.Input.AdvanceTo(position); + break; } - context.Features.Set(httpRequest); - await next(context); + try + { + if (ParseRequest(result, request, out var consumed)) + { + if (request.ProxyProtocol == ProxyProtocol.TunnelProxy) + { + input.AdvanceTo(consumed); + await output.WriteAsync( + "HTTP/1.1 400 Bad Request\r\n\r\n"u8.ToArray(), + context.ConnectionClosed); + } + else + { + input.AdvanceTo(result.Buffer.Start); + } + + context.Features.Set(request); + await next(context); + + break; + } + else + { + input.AdvanceTo(result.Buffer.Start, result.Buffer.End); + } + + if (result.IsCompleted) + { + break; + } + } + catch (Exception) + { + await output.WriteAsync( + "HTTP/1.1 200 Connection Established\r\n\r\n"u8.ToArray(), + context.ConnectionClosed); + break; + } } } - HttpRequestHandler GetHttpRequestHandler(ReadResult result, out long consumed) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + bool ParseRequest(ReadResult result, HttpRequestHandler request, out SequencePosition consumed) { - var handler = new HttpRequestHandler(); var reader = new SequenceReader(result.Buffer); - - if (httpParser.ParseRequestLine(handler, ref reader) && - httpParser.ParseHeaders(handler, ref reader)) + if (httpParser.ParseRequestLine(request, ref reader) && + httpParser.ParseHeaders(request, ref reader)) { - consumed = reader.Consumed; + consumed = reader.Position; + return true; } else { - consumed = 0L; + consumed = default; + return false; } - return handler; } /// /// 代理请求处理器 /// - private class HttpRequestHandler : IHttpRequestLineHandler, IHttpHeadersHandler, IHttpProxyFeature + sealed class HttpRequestHandler : IHttpRequestLineHandler, IHttpHeadersHandler, IHttpProxyFeature { private AspNetCoreHttpMethod method; diff --git a/src/BD.WTTS.Client.Plugins.Accelerator.ReverseProxy/Services.Implementation/HttpServer/Middleware/TlsInvadeMiddleware.cs b/src/BD.WTTS.Client.Plugins.Accelerator.ReverseProxy/Services.Implementation/HttpServer/Middleware/TlsInvadeMiddleware.cs index e0e247c5f..ac32a68c4 100644 --- a/src/BD.WTTS.Client.Plugins.Accelerator.ReverseProxy/Services.Implementation/HttpServer/Middleware/TlsInvadeMiddleware.cs +++ b/src/BD.WTTS.Client.Plugins.Accelerator.ReverseProxy/Services.Implementation/HttpServer/Middleware/TlsInvadeMiddleware.cs @@ -6,7 +6,7 @@ namespace BD.WTTS.Services.Implementation; /// /// Https 入侵中间件 /// -sealed class TlsInvadeMiddleware +static class TlsInvadeMiddleware { /// /// 执行中间件 @@ -14,7 +14,7 @@ sealed class TlsInvadeMiddleware /// /// /// - public async Task InvokeAsync(ConnectionDelegate next, ConnectionContext context) + public static async Task InvokeAsync(ConnectionDelegate next, ConnectionContext context) { // 连接不是 tls if (await IsTlsConnectionAsync(context) == false) diff --git a/src/BD.WTTS.Client.Plugins.Accelerator.ReverseProxy/Services.Implementation/HttpServer/Middleware/TlsRestoreMiddleware.cs b/src/BD.WTTS.Client.Plugins.Accelerator.ReverseProxy/Services.Implementation/HttpServer/Middleware/TlsRestoreMiddleware.cs index 6822112da..4572aa160 100644 --- a/src/BD.WTTS.Client.Plugins.Accelerator.ReverseProxy/Services.Implementation/HttpServer/Middleware/TlsRestoreMiddleware.cs +++ b/src/BD.WTTS.Client.Plugins.Accelerator.ReverseProxy/Services.Implementation/HttpServer/Middleware/TlsRestoreMiddleware.cs @@ -6,7 +6,7 @@ namespace BD.WTTS.Services.Implementation; /// /// Https 恢复中间件 /// -sealed class TlsRestoreMiddleware +static class TlsRestoreMiddleware { /// /// 执行中间件 @@ -14,7 +14,7 @@ sealed class TlsRestoreMiddleware /// /// /// - public async Task InvokeAsync(ConnectionDelegate next, ConnectionContext context) + public static async Task InvokeAsync(ConnectionDelegate next, ConnectionContext context) { if (context.Features.Get() == FakeTlsConnectionFeature.Instance) { diff --git a/src/BD.WTTS.Client.Plugins.Accelerator.ReverseProxy/Services.Implementation/LazyReverseProxyServiceImpl.cs b/src/BD.WTTS.Client.Plugins.Accelerator.ReverseProxy/Services.Implementation/LazyReverseProxyServiceImpl.cs index dc5d7dad2..a0ac69375 100644 --- a/src/BD.WTTS.Client.Plugins.Accelerator.ReverseProxy/Services.Implementation/LazyReverseProxyServiceImpl.cs +++ b/src/BD.WTTS.Client.Plugins.Accelerator.ReverseProxy/Services.Implementation/LazyReverseProxyServiceImpl.cs @@ -21,7 +21,7 @@ sealed class LazyReverseProxyServiceImpl : IReverseProxyService public void Dispose() => impl().Dispose(); - public FlowStatistics? GetFlowStatistics() => impl().GetFlowStatistics(); + public byte[]? GetFlowStatistics_Bytes() => impl().GetFlowStatistics_Bytes(); public async Task StartProxyAsync(byte[] reverseProxySettings) { diff --git a/src/BD.WTTS.Client.Plugins.Accelerator.ReverseProxy/Services.Implementation/YarpReverseProxyServiceImpl.Startup.cs b/src/BD.WTTS.Client.Plugins.Accelerator.ReverseProxy/Services.Implementation/YarpReverseProxyServiceImpl.Startup.cs index 6b1dcf2b6..9941c37c4 100644 --- a/src/BD.WTTS.Client.Plugins.Accelerator.ReverseProxy/Services.Implementation/YarpReverseProxyServiceImpl.Startup.cs +++ b/src/BD.WTTS.Client.Plugins.Accelerator.ReverseProxy/Services.Implementation/YarpReverseProxyServiceImpl.Startup.cs @@ -45,16 +45,6 @@ partial class YarpReverseProxyServiceImpl app.UseRequestLogging(); app.UseHttpReverseProxy(); - //app.UseRouting(); app.DisableRequestLogging(); - - //app.UseEndpoints(endpoint => - //{ - // endpoint.MapGet("/flowStatistics", context => - // { - // var flowStatistics = context.RequestServices.GetRequiredService().GetFlowStatistics(); - // return context.Response.WriteAsJsonAsync(flowStatistics); - // }); - //}); } } \ No newline at end of file diff --git a/src/BD.WTTS.Client.Plugins.Accelerator.ReverseProxy/Services.Implementation/YarpReverseProxyServiceImpl.cs b/src/BD.WTTS.Client.Plugins.Accelerator.ReverseProxy/Services.Implementation/YarpReverseProxyServiceImpl.cs index 3bd7eccb3..ebfbdb4ad 100644 --- a/src/BD.WTTS.Client.Plugins.Accelerator.ReverseProxy/Services.Implementation/YarpReverseProxyServiceImpl.cs +++ b/src/BD.WTTS.Client.Plugins.Accelerator.ReverseProxy/Services.Implementation/YarpReverseProxyServiceImpl.cs @@ -141,7 +141,13 @@ sealed partial class YarpReverseProxyServiceImpl : ReverseProxyServiceImpl, IRev app = null; } - public FlowStatistics? GetFlowStatistics() => app?.Services.GetService()?.GetFlowStatistics(); + public byte[]? GetFlowStatistics_Bytes() + { + var flowAnalyzer = app?.Services.GetService(); + var flowStatistics = flowAnalyzer?.GetFlowStatistics(); + var bytes = Serializable.SMP2(flowStatistics); + return bytes; + } // IDisposable diff --git a/src/BD.WTTS.Client.Plugins.Accelerator.ReverseProxy/Services/IReverseProxyService.cs b/src/BD.WTTS.Client.Plugins.Accelerator.ReverseProxy/Services/IReverseProxyService.cs index 2554f3887..92ca8bf7e 100644 --- a/src/BD.WTTS.Client.Plugins.Accelerator.ReverseProxy/Services/IReverseProxyService.cs +++ b/src/BD.WTTS.Client.Plugins.Accelerator.ReverseProxy/Services/IReverseProxyService.cs @@ -14,5 +14,17 @@ partial interface IReverseProxyService /// 获取流量统计信息 /// /// - FlowStatistics? GetFlowStatistics(); + byte[]? GetFlowStatistics_Bytes(); +} + +public static partial class ReverseProxyServiceExtensions +{ + /// + public static FlowStatistics? GetFlowStatistics(this IReverseProxyService s) + { + var bytes = s.GetFlowStatistics_Bytes(); + if (bytes == default) return default; + var flowStatistics = Serializable.DMP2(bytes); + return flowStatistics; + } } \ No newline at end of file