摘要

  • RFC 3493 允许 AF_INET6 套接字通过 IPv4 映射 IPv6 地址与 IPv4 对端通信;IPV6_V6ONLY 可以把它限制为 IPv6,但 RFC 规定该选项默认关闭。
  • 因而,套接字族名称与一次成功的通配 bind 都不能证明实际对端族,也不能证明另一个 IPv4 监听器取得了同一端口。有效选项值、bind 结果与已接收连接必须分别取证。

设想一次发布:团队把 IPv6 服务和 IPv4 服务拆成两个进程,两者都配置同一个端口。IPv6 进程先启动,IPv4 进程随后报告地址已被占用。代码没有拼错端口;问题是第一个 AF_INET6 监听器可能已经替两个协议族占住了入口。

RFC 3493 的兼容办法是 IPv4 映射 IPv6 地址。IPv4 的 32 位地址被放进一个 128 位结构的低位,前面带固定的 ::ffff: 前缀。应用可以拿 AF_INET6 套接字连接 IPv4 节点;接收时,系统也可以在 sockaddr_in6 中交回映射后的对端。需要区分的程序可以调用 IN6_IS_ADDR_V4MAPPED()。

这个结构只证明应用与内核如何表示地址。它不证明远端原生运行 IPv6,不证明中间路径只经过 IPv6,也不证明 IPv4 与 IPv6 对端接受了相同授权策略。把结构标签当成网络事实,就把一个接口层收据误升成了路径收据。

RFC 3493 第 5.3 节把监听边界变成显式控制项。启用 IPV6_V6ONLY 后,AF_INET6 套接字只能用于 IPv6 通信。RFC 当时规定它默认关闭,所以通配 IPv6 监听器可能同时接收原生 IPv6 与以映射形式呈现的 IPv4 对端。

规范给出的用途直接涉及端口所有权:启用该选项后,同一服务器的两个版本可以使用同一个端口,一个服务 IPv6,另一个服务 IPv4。选项不是注释,也不只是显示格式;它决定一个 bind 是占一个族还是跨两个族,以及第二个进程还有没有机会获得自己的监听器。

因此,“两个进程都在运行”不够。某个进程可能启动了,却没有成功 bind;监督器也可能只看总服务单元。反过来,“只有一个 IPv6 套接字”也不能推出只接收 IPv6。审计至少要保存套接字族、IPV6_V6ONLY 的实际读回值、通配或具体地址、网络命名空间、端口、bind 返回值,以及真实接收对端的类别。

规范还留下一个关键限定:IPV6_V6ONLY 不影响经 SIIT 作为有效 IPv6 流量进入节点的 IPv4 映射地址。RFC 6052 与 RFC 6145 描述嵌入地址与分组翻译,那不同于本地双栈套接字把 IPv4 对端包装进 IPv6 结构。仅凭映射外观,不能反推出转换发生在哪里。

名称解析也只是前置证据。getaddrinfo() 可以按地址族与标志返回候选;RFC 6724 讨论默认地址选择,RFC 8305 则把 IPv6 与 IPv4 候选当作需要竞速的路径。候选存在不等于对端 bind 成功,更不等于连接、授权或业务完成。

“默认关闭”必须带着 2003 年的日期阅读。RFC 3493 是 Informational 文档,替代 RFC 2553,并说明正式套接字标准另有来源。今天的操作系统、运行时与容器平台可能采用不同默认值和端口冲突规则。历史事实不是免测的现代配置答案。

真正可复用的是证据链:声明的地址族、实际选项值、bind 边界、端口所有权、接收的对端表示、应用授权与服务结果。漏掉其中一级,“IPv6 监听器”就可能掩盖一个 IPv4 入口,也可能掩盖原定 IPv4 服务从未取得端口。

来源