主题
NAT66:IPv6 到 IPv6 也需要 NAT?
第一反应通常是"IPv6 地址多到用不完,为什么还要 NAT"。
确实不是为了省地址。
三个真实动机
地址独立性。 这是最常见的理由。如果内网设备直接使用 ISP 分配的前缀, 换 ISP 就意味着给所有设备重新编址 —— 改配置、改 DNS、改 ACL、改监控。 用固定的内部编址加一层 NAT,换 ISP 时只改 NAT 映射。
text
没有 NAT66 有 NAT66
────────────────────────── ──────────────────────────────
内网直接用 ISP-A 的前缀 内网永久使用 2001:db8:1::/64
换到 ISP-B → 全网重新编址 换 ISP → 只改 NAT 的外部地址拓扑隐藏。 内网的编址结构本身就是情报 —— 哪个网段是财务、 哪个网段是研发、有多少个子网。IPv6 地址里往往还嵌着接口 MAC(EUI-64), 等于对外广播硬件信息。
多归属呈现。 同一台服务器,对上游 A 呈现一个地址,对上游 B 呈现另一个地址。
IPv6 社区对 NAT66 的态度是矛盾的
IETF 主流观点是 NAT 破坏端到端连通性,IPv6 的设计目标之一就是消灭 NAT。 RFC 4864 专门论证了"IPv6 网络不需要 NAT 也能获得 NAT 的各项好处"。
但现实中 NPTv6(RFC 6296,无状态前缀转换)和各种 NAT66 实现依然存在, 因为"地址独立性"这个需求是真实的,而 IPv6 官方给的答案(用 PA 前缀 + 重编址,或者申请 PI 前缀)对很多组织成本太高。
结论:能不用就不用,但需要时它确实解决问题。
VPP 的 nat66 能力很有限
先把期望降下来。VPP 的 nat66 只做静态 1:1 地址映射:
text
✓ 有 ✗ 没有
──────────────────────── ──────────────────────────────
静态 1:1 地址映射 地址池
内外侧接口划分 动态会话
端口转换(NAPT)
前缀级转换(NPTv6 那种)命令族总共就四条:
bash
nat66 plugin <enable [outside-vrf <vrf-id>]>|disable
nat66 add static mapping local <ip6-addr> external <ip6-addr> [vrf <table-id>] [del]
show nat66 interfaces
show nat66 static mappings没有端口转换意味着这是纯地址替换 —— 一个内部地址对应一个外部地址, 不能多个内部地址共享一个外部地址。规模上就是 1:1。
配置
应用配置
bash
./labctl reset v6
./labctl apply v6 02bash
vppctl nat66 plugin enable
vppctl set interface nat66 in host-eth1
vppctl set interface nat66 out host-eth3
vppctl nat66 add static mapping local 2001:db8:1::11 external 2001:db8:2::99验证
跑自检
bash
./labctl verify v6 02先看没有 NAT66 时 s6 看到什么:
text
s6 看到的源地址:2001:db8:1::11 ← 内网真实地址,拓扑暴露配上 NAT66 之后:
text
s6 看到的源地址:2001:db8:2::99 ← 外部呈现地址
✓ 源地址已被换成 2001:db8:2::99映射的报文计数也在涨:
bash
./labctl vppctl v6 show nat66 static mappingstext
NAT66 static mappings:
local 2001:db8:1::11 external 2001:db8:2::99 vrf 0
total pkts 4, total bytes 344最容易踩的坑:外部地址不会被自动认领
nat66 的外部地址需要外部网络有路由指过来
这是 nat66 和 nat44 一个非常容易搞错的差别。
text
nat44 add address 203.0.113.100
→ VPP 把它装进 FIB 当作本地地址(dpo-receive),
自动代答 ARP,外网零配置可达
nat66 add static mapping ... external 2001:db8:2::99
→ VPP **完全不认领**这个地址。
外网侧发 ND 请求,没人应答,流量静默不通实测把外网侧的路由删掉,立刻不通,而 s6 的邻居表是这样:
bash
ssh chenzhong@192.168.49.182 \
'docker exec clab-nat64-s6 ip -6 neigh'text
2001:db8:2::99 dev eth1 ref 1 used 0/0/0 probes 6 INCOMPLETE
^^^^^^^^^^INCOMPLETE 就是这个故障的签名:s6 一直在问"谁是 2001:db8:2::99", 但没有任何人回答。
解法是让外部网络有一条指向 NAT 设备的路由:
bash
# 实验里手工加
ip -6 route add 2001:db8:2::99/128 via 2001:db8:2::1
# 生产环境里由上游路由器为这段前缀指路由,
# 或者通过路由协议宣告想把外部地址配到接口上?不行
一个自然的念头是"既然 VPP 不认领,我手工把这个地址配到接口上"。 试了,被拒绝:
bash
vppctl set interface ip address host-eth3 2001:db8:2::99/128text
set interface ip address: failed to add 2001:db8:2::99/128
which conflicts with 2001:db8:2::1/64 for interface host-eth3VPP 不允许同一接口上有重叠地址。要让外部地址落在接口上, 它就必须来自一个不与接口地址重叠的前缀 —— 而那个前缀同样需要路由。
所以结论不变:靠路由。
nat64 与 nat66 不能共存于同一接口
同时启用会让 NAT66 盖住 NAT64
两个插件都要在内网接口上注册处理节点,互相冲突。实测:
text
只启用 nat64 → NAT64 正常
只启用 nat66 → NAT66 正常
两个都启用(同一内网口) → NAT66 正常,NAT64 完全失效自检脚本里做了这个对照:
text
── 5) nat64 与 nat66 不能共存于同一接口 ──────────
在已启用 nat66 的情况下,再把 nat64 也配上
NAT64 结果:(不通)
NAT66 结果:2001:db8:2::99:46065
✓ NAT66 盖住了 NAT64 —— 两者抢同一个内网接口,先注册的 nat66 胜出好消息是它比 det44 好得多:nat66 plugin disable 会正常摘掉自己注册的节点,关掉之后 NAT64 立刻恢复, 不需要重建 VPP:
text
关掉 nat66,确认 nat64 恢复
✓ NAT64 已恢复:[s4 tcp/9000] 我看到你的地址是 203.0.113.102:47184如果确实需要同时提供 NAT64 和 NAT66,只能让它们挂在不同的内网接口上。
和 NPTv6 的区别
你可能听过 NPTv6(RFC 6296,IPv6-to-IPv6 Network Prefix Translation)。 它和 VPP 的 nat66 不是一回事:
text
┌──────────────┬──────────────────────┬──────────────────────────┐
│ │ VPP nat66 │ NPTv6 (RFC 6296) │
├──────────────┼──────────────────────┼──────────────────────────┤
│ 转换粒度 │ 单个地址 1:1 │ 整个前缀 1:1 │
│ 有状态? │ 无状态(静态映射) │ 无状态 │
│ 配置量 │ 每台设备一条映射 │ 一条前缀映射覆盖全网段 │
│ 校验和 │ 需要重算 │ 用算法保证校验和中性 │
│ 可规模化 │ 差 │ 好 │
└──────────────┴──────────────────────┴──────────────────────────┘NPTv6 的巧妙之处是校验和中性:它调整前缀时同步补偿一个 16 位字, 使得整个地址的反码和保持不变,因此 TCP/UDP 校验和完全不用改。 这让它可以做到真正无状态、且不触碰传输层。
VPP 26.06 没有 NPTv6 实现。如果你的需求是"给整个 /64 做前缀转换", nat66 逐地址配置在几十台设备时就已经难以维护了。
需要前缀级转换怎么办
- Linux 内核有
netfilter的SNPT/DNPTtarget 实现 NPTv6 - 部分商业防火墙支持
- VPP 侧可以考虑用
pnat(策略 1:1 NAT,第 6 章会讲)或者自己写插件
或者回到最初的问题:真的需要 NAT66 吗? 如果目标是地址独立性,先评估一下申请 PI 前缀或使用 ULA + 前缀翻译的成本。
小结
| 为什么需要 | 地址独立性、拓扑隐藏、多归属呈现 —— 不是为了省地址 |
| VPP 的能力 | 只有静态 1:1 地址映射,无池、无端口转换、无动态会话 |
| 配置 | nat66 add static mapping local X external Y + set interface nat66 in/out |
| 最大的坑 | 外部地址不会被 VPP 认领,必须靠外部路由;症状是 ND INCOMPLETE |
| 与 nat64 | 同一内网接口上互斥,nat66 会盖住 nat64;但 disable 能干净恢复 |
| 规模化 | 差。需要前缀级转换请看 NPTv6,VPP 26.06 未实现 |
下一篇:464XLAT —— 当 IPv4 地址字面量绕不过去的时候。