确定何时尝试 IPv6 连接以及何时使用 IPv4

发布于 2024-08-03 05:40:15 字数 409 浏览 8 评论 0原文

我正在开发一个连接到用户指定的公共服务器的网络客户端程序。如果用户给我一个要连接的主机名,该主机名同时具有 IPv4 和 IPv6 地址(通常是同时具有 AAAAA 记录的 DNS 名称),我不确定我应该如何决定应该连接到哪个地址。

问题在于,机器同时支持 IPv4 和 IPv6,但只能通过 IPv4 进行全球连接,这是很常见的。最常见的情况是仅配置 IPv6 链路本地地址。目前我能想到的最佳替代方案是:

  1. 首先尝试 IPv6 地址 - 如果连接失败,请尝试 IPv4 地址;或者
  2. 只是让用户将其指定为配置设置(“prefer_ipv6”与“prefer_ipv4”)。

我看到选项 1 的问题是连接可能不会立即失败 - 可能需要相当长的时间才会超时。

I'm working on a network client program that connects to public servers, specified by the user. If the user gives me a hostname to connect to that has both IPv4 and IPv6 addresses (commonly, a DNS name with both A and AAAA records), I'm not sure how I should decide which address I should connect to.

The problem is that it's quite common for machines to support both IPv4 and IPv6, but only to have global connectivity over IPv4. The most common case of this is when only IPv6 link-local addresses are configured. At the moment the best alternatives I can come up with are:

  1. Try the IPv6 address(es) first - if the connection fails, try the IPv4 address(es); or
  2. Just let the user specify it as a config setting ("prefer_ipv6" versus "prefer_ipv4").

The problem I can see with option 1 is that the connection might not fail straight away - it might take quite a while to time out.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

埖埖迣鎅 2024-08-10 05:40:15

请尝试 IPv6。在绝大多数安装中,如果由于某种原因无法成功创建 IPv6 连接,尝试创建 IPv6 连接将立即失败:

  • 如果系统不支持 IPv6 套接字,则创建套接字将失败
  • ,如果系统确实支持 IPv6,并且配置了链路本地地址,因此不会有任何全局 IPv6 地址的路由表条目。同样,本地内核将报告失败而不发送任何数据包。
  • 如果系统确实有全局 IP 地址,但缺少路由所需的某些链路,则源应该收到 ICMPv6 错误消息,表明无法到达目的地;同样,如果目标有 IPv6 地址,但服务未侦听该地址。

当然,在某些情况下可能会出现问题,例如,如果配置了全局(或隧道)地址,并且某些内容错误地过滤掉了 ICMPv6 错误消息。您不必担心这种情况 - IPv4 连接可能因某种原因被破坏。

当然,您是否真的需要首先尝试 IPv6 地址是有争议的 - 您不妨再尝试一下。一般来说,您应该按照从 getaddrinfo 返回地址的顺序尝试地址。如今,系统支持配置选项,让管理员可以决定从 getaddrinfo 返回地址的顺序。

Please do try IPv6. In the significant majority of installations, trying to create an IPv6 connection will fail right away if it can't succeed for some reason:

  • if the system doesn't support IPv6 sockets, creating the socket will fail
  • if the system does support IPv6, and has link-local addresses configured, there won't be any routing table entry for the global IPv6 addresses. Again, the local kernel will report failure without sending any packets.
  • if the system does have a global IP address, but some link necessary for routing is missing, the source should be getting an ICMPv6 error message, indicating that the destination cannot be reached; likewise if the destination has an IPv6 address, but the service isn't listening on it.

There are of course cases where things can break, e.g. if a global (or tunnel) address is configured, and something falsely filters out ICMPv6 error messages. You shouldn't worry about this case - it may be just as well that IPv4 connectivity is somehow broken.

Of course, it's debatable whether you really need to try the IPv6 addresses first - you might just as well try them second. In general, you should try addresses in the order in which they are returned from getaddrinfo. Today, systems support configuration options that let administators decide in what order addresses should be returned from getaddrinfo.

浮云落日 2024-08-10 05:40:15

在提出问题之后,IETF 通过 RFC6555 提出了该问题的答案,又名快乐眼球

相关点是客户端和服务器可能都具有 IPv4 和 IPv6,但中间的一跳可能没有,因此不可能可靠地预测哪条路径将起作用。

Subsequent to the question being asked the IETF has proposed an answer to this question with RFC6555, a.k.a. Happy Eyeballs.

The pertinent point being the client and server may both have IPv4 and IPv6 but a hop in between may not so it is impossible to reliably predict which path will work.

十年九夏 2024-08-10 05:40:15

