HttpsInterceptor.cs 3.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. using FastGithub.Configuration;
  2. using Microsoft.Extensions.Logging;
  3. using System;
  4. using System.Buffers.Binary;
  5. using System.Runtime.Versioning;
  6. using System.Threading;
  7. using WinDivertSharp;
  8. namespace FastGithub.Dns
  9. {
  10. /// <summary>
  11. /// https拦截器
  12. /// </summary>
  13. [SupportedOSPlatform("windows")]
  14. sealed class HttpsInterceptor
  15. {
  16. private readonly ILogger<DnsInterceptor> logger;
  17. private readonly ushort https443Port = BinaryPrimitives.ReverseEndianness((ushort)443);
  18. private readonly ushort httpReverseProxyPort = BinaryPrimitives.ReverseEndianness((ushort)HttpsReverseProxyPort.Value);
  19. /// <summary>
  20. /// https拦截器
  21. /// </summary>
  22. /// <param name="logger"></param>
  23. public HttpsInterceptor(ILogger<DnsInterceptor> logger)
  24. {
  25. this.logger = logger;
  26. }
  27. /// <summary>
  28. /// 拦截443端口的数据包
  29. /// </summary>
  30. /// <param name="cancellationToken"></param>
  31. public void Intercept(CancellationToken cancellationToken)
  32. {
  33. if (HttpsReverseProxyPort.Value == 443)
  34. {
  35. return;
  36. }
  37. var filter = $"loopback and (tcp.DstPort == 443 or tcp.SrcPort == {HttpsReverseProxyPort.Value})";
  38. var handle = WinDivert.WinDivertOpen(filter, WinDivertLayer.Network, 0, WinDivertOpenFlags.None);
  39. if (handle == IntPtr.Zero)
  40. {
  41. return;
  42. }
  43. cancellationToken.Register(hwnd => WinDivert.WinDivertClose((IntPtr)hwnd!), handle);
  44. var packetLength = 0U;
  45. using var winDivertBuffer = new WinDivertBuffer();
  46. var winDivertAddress = new WinDivertAddress();
  47. while (cancellationToken.IsCancellationRequested == false)
  48. {
  49. if (WinDivert.WinDivertRecv(handle, winDivertBuffer, ref winDivertAddress, ref packetLength))
  50. {
  51. try
  52. {
  53. this.ModifyHttpsPacket(winDivertBuffer, ref winDivertAddress, ref packetLength);
  54. }
  55. catch (Exception ex)
  56. {
  57. this.logger.LogWarning(ex.Message);
  58. }
  59. finally
  60. {
  61. WinDivert.WinDivertSend(handle, winDivertBuffer, packetLength, ref winDivertAddress);
  62. }
  63. }
  64. }
  65. }
  66. /// <summary>
  67. /// 443端口转发到https反向代理端口
  68. /// </summary>
  69. /// <param name="winDivertBuffer"></param>
  70. /// <param name="winDivertAddress"></param>
  71. /// <param name="packetLength"></param>
  72. unsafe private void ModifyHttpsPacket(WinDivertBuffer winDivertBuffer, ref WinDivertAddress winDivertAddress, ref uint packetLength)
  73. {
  74. var packet = WinDivert.WinDivertHelperParsePacket(winDivertBuffer, packetLength);
  75. if (packet.TcpHeader->DstPort == https443Port)
  76. {
  77. packet.TcpHeader->DstPort = this.httpReverseProxyPort;
  78. }
  79. else
  80. {
  81. packet.TcpHeader->SrcPort = https443Port;
  82. }
  83. winDivertAddress.Impostor = true;
  84. WinDivert.WinDivertHelperCalcChecksums(winDivertBuffer, packetLength, ref winDivertAddress, WinDivertChecksumHelperParam.All);
  85. }
  86. }
  87. }