using FastGithub.WinDiverts; using Microsoft.Extensions.Logging; using System; using System.ComponentModel; using System.Net; using System.Runtime.Versioning; using System.Threading; using System.Threading.Tasks; namespace FastGithub.PacketIntercept.Tcp { /// /// 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 = (ushort)oldServerPort; this.newServerPort = (ushort)newServerPort; this.logger = logger; } /// /// 拦截指定端口的数据包 /// /// /// public async Task InterceptAsync(CancellationToken cancellationToken) { if (this.oldServerPort == this.newServerPort) { return; } await Task.Yield(); var handle = WinDivert.WinDivertOpen(this.filter, WinDivertLayer.Network, 0, WinDivertOpenFlags.None); if (handle == new IntPtr(unchecked((long)ulong.MaxValue))) { throw new Win32Exception(); } this.logger.LogInformation($"tcp://{IPAddress.Loopback}:{this.oldServerPort} => tcp://{IPAddress.Loopback}:{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) == false) { throw new Win32Exception(); } 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); } } }