由于 getaddrinfo(),您应该让系统范围的配置来决定。就像 Java 一样。要求每个应用程序都尝试满足每个可能的 IPv6(错误)配置确实是不可扩展的!如果配置错误,用户会更直观地看到所有或没有应用程序崩溃。

另一方面,您希望尝试大量记录令人烦恼的延迟和超时,以便用户可以快速确定责任所在。就像所有其他理想情况下的延迟一样,包括(非常常见的)DNS 超时。

You should let the system-wide configuration decide thanks to getaddrinfo(). Just like Java does. Asking every single application to try to cater for every single possible IPv6 (mis)configuration is really not scalable! In case of a misconfiguration it is much more intuitive to the user if all or none applications break.

On the other hand you want to try to log annoying delays and time-outs profusely, so users can quickly identify what to blame. Just like every other delays ideally, including (very common) DNS time-outs.

情深缘浅 2024-08-10 05:40:15

这个演讲有解决方案。总结一下;

  • 有时,DNS 查找或与已解析地址的后续连接会出现问题
  • 您不想等待连接到 IPv6 地址超时后再连接到 IPv4 地址,反之亦然
  • 您不想等待在查找 A 记录之前查找 AAAA 记录超时,反之亦然
  • 在尝试连接您先返回的记录之前,您不希望在等待 AAAA 和 A 记录时停止。

解决方案是同时独立地查找 AAAA 和 A 记录,并独立连接到解析的地址。首先使用成功的连接。


最简单的方法是允许网络 API 使用按名称连接网络 API 为您完成此操作。例如,在 Java 中:

InetSocketAddress socketAddress = new InetSocketAddress("www.example.com", 80);
SocketChannel channel = SocketChannel.open(socketAddress);
channel.write(buffer);

幻灯片注释此时显示:

这里我们从主机创建一个名为 InetSocketAddress 的不透明对象
和端口,然后当我们打开那个SocketChannel时,就可以完成
在幕后,做任何必要的事情,而不需要
应用程序曾经看到过 IP 地址。

Windows 也有按名称连接 API。我没有代码片段
那些在这里。

现在,我并不是说这些 API 的所有实现都必须
现在就做正确的事情,但如果应用程序正在使用这些 API,
然后随着时间的推移可以改进实现。

与 getaddrinfo() 和类似 API 的区别在于,它们
随着时间的推移根本无法改善。 API 的定义是
他们会向您返回完整的地址列表,因此他们必须等到
他们有完整的清单可以给你。 getaddrinfo 没有办法
返回给您部分列表,然后再给您更多。

This talk has the solution. To summarize;

  • Sometimes there are problems with either DNS lookups or the subsequent connection to the resolved address
  • You don't want to wait for connecting to an IPv6 address to timeout before connecting to the IPv4 address, or vice versa
  • You don't want to wait for a lookup for an AAAA record to timeout before looking for an A record or vice versa
  • You don't want to stall while waiting for both AAAA and A records before attempting to connect with whichever record you get back first.

The solution is to lookup AAAA and A records simultaneously and independently, and to connect independently to the resolved addresses. Use whatever connection succeeds first.


The easiest way to do this is to allow the networking API do it for you using connect-by-name networking APIs. For example, in Java:

InetSocketAddress socketAddress = new InetSocketAddress("www.example.com", 80);
SocketChannel channel = SocketChannel.open(socketAddress);
channel.write(buffer);

The slide notes say at this point:

Here we make an opaque object called an InetSocketAddress from a host
and port, and then when we open that SocketChannel, that can complete
under the covers, doing whatever is necessary, without the
application ever seeing an IP address.

Windows also has connect-by-name APIs. I don’t have code fragments for
those here.

Now, I’m not saying that all implementations of these APIs necessarily
do the right thing today, but if applications are using these APIs,
then the implementations can be improved over time.

The di!erence with getaddrinfo() and similar APIs is that they
fundamentally can’t be improved over time. The API definition is that
they return you a full list of addresses, so they have to wait until
they have that full list to give you. There’s no way getaddrinfo can
return you a partial list and then later give you some more.

怼怹恏 2024-08-10 05:40:15

一些想法:

  1. 允许用户在每个站点的基础上指定首选项。
  2. 首先尝试 IPv4。
  3. 在第一次连接时尝试并行 IPv6。
  4. 如果之前连接成功,则在后续连接中使用 IPv6。

我说首先尝试 IPv4,因为这是一个建立和测试得更好的协议。

Some ideas:

  1. Allow the user to specify the preference on a per-site basis.
  2. Try IPv4 first.
  3. Attempt IPv6 in parallel upon the first connection.
  4. On subsequent connections, use IPv6 if the connection was successful previously.

I say to try IPv4 first because that is the protocol which is better established and tested.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文