From 9850bbdb24e6a0a26cd7bf74062f765e5479b209 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 12:02:57 +0800
Subject: [PATCH] =?UTF-8?q?=E6=8B=A6=E6=88=AAtcp443=E7=9A=84=E6=95=B0?=
=?UTF-8?q?=E6=8D=AE=E5=8C=85?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../HttpsReverseProxyPort.cs | 23 ++-
.../KestrelServerOptionsExtensions.cs | 7 +-
FastGithub.HttpServer/TcpTable.cs | 139 ------------------
.../DnsInterceptHostedService.cs | 0
.../DnsInterceptor.cs | 3 +-
.../FastGithub.PacketIntercept.csproj | 1 +
.../HostsConflictSolver.cs | 0
.../HttpsInterceptHostedService.cs | 37 +++++
.../HttpsInterceptor.cs | 95 ++++++++++++
.../IConflictSolver.cs | 0
.../ProxyConflictSolver.cs | 0
.../ServiceCollectionExtensions.cs | 8 +-
FastGithub.sln | 16 +-
FastGithub/FastGithub.csproj | 2 +-
FastGithub/Startup.cs | 2 +-
15 files changed, 168 insertions(+), 165 deletions(-)
rename {FastGithub.HttpServer => FastGithub.Configuration}/HttpsReverseProxyPort.cs (65%)
delete mode 100644 FastGithub.HttpServer/TcpTable.cs
rename {FastGithub.Dns => FastGithub.PacketIntercept}/DnsInterceptHostedService.cs (100%)
rename {FastGithub.Dns => FastGithub.PacketIntercept}/DnsInterceptor.cs (99%)
rename FastGithub.Dns/FastGithub.Dns.csproj => FastGithub.PacketIntercept/FastGithub.PacketIntercept.csproj (90%)
rename {FastGithub.Dns => FastGithub.PacketIntercept}/HostsConflictSolver.cs (100%)
create mode 100644 FastGithub.PacketIntercept/HttpsInterceptHostedService.cs
create mode 100644 FastGithub.PacketIntercept/HttpsInterceptor.cs
rename {FastGithub.Dns => FastGithub.PacketIntercept}/IConflictSolver.cs (100%)
rename {FastGithub.Dns => FastGithub.PacketIntercept}/ProxyConflictSolver.cs (100%)
rename {FastGithub.Dns => FastGithub.PacketIntercept}/ServiceCollectionExtensions.cs (67%)
diff --git a/FastGithub.HttpServer/HttpsReverseProxyPort.cs b/FastGithub.Configuration/HttpsReverseProxyPort.cs
similarity index 65%
rename from FastGithub.HttpServer/HttpsReverseProxyPort.cs
rename to FastGithub.Configuration/HttpsReverseProxyPort.cs
index f3d33db..eae78f8 100644
--- a/FastGithub.HttpServer/HttpsReverseProxyPort.cs
+++ b/FastGithub.Configuration/HttpsReverseProxyPort.cs
@@ -1,21 +1,32 @@
-using FastGithub.Configuration;
-using System;
+using System;
using System.Collections.Generic;
using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets;
-namespace FastGithub.HttpServer
+namespace FastGithub.Configuration
{
///
/// https反向代理端口
///
- static class HttpsReverseProxyPort
+ public static class HttpsReverseProxyPort
{
///
/// 获取端口值
///
- public static int Value { get; } = OperatingSystem.IsWindows() ? 443 : GetAvailableTcpPort(AddressFamily.InterNetwork);
+ public static int Value { get; } = GetAvailableTcpPort(AddressFamily.InterNetwork);
+
+ ///
+ /// 获取可用的随机Tcp端口
+ ///
+ ///
+ ///
+ private static int GetAvailableTcpPort(AddressFamily addressFamily)
+ {
+ return OperatingSystem.IsWindows()
+ ? GetAvailableTcpPort(addressFamily, 443)
+ : GetAvailableTcpPort(addressFamily, 12345);
+ }
///
/// 获取可用的随机Tcp端口
@@ -23,7 +34,7 @@ namespace FastGithub.HttpServer
///
/// 最小值
///
- private static int GetAvailableTcpPort(AddressFamily addressFamily, int min = 12345)
+ private static int GetAvailableTcpPort(AddressFamily addressFamily, int min)
{
var hashSet = new HashSet();
var tcpListeners = IPGlobalProperties.GetIPGlobalProperties().GetActiveTcpListeners();
diff --git a/FastGithub.HttpServer/KestrelServerOptionsExtensions.cs b/FastGithub.HttpServer/KestrelServerOptionsExtensions.cs
index fb9e3d1..312c1e1 100644
--- a/FastGithub.HttpServer/KestrelServerOptionsExtensions.cs
+++ b/FastGithub.HttpServer/KestrelServerOptionsExtensions.cs
@@ -86,11 +86,6 @@ namespace FastGithub
public static int ListenHttpsReverseProxy(this KestrelServerOptions kestrel)
{
var httpsPort = HttpsReverseProxyPort.Value;
- if (OperatingSystem.IsWindows())
- {
- TcpTable.KillPortOwner(httpsPort);
- }
-
if (CanListenTcp(httpsPort) == false)
{
throw new FastGithubException($"tcp端口{httpsPort}已经被其它进程占用");
@@ -105,7 +100,7 @@ namespace FastGithub
https.ServerCertificateSelector = (ctx, domain) =>
certService.GetOrCreateServerCert(domain)));
- if (httpsPort == 443)
+ if (OperatingSystem.IsWindows())
{
var logger = kestrel.GetLogger();
logger.LogInformation($"已监听https://{IPAddress.Loopback}:{httpsPort},https反向代理服务启动完成");
diff --git a/FastGithub.HttpServer/TcpTable.cs b/FastGithub.HttpServer/TcpTable.cs
deleted file mode 100644
index 9737305..0000000
--- a/FastGithub.HttpServer/TcpTable.cs
+++ /dev/null
@@ -1,139 +0,0 @@
-using System;
-using System.Buffers.Binary;
-using System.Diagnostics;
-using System.Net;
-using System.Net.Sockets;
-using System.Runtime.InteropServices;
-using System.Runtime.Versioning;
-
-namespace FastGithub.HttpServer
-{
- ///
- /// windows iphlpapi
- ///
- [SupportedOSPlatform("windows")]
- unsafe static class TcpTable
- {
- private const int ERROR_INSUFFICIENT_BUFFER = 122;
-
- [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
- {
- var proess = Process.GetProcessById(pid);
- proess.Kill();
- return proess.WaitForExit(1000);
- }
- catch (ArgumentException)
- {
- return true;
- }
- catch (Exception)
- {
- return false;
- }
- }
-
- ///
- /// 获取tcp端口的占用进程id
- ///
- ///
- ///
- ///
- public static bool TryGetOwnerProcessId(int port, out int processId)
- {
- processId = 0;
- var pdwSize = 0;
- var result = GetExtendedTcpTable(null, ref pdwSize, false, AddressFamily.InterNetwork, TCP_TABLE_CLASS.TCP_TABLE_OWNER_PID_LISTENER);
- if (result != ERROR_INSUFFICIENT_BUFFER)
- {
- return false;
- }
-
- var buffer = new byte[pdwSize];
- fixed (byte* pTcpTable = &buffer[0])
- {
- result = GetExtendedTcpTable(pTcpTable, ref pdwSize, false, AddressFamily.InterNetwork, TCP_TABLE_CLASS.TCP_TABLE_OWNER_PID_LISTENER);
- if (result != 0)
- {
- return false;
- }
-
- var prt = new IntPtr(pTcpTable);
- var table = Marshal.PtrToStructure(prt);
- prt += sizeof(int);
- for (var i = 0; i < table.dwNumEntries; i++)
- {
- var row = Marshal.PtrToStructure(prt);
- if (row.LocalPort == port)
- {
- processId = row.ProcessId;
- return true;
- }
-
- prt += Marshal.SizeOf();
- }
- }
-
- return false;
- }
-
-
- private enum TCP_TABLE_CLASS
- {
- TCP_TABLE_BASIC_LISTENER,
- TCP_TABLE_BASIC_CONNECTIONS,
- TCP_TABLE_BASIC_ALL,
- TCP_TABLE_OWNER_PID_LISTENER,
- TCP_TABLE_OWNER_PID_CONNECTIONS,
- TCP_TABLE_OWNER_PID_ALL,
- TCP_TABLE_OWNER_MODULE_LISTENER,
- TCP_TABLE_OWNER_MODULE_CONNECTIONS,
- TCP_TABLE_OWNER_MODULE_ALL
- }
-
- [StructLayout(LayoutKind.Sequential)]
- private struct MIB_TCPTABLE_OWNER_PID
- {
- public uint dwNumEntries;
- }
-
- [StructLayout(LayoutKind.Sequential)]
- private struct MIB_TCPROW_OWNER_PID
- {
- public uint state;
-
- public uint localAddr;
-
- [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
- public byte[] localPort;
-
- public uint remoteAddr;
-
- [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
- public byte[] remotePort;
-
- public int owningPid;
-
- public int ProcessId => owningPid;
-
- public IPAddress LocalAddress => new(localAddr);
-
- public ushort LocalPort => BinaryPrimitives.ReadUInt16BigEndian(this.localPort);
- }
- }
-}
diff --git a/FastGithub.Dns/DnsInterceptHostedService.cs b/FastGithub.PacketIntercept/DnsInterceptHostedService.cs
similarity index 100%
rename from FastGithub.Dns/DnsInterceptHostedService.cs
rename to FastGithub.PacketIntercept/DnsInterceptHostedService.cs
diff --git a/FastGithub.Dns/DnsInterceptor.cs b/FastGithub.PacketIntercept/DnsInterceptor.cs
similarity index 99%
rename from FastGithub.Dns/DnsInterceptor.cs
rename to FastGithub.PacketIntercept/DnsInterceptor.cs
index 7244333..64df7af 100644
--- a/FastGithub.Dns/DnsInterceptor.cs
+++ b/FastGithub.PacketIntercept/DnsInterceptor.cs
@@ -154,6 +154,7 @@ namespace FastGithub.Dns
packet.UdpHeader->Length = BinaryPrimitives.ReverseEndianness((ushort)(sizeof(UdpHeader) + responsePayload.Length));
// 反转方向
+ winDivertAddress.Impostor = true;
if (winDivertAddress.Direction == WinDivertDirection.Inbound)
{
winDivertAddress.Direction = WinDivertDirection.Outbound;
@@ -162,7 +163,7 @@ namespace FastGithub.Dns
{
winDivertAddress.Direction = WinDivertDirection.Inbound;
}
-
+
WinDivert.WinDivertHelperCalcChecksums(winDivertBuffer, packetLength, ref winDivertAddress, WinDivertChecksumHelperParam.All);
this.logger.LogInformation($"已拦截dns查询{domain}并伪造解析结果为{IPAddress.Loopback}");
}
diff --git a/FastGithub.Dns/FastGithub.Dns.csproj b/FastGithub.PacketIntercept/FastGithub.PacketIntercept.csproj
similarity index 90%
rename from FastGithub.Dns/FastGithub.Dns.csproj
rename to FastGithub.PacketIntercept/FastGithub.PacketIntercept.csproj
index 08a71e8..cbc4b61 100644
--- a/FastGithub.Dns/FastGithub.Dns.csproj
+++ b/FastGithub.PacketIntercept/FastGithub.PacketIntercept.csproj
@@ -9,6 +9,7 @@
+
diff --git a/FastGithub.Dns/HostsConflictSolver.cs b/FastGithub.PacketIntercept/HostsConflictSolver.cs
similarity index 100%
rename from FastGithub.Dns/HostsConflictSolver.cs
rename to FastGithub.PacketIntercept/HostsConflictSolver.cs
diff --git a/FastGithub.PacketIntercept/HttpsInterceptHostedService.cs b/FastGithub.PacketIntercept/HttpsInterceptHostedService.cs
new file mode 100644
index 0000000..2200556
--- /dev/null
+++ b/FastGithub.PacketIntercept/HttpsInterceptHostedService.cs
@@ -0,0 +1,37 @@
+using FastGithub.Configuration;
+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
new file mode 100644
index 0000000..8bbe9ec
--- /dev/null
+++ b/FastGithub.PacketIntercept/HttpsInterceptor.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
+{
+ ///
+ /// https拦截器
+ ///
+ [SupportedOSPlatform("windows")]
+ sealed class HttpsInterceptor
+ {
+ private readonly ILogger logger;
+ private readonly ushort https443Port = BinaryPrimitives.ReverseEndianness((ushort)443);
+ private readonly ushort httpReverseProxyPort = BinaryPrimitives.ReverseEndianness((ushort)HttpsReverseProxyPort.Value);
+
+ ///
+ /// https拦截器
+ ///
+ ///
+ public HttpsInterceptor(ILogger logger)
+ {
+ this.logger = logger;
+ }
+
+ ///
+ /// 拦截443端口的数据包
+ ///
+ ///
+ public void Intercept(CancellationToken cancellationToken)
+ {
+ if (HttpsReverseProxyPort.Value == 443)
+ {
+ return;
+ }
+
+ var filter = $"loopback and (tcp.DstPort == 443 or tcp.SrcPort == {HttpsReverseProxyPort.Value})";
+ 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.httpReverseProxyPort;
+ }
+ else
+ {
+ packet.TcpHeader->SrcPort = https443Port;
+ }
+ winDivertAddress.Impostor = true;
+ WinDivert.WinDivertHelperCalcChecksums(winDivertBuffer, packetLength, ref winDivertAddress, WinDivertChecksumHelperParam.All);
+ }
+ }
+}
diff --git a/FastGithub.Dns/IConflictSolver.cs b/FastGithub.PacketIntercept/IConflictSolver.cs
similarity index 100%
rename from FastGithub.Dns/IConflictSolver.cs
rename to FastGithub.PacketIntercept/IConflictSolver.cs
diff --git a/FastGithub.Dns/ProxyConflictSolver.cs b/FastGithub.PacketIntercept/ProxyConflictSolver.cs
similarity index 100%
rename from FastGithub.Dns/ProxyConflictSolver.cs
rename to FastGithub.PacketIntercept/ProxyConflictSolver.cs
diff --git a/FastGithub.Dns/ServiceCollectionExtensions.cs b/FastGithub.PacketIntercept/ServiceCollectionExtensions.cs
similarity index 67%
rename from FastGithub.Dns/ServiceCollectionExtensions.cs
rename to FastGithub.PacketIntercept/ServiceCollectionExtensions.cs
index f4736dc..b5506ea 100644
--- a/FastGithub.Dns/ServiceCollectionExtensions.cs
+++ b/FastGithub.PacketIntercept/ServiceCollectionExtensions.cs
@@ -11,17 +11,19 @@ namespace FastGithub
public static class ServiceCollectionExtensions
{
///
- /// 注册dns拦截器
+ /// 注册数据包拦截器
///
///
///
[SupportedOSPlatform("windows")]
- public static IServiceCollection AddDnsInterceptor(this IServiceCollection services)
+ public static IServiceCollection AddPacketIntercept(this IServiceCollection services)
{
services.TryAddSingleton();
+ services.TryAddSingleton();
services.AddSingleton();
services.AddSingleton();
- return services.AddHostedService();
+ services.AddHostedService();
+ return services.AddHostedService();
}
}
}
diff --git a/FastGithub.sln b/FastGithub.sln
index 40a868f..7bfdb8e 100644
--- a/FastGithub.sln
+++ b/FastGithub.sln
@@ -1,12 +1,10 @@
Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio Version 16
-VisualStudioVersion = 16.0.31320.298
+# Visual Studio Version 17
+VisualStudioVersion = 17.0.31612.314
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FastGithub", "FastGithub\FastGithub.csproj", "{C1099390-6103-4917-A740-A3002B542FE0}"
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FastGithub.Dns", "FastGithub.Dns\FastGithub.Dns.csproj", "{43FF9C79-51D5-4037-AA0B-CA3006E2A7E6}"
-EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FastGithub.Http", "FastGithub.Http\FastGithub.Http.csproj", "{B5DCB3E4-5094-4170-B844-6F395002CA42}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FastGithub.DomainResolve", "FastGithub.DomainResolve\FastGithub.DomainResolve.csproj", "{5D26ABDD-F341-4EB7-9D08-FCB80F79B4B4}"
@@ -15,6 +13,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FastGithub.Configuration",
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FastGithub.HttpServer", "FastGithub.HttpServer\FastGithub.HttpServer.csproj", "{C9807DA0-4620-445E-ABBF-57A617B8E773}"
EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FastGithub.PacketIntercept", "FastGithub.PacketIntercept\FastGithub.PacketIntercept.csproj", "{701FF90C-E651-4E0B-AE7F-84D1F17DD178}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -25,10 +25,6 @@ Global
{C1099390-6103-4917-A740-A3002B542FE0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C1099390-6103-4917-A740-A3002B542FE0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C1099390-6103-4917-A740-A3002B542FE0}.Release|Any CPU.Build.0 = Release|Any CPU
- {43FF9C79-51D5-4037-AA0B-CA3006E2A7E6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {43FF9C79-51D5-4037-AA0B-CA3006E2A7E6}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {43FF9C79-51D5-4037-AA0B-CA3006E2A7E6}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {43FF9C79-51D5-4037-AA0B-CA3006E2A7E6}.Release|Any CPU.Build.0 = Release|Any CPU
{B5DCB3E4-5094-4170-B844-6F395002CA42}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B5DCB3E4-5094-4170-B844-6F395002CA42}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B5DCB3E4-5094-4170-B844-6F395002CA42}.Release|Any CPU.ActiveCfg = Release|Any CPU
@@ -45,6 +41,10 @@ Global
{C9807DA0-4620-445E-ABBF-57A617B8E773}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C9807DA0-4620-445E-ABBF-57A617B8E773}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C9807DA0-4620-445E-ABBF-57A617B8E773}.Release|Any CPU.Build.0 = Release|Any CPU
+ {701FF90C-E651-4E0B-AE7F-84D1F17DD178}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {701FF90C-E651-4E0B-AE7F-84D1F17DD178}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {701FF90C-E651-4E0B-AE7F-84D1F17DD178}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {701FF90C-E651-4E0B-AE7F-84D1F17DD178}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/FastGithub/FastGithub.csproj b/FastGithub/FastGithub.csproj
index b3a7101..9b803de 100644
--- a/FastGithub/FastGithub.csproj
+++ b/FastGithub/FastGithub.csproj
@@ -12,9 +12,9 @@
-
+
diff --git a/FastGithub/Startup.cs b/FastGithub/Startup.cs
index 9698b93..4bd6efd 100644
--- a/FastGithub/Startup.cs
+++ b/FastGithub/Startup.cs
@@ -40,7 +40,7 @@ namespace FastGithub
if (OperatingSystem.IsWindows())
{
- services.AddDnsInterceptor();
+ services.AddPacketIntercept();
}
}