📚 第五章 IP协议相关技术
📄 一句话概括

NAT-PT 是「把 v6 包翻成 v4 包」的网关:地址和协议头一起改,两端都不用动。 它因为「改协议头」这一步被 RFC 4966 判了死刑,现在的替代叫 NAT64 加 DNS64。

📝 本节和前面几节的关系

5.6.1 讲的 NAT 只改地址,这一节讲「连协议头也改」要付什么代价。 4.6.1 讲了 v6 为什么必要,这一节讲「过渡期怎么让两边说话」。

一、过渡期有三条路

v4 和 v6 不是「版本号不同」,是两套地址体系:v6 主机发一个包,纯 v4 网络根本看不懂。 所以过渡只有三条路:

办法 做什么 代价
双栈 一台机器两套地址 每台都要升级
隧道 v6 包塞进 v4 包里运 只解决两点之间
翻译 在边界上改包 破坏端到端

第一行最稳,第二行最省事,第三行最省地址: 翻译的初衷是「让只有 v6 的主机能访问只有 v4 的服务器」。 这个场景在过渡初期非常真实——新装的系统默认开 v6,但大量老服务还是 v4。

二、NAT-PT 怎么改

NAT-PT 站在 v6 和 v4 的交界上:一边收 v6 包,一边发 v4 包。 它的动作分四步:

步 做什么 容易忽略的地方
1 收 v6 包,取出源和目的 判断要不要翻译
2 把 v6 源换成地址池里的 v4 要建会话表
3 重建一个 v4 头 校验和、TTL 全部重算
4 回程包再翻一次 靠表,不能靠算

第三行是「重建」不是「改写」: v6 头 40 字节、v4 头 20 字节,字段根本对不上,只能新建一个头。 一旦是「新建」,就意味着「中间设备完全理解了两边的协议」——这是后面所有麻烦的根。 NAPT-PT 只是在这一步上多加了一个端口复用: 一个 v4 地址可以带多台 v6 主机,和 5.6.2 的 NAPT 一个思路。 它能省地址,但省不掉「重建协议头」这件事。

三、为什么这条路走不通

四个理由,一个比一个硬:

原因 具体表现
端到端校验过不去 IPsec 的 AH 校验整个 IP 头,改一个字节就验不过
地址写在载荷里 FTP 的 PORT、SIP 的 SDP 里都有 IP,翻译器看不见
DNS 也要跟着改 A 记录得变成 AAAA,于是又要有 DNS-ALG
状态在中间设备上 设备一重启,所有连接全断

第一行最致命:AH 的设计目的就是「谁也别动我的头」,而 NAT-PT 的全部工作就是动头。 这两件事在原理上直接冲突,没有折中。 第二、三行是「越补越复杂」:每支持一个应用就要加一段 ALG 代码, 而互联网上的应用是无穷的——所以这条路从一开始就注定要一直补下去。 RFC 4966(2007 年)把 NAT-PT 正式标为 Historic,原因就这几条。

四、现在的做法:NAT64 加 DNS64

NAT64 也在改协议头,那它凭什么活下来? 因为它只做「机械的一对一替换」,不猜应用。

组件 负责什么 怎么做到不猜
NAT64 地址端口的有状态映射 按固定前缀算,不读载荷
DNS64 把 A 记录合成 AAAA 在名字层解决,不碰数据

第一行那个「固定前缀」是标准化的:64:ff9b::/96,后面 32 位直接放原来的 v4 地址。 所以 8.8.8.8 会变成 64:ff9b::808:808,网关看到这个前缀就知道「后面那 32 位是 v4」。 这种「地址里包地址」的做法叫「嵌入」,好处是不用查表就能反推。 第二行是关键的一招:v6 主机要访问 www.example.com,先问 DNS; DNS64 发现只有 A 记录,就合成一条 AAAA 返回,内容是「64:ff9b:: + 那个 v4 地址」。 于是应用层根本不知道对面是 v4,也就没有 ALG 那一堆补丁。 代价是「只支持 v6 主动访问 v4」: v4 主机想主动连一个纯 v6 的服务,还是没有办法—— 这与 5.6.4 要讲的「NAT 后面连不进来」是同一个病。

