HttpClientHanlder.cs 3.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. using System;
  2. using System.Net.Http;
  3. using System.Net.Security;
  4. using System.Net.Sockets;
  5. using System.Security.Cryptography.X509Certificates;
  6. using System.Threading;
  7. using System.Threading.Tasks;
  8. namespace FastGithub.ReverseProxy
  9. {
  10. /// <summary>
  11. /// YARP的HttpClientHandler
  12. /// </summary>
  13. class HttpClientHanlder : DelegatingHandler
  14. {
  15. private readonly DomainResolver domainResolver;
  16. /// <summary>
  17. /// YARP的HttpClientHandler
  18. /// </summary>
  19. /// <param name="domainResolver"></param>
  20. public HttpClientHanlder(DomainResolver domainResolver)
  21. {
  22. this.domainResolver = domainResolver;
  23. this.InnerHandler = CreateSocketsHttpHandler();
  24. }
  25. /// <summary>
  26. /// 创建转发代理的httpHandler
  27. /// </summary>
  28. /// <returns></returns>
  29. private static SocketsHttpHandler CreateSocketsHttpHandler()
  30. {
  31. return new SocketsHttpHandler
  32. {
  33. Proxy = null,
  34. UseProxy = false,
  35. AllowAutoRedirect = false,
  36. ConnectCallback = async (context, cancellationToken) =>
  37. {
  38. var socket = new Socket(SocketType.Stream, ProtocolType.Tcp);
  39. await socket.ConnectAsync(context.DnsEndPoint, cancellationToken);
  40. var stream = new NetworkStream(socket, ownsSocket: true);
  41. var tlsSniContext = context.InitialRequestMessage.GetTlsSniContext();
  42. if (tlsSniContext.IsHttps == false)
  43. {
  44. return stream;
  45. }
  46. var sslStream = new SslStream(stream, leaveInnerStreamOpen: false);
  47. await sslStream.AuthenticateAsClientAsync(new SslClientAuthenticationOptions
  48. {
  49. TargetHost = tlsSniContext.TlsSniPattern.Value,
  50. RemoteCertificateValidationCallback = ValidateServerCertificate
  51. }, cancellationToken);
  52. return sslStream;
  53. // 这里最好需要验证证书的使用者和所有使用者可选名称
  54. static bool ValidateServerCertificate(object sender, X509Certificate? cert, X509Chain? chain, SslPolicyErrors errors)
  55. {
  56. return errors == SslPolicyErrors.None || errors == SslPolicyErrors.RemoteCertificateNameMismatch;
  57. }
  58. }
  59. };
  60. }
  61. /// <summary>
  62. /// 替换域名为ip
  63. /// </summary>
  64. /// <param name="request"></param>
  65. /// <param name="cancellationToken"></param>
  66. /// <returns></returns>
  67. protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
  68. {
  69. var uri = request.RequestUri;
  70. if (uri != null && uri.HostNameType == UriHostNameType.Dns)
  71. {
  72. var address = await this.domainResolver.ResolveAsync(uri.Host, cancellationToken);
  73. var builder = new UriBuilder(uri)
  74. {
  75. Scheme = Uri.UriSchemeHttp,
  76. Host = address.ToString(),
  77. };
  78. request.RequestUri = builder.Uri;
  79. request.Headers.Host = uri.Host;
  80. var context = request.GetTlsSniContext();
  81. context.TlsSniPattern = context.TlsSniPattern.WithDomain(uri.Host).WithIPAddress(address).WithRandom();
  82. }
  83. return await base.SendAsync(request, cancellationToken);
  84. }
  85. }
  86. }