简体   繁体   English

连接到VPN时,HttpClient.GetAsync超时

[英]HttpClient.GetAsync times out when connected to VPN

C# 4.5.2 framework HttpClient.GetAsync() method works fine on Windows 10 when system is not using VPN. C#4.5.2框架当系统不使用VPN时,HttpClient.GetAsync()方法在Windows 10上正常工作。

When VPN is connected HttpClient.GetAsync() call to the same address just blocks until it times out. 当VPN连接时,HttpClient.GetAsync()调用相同的地址只会阻塞,直到它超时。 Both Edge and Chrome have no issues accessing that same address. Edge和Chrome在访问同一地址时都没有问题。

Is there a way to see what is happening? 有没有办法看看发生了什么? What is HttpClient doing differently? 什么是HttpClient做的不同?

Update: Got some interesting clues by calling Dns.GetHostEntry() . 更新:通过调用Dns.GetHostEntry()获得一些有趣的线索。 Without VPN this call returned only IPv4 addresses that all could be connected to. 如果没有VPN,则此调用仅返回所有可以连接的IPv4地址。 With VPN client connected Dns.GetHostEntry() returned additional IPv6 addresses at the top of the list. 连接VPN客户端后, Dns.GetHostEntry()在列表顶部返回其他IPv6地址。 Connection to all IPv6 addresses timed out but all IPv4 ones still worked OK. 连接到所有IPv6地址超时但所有IPv4仍然正常工作。 Now is there a way to figure out without trying to connect which addresses work and which ones do not? 现在有没有办法弄清楚,而不是试图连接哪些地址工作,哪些不工作?

In my experience, this sounds like a VPN / firewall issue to me. 根据我的经验,这对我来说听起来像VPN /防火墙问题。 One quick thing to toggle in windows is under you VPN adapter properties, try unchecking "Use default gateway on remote network" - I know it sounds like a long shot but have had this problem in the past... 在Windows中切换的一个快速的事情是你的VPN适配器属性,尝试取消选中“在远程网络上使用默认网关” - 我知道这听起来像是一个长镜头,但过去有这个问题... 在此输入图像描述

Have to answer this myself as this problem has a simple cause but very confusing symptoms. 我必须自己回答,因为这个问题有一个简单的原因,但症状非常混乱。

The root cause: 根本原因:

DNS reports only IPv4 addresses for the host when system is not connected to VPN. 系统未连接到VPN时,DNS仅报告主机的IPv4地址。 All IPv4 addresses are usable. 所有IPv4地址都可用。

When VPN connection is active DNS returns IPv6 addresses in addition to IPv4. 当VPN连接处于活动状态时,除IPv4之外,DNS还会返回IPv6地址。 IPv4 addresses are still accessible but IPv6 are not. IPv4地址仍可访问,但IPv6不可访问。

The cause of such invalid network configuration is still a mystery that deserves its own separate post. 这种无效的网络配置的原因仍然是一个谜,值得它自己单独的帖子。

Confusing part: 令人困惑的部分:

Some apps work no matter what VPN connection status is. 无论VPN连接状态如何,某些应用程序都能正常运行

"But web browser can connect to the same host with or without VPN." “但是,无论有没有VPN,网络浏览器都可以连接到同一台主机。” True. 真正。 Browsers may use Happy eyeballs approach attempting to connect using both IPv4 and IPv6 at the same time. 浏览器可能会使用Happy eyeballs方法尝试同时使用IPv4和IPv6进行连接。

"But my old app has not problems connecting." “但我的旧应用程序没有连接问题。” Also true. 也是如此。 Some older and not so old apps use IPv4 protocol by default. 一些较旧且不太旧的应用程序默认使用IPv4协议。 Support for IPv6 or IPv4+IPv6 has to be explicitly implemented. 必须明确实现对IPv6或IPv4 + IPv6的支持。

"But it works sometimes". “但它有时会起作用”。 This happens when VPN connections are not reliable. 当VPN连接不可靠时会发生这种情况。 It leads to all sorts of solutions that are mere coincidences. 它导致各种各样的解决方案仅仅是巧合。

What exactly is happening: 究竟发生了什么:

HttpClient.GetAsync() uses default DNS resolution and can connect using both IPv4 and IPv6 addresses. HttpClient.GetAsync()使用默认DNS解析,可以使用IPv4和IPv6地址进行连接。 It does not discriminate and there is no direct way to influence protocol selection. 它没有区别,也没有直接影响协议选择的方法。 If DNS returns inaccessible address then HttpClient may use that invalid address to connect resulting in timeout. 如果DNS返回不可访问的地址,则HttpClient可能会使用该无效地址进行连接,从而导致超时。

Possible workarounds: 可能的解决方法:

The best: ask IT to fix IPv6 DNS issues. 最好的:请IT部门解决IPv6 DNS问题。 DNS should not report inaccessible addresses. DNS不应报告无法访问的地址。

Good: implement Happy eyeballs approach. 好:实施快乐眼球的方法。 Connect to both IPv6 and IPv4 host addresses using numeric IP instead of automatic resolution using host name. 使用数字IP连接到IPv6和IPv4主机地址,而不是使用主机名自动解析。

OK: Always connect to IPv4 using numeric IP. 确定:始终使用数字IP连接到IPv4。

Here is the piece of code that shows how to connect to a specific IP address: 以下是显示如何连接到特定IP地址的代码:

// Get DNS entries for the host.
var hostEntry = Dns.GetHostEntry(uri.Host); 

// Get IPv4 address
var ip4 = hostEntry.AddressList.First(addr => addr.AddressFamily == AddressFamily.InterNetwork);
// Build URI with numeric IPv4
var uriBuilderIP4 = new UriBuilder(uri); 
uriBuilderIP4.Host = ip4.ToString()); 
var uri4 = uriBuilder4.Uri; 

// Get IPv6 address
var ip6 = hostEntry.AddressList.First(addr => addr.AddressFamily == AddressFamily.InterNetworkV6);

// Build URI with numeric IPv6
var uriBuilderIP6 = new UriBuilder(uri); 
uriBuilderIP6.Host = $"[{ip6}]"; 
var uri6 = uriBuilder6.Uri; 

For HTTPS connections numeric addresses work only with "host" header with the name of the host (not an IP address) in it. 对于HTTPS连接,数字地址仅适用于带有主机名称(不是IP地址)的“host”标头。 Here is the way to add it. 这是添加它的方法。

var client = new HttpClient(); 
// Add "host" header with real host name e.g. stackoverflow.com 
client.DefaultRequestHeaders.Add("Host", uri.Host); 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM