只有IPv6的网络与IPv4最后的倔强


464XLAT 是走向 IPv6 单栈的过程中,用来让纯 IPv6 网络能够通过地址翻译访问 IPv4 网络的技术。他的工作流程是:IPv4 应用直接发送 IPv4 分组,到达 CLAT(Customer-side Translator,用户侧翻译器)进行无状态 NAT46 转换成 IPv6 分组,通过 IPv6 网络传输到达 PLAT(Provider-side Translator,运营商侧翻译器)后再进行 NAT64 转换成 IPv4 分组到达目标 IPv4 主机。

有了这个技术,IPv4 协议栈就可以在接入层上完全砍掉了,只需要有 CLAT 将 IPv4 分组送到 IPv4 网络的边界即可。CLAT 之所以叫“用户侧”,是因为他通常运行在光猫,甚至终端设备(如手机、电脑等)上。本文记录的是终端设备运行 CLAT。

2 月春节期间,我在家里的网络上设置了 NAT64 作为 PLAT,并配置了 DHCPv4 的 IPv6-Only Preferred 标记之后,DHCPv4 的地址分配骤减到 4 个,还在使用 IPv4 的只剩下智能家居、无线电台这些嵌入式设备了。

NAT64 enabled on 3 platforms

可以见到,图中 3 个平台的 IPv4 地址均为空或者 RFC 7335 指定用于 v4 转换的 192.0.0.0/29。

其实这种事情不是第一次干,早在 2019 年就尝试过一次:当时我用 tayga 在大学寝室的 OpenWrt 上配置了 NAT64,然后使用 bind9 做了 DNS64。这一套方案通过将没有 AAAA 记录的域名的 A 记录转换成 AAAA 的方式来实现 IPv4 网络的访问,也是当时的标准做法。这样操作的问题显而易见,毕竟总有应用不按照你所想的方式去查找服务器:他们使用指定的 DNS 服务器、使用 HTTPDNS,甚至使用了硬编码的 IPv4 地址。这些都是 DNS64 方案无法解决的,因此 DNS64 只能提升接入层的 IPv6 流量比例,而并不能完全抛弃接入层的 IPv4 协议栈。

所以更好的方案是,让设备去完成这个 IPv4→IPv6 的转换。那么问题来了,设备怎么知道 NAT64 可用、怎么知道使用什么前缀呢?当时 RFC 7050 提供了通过查询 ipv4only.arpa 获得 NAT64 前缀自动配置的方案,但是他依旧受到了 DNS 服务器的限制,不适合反映接入网络的真实情况,支持度也基本局限于蜂窝网络。甚至这个域名加入 IANA 的 Special-Use Domain Names 列表都是 2020 年的事情。

到了 2020 年,RFC 8781 往 Router Advertisement 中新增了一个名为 PREF64(Type 38)的选项,路由器可以在宣告默认路由、前缀等 v6 信息的同时,宣告将 IPv4 地址嵌入什么前缀就可以通过 NAT64 访问 IPv4 网络了。这才是自动发现应该有的最佳方案,毕竟 Router Advertisement 作为通常的终端设备自动发现并配置 IPv6 网络的必要手段,反应的也正是当前网络的信息。

PREF64 in RA and IPv6OnlyPreferred in DHCPv6

2021 年发布的 Android、2022 年发布的 iOS 16 和 macOS 13 都支持了 PREF64 参数。同期支持的还有 RFC 8925:他往 DHCPv4 中新增了一个名为 IPv6-Only Preferred(Option 108)的选项,支持 CLAT 的设备在尝试请求 IPv4 地址时如果收到了这个选项,那么他就会主动放弃 IPv4 协议栈。(当然也可以选择直接关闭 DHCPv4,只是这样不支持 CLAT 的设备就无法访问 IPv4 了。)

2025 年秋天,Windows 发布了 CLAT 的封测,我光速报名了。这下三大厂都支持了,于是便有了文章开头的内容。当然在测试过程中,我也发现了一些问题,已经反馈回相关负责人了。