五、动手 Demo:把 v4 地址嵌进 v6 前缀里

按 RFC 6052 的规则,把 8.8.8.8 放进 64:ff9b::/96。 做法是「取 32 位,拆成两个 16 位,用十六进制写进去」。

import ipaddress

v4 = int(ipaddress.IPv4Address('8.8.8.8'))
print('64:ff9b::%x:%x' % (v4 >> 16, v4 & 0xffff))

实跑输出:

--------------------------------------------------------------------
NAT-PT,把 v4 和 v6 接起来
--------------------------------------------------------------------
**NAT-PT 是「在 v6 和 v4 之间做翻译」**:**它同时改地址和改协议头。**
**注意它已经被 RFC 废弃**,但思路值得了解。

  类型                 连接什么                  做什么
  --------------------------------------------------------------------
  **NAT44**            **v4 私网 ↔ v4 公网**     **改地址端口**
  **NAT66**            **v6 私网 ↔ v6 公网**     **改前缀**
  **NAT-PT**           **v6 ↔ v4**               **改协议头,已废弃**
  **NAT64/DNS64**     **v6 访问 v4**            **现在的做法**

**第三行为什么被废弃**:**因为「翻译协议头」破坏了端到端**,
**而且很多应用把地址写进了载荷里(FTP、SIP),翻译器根本看不懂。**
**这和 5.6.4 要讲的 NAT 老问题是同一个病。**

**第四行是现在的方案**:**NAT64 只做「有状态的地址映射」,不碰协议头**;
**DNS64 负责「合成 AAAA 记录」**——**它把 v4 地址包进一个特殊前缀里返回给客户端。**

**算一下那个「特殊前缀」**:
**64:ff9b::/96 是标准前缀,后面 32 位直接放原来的 IPv4 地址。**
**所以 8.8.8.8 会变成 64:ff9b::808:808。**
**这种「地址里包地址」的做法叫「嵌入」,好处是网关一眼能看出原始地址。**

输出的 808:808 就是 8.8.8.8 的十六进制写法:每段 8 位十六进制里放两个字节, 所以 08 08 写成 808,两组就是 808:808。 这个前缀是「知名前缀」(well-known prefix): 全球统一,谁都能算,所以不需要任何配置就能互通。 企业也可以用自己的一段前缀(叫网络特定前缀),代价是「出了自己的网就不认」。 注意 64:ff9b::/96 只能放 v4 地址,放不下端口: 要让多台 v6 主机共用一个 v4 地址,就得靠 NAT64 的会话表,用端口区分。 所以 NAT64 依然是「有状态」的设备,只是状态比 NAT-PT 干净得多。

30 秒实验

  1. 想一下:为什么 NAT-PT 不能像 5.6.1 的 NAT 那样「只改地址」?
  2. 算一下:64:ff9b::/96 里最多能表示多少个 v4 地址?
  3. 想一下:为什么「地址写在载荷里」这个问题,普通 NAT 也躲不掉?

常见误区

  1. 以为「NAT-PT 就是 NAT 的 v6 版」。 它还要重建协议头,代价比 NAT 大一个量级。
  2. 以为「翻译是首选的过渡方案」。 双栈和隧道更常用,翻译只在「一端只有 v4」时上。
  3. 以为「NAT64 只是 NAT-PT 改了名字」。 NAT64 不碰载荷、不猜应用,靠 DNS64 在名字层解决, 这是本质差别。
自测三问(点开对答案) 1. NAT-PT 为什么被废弃? —— **它要重建协议头、还要改写载荷里的地址**:IPsec 的 AH 过不去,ALG 越加越多, RFC 4966 把它标为 Historic。 2. 64:ff9b::/96 后面 32 位放什么? —— **直接放原来的 IPv4 地址**,所以 8.8.8.8 变成 64:ff9b::808:808。 3. NAT64 和 NAT-PT 最大的区别在哪? —— **NAT64 按固定前缀机械映射、不读载荷**,跨协议的名字解析交给 DNS64,从应用层绕开了 ALG。

下一节换个角度:NAT 本身留下了哪些甩不掉的麻烦。

相关笔记