ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

NAT66实战:IPv6前缀翻译解决多线路与地址重编号痛点

NAT66实战:IPv6前缀翻译解决多线路与地址重编号痛点 NAT66这个名词不少刚接触IPv6改造的同行第一次看到都会愣一下IPv6地址不是多到能把地球上每粒沙子都分一遍吗怎么还需要NAT我在项目交流里被问过很多次每次都有人当场抬杠觉得NAT66是脱裤子放屁。但真到了组网环节多线路接入、运营商改前缀、内网不想重编号这些问题摆出来NAT66往往又成了最务实的答案。这篇文章我把NAT66讲透它正式名字叫NPTv6由RFC 6296定义本质是IPv6前缀翻译——把地址的前半段换掉后半段接口ID完全保留。你会在下文看到它和传统IPv4 NAT的根本差异看到Linux上用nftables把它跑起来的具体命令也会看到我实际部署中踩过的一些坑。适合正在规划IPv6改造、或者被“内网不想跟着运营商变地址”这类需求卡住的网络工程师。1. IPv6 都够地址了为什么还需要 NAT661.1 IPv6 设计初衷和它跟现实的落差IPv6当初最响亮的口号是“找回端到端透明性”。IPv4被NAT折磨了二十多年端口复用、状态表、ALG、P2P打洞各种补丁打得千疮百孔IETF希望IPv6能一劳永逸地址空间足够大每个设备都拿真正的全球单播地址网络中间层啥都不用做管好路由就行。这个愿景本身没毛病但落地的时候碰上了很现实的问题。问题出在全球单播地址的分配机制上。企业的IPv6前缀大部分来自运营商运营商会给你一段类似2001:db8:aaaa::/48的地址这段地址并不是你永久拥有的续约、换套餐、更换运营商、接入资费调整都可能让前缀变化。IPv6有SLAAC理论上重新编址比IPv4简单但那只是理论上。实际生产网里几十条防火墙策略绑了地址、DNS记录要改、SSL证书如果绑了IP也要处理、监控系统的地址白名单要同步更别提那些把IPv6地址硬编码在配置文件里的老系统。真到操作那天没有一个网络工程师敢拍胸脯说半小时能搞定。更麻烦的是多运营商接入。企业为了线路冗余接了两家ISP结果拿到两段不同前缀内网设备得同时配两段地址或者一套网络规划被生生撕成两半。业务流量要在两条线路间切换地址稳定性就很难保障。这种时候把“内部使用的地址空间”和“运营商分配的外部前缀”彻底解耦就成了很自然的诉求。NAT66就是干这件事的。1.2 三种必须做前缀翻译的现实场景第一类是多线路接入。我见过一个典型客户总部两条专线分别接电信和联通每家的IPv6前缀不一样。原来方案是内网同时配置两段前缀策略路由按目的网段分流结果出了故障后很难判断到底是哪条链路上的哪个前缀在回包排查一次要很久。后来改成内网统一用一个ULA前缀边界路由器上做两段NAT66映射电信线路映射成电信前缀联通线路映射成联通前缀。内部逻辑一下子干净了切换线路时不用动内网任何设备。第二类是运营商前缀变更。很多企业客户是租用专线接入虽然IPv4业务已经习以为常但一旦局端调整IPv6前缀说变就变。没有NAT66的话这就是一场小型网络割接。有了NAT66内网始终用自己规划的前缀运营商的变更只在边界设备上改一行映射规则风险范围小一个量级。第三类是网络合并和迁移。两家公司并购两套各自规划的IPv6内网要互通但都不想动原有编址数据中心的服务器要从一栋楼迁到另一栋楼对外服务地址要保持不变。在这些场景里NAT66相当于在地址空间之间搭了一个软桥不必全网重做。本质逻辑都是同一句话让内网的编制独立于外部的客观约束翻译这件事留给边界设备去做。1.3 ULA 搭配 NAT66最常见的组合姿势聊NAT66就绕不开ULA也就是RFC 4193定义的“本地唯一地址”。它使用fd00::/8空间看起来像IPv6里的私网地址但它的语义和IPv4私网地址不太一样。ULA在互联网上不会被路由出去但也不像IPv4私有地址那样天生被所有路由器当作不合法地址它只是在正常路由体系里“没人愿意转发”而已。企业内网用它做统一编址完全没问题问题在于内网主机要上外网源地址必须换成全球单播前缀这时边界设备上的NAT66就发挥作用了。于是很多企业的IPv6落地姿势变成了核心内网用ULA做长期稳定的地址规划边界路由器把ULA前缀映射成运营商分配的全球单播前缀。内网无论怎么调整都不影响对外通信运营商无论怎么换前缀内网也纹丝不动。这个组合看起来不“纯正”但运维省心是真的省心。IPv6原教旨主义者把NAT66批得一无是处这我能理解但在生产环境里与其让业务配合理想不如让网络适配业务。2. 拆开 NAT66 的底层原理其实它叫 NPTv62.1 NAT66 的标准身份RFC 6296 NPTv6很多人以为NAT66是某个厂商搞出来的私有特性其实它是正经的IETF标准。RFC 6296给出正式机制名称叫NPTv6全称Network Prefix Translation for IPv6。国内习惯叫NAT66只是顺口。它做的事情就一句话把IPv6报文里的地址前缀从一个值翻译成另一个值而接口ID也就是低64位原封不动。这个设计动机很明确IPv6地址空间充足没必要像IPv4那样搞端口复用所以标准里压根没有“端口转换”这个词。它也不维护连接状态表每个报文进来看一眼前缀是否匹配规则匹配就替换不匹配就放行处理完就忘记。这种无状态的设计让NPTv6可以部署在高速转发路径上不需要像IPv4 NAT那样为每个TCP/UDP连接做表项跟踪也不存在表项老化、连接数上限、NAT会话同步一类的问题。顺带澄清一个容易混淆的点NAT64也是IPv6时代的地址翻译技术但它是把IPv6翻译成IPv4解决“纯IPv6网络怎么访问IPv4服务”的问题。NAT66则是IPv6到IPv6解决“IPv6前缀怎么隔离和映射”的问题。两个东西方向不同、机制不同、解决的问题也不同别搞混。2.2 出入两个方向的完整转换流程NAT66的报文旅程可以用一个很简单的模型描述。假设内部前缀是fd00:1::/64外部映射前缀是2001:db8:1::/64。内部主机地址是fd00:1::10对应外部可见地址就是2001:db8:1::10后64位的::10保持不变。出方向内部主机发往外部网络的报文源地址是fd00:1::10。边界路由器收到后检查源地址落在内部前缀范围内把高64位替换成2001:db8:1::于是源地址变成2001:db8:1::10再把报文转发出去。入方向外部主机访问2001:db8:1::10边界路由器检查目的地址落在外部映射前缀范围内把高64位替换回fd00:1::报文进入内网并被送到fd00:1::10。整个过程里TCP端口、UDP端口完全不动传输层协议也不需要额外适配。拿“整条街改名”来类比很好理解街名换了门牌号没变邮递员不需要重新登记每家每户的信息就能找到目标。因为接口ID没变内网用SLAAC自动生成的地址在外网依然能保持一一对应不需要额外维护一张IP地址映射表。但有个技术细节容易被忽略IPv6的TCP和UDP校验和是把源地址和目的地址放入伪头部参与计算的。前缀变了校验和就得跟着调整。NAT66设备需要对ICMPv6、TCP、UDP报文做校验和修正否则对端收到后校验失败直接丢包。Linux内核的NETMAP框架会自动处理这个步骤但如果你在纠结该用硬件设备还是软件方案这条是评估厂商实现是否完整的重要检查项。2.3 为什么 NAT66 是无状态的而 NAT44 是有状态的传统IPv4 NAT必须是有状态的原因在于它做的事是“多对一复用”。一个公网IP要想承载几百个内网用户只能靠端口区分内网用户A的192.168.1.5:12345被翻译成203.0.113.1:40001用户B的192.168.1.6:12345被翻译成203.0.113.1:40002。路由器必须把这种映射关系记下来后边的响应报文来了才能知道该还原给谁。这个记录就是NAT会话表所有有状态NAT设备都绕不开。NAT66完全不是这套逻辑。它做的是前缀级别的1:1映射内网任何一个地址都唯一对应一个外网可见地址转换天然可逆。我只要知道外部地址2001:db8:1::10不需要查任何状态表反推就能知道它对应内部地址fd00:1::10。因此路由器不需要创建会话、不需要跟踪连接状态、不需要处理老化超时也不存在“NAT表项满了打不开新连接”这类IPv4时代很常见的故障。这个特性带来的实际收益很直接转发性能稳定不会因为连接数增长而出现性能拐点设备重启后不需要担心状态表丢失导致连接中断多设备做负载均衡时也不需要做会话同步。运维层面少操心一大块。2.4 NAT66 / NAT44 / NAT64 一张表看懂对比项NAT44 / NAPTNAT66 / NPTv6NAT64地址方向IPv4到IPv4IPv6到IPv6IPv6到IPv4转换内容IP地址加端口仅IPv6前缀IPv6与IPv4地址、IP头转换通常带端口复用状态维护有状态无状态有状态为主地址映射关系多对一复用1:1前缀映射多对一复用标准参考无单一RFCRFC 7857RFC 6296RFC 6146典型用途节省IPv4公网地址前缀隔离、多宿主、免重编号IPv6-only网络访问IPv4资源协议兼容性需要ALG适配天然兼容TCP/UDP需要DNS64和ALG辅助表格里最值得记住的是最后一行。NAT44要处理FTP的主动模式、SIP的SDP信息各种ALG模块又乱又难调。NAT66因为不碰端口也不改变传输层荷载里的东西绝大多数应用都不需要特殊照顾。这不是“更强”是因为它做的工作更少。3. 手把手实操Linux 上把 NAT66 跑起来3.1 实验拓扑与地址规划纸上谈兵讲完了直接上真东西。我用一台Linux路由器做NAT66双网卡结构如下边界路由器eth0接外部网络地址2001:db8:9::1/64边界路由器eth1接内部网络地址fd00:1::1/64内部测试主机地址fd00:1::10/64默认网关fd00:1::1外部测试主机地址2001:db8:9::100/64默认网关2001:db8:9::1NAT66映射前缀fd00:1::/64 ↔ 2001:db8:1::/64这里有一个设计上的关键点NAT66的“外部可见前缀”2001:db8:1::/64和物理接口所在网段2001:db8:9::/64是两回事。外部主机访问2001:db8:1::10时报文会交给默认网关2001:db8:9::1也就是边界路由器处理。为了让边界路由器确认自己可以接收这个前缀的流量我在实验里给它加了一个本地路由ip -6 route add local 2001:db8:1::/64 dev lo同时在外部测试主机上加一条静态路由把目标前缀指到边界路由器ip -6 route add 2001:db8:1::/64 via 2001:db8:9::1生产环境中外部前缀通常通过运营商路由或BGP对外通告原理是类似的只要报文能正常送到边界路由器NAT66入方向规则就能处理。内部主机的IPv6地址可以手工配置也可以用radvd通告fd00:1::/64让内网主机通过SLAAC自动获取。3.2 nftables 配置 NAT66 的关键命令先打开IPv6转发否则路由器不会帮忙转发IPv6报文sysctl -w net.ipv6.conf.all.forwarding1推荐用nftables语法比iptables清晰也是现代Linux默认趋势。直接照着抄nft add table ip6 nat66 nft add chain ip6 nat66 prerouting { type nat hook prerouting priority dstnat \; } nft add chain ip6 nat66 postrouting { type nat hook postrouting priority srcnat \; } nft add rule ip6 nat66 postrouting ip6 saddr fd00:1::/64 oifname eth0 counter netmap to 2001:db8:1::/64 nft add rule ip6 nat66 prerouting ip6 daddr 2001:db8:1::/64 iifname eth0 counter netmap to fd00:1::/64第一段创建了NAT66专用的表和两条链prerouting处理入方向postrouting处理出方向。优先级用的dstnat和srcnat这是NAT处理路径上的标准挂载点。第二段是核心翻译规则。前一条是出方向规则匹配源地址属于fd00:1::/64、且从eth0出去的报文用netmap to 2001:db8:1::/64把源地址前缀映射成外部前缀。后一条是入方向规则匹配目的地址属于2001:db8:1::/64、且从eth0进来的报文反向映射回内部前缀。注意这里没有MASQUERADE没有SNAT没有任何端口操作就是纯粹的前缀翻译。两条规则必须同时存在。少了出方向内部主机出不去少了入方向外部主机的回包根本送不回来。这也是NAT66部署时最常犯的错只配了一半。3.3 还可用 ip6tables 的 NETMAP 实现如果你维护的服务器还在用传统的iptables体系用ip6tables也能做到同样效果ip6tables -t nat -A PREROUTING -i eth0 -d 2001:db8:1::/64 -j NETMAP --to fd00:1::/64 ip6tables -t nat -A POSTROUTING -o eth0 -s fd00:1::/64 -j NETMAP --to 2001:db8:1::/64这里的关键是NETMAP目标。它和SNAT、DNAT有个本质区别NETMAP做的是整个地址段的映射把匹配到的源或目的前缀整体翻译成另一段前缀而不是只改单个IP。和nftables的netmap是同一个原理。不过提醒一下老版本内核和旧版iptables对IPv6的NETMAP支持可能存在差异。我在CentOS 7的内核上就遇到过规则装不上或行为怪异的情况。如果你也碰到这种问题别纠结直接换nftables新内核上稳很多。3.4 验证与排错配置完成后先在内部主机上ping外部测试机ping6 2001:db8:9::100能通就说明出方向没问题。这时在外网口抓包会看到源地址已经变成2001:db8:1::10而不是内网的fd00:1::10tcpdump -i eth0 -n icmp6外部主机再反向访问内网映射地址ping6 2001:db8:1::10能通说明入方向也正常。检查一下边界路由器上的规则计数器这是判断规则有没有被命中最直接的手段nft list table ip6 nat66如果计数器一直是零优先查三层路由再看规则里的接口名。很多问题不是NAT规则错了而是报文根本没走到这个链上来。排错顺序我每次都是固定的先看ip -6 route get能不能找到路由再看tcpdump确认报文落在哪个接口上最后才查NAT规则和防火墙。4. 部署中的坑与排查清单4.1 NAT66 不是防火墙别指望它掩盖拓扑和NAT66打交道多了我最大的体会是别拿IPv4 NAT的思维去套它。IPv4 NAT在客观上演化出了“隐藏内网”的效果外网只能看到一个公网IP内网多少台主机、什么结构别人看不见。这不完全是NAT的本意但很多安全合规检查里它会变成一道心理防线。NAT66完全没有这个功能。它只换前缀接口ID原封不动暴露在外网。你内网有一台fd00:1::10和一台fd00:1::dead:beef映射到外网就是2001:db8:1::10和2001:db8:1::dead:beef别人抓包一看就知道你有多少主机甚至能根据接口ID规律推测主机类型。如果有安全顾问跟你说“上了NAT66就能像以前那样隐藏内网”你直接驳回。NAT66的定位是地址隔离和网络规划解耦安全边界必须靠防火墙策略来兜底这层认知一定要立住。4.2 校验和、ICMPv6 错误消息与MTU问题校验和问题是NAT66实现质量的分水岭。好的实现会把IPv6伪头部变化对应的TCP/UDP/ICMPv6校验和一并修正差的实现只改IP头结果是报文发出去对端直接丢。Linux内核的netmap框架处理得比较成熟但我在一些国产防火墙设备上实测过NPTv6的校验和更新逻辑一言难尽。遇到“双向规则都配了、路由也通了、就是TCP握手卡住”的问题抓包看校验和字段基本就能定位。更隐蔽的是ICMPv6错误消息。IPv6的PMTUD依赖ICMPv6的Packet Too Big消息这类消息体里会嵌入触发错误的原始IPv6报文片段而那个片段里也包含原始源和目的地址。NAT66设备如果只改外层IPv6头的地址不改内嵌报文里的地址接收方解析这个错误消息时就会看到错位的前缀导致MTU发现链路断掉。这个问题的表现很随机小包一切正常大包莫名其妙不通而且不同操作系统表现还不一样。应对方法分三层选型时测试设备对ICMPv6的处理能力边界路由器上准备好tcpdump抓包线上验证时用ping -c 3 -M do -s 1400这类固定报文大小的方法主动检查路径MTU。NAT66本身不改报文长度不会像NAT64那样天然引入分片重组问题所以MTU问题基本都是外围设备的ICMP处理不完整导致的。4.3 IPsec / DNS / SLAAC 兼容性问题IPsec和NAT66的配合要特别谨慎。ESP加密后负载是加密的NAT66设备不可能去调整加密内容里内嵌的地址和校验和这是硬伤。IKE协商时双方地址如果经过NPTv6翻译流量选择子可能对不上SA建立就会失败。我在一个客户现场见过IPsec隧道在NAT66内外反复横跳最终方案是把IPsec流量单独绕过NPTv6或改用支持NAT-T的UDP封装。不是不能解决但设计网络架构时最好提前把这个因素算进去。DNS是另一个容易忽略的环节。NAT66只翻译IP头不翻译DNS报文里携带的AAAA记录。内部DNS服务器给内网客户端返回fd00:1::10外部客户端拿来也用不了因为ULA在互联网上不可达。解决思路有两个一是搞分离式DNS内部区域解析返回内部前缀外部区域解析返回映射后的外部前缀二是在外部DNS区域手工维护映射记录。好在NAT66保留了接口ID你只需要把内部主机的低64位接口ID拼上外部前缀就能生成正确的映射记录维护成本相对可控。SLAAC方面NAT66保留了后64位内外地址天然对应内网主机通过SLAAC自动生成的地址在外网侧看起来依然合法这是个好消息。但要注意抓包时容易看晕同一台主机在内网抓包显示的是ULA地址在外网抓包显示的是全球单播地址两边对不上会让初次排查的人很困惑。建议在运维文档里写清楚前缀映射表抓包时同时标注内外两个视角。4.4 常见问题速查表问题现象可能原因排查思路内网出外网不通出方向规则缺失、路由没指对、防火墙拦截查看postrouting链计数检查默认网关外网访问映射地址不通入方向规则缺失、外部前缀路由没有指向边界设备检查prerouting链计数确认外部主机静态路由TCP/UDP偶发断连NAT66设备校验和更新不完整抓包比对校验和换用Linux nftables做对照实验大包不通小包通ICMPv6 Packet Too Big处理异常检查边界设备对ICMPv6错误消息的转换逻辑手动限制MTU测试多个上游出方向回包走错链路多线路环境下策略路由缺失按出接口拆分NPTv6映射规则配合策略路由固定回包路径DNS解析正常但外部访问失败外部客户端拿到的是内部ULA地址部署分离式DNS或在外部区域维护映射后的AAAA记录5. 什么时候该用 NAT66什么时候真没必要5.1 适合用 NAT66 的场景多ISP接入是最典型的一种。企业同时接了电信和联通两家前缀不一样内网不想分成两套地址体系那就统一用ULA边界路由器按线路做两套NPTv6映射。内网规划一次到位后续线路切换不影响内部任何设备。拿不到PI地址、也不愿意花大价钱上BGP的场景NAT66是成本最低的多宿方案。运营商前缀变更频繁、而内网业务对地址稳定性要求高的场景也适合。你把内部地址空间和外部前缀完全隔离运营商今后怎么调整都只是边界设备上改一条映射规则。还有网络合并和改造场景两套网络带着各自的地址体系往一块儿并暂时不想做全网重新编址用NAT66作为过渡桥接能省下巨大的割接成本。5.2 不要用 NAT66 的场景如果你只有一个运营商、单条线路内网地址规划也没有必须稳定的硬性约束那直接给内网分配全球单播地址就好不需要中间再加一层翻译。NAT66不是IPv6的必备组件能不用就不用少一层转换就少一类故障。如果你的内网存在大量端到端IPsec加密流量也要谨慎。ESP加密后NAT66连校验和都调不了强行使用很可能导致隧道起不来或频繁中断。还有如果你纯粹是想给内网加一道安全屏障指望NAT66起到IPv4 NAT那种“隐藏”效果那是找错了工具。安全需求应该用防火墙解决而不是地址翻译。5.3 替代方案与最终建议想保持地址稳定最理想的方案还是申请PI地址配合BGP做多宿主。地址是自己的换运营商也不受影响这是真正的根治方案。但PI和BGP不是所有企业都负担得起特别是中大型网络部署BGP需要AS号、需要和运营商对接每年的资源费用和运维成本都不低。NAT66未必是最优雅的方案但它是解决现实问题的高性价比方案。还有一类更轻量的思路直接在内部使用运营商分配的全局单播前缀借助DHCPv6 PD机制动态获取前缀。这个方法在家庭和小型分支网络里很常见但企业网络一旦涉及多线路还是会绕回地址隔离的问题。我的最终建议是先把业务需求列清楚再决定要不要NAT66。如果只是单线路常规接入直接上全球单播地址最省事如果明确有“内网地址永远不要跟着上游变”的诉求NAT66就是值得纳入技术对比的方案。选型时多关注设备对RFC 6296的实现完整性重点测试ICMPv6错误消息和校验和修正这两个细节它们决定了生产环境稳不稳。5.4 部署前检查清单部署NAT66之前我习惯按这份清单过一遍明确内部前缀和外部映射前缀确保前缀长度一致通常都用/64确认边界设备固件版本对RFC 6296的支持程度设计外部前缀的路由发布方式确保入站报文能到达边界设备检查防火墙和NAT规则先后顺序不要互相拦截提前规划DNS解析策略内部区域和外部区域各返回对应前缀识别关键业务中是否有IPsec流量必要时单独绕行或采用UDP封装先小范围试点验证双向连通后再逐步扩大记录回滚方案一旦出现问题能快速摘掉NAT规则恢复原状最后聊一点我自己的现场经验。NAT66在国内企业网里讨论度很高很多时候是因为很多网络已经用IPv4 NAT用了十几年惯性思维让“网关总得做点什么转换”的想法根深蒂固。我在实际项目里凡是能直接分全球单播的就尽量不引入NPTv6少一层转换就少一类问题。但一旦客户明确表示“内网规划必须独立于运营商”NAT66往往就是成本最低、效果最直接的那个答案。如果你的设备固件对NPTv6支持得完整配起来其实比IPv4 NAT简单得多两条方向各一条前缀映射规则就结束了。建议你先拿Linux搭一个小环境把双向ping通和DNS映射跑顺了再决定要不要上生产。
返回列表