2 月 19 日,Windows Insider Preview (Canary) 的代码从 Br(溴)更新到了 Kr(氪),build number 为 29531。这个版本引入了 CLAT,只是默认没有启用。6 月 9 日,Windows 网络团队宣布:自 Build 29599.1000 起,该功能正式开始公测。如果你家也部署了 IPv6-mostly 的网络,并想体验 Windows 的 CLAT 的话,可以使用以下操作开启:

  1. 使用 netsh.exe interface clat set global permit=enabled pref64fromdns=enabled pref64fromra=enabled 开启 CLAT,并重新启动系统。
  2. 重启后可使用 netsh.exe interface clat show globalnetsh.exe interface clat show instance interface = [interface-name] 两条指令查看情况。

除了 netsh 之外,该功能还支持使用组策略配置。想知道组策略的操作或更多 netsh 参数,请阅读 Windows 网络团队的博客

因为 Windows 的实现还有些问题,所以暂时不太建议在自家网络之外的地方开启。等 Windows 正式版支持 CLAT 后,微软/苹果/谷歌三大商业操作系统就都有 CLAT 且 IPv6-only capable 了,接入层可以只有 IPv6 的好时代就来了!


另外再借个位置记录一些东西,是我在配置 464XLAT 过程中遇到的一些其他的坑。

首先是 Juniper。我使用 Juniper SRX 系列产品作为家里的防火墙已经有 7 年历史了,配置文件也是祖传的。为了能够把自己的 IPv6 在传出到电信之前转换成电信 DHCPv6-PD 下发的前缀,之前正常的工作的 static NAT 是这么写的:

set security nat static rule-set ctv6 from interface pp0.0
set security nat static rule-set ctv6 rule soha-home match destination-address 240e:390:REDA:CTED::/64
set security nat static rule-set ctv6 rule soha-home then static-nat prefix 2a0e:aa06:40e:beef::/64

而 IPv4 地址嵌入 IPv6 前缀也是一种 static NAT,我又加入了这样的代码:

set security nat static rule-set nat64 from zone INT-soha-home
set security nat static rule-set nat64 rule plat-soha match source-address ::/0
set security nat static rule-set nat64 rule plat-soha match destination-address 2a0e:aa06:40e:64::/96
set security nat static rule-set nat64 rule plat-soha then static-nat inet

结果 PLAT 一直不工作,打 trace 以后注意到系统说 The packet destination ip is not same as source ip version, drop it。原来之前因为偷懒,match 条件只写了 destination-address 而没写 source-address ::/0,导致他在处理跨地址簇报文的时候爆炸了。补回去以后工作正常,又顺手把 source NAT 那边的也都补上了。

然后是 Android 的坑。刚设置上 IPv6-Only Preferred 的时候,Android 手机直接掉线,显示 Wi-Fi 连接失败,而我可以确认他是在收到 DHCPv4 响应以后断开的,一开始我百思不得其解,直到发现了我手机上并没有 IPv6 的默认路由,紧接着注意到系统上设置了 accept_ra_min_lft=180。

accept_ra_min_lft on Android

我配置的 Router Advertisement 的最大发送间隔是 45s,而 Juniper 默认在 Router Advertisement 报文中填入的 lifetime 是最大发送间隔的 3 倍,即 135s,小于 Android 的默认 180s 限制,故不会自动产生默认路由。没有默认路由更别提上网了,所以 Android 就显示了“Wi-Fi 连接失败”。修改 lifetime 后 Android 也正常工作了。

这种行为比较违反 RFC,RFC 4861 可是说“receivers should handle any value”,只要 >0 就应当创建默认路由的。但 Android 这么设计是为了减少收到 RA 时拉起系统处理的电量消耗,变更发生于 2023 年 9 月。这下同样解答了我之前的另外一个疑惑,最近半年多来总是发现手机在用 IPv4 上网,而我一直以为是自己 IPv6 网太烂而回落到了 IPv4……


协议: 本文根据 Creative Commons Attribution-NonCommercial-ShareAlike 4.0 License 进行授权。

