Ubuntu下搭建DS-Lite:AFTR与B4完整配置与验证指南
搞网络的人应该都有体会IPv4地址池见底这件事运营商比我们着急得多。现在很多宽带接入网已经逐步转向IPv6-only但用户还要打开IPv4时代的网站和应用于是就有了各种过渡技术。DS-Lite是目前运营商用得最多的一套方案核心就是AFTR和B4这两个角色。我这次要在Ubuntu上把AFTR和B4整套环境搭起来从原理到配置、从排查到验证一次说清楚。这篇文章适合网络工程师、ISP运维以及所有想在实验室里复现IPv6过渡网络的朋友。1. AFTR和B4到底是什么1.1 先从DS-Lite的名字说起DS-Lite全称Dual-Stack Lite直译过来是“轻量级双栈”。名字里带Lite是因为它和传统双栈不同用户侧不再分配公网IPv4地址只分配IPv6地址IPv4流量通过隧道送给运营商侧统一处理。这套架构里有两个角色B4Basic Bridging Broadband Element部署在用户CPE侧也就是家庭网关或小型路由器里。它负责把用户内网的IPv4报文封装进IPv6隧道发给AFTR。AFTRAddress Family Transition Router部署在运营商网络边缘是隧道的终点同时承担NAT44功能把用户的私有IPv4流量转换成公网IPv4后送去IPv4互联网。打个比方B4像一个快递揽收点用户家中的IPv4报文在这里打包贴上IPv6地址标签然后走IPv6骨干网送到AFTR这个分拣中心。AFTR拆包、改地址、重新投递到IPv4互联网回程反过来再走一遍。1.2 两边的职责可不能搞混很多初学者容易把B4当成简单的IPv4路由器其实B4的关键能力是“IPv4 over IPv6封装”。它要能在自己的LAN口收到普通IPv4报文之后把这些报文塞进外层的IPv6头里发往AFTR的IPv6地址。AFTR这边的职责更重终结来自所有B4设备的隧道连接解封装IPv6报文还原出原始的IPv4报文对IPv4报文做NAT44实现私网到公网的源地址转换维护连接跟踪保证回程流量能够原路返回在实际运营商网络中一个AFTR会同时承载成千上万个B4隧道所以性能要求比普通路由器高得多。但在实验室里用Ubuntu加Linux内核自带的隧道能力就能完全模拟这套流程。1.3 为什么不用NAT64或者6rd这里顺便说说DS-Lite和其他过渡技术的区别。NAT64方案要求运营商的DNS服务器做DNS64改造还要在IPv6-only网络中引入NAT64网关整个链路的应用层可能会因为MTU或者协议问题踩坑而且纯IPv4的老客户端根本用不了。6rd则是IPv6 over IPv4的隧道方案方向正好相反它解决的是“没有IPv6接入但有IPv4接入”的场景。DS-Lite的目标场景很明确接入网是IPv6-only用户终端还是IPv4。它不需要改动用户终端也不需要在用户侧做DNS适配只要CPE支持B4就能无缝接入。2. 实验环境准备与地址规划2.1 拓扑设计与硬件准备搭建这套环境不一定要真实硬件两台Ubuntu虚拟机就够了。我在实验室里用的是Ubuntu 22.04 LTS内核版本5.15系统自带的iproute2、netplan、iptables都是现成的。如果你用24.04 LTS也没问题配置方式完全一样。拓扑上需要三台设备一台模拟用户内网客户端的Linux机器可以放进B4的LAN侧一台B4设备充当CPE角色一台AFTR设备充当运营商边缘路由器实际测试时客户端这台机器也可以用B4设备上的虚拟网卡或者命名空间来替代。最简单的拓扑是客户端 --B4-- IPv6网络 --AFTR-- IPv4公网出口。这里有个前提要确认AFTR设备上需要准备两个公网出口一个是IPv6地址接收B4隧道一个是IPv4地址访问IPv4互联网。在纯实验室环境里IPv4互联网用一台普通公网IP的服务器甚至另一台Ubuntu模拟都可以。2.2 地址规划表我习惯把地址规划写清楚再动手避免配置过程中搞混。设备接口IPv6地址隧道IPv4地址说明AFTReth0-up2001:db8:1::1/64-面向IPv6接入网隧道源地址AFTReth0-v4192.0.2.200/24-模拟公网IPv4出口AFTRtun4over6-192.0.2.1/29隧道虚拟接口B4eth02001:db8:1::2/64-面向AFTR的IPv6地址B4eth1--面向LAN地址192.168.100.1/24B4tun4over6-192.0.2.2/29隧道虚拟接口Clienteth0--192.168.100.10/24网关指向B4这里隧道地址段用的是192.0.2.0/29这是文档保留地址段适合实验。生产环境中DS-Lite常用RFC 6333建议的192.0.0.0/29局部保留段不过原理一样。2.3 Ubuntu基础环境准备在开始前先把两台设备的apt源换一下国内镜像能省很多等待时间这点不用多说。安装必要的工具包sudo apt update sudo apt install -y net-tools iproute2 iptables tcpdump还要确认内核模块是否加载。IPv4 in IPv6隧道依赖ip6_tunnel模块sudo modprobe ip6_tunnel lsmod | grep ip6_tunnel如果模块没加载会报隧道创建失败的错误。对于IPv6隧道模式Linux内核默认支持一般不会有大问题。3. 在Ubuntu上配置AFTR3.1 用netplan创建IPv4-in-IPv6隧道Ubuntu从18.04开始默认使用netplan管理网络配置文件在/etc/netplan/目录下。AFTR侧的隧道配置如下network: version: 2 ethernets: eth0: accept-ra: false addresses: - 2001:db8:1::1/64 eth0-v4: addresses: - 192.0.2.200/24 tunnels: tun4over6: mode: ipip6 local: 2001:db8:1::1 remote: 2001:db8:1::2 addresses: - 192.0.2.1/29 routes: - to: 192.0.2.0/29 via: 192.0.2.1这里mode填ipip6表示IPv4-in-IPv6隧道也就是RFC 2473定义的IPv6隧道封装。local是本端IPv6地址remote是B4的IPv6地址。隧道虚拟接口分配192.0.2.1/29并添加去往隧道网段的路由。如果你更喜欢用ip命令临时创建隧道做验证可以这么写sudo ip -6 tunnel add tun4over6 mode ipip6 local 2001:db8:1::1 remote 2001:db8:1::2 sudo ip addr add 192.0.2.1/29 dev tun4over6 sudo ip link set tun4over6 upnetplan配置完成后执行sudo netplan apply生效。用ip addr show tun4over6确认隧道接口状态是UP。3.2 开启IPv4/IPv6转发与NAT44隧道建立后AFTR要做两件事开启转发、配置NAT。编辑/etc/sysctl.confnet.ipv4.ip_forward1 net.ipv6.conf.all.forwarding1执行sysctl -p生效。然后配置iptablessudo iptables -t nat -A POSTROUTING -o eth0-v4 -j MASQUERADE sudo iptables -A FORWARD -i tun4over6 -o eth0-v4 -j ACCEPT sudo iptables -A FORWARD -i eth0-v4 -o tun4over6 -m state --state RELATED,ESTABLISHED -j ACCEPT第一条规则把从隧道进来的内部私网地址转换成eth0-v4接口的公网地址发出去。这里我直接MASQUERADE好处是不用关心出口IP具体是多少适合动态出口地址。如果网络规划要求固定公网IP换成SNAT也行sudo iptables -t nat -A POSTROUTING -o eth0-v4 -s 192.168.0.0/16 -j SNAT --to-source 192.0.2.200MASQUERADE和SNAT的核心区别在于MASQUERADE在每次连接建立时自动读取出口网卡当前IP适合PPPoE拨号这类动态地址场景SNAT则固定转换到指定IP适合固定公网地址场景。测试环境用MASQUERADE省心。注意iptables规则默认不持久化重启后会丢失。Ubuntu上可以用iptables-persistent保存sudo apt install -y iptables-persistent sudo netfilter-persistent save3.3 可选配置DHCPv6下发AFTR地址实验环境手动配置隧道地址就够了但如果你模拟真实运营商场景B4设备上线后应该自动获取AFTR地址而不是手工指定。DS-Lite定义了DHCPv6选项64OPTION_S46_BR用于向B4下发AFTR的IPv6地址。在Ubuntu上可以用KEA DHCPv6服务器来做。安装后配置option-def然后在下发子网中携带该选项。这种做法生产环境很常见因为运营商不可能给每个用户手工配置AFTR地址必须要让CPE通过DHCPv6自动发现AFTR。实验室里如果没有那么多设备先把静态配置跑通就行。4. 在Ubuntu上配置B44.1 B4侧隧道与路由配置B4设备的IPv6上行接口是eth0IPv4 LAN接口是eth1。netplan配置如下network: version: 2 ethernets: eth0: accept-ra: false addresses: - 2001:db8:1::2/64 eth1: addresses: - 192.168.100.1/24 tunnels: tun4over6: mode: ipip6 local: 2001:db8:1::2 remote: 2001:db8:1::1 addresses: - 192.0.2.2/29 routes: - to: 192.0.2.0/29 via: 192.0.2.1 - to: 0.0.0.0/0 via: 192.0.2.1 dev: tun4over6关键点在最后一条默认路由它把所有IPv4互联网流量引导到tun4over6隧道接口。这样客户端无论访问哪个IPv4地址都会被转发到AFTR。同时需要确认eth0上有一个IPv6默认路由指向AFTR。因为B4和AFTR在同一网段内联链路可达如果是跨网络部署需要保证外层IPv6路由可达比如sudo ip -6 route add default via 2001:db8:1::1 dev eth0B4同样需要开启IPv4转发因为要转发LAN侧客户端的流量sudo sysctl -w net.ipv4.ip_forward1 sudo sysctl -w net.ipv6.conf.all.forwarding14.2 B4要不要做NAT这是新手最容易纠结的问题。标准DS-Lite架构里NAT44统一由AFTR做B4只是桥接转发不做地址转换。这样运营商可以集中管理地址池用户私网地址在AFTR侧统一转换。但实际CPE产品中为了隔离用户侧流量或者限制单用户并发连接数很多B4设备会先做一次NAT到隧道地址段然后AFTR再做一次NAT形成双层NAT。这种方式并不违反DS-Lite规范只是增加了AFTR连接跟踪表的压力。实验环境我推荐严格按标准来B4不做NATAFTR统一做。这样便于观察DS-Lite的原始转发路径排查问题时也更清晰。客户端流量路径是client 192.168.100.10 - B4 eth1 - B4 tun4over6 - IPv6隧道 - AFTR tun4over6 - NAT44 - 公网IPv4如果B4想要限速或者做用户隔离可以在转发链上额外加流量控制规则但地址转换留给AFTR。4.3 LAN侧客户端配置客户端机器很简单给它一个192.168.100.10/24的地址网关指向192.168.100.1。在真实的CPE场景中B4通常还会内置一个小型DHCP服务器给LAN设备分配地址实验里手动配置就可以了。sudo ip addr add 192.168.100.10/24 dev eth0 sudo ip route add default via 192.168.100.1如果客户端上还需要配置DNS我在测试时一般临时用公共DNS反正最终还是要走到IPv4互联网去解析。5. 联通性测试与抓包验证5.1 基础连通性检查配置完成后从B4上先ping通AFTR的隧道地址ping 192.0.2.1 -c 3如果通了说明隧道链路没问题。然后再从客户端ping一个公网IPv4地址比如ping 8.8.8.8 -c 3第一次测试很可能不通这时不要慌。先检查AFTR的NAT和转发规则是不是生效了sudo iptables -t nat -L -n -v sudo iptables -L -n -v再看B4上能不能ping通AFTR的隧道地址。一层层排查下来问题基本都出在转发开关或者防火墙规则上。5.2 用tcpdump抓包确认隧道封装链路通了之后最有意思的就是抓包看隧道封装。在AFTR的eth0上执行sudo tcpdump -i eth0 -nn ip6 proto 4然后从客户端ping一个IPv4目标。你会看到外层IPv6头的next header是4说明里面封装的是IPv4协议。源地址是B4的IPv6地址目的地址是AFTR的IPv6地址。在AFTR的tun4over6接口上再抓看到的就是解封装后的原始IPv4报文源地址变成了客户端的192.168.100.10。sudo tcpdump -i tun4over6 -nn icmp这两个抓包对照起来看整个DS-Lite转发路径就非常清晰了。在B4侧也能做同样的抓包验证逻辑完全对称。这个步骤我很推荐每一步操作之前都做一下能明显减少后面的玄学问题。5.3 验证NAT后的回程路径在AFTR的eth0-v4接口上抓包sudo tcpdump -i eth0-v4 -nn icmp抓包结果里ICMP请求的源地址是192.0.2.200也就是AFTR的NAT出口地址而不是客户端的192.168.100.10。这就是NAT44生效的直接证据。回程的ICMP回复会回到AFTR然后AFTR查连接跟踪表找到这个连接对应的原始源地址和隧道信息再封装进IPv6隧道送回B4。整个过程依赖Linux内核的conntrack机制在/proproc/net/nf_conntrack里能看到当时的连接记录。6. 常见问题与避坑记录6.1 隧道接口起不来或者状态异常创建隧道时报“Operation not permitted”第一反应检查两个东西内核模块ip6_tunnel是否加载以及当前用户是否有创建网络接口的权限。root下一般都能解决。还有一个坑是netplan中tunnel的mode写错了比如写成ipip或者greLinux不会报错但隧道就是不通。ipip是IPv4 over IPv4ipip6才是IPv4 over IPv6一字之差行为完全不同。如果netplan apply后tun4over6接口状态是DOWN可以手动执行ip link set tun4over6 up或者用networkctl status tun4over6看systemd-networkd日志。也有可能是IPv6地址没配上隧道local地址缺失会导致起不来检查eth0是否有对应的IPv6地址。6.2 能ping通隧道地址但客户端访问外网不通这个问题我踩过好几回最常见原因是AFTR的iptables FORWARD链策略是DROP。Ubuntu默认没有自带防火墙规则但如果安装过ufw或者之前跑过其他防火墙管理工具FORWARD链策略可能变成DROP。先检查再放行sudo iptables -L FORWARD -n -v确认策略后加上前面提到的两条FORWARD ACCEPT规则。还有另一个原因B4设备上如果之前做过NAT测试会在POSTROUTING链留下规则导致客户端流量源地址变成B4的隧道地址AFTR解封装后看到的源地址和预期不符影响NAT连接跟踪。建议排查时把B4的NAT规则先清掉sudo iptables -t nat -F6.3 MTU问题导致网页打不开、图片加载不全IPv4-in-IPv6封装会带来40字节的外层IPv6头开销如果内网链路MTU设置不对大包传输就会失败。现象很典型小包通的大包超时打开网页能显示文字但加载不出图片。解决办法是在隧道接口上调整MTU。B4和AFTR的tun4over6接口都设为1440sudo ip link set tun4over6 mtu 14401440这个值怎么来的外层IPv6 MTU按1500计算减去40字节IPv6头再减去20字节内层IPv4头就是1440。实际使用时还可以留点余量比如设成1420避免IPv6网络上还有额外封装比如PPPoE会再减8字节。用ping可以验证ping -M do -s 1400 192.0.2.1 -c 3-M do表示禁止分片如果1400字节能通说明当前MTU配置合理。如果1440字节的包不通可以试试1420、1400找到合适的值。生产环境还需要关注PMTUD路径MTU发现是否正常工作ICMPv6错误消息能不能顺利返回B4侧。6.4 NAT表满或者性能不足实验环境不会遇到这个问题但我实际参与过的DS-Lite项目中AFTR最大的瓶颈往往是连接跟踪表和NAT44的转发性能。几万用户同时在线时Linux默认的conntrack哈希表很容易被打满。调整方法sudo sysctl -w net.netfilter.nf_conntrack_max1048576 sudo sysctl -w net.netfilter.nf_conntrack_buckets262144第二个参数要求在加载nf_conntrack模块之前设置才能生效生产环境可以考虑写进/etc/sysctl.conf。另外多队列网卡和RSSReceive Side Scaling配置也能显著提升隧道吞吐参数调整和内核配置相关。6.5 B4设备重启后配置丢失netplan写的配置重启后是持久的但如果你用ip命令临时创建的隧道重启后会消失。如果遇到重启后隧道起不来优先检查netplan配置里local/remote的IPv6地址是否和实际接口匹配。另外要注意eth0如果启用了DHCPv6或者RA它获取到的IPv6地址可能会变化导致隧道源地址失效。实验环境建议关闭accept-ra或者给eth0配置静态IPv6地址。还有一个容易忽略的点如果AFTR设备的IPv6地址变了所有B4设备的remote地址都要跟着改。这就是为什么生产环境要用DHCPv6选项64动态下发AFTR地址静态配置虽然简单但可维护性太差。6.6 关于双栈和464XLAT的扩展思考DS-Lite解决了IPv4互联网访问的问题但它没有解决双栈IPv4路径上的真双栈问题。如果用户终端本身是IPv6-only需要访问IPv4-only服务可以考虑464XLAT方案它的CLAT端和B4类似但需要额外做一次NAT46转换。DS-Lite和464XLAT在实际网络中经常并存AFTR同时承担PLAT角色。在Linux上做464XLAT改造只需要在B4侧加入NAT46规则AFTR侧增加对应的NAT64逻辑即可。搭建这套环境如果只是为了应付考试或者面试静态配置跑通DS-Lite就足够。但如果你真的想搞懂运营商级IPv6过渡网络强烈建议把DHCPv6选项64、动态隧道建立、NAT44性能压测都做一遍。我在实际调试过程中的体会是DS-Lite最难的部分不是配置命令而是理解流量到底在哪一层被封装、在哪一层被转换、回程流量如何被正确处理。把这套逻辑想透了后续遇到任何隧道类问题都能很快定位。