From 48e994182fd79973fd0426a41c306f301ef75788 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E5=9B=BD=E4=BC=9F?= <366193849@qq.com> Date: Thu, 29 Jul 2021 13:59:22 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0http=E5=8F=8D=E5=90=91?= =?UTF-8?q?=E4=BB=A3=E7=90=86=EF=BC=9B=20=E4=BD=BF=E7=94=A8IPGlobalPropert?= =?UTF-8?q?ies=E8=8E=B7=E5=8F=96=E5=85=A8=E5=B1=80ip=EF=BC=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- FastGithub.Configuration/DnsConfig.cs | 16 +-- FastGithub.Dns/DnsServer.cs | 14 ++- FastGithub.Dns/HostsValidator.cs | 10 +- FastGithub.Dns/UdpTable.cs | 29 +++++ .../KestrelServerOptionsExtensions.cs | 105 +++++++++++++----- ...everseProxyApplicationBuilderExtensions.cs | 4 +- .../ReverseProxyHostedService.cs | 65 ----------- .../ReverseProxyMiddleware.cs | 12 +- ...ReverseProxyServiceCollectionExtensions.cs | 3 +- FastGithub.ReverseProxy/TcpTable.cs | 29 +++++ FastGithub/HostedService.cs | 2 +- FastGithub/Program.cs | 6 +- FastGithub/Startup.cs | 2 +- README.md | 2 +- 14 files changed, 169 insertions(+), 130 deletions(-) delete mode 100644 FastGithub.ReverseProxy/ReverseProxyHostedService.cs diff --git a/FastGithub.Configuration/DnsConfig.cs b/FastGithub.Configuration/DnsConfig.cs index f636a38..e03055b 100644 --- a/FastGithub.Configuration/DnsConfig.cs +++ b/FastGithub.Configuration/DnsConfig.cs @@ -1,4 +1,5 @@ using System.Diagnostics.CodeAnalysis; +using System.Linq; using System.Net; using System.Net.NetworkInformation; @@ -52,17 +53,10 @@ namespace FastGithub.Configuration /// private static bool IsLocalMachineIPAddress(IPAddress address) { - foreach (var @interface in NetworkInterface.GetAllNetworkInterfaces()) - { - foreach (var addressInfo in @interface.GetIPProperties().UnicastAddresses) - { - if (addressInfo.Address.Equals(address)) - { - return true; - } - } - } - return false; + return IPGlobalProperties + .GetIPGlobalProperties() + .GetUnicastAddresses() + .Any(item => item.Address.Equals(address)); } } } diff --git a/FastGithub.Dns/DnsServer.cs b/FastGithub.Dns/DnsServer.cs index 6116aa3..9ab0a1d 100644 --- a/FastGithub.Dns/DnsServer.cs +++ b/FastGithub.Dns/DnsServer.cs @@ -1,8 +1,10 @@ using DNS.Protocol; +using FastGithub.Configuration; using Microsoft.Extensions.Logging; using System; -using System.Diagnostics; +using System.Linq; using System.Net; +using System.Net.NetworkInformation; using System.Net.Sockets; using System.Threading; using System.Threading.Tasks; @@ -40,9 +42,15 @@ namespace FastGithub.Dns /// public void Bind(IPAddress address, int port) { - if (OperatingSystem.IsWindows() && UdpTable.TryGetOwnerProcessId(port, out var processId)) + if (OperatingSystem.IsWindows()) { - Process.GetProcessById(processId).Kill(); + UdpTable.KillPortOwner(port); + } + + var udpListeners = IPGlobalProperties.GetIPGlobalProperties().GetActiveUdpListeners(); + if (udpListeners.Any(item => item.Port == port)) + { + throw new FastGithubException($"udp端口{port}已经被其它进程占用"); } if (OperatingSystem.IsWindows()) diff --git a/FastGithub.Dns/HostsValidator.cs b/FastGithub.Dns/HostsValidator.cs index 2fb76b2..3ba84f4 100644 --- a/FastGithub.Dns/HostsValidator.cs +++ b/FastGithub.Dns/HostsValidator.cs @@ -84,15 +84,9 @@ namespace FastGithub.Dns /// private static IEnumerable GetLocalMachineIPAddress() { - yield return IPAddress.Loopback; - yield return IPAddress.IPv6Loopback; - - foreach (var @interface in NetworkInterface.GetAllNetworkInterfaces()) + foreach (var item in IPGlobalProperties.GetIPGlobalProperties().GetUnicastAddresses()) { - foreach (var addressInfo in @interface.GetIPProperties().UnicastAddresses) - { - yield return addressInfo.Address; - } + yield return item.Address; } } } diff --git a/FastGithub.Dns/UdpTable.cs b/FastGithub.Dns/UdpTable.cs index 8657c96..f126fdc 100644 --- a/FastGithub.Dns/UdpTable.cs +++ b/FastGithub.Dns/UdpTable.cs @@ -1,5 +1,6 @@ using System; using System.Buffers.Binary; +using System.Diagnostics; using System.Net; using System.Net.Sockets; using System.Runtime.InteropServices; @@ -18,6 +19,34 @@ namespace FastGithub.Dns [DllImport("iphlpapi.dll", SetLastError = true)] private static extern uint GetExtendedUdpTable(void* pUdpTable, ref int pdwSize, bool bOrder, AddressFamily ulAf, UDP_TABLE_CLASS tableClass, uint reserved = 0); + + /// + /// 杀死占用进程 + /// + /// + /// + public static bool KillPortOwner(int port) + { + if (TryGetOwnerProcessId(port, out var pid) == false) + { + return true; + } + + try + { + Process.GetProcessById(pid).Kill(); + return true; + } + catch (ArgumentException) + { + return true; + } + catch (Exception) + { + return false; + } + } + /// /// 获取udp端口的占用进程id /// diff --git a/FastGithub.ReverseProxy/KestrelServerOptionsExtensions.cs b/FastGithub.ReverseProxy/KestrelServerOptionsExtensions.cs index 8be4fe0..f4871c9 100644 --- a/FastGithub.ReverseProxy/KestrelServerOptionsExtensions.cs +++ b/FastGithub.ReverseProxy/KestrelServerOptionsExtensions.cs @@ -22,9 +22,34 @@ namespace FastGithub public static class KestrelServerOptionsExtensions { /// - /// 域名证书缓存 + /// 服务器证书缓存 /// - private static readonly IMemoryCache domainCertCache = new MemoryCache(Options.Create(new MemoryCacheOptions())); + private static readonly IMemoryCache serverCertCache = new MemoryCache(Options.Create(new MemoryCacheOptions())); + + /// + /// 监听http的反向代理 + /// + /// + public static void ListenHttpReverseProxy(this KestrelServerOptions kestrel) + { + var loggerFactory = kestrel.ApplicationServices.GetRequiredService(); + var logger = loggerFactory.CreateLogger($"{nameof(FastGithub)}.{nameof(ReverseProxy)}"); + + const int HTTP_PORT = 80; + if (OperatingSystem.IsWindows()) + { + TcpTable.KillPortOwner(HTTP_PORT); + } + + if (CanTcpListen(HTTP_PORT) == false) + { + logger.LogWarning($"无法监听tcp端口{HTTP_PORT},{nameof(FastGithub)}无法http反向代理"); + } + else + { + kestrel.Listen(IPAddress.Any, HTTP_PORT); + } + } /// /// 监听https的反向代理 @@ -43,10 +68,34 @@ namespace FastGithub GeneratorCaCert(caPublicCerPath, caPrivateKeyPath); InstallCaCert(caPublicCerPath, logger); - kestrel.Listen(IPAddress.Any, 443, listen => - listen.UseHttps(https => - https.ServerCertificateSelector = (ctx, domain) => - GetDomainCert(domain, caPublicCerPath, caPrivateKeyPath))); + const int HTTPS_PORT = 443; + if (OperatingSystem.IsWindows()) + { + TcpTable.KillPortOwner(HTTPS_PORT); + } + + if (CanTcpListen(HTTPS_PORT) == false) + { + logger.LogWarning($"无法监听tcp端口{HTTPS_PORT},{nameof(FastGithub)}无法https反向代理"); + } + else + { + kestrel.Listen(IPAddress.Any, HTTPS_PORT, listen => + listen.UseHttps(https => + https.ServerCertificateSelector = (ctx, domain) => + GetServerCert(domain, caPublicCerPath, caPrivateKeyPath))); + } + } + + /// + /// 是否可以监听指定端口 + /// + /// + /// + private static bool CanTcpListen(int port) + { + var tcpListeners = IPGlobalProperties.GetIPGlobalProperties().GetActiveTcpListeners(); + return tcpListeners.Any(item => item.Port == port) == false; } /// @@ -81,25 +130,24 @@ namespace FastGithub if (OperatingSystem.IsWindows() == false) { logger.LogWarning($"不支持自动安装证书{caPublicCerPath}:请手动安装证书到根证书颁发机构"); + return; } - else + + try { - try + var caCert = new X509Certificate2(caPublicCerPath); + using var store = new X509Store(StoreName.Root, StoreLocation.LocalMachine); + store.Open(OpenFlags.ReadWrite); + if (store.Certificates.Find(X509FindType.FindByThumbprint, caCert.Thumbprint, true).Count == 0) { - var caCert = new X509Certificate2(caPublicCerPath); - using var store = new X509Store(StoreName.Root, StoreLocation.LocalMachine); - store.Open(OpenFlags.ReadWrite); - if (store.Certificates.Find(X509FindType.FindByThumbprint, caCert.Thumbprint, true).Count == 0) - { - store.Add(caCert); - store.Close(); - } - } - catch (Exception) - { - logger.LogWarning($"安装证书{caPublicCerPath}失败:请手动安装到“将所有的证书都放入下载存储”\\“受信任的根证书颁发机构”"); + store.Add(caCert); + store.Close(); } } + catch (Exception) + { + logger.LogWarning($"安装证书{caPublicCerPath}失败:请手动安装到“将所有的证书都放入下载存储”\\“受信任的根证书颁发机构”"); + } } /// @@ -109,9 +157,9 @@ namespace FastGithub /// /// /// - private static X509Certificate2 GetDomainCert(string? domain, string caPublicCerPath, string caPrivateKeyPath) + private static X509Certificate2 GetServerCert(string? domain, string caPublicCerPath, string caPrivateKeyPath) { - return domainCertCache.GetOrCreate(domain ?? string.Empty, GetOrCreateCert); + return serverCertCache.GetOrCreate(domain ?? string.Empty, GetOrCreateCert); // 生成域名的1年证书 X509Certificate2 GetOrCreateCert(ICacheEntry entry) @@ -138,17 +186,14 @@ namespace FastGithub yield return host; } - yield return Environment.MachineName; - yield return IPAddress.Loopback.ToString(); + var globalPropreties = IPGlobalProperties.GetIPGlobalProperties(); - foreach (var @interface in NetworkInterface.GetAllNetworkInterfaces()) + yield return globalPropreties.HostName; + foreach (var item in globalPropreties.GetUnicastAddresses()) { - foreach (var addressInfo in @interface.GetIPProperties().UnicastAddresses) + if (item.Address.AddressFamily == AddressFamily.InterNetwork) { - if (addressInfo.Address.AddressFamily == AddressFamily.InterNetwork) - { - yield return addressInfo.Address.ToString(); - } + yield return item.Address.ToString(); } } } diff --git a/FastGithub.ReverseProxy/ReverseProxyApplicationBuilderExtensions.cs b/FastGithub.ReverseProxy/ReverseProxyApplicationBuilderExtensions.cs index 79f6996..be7febd 100644 --- a/FastGithub.ReverseProxy/ReverseProxyApplicationBuilderExtensions.cs +++ b/FastGithub.ReverseProxy/ReverseProxyApplicationBuilderExtensions.cs @@ -21,11 +21,11 @@ namespace FastGithub } /// - /// 使用https反向代理中间件 + /// 使用反向代理中间件 /// /// /// - public static IApplicationBuilder UseHttpsReverseProxy(this IApplicationBuilder app) + public static IApplicationBuilder UseReverseProxy(this IApplicationBuilder app) { var middleware = app.ApplicationServices.GetRequiredService(); return app.Use(next => context => middleware.InvokeAsync(context, next)); diff --git a/FastGithub.ReverseProxy/ReverseProxyHostedService.cs b/FastGithub.ReverseProxy/ReverseProxyHostedService.cs deleted file mode 100644 index 5bae00d..0000000 --- a/FastGithub.ReverseProxy/ReverseProxyHostedService.cs +++ /dev/null @@ -1,65 +0,0 @@ -using Microsoft.Extensions.Hosting; -using Microsoft.Extensions.Logging; -using System; -using System.Diagnostics; -using System.Threading; -using System.Threading.Tasks; - -namespace FastGithub.ReverseProxy -{ - /// - /// 反向代理端口检测后台服务 - /// - sealed class ReverseProxyHostedService : IHostedService - { - private readonly ILogger logger; - - /// - /// 反向代理端口检测后台服务 - /// - /// - public ReverseProxyHostedService(ILogger logger) - { - this.logger = logger; - } - - /// - /// 服务启动时 - /// - /// - /// - public Task StartAsync(CancellationToken cancellationToken) - { - const int HTTPSPORT = 443; - if (OperatingSystem.IsWindows()) - { - if (TcpTable.TryGetOwnerProcessId(HTTPSPORT, out var pid)) - { - try - { - Process.GetProcessById(pid).Kill(); - } - catch (ArgumentException) - { - } - catch (Exception) - { - var processName = Process.GetProcessById(pid).ProcessName; - this.logger.LogError($"由于进程{processName}({pid})占用了{HTTPSPORT}端口,{nameof(FastGithub)}的反向代理无法工作"); - } - } - } - return Task.CompletedTask; - } - - /// - /// 服务停止时 - /// - /// - /// - public Task StopAsync(CancellationToken cancellationToken) - { - return Task.CompletedTask; - } - } -} diff --git a/FastGithub.ReverseProxy/ReverseProxyMiddleware.cs b/FastGithub.ReverseProxy/ReverseProxyMiddleware.cs index 2600627..b0c451c 100644 --- a/FastGithub.ReverseProxy/ReverseProxyMiddleware.cs +++ b/FastGithub.ReverseProxy/ReverseProxyMiddleware.cs @@ -23,7 +23,7 @@ namespace FastGithub.ReverseProxy IHttpClientFactory httpClientFactory, FastGithubConfig fastGithubConfig, ILogger logger) - { + { this.httpForwarder = httpForwarder; this.httpClientFactory = httpClientFactory; this.fastGithubConfig = fastGithubConfig; @@ -54,7 +54,8 @@ namespace FastGithub.ReverseProxy } else { - var destinationPrefix = GetDestinationPrefix(host, domainConfig.Destination); + var scheme = context.Request.Scheme; + var destinationPrefix = GetDestinationPrefix(scheme, host, domainConfig.Destination); var httpClient = this.httpClientFactory.CreateHttpClient(domainConfig); var error = await httpForwarder.SendAsync(context, destinationPrefix, httpClient); await HandleErrorAsync(context, error); @@ -64,12 +65,13 @@ namespace FastGithub.ReverseProxy /// /// 获取目标前缀 /// - /// + /// + /// /// /// - private string GetDestinationPrefix(string host, Uri? destination) + private string GetDestinationPrefix(string scheme, string host, Uri? destination) { - var defaultValue = $"https://{host}/"; + var defaultValue = $"{scheme}://{host}/"; if (destination == null) { return defaultValue; diff --git a/FastGithub.ReverseProxy/ReverseProxyServiceCollectionExtensions.cs b/FastGithub.ReverseProxy/ReverseProxyServiceCollectionExtensions.cs index 72858a9..069a745 100644 --- a/FastGithub.ReverseProxy/ReverseProxyServiceCollectionExtensions.cs +++ b/FastGithub.ReverseProxy/ReverseProxyServiceCollectionExtensions.cs @@ -19,8 +19,7 @@ namespace FastGithub .AddMemoryCache() .AddHttpForwarder() .AddSingleton() - .AddSingleton() - .AddHostedService(); + .AddSingleton(); } } } diff --git a/FastGithub.ReverseProxy/TcpTable.cs b/FastGithub.ReverseProxy/TcpTable.cs index fcf0033..4e8065d 100644 --- a/FastGithub.ReverseProxy/TcpTable.cs +++ b/FastGithub.ReverseProxy/TcpTable.cs @@ -1,5 +1,6 @@ using System; using System.Buffers.Binary; +using System.Diagnostics; using System.Net; using System.Net.Sockets; using System.Runtime.InteropServices; @@ -18,6 +19,34 @@ namespace FastGithub.ReverseProxy [DllImport("iphlpapi.dll", SetLastError = true)] private static extern uint GetExtendedTcpTable(void* pTcpTable, ref int pdwSize, bool bOrder, AddressFamily ulAf, TCP_TABLE_CLASS tableClass, uint reserved = 0); + + /// + /// 杀死占用进程 + /// + /// + /// + public static bool KillPortOwner(int port) + { + if (TryGetOwnerProcessId(port, out var pid) == false) + { + return true; + } + + try + { + Process.GetProcessById(pid).Kill(); + return true; + } + catch (ArgumentException) + { + return true; + } + catch (Exception) + { + return false; + } + } + /// /// 获取tcp端口的占用进程id /// diff --git a/FastGithub/HostedService.cs b/FastGithub/HostedService.cs index daffbac..8d1bd99 100644 --- a/FastGithub/HostedService.cs +++ b/FastGithub/HostedService.cs @@ -29,7 +29,7 @@ namespace FastGithub /// public Task StartAsync(CancellationToken cancellationToken) { - this.logger.LogInformation($"{nameof(FastGithub)}启动完成,访问https://127.0.0.1或本机其它任意ip可进入Dashboard"); + this.logger.LogInformation($"{nameof(FastGithub)}启动完成,访问http://127.0.0.1或本机其它任意ip可进入Dashboard"); return Task.CompletedTask; } diff --git a/FastGithub/Program.cs b/FastGithub/Program.cs index d297bdf..6a455f6 100644 --- a/FastGithub/Program.cs +++ b/FastGithub/Program.cs @@ -41,7 +41,11 @@ namespace FastGithub .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup(); - webBuilder.UseKestrel(kestrel => kestrel.ListenHttpsReverseProxy()); + webBuilder.UseKestrel(kestrel => + { + kestrel.ListenHttpReverseProxy(); + kestrel.ListenHttpsReverseProxy(); + }); }); } } diff --git a/FastGithub/Startup.cs b/FastGithub/Startup.cs index f927251..fc80690 100644 --- a/FastGithub/Startup.cs +++ b/FastGithub/Startup.cs @@ -43,7 +43,7 @@ namespace FastGithub public void Configure(IApplicationBuilder app) { app.UseRequestLogging(); - app.UseHttpsReverseProxy(); + app.UseReverseProxy(); app.UseRouting(); app.UseEndpoints(endpoints => { diff --git a/README.md b/README.md index 7206a53..3ec3d25 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ github加速神器 如果不能下载[releases](https://github.com/xljiulang/FastGithub/releases)里发布的程序,可以到Q群`307306673`里面的群文件下载。 ### 使用说明 -运行FastGithub,然后浏览器访问 https://127.0.0.1 或其它ip进入Dashboard +运行FastGithub,然后浏览器访问 http://127.0.0.1 或其它ip进入Dashboard ### 安全性说明 FastGithub生成自签名CA证书,要求安装到本机设备。FastGithub为每台不同设备生成的CA不同的证书,保存在CACert文件夹下,请不要将证书私钥泄露给他人,以免造成损失。