使用 httpClient 但从未通过邮递员进行 rdap 响应的某些 Internet 连接出现奇怪故障

Strange failure from some Internet connections for rdap responses using httpClient, but never through postman

提问人:user4779 提问时间:11/18/2023 最后编辑:user4779 更新时间:11/19/2023 访问量:53

问:

我正在尝试编写一个应用程序,该应用程序将允许位于世界任何地方的任何用户根据此处的官方 rdap 服务器列表获得任何域名的相应 tld 的 rdap 响应:https://data.iana.org/rdap/dns.json,同时使用他们自己的本地互联网连接。

然而,奇怪的事情正在发生。使用我的本地 Internet 连接(目前位于东南亚)时,以下 google.com 查询(在 .com 的相应 rdap 服务器上,即 https://rdap.verisign.com/com/v1/)将在大约 80% 的时间内失败:

open System.Net.Http

let httpClient = new HttpClient()
let resp = httpClient.GetAsync($"https://rdap.verisign.com/com/v1/domain/google.com").Result
resp

以下是收到的错误:

System.AggregateException: One or more errors occurred. (The SSL connection could not be established, see inner exception.)
 ---> System.Net.Http.HttpRequestException: The SSL connection could not be established, see inner exception.
 ---> System.IO.IOException: Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host..
 ---> System.Net.Sockets.SocketException (10054): An existing connection was forcibly closed by the remote host.
   --- End of inner exception stack trace ---
   at System.Net.Sockets.Socket.AwaitableSocketAsyncEventArgs.ThrowException(SocketError error, CancellationToken cancellationToken)
   at System.Net.Sockets.Socket.AwaitableSocketAsyncEventArgs.System.Threading.Tasks.Sources.IValueTaskSource<System.Int32>.GetResult(Int16 token)
   at System.Net.Security.SslStream.EnsureFullTlsFrameAsync[TIOAdapter](CancellationToken cancellationToken)
   at System.Runtime.CompilerServices.PoolingAsyncValueTaskMethodBuilder`1.StateMachineBox`1.System.Threading.Tasks.Sources.IValueTaskSource<TResult>.GetResult(Int16 token)
   at System.Net.Security.SslStream.ReceiveBlobAsync[TIOAdapter](CancellationToken cancellationToken)
   at System.Net.Security.SslStream.ForceAuthenticationAsync[TIOAdapter](Boolean receiveFirst, Byte[] reAuthenticationData, CancellationToken cancellationToken)
   at System.Net.Http.ConnectHelper.EstablishSslConnectionAsync(SslClientAuthenticationOptions sslOptions, HttpRequestMessage request, Boolean async, Stream stream, CancellationToken cancellationToken)
   --- End of inner exception stack trace ---
   at System.Net.Http.ConnectHelper.EstablishSslConnectionAsync(SslClientAuthenticationOptions sslOptions, HttpRequestMessage request, Boolean async, Stream stream, CancellationToken cancellationToken)
   at System.Net.Http.HttpConnectionPool.ConnectAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
   at System.Net.Http.HttpConnectionPool.CreateHttp11ConnectionAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
   at System.Net.Http.HttpConnectionPool.AddHttp11ConnectionAsync(QueueItem queueItem)
   at System.Threading.Tasks.TaskCompletionSourceWithCancellation`1.WaitWithCancellationAsync(CancellationToken cancellationToken)
   at System.Net.Http.HttpConnectionPool.HttpConnectionWaiter`1.WaitForConnectionAsync(Boolean async, CancellationToken requestCancellationToken)
   at System.Net.Http.HttpConnectionPool.SendWithVersionDetectionAndRetryAsync(HttpRequestMessage request, Boolean async, Boolean doRequestAuth, CancellationToken cancellationToken)
   at System.Net.Http.DiagnosticsHandler.SendAsyncCore(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
   at System.Net.Http.RedirectHandler.SendAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
   at System.Net.Http.HttpClient.<SendAsync>g__Core|83_0(HttpRequestMessage request, HttpCompletionOption completionOption, CancellationTokenSource cts, Boolean disposeCts, CancellationTokenSource pendingRequestsCts, CancellationToken originalCancellationToken)
   --- End of inner exception stack trace ---
   at System.Threading.Tasks.Task.ThrowIfExceptional(Boolean includeTaskCanceledExceptions)
   at System.Threading.Tasks.Task`1.GetResultCore(Boolean waitCompletionNotification)
   at FSI_0138.makeRequestWithHeaders(String url)
   at <StartupCode$FSI_0138>.$FSI_0138.main@()
   at System.RuntimeMethodHandle.InvokeMethod(Object target, Void** arguments, Signature sig, Boolean isConstructor)
   at System.Reflection.MethodInvoker.Invoke(Object obj, IntPtr* args, BindingFlags invokeAttr)
   at System.Threading.Tasks.Task.ThrowIfExceptional(Boolean includeTaskCanceledExceptions)
   at System.Threading.Tasks.Task`1.GetResultCore(Boolean waitCompletionNotification)
   at FSI_0138.makeRequestWithHeaders(String url)
   at <StartupCode$FSI_0138>.$FSI_0138.main@()
   at System.RuntimeMethodHandle.InvokeMethod(Object target, Void** arguments, Signature sig, Boolean isConstructor)
   at System.Reflection.MethodInvoker.Invoke(Object obj, IntPtr* args, BindingFlags invokeAttr)

这没什么好玩的,可以很容易地用一些本地ISP问题来解释,对吧?

但是,该请求在 postman 中 100% 有效。例如:enter image description here

永远不会失败。有趣!

因此,我想到了在 Wireshark 中捕获数据包。下面显示了使用 httpClient 从 F# 进行的通信(我的真实 IP 已替换为“myip”):

95  2.307971    myip    rdap-1.verisigndns.com  TCP 86  4   63296 → 443 [SYN] Seq=0 Win=64952 Len=0 MSS=1412 WS=256 SACK_PERM=1
106 2.550129    rdap-1.verisigndns.com  myip    TCP 78  4   443 → 63296 [SYN, ACK] Seq=0 Ack=1 Win=1240 Len=0 MSS=1240
107 2.550336    myip    rdap-1.verisigndns.com  TCP 74  4   63296 → 443 [ACK] Seq=1 Ack=1 Win=64952 Len=0
108 2.550804    myip    rdap-1.verisigndns.com  TLSv1.2  253 4   Client Hello
118 3.112553    myip    rdap-1.verisigndns.com  TCP 253 4   [TCP Retransmission] 63296 → 443 [PSH, ACK] Seq=1 Ack=1 Win=64952 Len=179
134 3.832227    myip    rdap-1.verisigndns.com  TCP 253 4   [TCP Retransmission] 63296 → 443 [PSH, ACK] Seq=1 Ack=1 Win=64952 Len=179
159 5.264697    myip    rdap-1.verisigndns.com  TCP 253 4   [TCP Retransmission] 63296 → 443 [PSH, ACK] Seq=1 Ack=1 Win=64952 Len=179
215 7.797828    rdap-1.verisigndns.com  myip    TCP 74  4   443 → 63296 [RST, ACK] Seq=1 Ack=1 Win=24000 Len=0

可以看出,在握手成功后,rdap服务器似乎忽略了我的客户端请求。

以下是 postman 中的网络流量,它有效:

19193  526.178083  myip  rdap.verisign.com  TCP  66  98  53194 → 443 [SYN] Seq=0 Win=64240 Len=0 MSS=1460 WS=256 SACK_PERM=1
19199  526.406075  rdap.verisign.com  myip  TCP  58  98  443 → 53194 [SYN, ACK] Seq=0 Ack=1 Win=1480 Len=0 MSS=1412
19200  526.406368  myip  rdap.verisign.com  TCP  54  98  53194 → 443 [ACK] Seq=1 Ack=1 Win=64240 Len=0
19201  526.407322  myip  rdap.verisign.com  TLSv1.3  571  98  Client Hello
19208  526.638776  rdap.verisign.com  myip  TLSv1.3  1454  98  Server Hello, Change Cipher Spec, Application Data
19209  526.639594  rdap.verisign.com  myip  TCP  1454  98  443 → 53194 [ACK] Seq=1401 Ack=518 Win=28944 Len=1400 [TCP segment of a reassembled PDU]
19210  526.639648  myip  rdap.verisign.com  TCP  54  98  53194 → 443 [ACK] Seq=518 Ack=2801 Win=64952 Len=0
19211  526.640264  rdap.verisign.com  myip  TLSv1.3  1003  98  Application Data, Application Data, Application Data
19212  526.641121  myip  rdap.verisign.com  TLSv1.3  368  98  Change Cipher Spec, Application Data, Application Data
19213  526.645057  rdap.verisign.com  myip  TCP  54  98  443 → 53194 [ACK] Seq=1 Ack=518 Win=28944 Len=0
19214  526.645082  myip  rdap.verisign.com  TCP  54  98  [TCP Dup ACK 19212#1] 53194 → 443 [ACK] Seq=832 Ack=3750 Win=64003 Len=0
19219  526.868863  rdap.verisign.com  myip  TLSv1.3  293  98  Application Data
19220  526.870003  rdap.verisign.com  myip  TLSv1.3  1454  98  Application Data
19221  526.870305  myip  rdap.verisign.com  TCP  54  98  53194 → 443 [ACK] Seq=832 Ack=5389 Win=64952 Len=0
19222  526.870775  rdap.verisign.com  myip  TCP  1454  98  443 → 53194 [ACK] Seq=5389 Ack=832 Win=30016 Len=1400 [TCP segment of a reassembled PDU]
19223  526.871672  rdap.verisign.com  myip  TLSv1.3  127  98  Application Data
19224  526.871895  myip  rdap.verisign.com  TCP  54  98  53194 → 443 [ACK] Seq=832 Ack=6863 Win=64952 Len=0
19225  526.878734  myip  rdap.verisign.com  TCP  54  98  [TCP Previous segment not captured] 53194 → 443 [FIN, ACK] Seq=856 Ack=6863 Win=64952 Len=0
19226  526.878795  myip  rdap.verisign.com  TCP  78  98  [TCP Out-Of-Order] 53194 → 443 [PSH, ACK] Seq=832 Ack=6863 Win=64952 Len=24
19231  527.125064  rdap.verisign.com  myip  TCP  60  98  [TCP Dup ACK 19219#1] 443 → 53194 [ACK] Seq=6863 Ack=832 Win=300

所以我认为也许出于某种原因,rdap 服务器拒绝了来自 .NET httpClient 的流量,而不是 postman(尽管这当然没有意义,因为 rdap 服务应该期望其大部分请求来自自动源,而不是来自 postman 的手动请求)。我尝试手动设置标头以在 .NET 中复制邮递员:

open System.Net.Http
open System.Net.Http.Headers

let makeRequestWithHeaders (url: string) =
    let httpClient = new HttpClient()
    // Add headers similar to what Postman sends
    httpClient.DefaultRequestHeaders.UserAgent.ParseAdd("PostmanRuntime/7.26.10")
    httpClient.DefaultRequestHeaders.Accept.ParseAdd("application/json")
    httpClient.DefaultRequestHeaders.CacheControl <- CacheControlHeaderValue.Parse("no-cache")

    let response = httpClient.GetAsync(url).Result
    response

let url = "https://rdap.verisign.com/com/v1/domain/google.com"
let resp = makeRequestWithHeaders url
resp

然而,没有任何变化(仍然只有~20%的成功率)。

现在事情变得非常奇怪。我连接到美国 VPN 服务器(通过 NordVPN),现在 .NET 代码 100% 可以正常工作,没有任何故障(当然,邮递员仍然可以工作)。

但是,如果我连接到某些区域 VPN 服务器,则会遇到类似的问题,但针对不同的 RDAP 服务器!例如,如果通过 NordVPN 连接到阿根廷 VPN,那么 https://rdap.verisign.com/com/v1/domain/google.com 就可以正常工作,但是例如 .limo 的官方 rdap 服务器会失败 (https://rdap.identitydigital.services/rdap/)。下面是失败的 .NET 代码的示例:

open System.Net.Http

let httpClient = new HttpClient()
let resp = httpClient.GetAsync($"https://rdap.identitydigital.services/rdap/domain/virginia.limo/").Result
resp

仅在阿根廷 nord VPN 服务器上失败,而不是从任何其他服务器或我的本地互联网连接)。

因此,我对RDAP官方服务器提出了以下观察:

  1. 我的本地互联网连接可以在 .NET 和 Postman 中查询 .limo 域,但只能从 postman(而不是 .NET)中查询 .com 域
  2. NordVPN Argentina服务器可以在.NET和Postman中查询.com域,但只能从postman(而不是.NET)中查询.limo域
  3. NordVPN US 服务器可以很好地查询所有扩展/域,而不会在 .NET 和 postman 中遇到故障。

这一系列令人困惑的事实排除了很多合理的原因,例如httpClient,SSL协议等问题,因为如果是其中任何一个,那么它肯定总是会失败,并且切换到不同的IP和地理位置不应该解决它吗?

那么,如果某些 RDAP 服务器来自 httpClient,某些 RDAP 服务器是否出于某种原因有时会拒绝来自某些地理位置的请求,但如果它们来自 postman,则永远不会拒绝?为什么它不是相同的RDAP服务器,例如:官方.com服务器接受阿根廷流量罚款,但有时拒绝我的本地IP,而官方.limo rdap服务器接受我的本地流量罚款,但有时拒绝阿根廷流量。

这非常令人困惑,我正在寻求任何关于这里可能是什么问题的反馈?如果这真的是不同RDAP服务器和它们的一些奇怪策略的错误,那么我可以将其归咎于我的控制之外,但我想在得出结论之前确保情况确实如此。

警告:

  1. 这与呼叫无关。GetAsync 上的结果,用于说明目的
  2. 我的本地连接和阿根廷 nordVPN 服务器都可以直接查询网站(从 .NET 和 postman),只有在与官方 rdap 服务器交互时才会遇到这个问题。

更新(2023 年 11 月 19 日)- 2 天后

我今天的本地互联网连接对于所有请求都正常工作,就像它连接到 NordVPN US VPN 一样,但是阿根廷 VPN 在 .limo 上仍然失败

这越来越像第三方网络问题,但我不明白在哪里、如何或为什么

.NET F# Postman RDAP

评论


答: 暂无答案