From d0dcd990fba85aa1902da4c092330f5ceb538120 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, 22 Sep 2021 13:07:43 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A080=E7=AB=AF=E5=8F=A3=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E5=8C=85=E6=95=B0=E6=8D=AE=E5=8C=85=E6=8B=A6=E6=88=AA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...everseProxyPort.cs => ReverseProxyPort.cs} | 34 +++---- FastGithub.HttpServer/HttpProxyMiddleware.cs | 2 +- .../KestrelServerOptionsExtensions.cs | 10 +- .../HttpInterceptHostedService.cs | 36 +++++++ FastGithub.PacketIntercept/HttpInterceptor.cs | 95 +++++++++++++++++++ .../HttpsInterceptHostedService.cs | 3 +- .../HttpsInterceptor.cs | 12 +-- .../ServiceCollectionExtensions.cs | 8 +- 8 files changed, 163 insertions(+), 37 deletions(-) rename FastGithub.Configuration/{HttpsReverseProxyPort.cs => ReverseProxyPort.cs} (55%) create mode 100644 FastGithub.PacketIntercept/HttpInterceptHostedService.cs create mode 100644 FastGithub.PacketIntercept/HttpInterceptor.cs diff --git a/FastGithub.Configuration/HttpsReverseProxyPort.cs b/FastGithub.Configuration/ReverseProxyPort.cs similarity index 55% rename from FastGithub.Configuration/HttpsReverseProxyPort.cs rename to FastGithub.Configuration/ReverseProxyPort.cs index eae78f8..9965fc1 100644 --- a/FastGithub.Configuration/HttpsReverseProxyPort.cs +++ b/FastGithub.Configuration/ReverseProxyPort.cs @@ -1,5 +1,4 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Net; using System.Net.NetworkInformation; using System.Net.Sockets; @@ -7,34 +6,27 @@ using System.Net.Sockets; namespace FastGithub.Configuration { /// - /// https反向代理端口 + /// 反向代理端口 /// - public static class HttpsReverseProxyPort + public static class ReverseProxyPort { /// - /// 获取端口值 + /// http端口 /// - public static int Value { get; } = GetAvailableTcpPort(AddressFamily.InterNetwork); + public static int Http { get; } = GetAvailableTcpPort(80); + + /// + /// https端口 + /// + public static int Https { get; } = GetAvailableTcpPort(443); /// /// 获取可用的随机Tcp端口 /// + /// /// /// - private static int GetAvailableTcpPort(AddressFamily addressFamily) - { - return OperatingSystem.IsWindows() - ? GetAvailableTcpPort(addressFamily, 443) - : GetAvailableTcpPort(addressFamily, 12345); - } - - /// - /// 获取可用的随机Tcp端口 - /// - /// - /// 最小值 - /// - private static int GetAvailableTcpPort(AddressFamily addressFamily, int min) + private static int GetAvailableTcpPort(int minValue, AddressFamily addressFamily = AddressFamily.InterNetwork) { var hashSet = new HashSet(); var tcpListeners = IPGlobalProperties.GetIPGlobalProperties().GetActiveTcpListeners(); @@ -47,7 +39,7 @@ namespace FastGithub.Configuration } } - for (var port = min; port < IPEndPoint.MaxPort; port++) + for (var port = minValue; port < IPEndPoint.MaxPort; port++) { if (hashSet.Contains(port) == false) { diff --git a/FastGithub.HttpServer/HttpProxyMiddleware.cs b/FastGithub.HttpServer/HttpProxyMiddleware.cs index ba5bdf0..1e0308b 100644 --- a/FastGithub.HttpServer/HttpProxyMiddleware.cs +++ b/FastGithub.HttpServer/HttpProxyMiddleware.cs @@ -148,7 +148,7 @@ namespace FastGithub.HttpServer // 目标端口为443,走https代理中间人 if (targetPort == HTTPS_PORT && targetHost != "ssh.github.com") { - return new IPEndPoint(IPAddress.Loopback, HttpsReverseProxyPort.Value); + return new IPEndPoint(IPAddress.Loopback, ReverseProxyPort.Https); } // dns优选 diff --git a/FastGithub.HttpServer/KestrelServerOptionsExtensions.cs b/FastGithub.HttpServer/KestrelServerOptionsExtensions.cs index 312c1e1..a686c17 100644 --- a/FastGithub.HttpServer/KestrelServerOptionsExtensions.cs +++ b/FastGithub.HttpServer/KestrelServerOptionsExtensions.cs @@ -69,11 +69,11 @@ namespace FastGithub /// public static void ListenHttpReverseProxy(this KestrelServerOptions kestrel) { - const int HTTP_PORT = 80; - if (CanListenTcp(HTTP_PORT) == true) + var httpPort = ReverseProxyPort.Http; + if (CanListenTcp(httpPort) == true) { - kestrel.Listen(IPAddress.Loopback, HTTP_PORT); - kestrel.GetLogger().LogInformation($"已监听http://{IPAddress.Loopback}:{HTTP_PORT},http反向代理服务启动完成"); + kestrel.Listen(IPAddress.Loopback, httpPort); + kestrel.GetLogger().LogInformation($"已监听http://{IPAddress.Loopback}:{httpPort},http反向代理服务启动完成"); } } @@ -85,7 +85,7 @@ namespace FastGithub /// public static int ListenHttpsReverseProxy(this KestrelServerOptions kestrel) { - var httpsPort = HttpsReverseProxyPort.Value; + var httpsPort = ReverseProxyPort.Https; if (CanListenTcp(httpsPort) == false) { throw new FastGithubException($"tcp端口{httpsPort}已经被其它进程占用"); diff --git a/FastGithub.PacketIntercept/HttpInterceptHostedService.cs b/FastGithub.PacketIntercept/HttpInterceptHostedService.cs new file mode 100644 index 0000000..a2308df --- /dev/null +++ b/FastGithub.PacketIntercept/HttpInterceptHostedService.cs @@ -0,0 +1,36 @@ +using Microsoft.Extensions.Hosting; +using System.Runtime.Versioning; +using System.Threading; +using System.Threading.Tasks; + +namespace FastGithub.Dns +{ + /// + /// http拦截后台服务 + /// + [SupportedOSPlatform("windows")] + sealed class HttpInterceptHostedService : BackgroundService + { + private readonly HttpInterceptor httpsInterceptor; + + /// + /// http拦截后台服务 + /// + /// + public HttpInterceptHostedService(HttpInterceptor httpInterceptor) + { + this.httpsInterceptor = httpInterceptor; + } + + /// + /// https后台 + /// + /// + /// + protected override async Task ExecuteAsync(CancellationToken stoppingToken) + { + await Task.Yield(); + this.httpsInterceptor.Intercept(stoppingToken); + } + } +} diff --git a/FastGithub.PacketIntercept/HttpInterceptor.cs b/FastGithub.PacketIntercept/HttpInterceptor.cs new file mode 100644 index 0000000..9cbb51d --- /dev/null +++ b/FastGithub.PacketIntercept/HttpInterceptor.cs @@ -0,0 +1,95 @@ +using FastGithub.Configuration; +using Microsoft.Extensions.Logging; +using System; +using System.Buffers.Binary; +using System.Runtime.Versioning; +using System.Threading; +using WinDivertSharp; + +namespace FastGithub.Dns +{ + /// + /// http拦截器 + /// + [SupportedOSPlatform("windows")] + sealed class HttpInterceptor + { + private readonly ILogger logger; + private readonly ushort http80Port = BinaryPrimitives.ReverseEndianness((ushort)80); + private readonly ushort httpReverseProxyPort = BinaryPrimitives.ReverseEndianness((ushort)ReverseProxyPort.Http); + + /// + /// http拦截器 + /// + /// + public HttpInterceptor(ILogger logger) + { + this.logger = logger; + } + + /// + /// 拦截80端口的数据包 + /// + /// + public void Intercept(CancellationToken cancellationToken) + { + if (ReverseProxyPort.Http == 80) + { + return; + } + + var filter = $"loopback and (tcp.DstPort == 80 or tcp.SrcPort == {ReverseProxyPort.Http})"; + var handle = WinDivert.WinDivertOpen(filter, WinDivertLayer.Network, 0, WinDivertOpenFlags.None); + if (handle == IntPtr.Zero) + { + return; + } + + cancellationToken.Register(hwnd => WinDivert.WinDivertClose((IntPtr)hwnd!), handle); + + var packetLength = 0U; + using var winDivertBuffer = new WinDivertBuffer(); + var winDivertAddress = new WinDivertAddress(); + + while (cancellationToken.IsCancellationRequested == false) + { + if (WinDivert.WinDivertRecv(handle, winDivertBuffer, ref winDivertAddress, ref packetLength)) + { + try + { + this.ModifyHttpsPacket(winDivertBuffer, ref winDivertAddress, ref packetLength); + } + catch (Exception ex) + { + this.logger.LogWarning(ex.Message); + } + finally + { + WinDivert.WinDivertSend(handle, winDivertBuffer, packetLength, ref winDivertAddress); + } + } + } + } + + /// + /// 443端口转发到https反向代理端口 + /// + /// + /// + /// + unsafe private void ModifyHttpsPacket(WinDivertBuffer winDivertBuffer, ref WinDivertAddress winDivertAddress, ref uint packetLength) + { + var packet = WinDivert.WinDivertHelperParsePacket(winDivertBuffer, packetLength); + if (packet.TcpHeader->DstPort == http80Port) + { + packet.TcpHeader->DstPort = this.httpReverseProxyPort; + } + else + { + packet.TcpHeader->SrcPort = http80Port; + } + winDivertAddress.Impostor = true; + WinDivert.WinDivertHelperCalcChecksums(winDivertBuffer, packetLength, ref winDivertAddress, WinDivertChecksumHelperParam.All); + } + } +} diff --git a/FastGithub.PacketIntercept/HttpsInterceptHostedService.cs b/FastGithub.PacketIntercept/HttpsInterceptHostedService.cs index 2200556..76d6306 100644 --- a/FastGithub.PacketIntercept/HttpsInterceptHostedService.cs +++ b/FastGithub.PacketIntercept/HttpsInterceptHostedService.cs @@ -1,5 +1,4 @@ -using FastGithub.Configuration; -using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Hosting; using System.Runtime.Versioning; using System.Threading; using System.Threading.Tasks; diff --git a/FastGithub.PacketIntercept/HttpsInterceptor.cs b/FastGithub.PacketIntercept/HttpsInterceptor.cs index 8bbe9ec..abdb301 100644 --- a/FastGithub.PacketIntercept/HttpsInterceptor.cs +++ b/FastGithub.PacketIntercept/HttpsInterceptor.cs @@ -14,15 +14,15 @@ namespace FastGithub.Dns [SupportedOSPlatform("windows")] sealed class HttpsInterceptor { - private readonly ILogger logger; + private readonly ILogger logger; private readonly ushort https443Port = BinaryPrimitives.ReverseEndianness((ushort)443); - private readonly ushort httpReverseProxyPort = BinaryPrimitives.ReverseEndianness((ushort)HttpsReverseProxyPort.Value); + private readonly ushort httpsReverseProxyPort = BinaryPrimitives.ReverseEndianness((ushort)ReverseProxyPort.Https); /// /// https拦截器 /// /// - public HttpsInterceptor(ILogger logger) + public HttpsInterceptor(ILogger logger) { this.logger = logger; } @@ -33,12 +33,12 @@ namespace FastGithub.Dns /// public void Intercept(CancellationToken cancellationToken) { - if (HttpsReverseProxyPort.Value == 443) + if (ReverseProxyPort.Https == 443) { return; } - var filter = $"loopback and (tcp.DstPort == 443 or tcp.SrcPort == {HttpsReverseProxyPort.Value})"; + var filter = $"loopback and (tcp.DstPort == 443 or tcp.SrcPort == {ReverseProxyPort.Https})"; var handle = WinDivert.WinDivertOpen(filter, WinDivertLayer.Network, 0, WinDivertOpenFlags.None); if (handle == IntPtr.Zero) { @@ -82,7 +82,7 @@ namespace FastGithub.Dns var packet = WinDivert.WinDivertHelperParsePacket(winDivertBuffer, packetLength); if (packet.TcpHeader->DstPort == https443Port) { - packet.TcpHeader->DstPort = this.httpReverseProxyPort; + packet.TcpHeader->DstPort = this.httpsReverseProxyPort; } else { diff --git a/FastGithub.PacketIntercept/ServiceCollectionExtensions.cs b/FastGithub.PacketIntercept/ServiceCollectionExtensions.cs index b5506ea..8fa9020 100644 --- a/FastGithub.PacketIntercept/ServiceCollectionExtensions.cs +++ b/FastGithub.PacketIntercept/ServiceCollectionExtensions.cs @@ -18,11 +18,15 @@ namespace FastGithub [SupportedOSPlatform("windows")] public static IServiceCollection AddPacketIntercept(this IServiceCollection services) { - services.TryAddSingleton(); - services.TryAddSingleton(); services.AddSingleton(); services.AddSingleton(); + + services.TryAddSingleton(); + services.TryAddSingleton(); + services.TryAddSingleton(); + services.AddHostedService(); + services.AddHostedService(); return services.AddHostedService(); } }