如何同时支持 IPv4 和 IPv6 连接

Posted

技术标签:

【中文标题】如何同时支持 IPv4 和 IPv6 连接【英文标题】:How to support both IPv4 and IPv6 connections 【发布时间】:2010-12-09 17:57:12 【问题描述】:

我目前正在开发一个 UDP 套接字应用程序,我需要构建支持,以便 IPV4 和 IPV6 连接可以将数据包发送到服务器。

我希望有人可以帮助我并指出正确的方向;我发现的大部分文档都不完整。如果您能指出 Winsock 和 BSD 套接字之间的任何区别,那也会很有帮助。

提前致谢!

【问题讨论】:

【参考方案1】:

最好的方法是创建一个也可以接受 IPv4 连接的 IPv6 服务器套接字。为此,请创建一个常规 IPv6 套接字,关闭套接字选项 IPV6_V6ONLY,将其绑定到“任意”地址,然后开始接收。 IPv4 地址将以IPv4-mapped 格式显示为 IPv6 地址。

系统之间的主要区别在于IPV6_V6ONLY 是否a) 可用,b) 默认情况下是打开还是关闭。它在 Linux 上默认关闭(即允许不使用 setsockopt 的双栈套接字),并在大多数其他系统上打开。

此外,Windows XP 上的 IPv6 堆栈不支持该选项。在这些情况下,您需要创建两个单独的服务器套接字,并将它们放入 select 或多个线程中。

【讨论】:

说 IPV6_V6ONLY 在 Linux 上默认关闭是错误的:它取决于操作系统,而不仅仅是内核。例如,在 Debian GNU/Linux 上,它最近默认开启。 OS X 默认情况下也将其关闭,但最好始终明确设置它。毕竟本地系统管理员可能已经更改了它。 Windows 上默认开启(Win7 刚刚实现)。 如果 IPV6_V6ONLY 不可用,是否意味着操作系统不支持双栈? 您能否指出支持 IPv4 和 IPv6 连接(也解析 IPv4 映射格式)的示例源代码?【参考方案2】:

套接字 API 由 IETF RFC 管理,在包括 windows WRT IPv6 在内的所有平台上都应相同。

对于 IPv4/IPv6 应用程序,所有都是关于 getaddrinfo()getnameinfo()getaddrinfo 是个天才 - 查看客户端的 DNS、端口名称和功能,以解决“我可以使用 IPv4、IPv6 还是两者都使用来到达特定目的地?”这个永恒的问题。或者,如果您要使用双栈路由并希望它返回 IPv4 映射的 IPv6 地址,它也会这样做。

它提供了一个直接的sockaddr * 结构,可以插入bind()recvfrom()sendto()socket() 的地址族...并处理。

对于 UDP 实现,我会小心设置双栈套接字,或者更一般地说,绑定到所有接口 (INADDR_ANY)。经典问题是,当地址未锁定(参见bind())到特定接口并且系统有多个接口请求时,响应可能会根据操作系统路由表的突发奇想从具有多个地址的计算机的不同地址传输,令人困惑的应用程序协议——尤其是任何具有身份验证要求的系统。

对于这不成问题的 UDP 实现或 TCP,当您的系统启用 IPv* 时,双堆栈套接字可以节省大量时间。必须注意不要完全依赖双栈,因为这不是绝对必要的,因为不乏使用不支持双栈套接字的 IPv6 栈部署的合理平台(旧 Linux、BSD、Windows 2003)。

【讨论】:

问题是......关于所述功能的手册页中的文档根本不清楚它“只是”适用于 ipv4 和 ipv6,它看起来会为任何协议系列提供一个 struct sockaddr它有一个解析为单词的主机名......还有整个“提示”的东西..到底有多少“提示”。就我而言,这不是“提示”,而是“命令”。 :P 当在一个盒子上启用 ipv6 时,它返回大量 ipv6 sockaddr 也存在相当大的操作风险,一个人也必须循环通过 connect() 超时,但实际上并没有路由到任何地方。【参考方案3】:

RFC 并没有真正指定 IPV6_V6ONLY 套接字选项的存在,但是,如果它不存在,RFC 非常清楚,实现应该就好像该选项为 FALSE。

如果存在该选项,我认为它应该默认为 FALSE,但出于难以理解的原因,BSD 和 Windows 实现默认为 TRUE。有一个奇怪的说法是,这是一个安全问题,因为不了解 IPv6 的程序员可能会认为他们仅绑定到 IN6ADDR_ANY 以仅用于 IPv6,并意外接受导致安全问题的 IPv4 连接。我认为这既牵强又荒谬,除了让任何期望符合 RFC 实现的人感到惊讶之外。

对于 Windows,不合规通常不会令人意外。在 BSD 的情况下,这充其量是不幸的。

【讨论】:

IPv6 API 标准,RFC 3493,如果您想阅读所有详细信息,请在其 5.3 节中描述 IPV6_V6ONLY。【参考方案4】:

我一直在 Windows 下玩这个,它实际上似乎是一个安全问题,如果你绑定到环回地址,那么 IPv6 套接字正确绑定到 [::1] 但映射的 IPv4 套接字是绑定到 INADDR_ANY,因此您的(据称)安全的仅限本地应用程序实际上是向世界公开的。

【讨论】:

以上是关于如何同时支持 IPv4 和 IPv6 连接的主要内容,如果未能解决你的问题,请参考以下文章

域名如何优先解析ipv6

如何判断自己的网络环境是不是支持ipv6

ubuntu服务器只有ipv6监听服务

如何设计优雅的IP检查API以支持IPv4和IPv6

ipv4与ipv6如何转换

CentOS安装配置nginx-rtmp-module(同时支持IPv4和IPv6)