diff --git a/FastGithub.Configuration/ReverseProxyPort.cs b/FastGithub.Configuration/ReverseProxyPort.cs index 9965fc1..ad2edf5 100644 --- a/FastGithub.Configuration/ReverseProxyPort.cs +++ b/FastGithub.Configuration/ReverseProxyPort.cs @@ -10,6 +10,11 @@ namespace FastGithub.Configuration /// public static class ReverseProxyPort { + /// + /// ssh端口 + /// + public static int Ssh { get; } = GetAvailableTcpPort(22); + /// /// http端口 /// diff --git a/FastGithub.HttpServer/KestrelServerOptionsExtensions.cs b/FastGithub.HttpServer/KestrelServerOptionsExtensions.cs index a686c17..589fd60 100644 --- a/FastGithub.HttpServer/KestrelServerOptionsExtensions.cs +++ b/FastGithub.HttpServer/KestrelServerOptionsExtensions.cs @@ -55,11 +55,12 @@ namespace FastGithub /// public static void ListenSshReverseProxy(this KestrelServerOptions kestrel) { - const int SSH_PORT = 22; - if (CanListenTcp(SSH_PORT) == true) + var sshPort = ReverseProxyPort.Ssh; + kestrel.Listen(IPAddress.Loopback, sshPort, listen => listen.UseConnectionHandler()); + + if (OperatingSystem.IsWindows()) { - kestrel.Listen(IPAddress.Loopback, SSH_PORT, listen => listen.UseConnectionHandler()); - kestrel.GetLogger().LogInformation($"已监听ssh://{IPAddress.Loopback}:{SSH_PORT},github的ssh反向代理服务启动完成"); + kestrel.GetLogger().LogInformation($"已监听ssh://{IPAddress.Loopback}:{sshPort},github的ssh反向代理服务启动完成"); } } @@ -70,9 +71,10 @@ namespace FastGithub public static void ListenHttpReverseProxy(this KestrelServerOptions kestrel) { var httpPort = ReverseProxyPort.Http; - if (CanListenTcp(httpPort) == true) + kestrel.Listen(IPAddress.Loopback, httpPort); + + if (OperatingSystem.IsWindows()) { - kestrel.Listen(IPAddress.Loopback, httpPort); kestrel.GetLogger().LogInformation($"已监听http://{IPAddress.Loopback}:{httpPort},http反向代理服务启动完成"); } } @@ -82,19 +84,13 @@ namespace FastGithub /// /// /// - /// - public static int ListenHttpsReverseProxy(this KestrelServerOptions kestrel) + public static void ListenHttpsReverseProxy(this KestrelServerOptions kestrel) { - var httpsPort = ReverseProxyPort.Https; - if (CanListenTcp(httpsPort) == false) - { - throw new FastGithubException($"tcp端口{httpsPort}已经被其它进程占用"); - } - var certService = kestrel.ApplicationServices.GetRequiredService(); certService.CreateCaCertIfNotExists(); certService.InstallAndTrustCaCert(); + var httpsPort = ReverseProxyPort.Https; kestrel.Listen(IPAddress.Loopback, httpsPort, listen => listen.UseHttps(https => https.ServerCertificateSelector = (ctx, domain) => @@ -105,8 +101,6 @@ namespace FastGithub var logger = kestrel.GetLogger(); logger.LogInformation($"已监听https://{IPAddress.Loopback}:{httpsPort},https反向代理服务启动完成"); } - - return httpsPort; } /// diff --git a/FastGithub.PacketIntercept/DnsInterceptHostedService.cs b/FastGithub.PacketIntercept/DnsInterceptHostedService.cs index c259f98..8583892 100644 --- a/FastGithub.PacketIntercept/DnsInterceptHostedService.cs +++ b/FastGithub.PacketIntercept/DnsInterceptHostedService.cs @@ -4,7 +4,7 @@ using System.Runtime.Versioning; using System.Threading; using System.Threading.Tasks; -namespace FastGithub.Dns +namespace FastGithub.PacketIntercept { /// /// dns拦截后台服务 diff --git a/FastGithub.PacketIntercept/DnsInterceptor.cs b/FastGithub.PacketIntercept/DnsInterceptor.cs index 64df7af..8b2081b 100644 --- a/FastGithub.PacketIntercept/DnsInterceptor.cs +++ b/FastGithub.PacketIntercept/DnsInterceptor.cs @@ -13,7 +13,7 @@ using System.Runtime.Versioning; using System.Threading; using WinDivertSharp; -namespace FastGithub.Dns +namespace FastGithub.PacketIntercept { /// /// dns拦截器 @@ -165,7 +165,7 @@ namespace FastGithub.Dns } WinDivert.WinDivertHelperCalcChecksums(winDivertBuffer, packetLength, ref winDivertAddress, WinDivertChecksumHelperParam.All); - this.logger.LogInformation($"已拦截dns查询{domain}并伪造解析结果为{IPAddress.Loopback}"); + this.logger.LogInformation($"{domain} => {IPAddress.Loopback}"); } diff --git a/FastGithub.PacketIntercept/HostsConflictSolver.cs b/FastGithub.PacketIntercept/HostsConflictSolver.cs index ce1805c..eceeaf9 100644 --- a/FastGithub.PacketIntercept/HostsConflictSolver.cs +++ b/FastGithub.PacketIntercept/HostsConflictSolver.cs @@ -6,7 +6,7 @@ using System.Text; using System.Threading; using System.Threading.Tasks; -namespace FastGithub.Dns +namespace FastGithub.PacketIntercept { /// /// host文件冲解决者 diff --git a/FastGithub.PacketIntercept/HttpInterceptHostedService.cs b/FastGithub.PacketIntercept/HttpInterceptHostedService.cs deleted file mode 100644 index a2308df..0000000 --- a/FastGithub.PacketIntercept/HttpInterceptHostedService.cs +++ /dev/null @@ -1,36 +0,0 @@ -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 index 9cbb51d..c663568 100644 --- a/FastGithub.PacketIntercept/HttpInterceptor.cs +++ b/FastGithub.PacketIntercept/HttpInterceptor.cs @@ -1,95 +1,22 @@ 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 +namespace FastGithub.PacketIntercept { /// /// http拦截器 /// [SupportedOSPlatform("windows")] - sealed class HttpInterceptor + sealed class HttpInterceptor : TcpInterceptor { - 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) + : base(80, ReverseProxyPort.Http, 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 deleted file mode 100644 index 76d6306..0000000 --- a/FastGithub.PacketIntercept/HttpsInterceptHostedService.cs +++ /dev/null @@ -1,36 +0,0 @@ -using Microsoft.Extensions.Hosting; -using System.Runtime.Versioning; -using System.Threading; -using System.Threading.Tasks; - -namespace FastGithub.Dns -{ - /// - /// https拦截后台服务 - /// - [SupportedOSPlatform("windows")] - sealed class HttpsInterceptHostedService : BackgroundService - { - private readonly HttpsInterceptor httpsInterceptor; - - /// - /// https拦截后台服务 - /// - /// - public HttpsInterceptHostedService(HttpsInterceptor httpsInterceptor) - { - this.httpsInterceptor = httpsInterceptor; - } - - /// - /// https后台 - /// - /// - /// - protected override async Task ExecuteAsync(CancellationToken stoppingToken) - { - await Task.Yield(); - this.httpsInterceptor.Intercept(stoppingToken); - } - } -} diff --git a/FastGithub.PacketIntercept/HttpsInterceptor.cs b/FastGithub.PacketIntercept/HttpsInterceptor.cs index abdb301..090ee50 100644 --- a/FastGithub.PacketIntercept/HttpsInterceptor.cs +++ b/FastGithub.PacketIntercept/HttpsInterceptor.cs @@ -1,95 +1,22 @@ 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 +namespace FastGithub.PacketIntercept { /// /// https拦截器 /// [SupportedOSPlatform("windows")] - sealed class HttpsInterceptor + sealed class HttpsInterceptor : TcpInterceptor { - private readonly ILogger logger; - private readonly ushort https443Port = BinaryPrimitives.ReverseEndianness((ushort)443); - private readonly ushort httpsReverseProxyPort = BinaryPrimitives.ReverseEndianness((ushort)ReverseProxyPort.Https); - /// /// https拦截器 /// /// public HttpsInterceptor(ILogger logger) + : base(443, ReverseProxyPort.Https, logger) { - this.logger = logger; - } - - /// - /// 拦截443端口的数据包 - /// - /// - public void Intercept(CancellationToken cancellationToken) - { - if (ReverseProxyPort.Https == 443) - { - return; - } - - 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) - { - 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 == https443Port) - { - packet.TcpHeader->DstPort = this.httpsReverseProxyPort; - } - else - { - packet.TcpHeader->SrcPort = https443Port; - } - winDivertAddress.Impostor = true; - WinDivert.WinDivertHelperCalcChecksums(winDivertBuffer, packetLength, ref winDivertAddress, WinDivertChecksumHelperParam.All); } } } diff --git a/FastGithub.PacketIntercept/IConflictSolver.cs b/FastGithub.PacketIntercept/IConflictSolver.cs index b72f2a3..b22dd8e 100644 --- a/FastGithub.PacketIntercept/IConflictSolver.cs +++ b/FastGithub.PacketIntercept/IConflictSolver.cs @@ -1,7 +1,7 @@ using System.Threading; using System.Threading.Tasks; -namespace FastGithub.Dns +namespace FastGithub.PacketIntercept { /// /// Dns冲突解决者 diff --git a/FastGithub.PacketIntercept/ITcpInterceptor.cs b/FastGithub.PacketIntercept/ITcpInterceptor.cs new file mode 100644 index 0000000..206a4f7 --- /dev/null +++ b/FastGithub.PacketIntercept/ITcpInterceptor.cs @@ -0,0 +1,16 @@ +using System.Threading; + +namespace FastGithub.PacketIntercept +{ + /// + /// tcp拦截器接口 + /// + interface ITcpInterceptor + { + /// + /// 拦截tcp + /// + /// + void Intercept(CancellationToken cancellationToken); + } +} \ No newline at end of file diff --git a/FastGithub.PacketIntercept/ProxyConflictSolver.cs b/FastGithub.PacketIntercept/ProxyConflictSolver.cs index 8b53543..a61278e 100644 --- a/FastGithub.PacketIntercept/ProxyConflictSolver.cs +++ b/FastGithub.PacketIntercept/ProxyConflictSolver.cs @@ -11,7 +11,7 @@ using System.Runtime.Versioning; using System.Threading; using System.Threading.Tasks; -namespace FastGithub.Dns +namespace FastGithub.PacketIntercept { /// /// 代理冲突解决者 diff --git a/FastGithub.PacketIntercept/ServiceCollectionExtensions.cs b/FastGithub.PacketIntercept/ServiceCollectionExtensions.cs index 8fa9020..1cfbbc4 100644 --- a/FastGithub.PacketIntercept/ServiceCollectionExtensions.cs +++ b/FastGithub.PacketIntercept/ServiceCollectionExtensions.cs @@ -1,4 +1,4 @@ -using FastGithub.Dns; +using FastGithub.PacketIntercept; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; using System.Runtime.Versioning; @@ -20,14 +20,15 @@ namespace FastGithub { services.AddSingleton(); services.AddSingleton(); - services.TryAddSingleton(); - services.TryAddSingleton(); - services.TryAddSingleton(); - services.AddHostedService(); - services.AddHostedService(); - return services.AddHostedService(); + + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddHostedService(); + + return services; } } } diff --git a/FastGithub.PacketIntercept/SshInterceptor.cs b/FastGithub.PacketIntercept/SshInterceptor.cs new file mode 100644 index 0000000..5f61817 --- /dev/null +++ b/FastGithub.PacketIntercept/SshInterceptor.cs @@ -0,0 +1,22 @@ +using FastGithub.Configuration; +using Microsoft.Extensions.Logging; +using System.Runtime.Versioning; + +namespace FastGithub.PacketIntercept +{ + /// + /// ssh拦截器 + /// + [SupportedOSPlatform("windows")] + sealed class SshInterceptor : TcpInterceptor + { + /// + /// ssh拦截器 + /// + /// + public SshInterceptor(ILogger logger) + : base(22, ReverseProxyPort.Ssh, logger) + { + } + } +} diff --git a/FastGithub.PacketIntercept/TcpInterceptHostedService.cs b/FastGithub.PacketIntercept/TcpInterceptHostedService.cs new file mode 100644 index 0000000..c639a8c --- /dev/null +++ b/FastGithub.PacketIntercept/TcpInterceptHostedService.cs @@ -0,0 +1,50 @@ +using Microsoft.Extensions.Hosting; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.Versioning; +using System.Threading; +using System.Threading.Tasks; + +namespace FastGithub.PacketIntercept +{ + /// + /// tcp拦截后台服务 + /// + [SupportedOSPlatform("windows")] + sealed class TcpInterceptHostedService : BackgroundService + { + private readonly IEnumerable tcpInterceptors; + + /// + /// tcp拦截后台服务 + /// + /// + public TcpInterceptHostedService(IEnumerable tcpInterceptors) + { + this.tcpInterceptors = tcpInterceptors; + } + + /// + /// https后台 + /// + /// + /// + protected override Task ExecuteAsync(CancellationToken stoppingToken) + { + var tasks = this.tcpInterceptors.Select(item => this.InterceptAsync(item, stoppingToken)); + return Task.WhenAll(tasks); + } + + /// + /// 拦截 + /// + /// + /// + /// + private async Task InterceptAsync(ITcpInterceptor interceptor, CancellationToken cancellationToken) + { + await Task.Yield(); + interceptor.Intercept(cancellationToken); + } + } +} diff --git a/FastGithub.PacketIntercept/TcpInterceptor.cs b/FastGithub.PacketIntercept/TcpInterceptor.cs new file mode 100644 index 0000000..4e32dc9 --- /dev/null +++ b/FastGithub.PacketIntercept/TcpInterceptor.cs @@ -0,0 +1,101 @@ +using Microsoft.Extensions.Logging; +using System; +using System.Buffers.Binary; +using System.Net; +using System.Runtime.Versioning; +using System.Threading; +using WinDivertSharp; + +namespace FastGithub.PacketIntercept +{ + /// + /// tcp拦截器 + /// + [SupportedOSPlatform("windows")] + abstract class TcpInterceptor : ITcpInterceptor + { + private readonly string filter; + private readonly ushort oldServerPort; + private readonly ushort newServerPort; + private readonly ILogger logger; + + /// + /// tcp拦截器 + /// + /// 修改前的服务器端口 + /// 修改后的服务器端口 + /// + public TcpInterceptor(int oldServerPort, int newServerPort, ILogger logger) + { + this.filter = $"loopback and (tcp.DstPort == {oldServerPort} or tcp.SrcPort == {newServerPort})"; + this.oldServerPort = BinaryPrimitives.ReverseEndianness((ushort)oldServerPort); + this.newServerPort = BinaryPrimitives.ReverseEndianness((ushort)newServerPort); + this.logger = logger; + } + + /// + /// 拦截指定端口的数据包 + /// + /// + public void Intercept(CancellationToken cancellationToken) + { + if (this.oldServerPort == this.newServerPort) + { + return; + } + + var handle = WinDivert.WinDivertOpen(this.filter, WinDivertLayer.Network, 0, WinDivertOpenFlags.None); + if (handle == IntPtr.Zero) + { + return; + } + + this.logger.LogInformation($"tcp://{IPAddress.Loopback}:{BinaryPrimitives.ReverseEndianness(this.oldServerPort)} => tcp://{IPAddress.Loopback}:{BinaryPrimitives.ReverseEndianness(this.newServerPort)}"); + 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.ModifyTcpPacket(winDivertBuffer, ref winDivertAddress, ref packetLength); + } + catch (Exception ex) + { + this.logger.LogWarning(ex.Message); + } + finally + { + WinDivert.WinDivertSend(handle, winDivertBuffer, packetLength, ref winDivertAddress); + } + } + } + } + + /// + /// 修改tcp数据端口的端口 + /// + /// + /// + /// + unsafe private void ModifyTcpPacket(WinDivertBuffer winDivertBuffer, ref WinDivertAddress winDivertAddress, ref uint packetLength) + { + var packet = WinDivert.WinDivertHelperParsePacket(winDivertBuffer, packetLength); + if (packet.TcpHeader->DstPort == oldServerPort) + { + packet.TcpHeader->DstPort = this.newServerPort; + } + else + { + packet.TcpHeader->SrcPort = oldServerPort; + } + winDivertAddress.Impostor = true; + WinDivert.WinDivertHelperCalcChecksums(winDivertBuffer, packetLength, ref winDivertAddress, WinDivertChecksumHelperParam.All); + } + } +}