标签: ipv6 nat64


  • 有 6 条评论, 不如再加一个评论?
  • 超能咸鱼王 超能咸鱼王 2026-03-16 17:25

    不懂就问:所以provider端是可以用常见的jool实现的NAT64作为翻译器 CLAT声明里面设置为对应的/96前缀就可以正常运行吗(只折腾过基于jool的DNS64+NAT64


    reply
    Soha Jin Soha Jin 2026-03-20 12:18

    对的,NAT64 实现任选,设置在哪里都行,只要在 RA 选项里写好且终端设备可达就行了。


    reply
    chariri chariri 2026-06-07 16:39

    464xlat还没在Windows铺开吧,目前似乎还是只在private preview阶段


    reply
    Soha Jin Soha Jin 2026-06-13 22:33

    之前虽然是内测,但是 3 月后的 canary build 都已经启用了功能,当然,默认没有配置生效。前两天 CLAT 已经宣布了公测,可以看看网络团队的博客内容: https://techcommunity.microsoft.com/blog/networkingblog/announcing-windows-clat-public-preview/4506046


    reply
    ybx332 ybx332 2026-06-15 16:02

    确实啊,有了464XLAT技术,只支持IPv4的设备也可以通过IPv6无障碍访问IPv4内容了。

    不过我还看到一个好玩的翻译技术,IVI,清华大学李星教授团队捣鼓出来的一个技术,说可以实现无状态的IPv4/IPv6转换,但这个东西的技术细节资料特别少,而且我看了相关的RFC文档,也不能理解它是怎么工作的。

    请问博主知道这个协议的细节吗?能不能大概分析一下为什么它最后没能得到广泛的部署?


    reply
    Soha Jin Soha Jin 2026-06-18 13:59

    当今 IVI 应当不是指某一种技术,而是指 464 翻译的一系列内容。这个名字的设计很有意思,在罗马数字中,IV 是 4、VI 是 6,IVI 就是把它们结合起来。

    IPv6 的地址空间有 128bit 之多,IPv4 的 32bit 与之相比实在是太渺小了。首先,v4 地址毫无疑问是可以完整嵌入 v6 地址的,问题在于, v6 主机在与 v4 网络沟通的时候使用什么地址。我们必须明确,想要真正地进行【无状态翻译】,必须进行一些取舍,因为地址空间的差异摆在这里,除非数学不存在了。

    所以早期的 IVI 方案(RFC 6219)就是直接把 v4 地址嵌入 v6,比如从 2001:db8::192.0.2.1 访问 v4 网络,就会被 nat 成 192.0.2.1。那么你发现问题了,这样做其实就是 v4 与 v6 的 1:1 对应,还是挺浪费地址空间的。 后来的 MAP-T(RFC 7599,研发时叫做 dIVI)在一定程度上缓解了这个问题,他把端口号范围一起编码进了 v6 地址来做这个翻译,扩大了 v4 空间的使用率。 还有另外一种叫做 MAP-E(RFC 7597)的实现,和 MAP-T 相似,他也是将端口范围信息编码在地址来实现无状态的转换。只是使用 IP 隧道封装——而不是翻译——的方式发回源主机。

    以上提到的几种实现,星老师都有参与( https://datatracker.ietf.org/person/xing@cernet.edu.cn )。另外,星老师之前有出过一本书,《新一代IPv6过渡技术:IPv6单栈和IPv4即服务》。这本书介绍了过渡到 IPv6 相关的技术,以及与 IVI 技术相关的内容。内容非常丰富,不过比较贵(小声)。我有买过一本拜读,但 3 月份去 IETF 的时候忘了带去,虽然和星老师聊上了几句,但没能让他签个名。

    我个人觉得,RFC 6219 中的方案主要还是在例如服务器之类的网络中应用比较多。毕竟有状态翻译需要 conntrack,就会浪费很多的算力,对于需要同时服务 v4 和 v6 网络的纯 v6 服务器,无状态翻译是可以“省电”的。而且服务器的 IP 本身也比较固定,即使无状态翻译对 v6 地址的使用相对就没那么自由,也无需担心 IP 一变就炸了的情况(毕竟 /64 的子网里面 interface ID 有 2^64 种可能呢)。

    出于同样的原因,另外两种方案也不太能应用在面向终端用户的环境里,但是很适合应用在运营商接入层、终结在用户 CPE 的这一段。在欧洲,MAP-T 有部分运营商在尝试用其作为 IPv6 only 的方案使用。

    不过,跨 address family 的翻译其实是很痛苦的,有 1145141919810 个坑(尺寸、分片、下层协议兼容性,等等)在路上等着你。所以 MAP-E 这种使用隧道封装技术,能够保留原始 v4 分组的特色的方式,使他可以在日本全国范围内部署。

    至于你觉得 IVI 翻译技术没有广泛部署,就有上述不适合面向终端用户的原因。面向终端用户更多还是使用有状态的 NAT64 进行传统的转换,反正在这一层往往也有防火墙,不差这一点了。


    reply

撰写新评论

account_circle
mail
insert_link
mode_comment