
使用OpenWRT实现IPv4/IPv6分流家宽和校园网并通过NAT66解决地址分配问题
本文原标题为《我家跨上了信息高速路,但是IPv6借道CERNET并被自己的车绊了一跤》,但被站长建议修改,原因是标题不利于访问者提取有效信息以及影响SEO。确实我自己看了下也很谜语人
本文诞生的背景是校园网的IPv6只能下发一个/128地址、没有PD,因此使用了最妥协的NAT66技术方案。若您是家庭宽带用户且上游有IPv6 PD下发,请不要参照本文进行网络配置!本文只适合无论如何都只能拿到一个/128地址的校园网用户参考。
背景
笔者就读的学校,在宿舍内提供每人一个千兆有线网口,从该网口可以PPPoE拨号连接运营商的家宽,也可以使用WebPortal认证连接校园网(PPPoE和WebPortal两种认证方式对应两个网络出口)。
由于某些操作系统在连接有线网口并收到来自校园网的IPv6 RA报文后,若进行PPPoE拨号得到来自运营商的RA报文时即会断开PPPoE连接,造成大量“宽带无法上网”投诉,运营商不得不关闭了IPv6 RA。
自此,宿舍区内若要使用IPv6,则只有选择使用校园网。尽管校园网存在带宽有限、按流量计费、设备仅能得到一个/128的单地址等诸多问题,但这是唯一可用的IPv6上游。
本文的全部内容基于上述背景展开。
无功而退
在运营商关闭了IPv6 RA后,宿舍网络只剩下IPv4,这在2025年实在是太过荒谬。由于运营商家宽速度快、不限流量的特点,决定了宿舍网络的主出口仍然必须是运营商家宽。因此,笔者选择了IPv4和IPv6走两条不同路线的方案:IPv4走运营商家宽(除部分校内业务IP),IPv6走校园网接入CERNET连接公网。
由于校园网只向设备提供一个/128的IPv6地址,这使得IPv6的常用三配置当中的Native、中继两种方式无法使用:
- Native需要至少/64的IPv6-PD(委托前缀)长度;
- 中继需要至少/64的IPv6地址区域。
因此,唯一的选择就是令人无奈的NAT66。
当时使用的路由器是那年最新的OpenWRT21版本,并不支持NAT66,笔者尝试安装第三方的NAT66实现napt66
也未能成功。最终,笔者只能在迫切需要IPv6的场景下,手动将计算机的第二块网卡接入闲置的有线网卡暂且凑合用。
偶然的发现
一日,笔者更换了新的路由器(MT7621A->MT7981),由于原厂固件并不怎么好用,便刷入了OpenWRT24.10。在迁移配置的时候,笔者留意到“网络-防火墙-区域设置-高级设置”中有一个“IPv6伪装”选项。显而易见的,这就是NAT66的开关。
经过查询,OpenWRT24.10使用的内核是Linux6.6,该版本中已经支持了NAT66的操作,且配置极为方便。
难道手动插拔双网卡接入IPv6的日子就要结束了吗?
IPv6借道CERNET
首先,为了实现单线同时接入PPPoE和WebPortal,我们需要对WAN口进行单线复用。安装macvlan
并在“网络-接口-设备”页面配置2个MACVLAN设备,模式为VEPA,基础设备选择路由器WAN口对应的设备(本例中为eth1
),并指定不同的MAC地址。
回到“网络-接口-接口”页面,移除默认配置的wan
和wan6
接口,然后新建所需的WAN接口并绑定到刚刚新建的MACVLAN设备上,再配置正确的WAN接口协议并分配防火墙区域到wan
。由于校园网的WebPortal认证必须在IPv4下完成,因此需要在同一个MACVLAN设备上同时建立两个接口,分别配置为DHCP客户端和DHCPv6客户端。
由于我们希望让IPv4流量优先走运营商家宽,故把三个WAN接口的网关度量值进行设置:
- 网络-接口-wan-高级设置-使用网关度量值:设置为“20”(较小)
- 网络-接口-wan_campus-高级设置-使用网关度量值:设置为“50”(较大)
- 网络-接口-wan6_campus-高级设置-使用网关度量值:设置为“50”(较大)
这样设置后,当wan
接口和wan_campus
接口同时在线时,由于wan
接口的网关度量值较小,路由器会默认将IPv4出口指向wan
接口;若wan
接口的连接断开,则路由器将IPv4出口指向wan_campus
接口,可作为备用。而IPv6只有一个wan6_campus
接口提供,故当该接口在线时,IPv6出口指向该接口。
利用NAT66应对上游只给/128地址
尽管我们已经完成了IPv6的路由设置,但此时只有路由器自己可以通过IPv6访问互联网。经过查阅官方wiki并结合网络知识,确定了在OpenWRT24.10上,通过配置NAT66为局域网接通IPv6仅需简单的几个步骤:
第一步:网络-接口-全局网络选项-IPv6 ULA 前缀:将默认生成的前缀开头的“fc”或“fd”改为“dd”开头
若不需要IPv6优先,可跳过此步。但对于某些存在问题的IPv6实现,这一项仍然是必须的。
OpenWRT会为局域网内设备提供一个ULA(唯一本地单播)地址,其一般以fd
或fc
(旧标准)开头。它们的作用是用于在局域网内进行寻址通信,类似于在IPv4环境下,RFC 5735或RFC 1918当中所规定的10.0.0.0/8
、172.16.0.0/12
、192.168.0.0/16
三个网段。
而由于一些设备的IPv6实现存在问题,当他们获得ULA地址后会认为“该IPv6地址是通向内网的”(公网不可路由的),就不会使用它连接局域网以外的网络。
解决办法就是做一个骚操作:把fd
前缀改为dd
前缀,而后者是一个目前被规定为保留地址的前缀,故很可能被设备当作是“一种很新的公网可路由的IPv6地址”,从而使用它连接互联网。这地址怎么有股味
第二步:网络-接口-lan-高级设置-IPv6前缀过滤器:设置为“local(本地ULA)”
这一步是为了确保下发到lan
接口的IPv6前缀全部来自于指定好的本地ULA。
第三步:网络-接口-lan-DHCP服务器-IPv6 RA设置-默认路由器:设置为“在可用的前缀上”
这一步要求路由器宣告自己是IPv6 ULA地址区域的默认路由。
第四步:网络-接口-wan6_campus-高级设置-IPv6源路由:取消勾选
由于我们需要使用NAT66,因此需要关闭提供IPv6的WAN口的该选项。
第五步:网络-防火墙-wan区域-高级设置-IPv6伪装:勾选
这就是我们本文的核心——NAT66。
第六步:网络-路由-静态IPv4路由-添加到WebPortal服务器的记录
若你校的IPv6无需认证,可跳过此步。
由于笔者的学校校园网IPv6需要认证才能上网,但认证服务器需要通过IPv4连接。由于我们前面已经将默认的IPv4出口流量导向运营商家宽,这会造成无法访问WebPortal服务器而无法认证校园网。最简单的方法就是补一条静态路由记录,指定去WebPortal服务器的流量走wan_campus
接口。
需要注意的是,一些高校的WebPortal认证过程需要访问多个地址才能完成,此时需要为所有认证过程涉及的IP地址添加静态路由。又或者你和网管关系很好,咨询一下WebPortal服务使用的子网并直接添加整个子网的静态路由指向wan_campus
接口也可以。
添加完成后,请访问校园网的登录页面并完成登录。
Done…?
完成上述步骤后,我们检查IPv6路由表,发现已经出现IPv6公网路由,这意味着此时局域网设备已经可以访问IPv6互联网了。
我们跑一下IPv6测试:
不幸注意到,学校又给校园网的IPv6出口套了一层NAT66,这下NAT666了(噗
真好,我家跨上了信息高速路,但是IPv6借道CERNET。跑个分试试:
不对啊,怎么这么慢???
网速慢?排查一下
由于测试时是用网高峰期,笔者次日清晨又进行了测试,但速度始终不尽如人意。
为了排除路由器影响,笔者使用另一台计算机直连校园网进行测试,发现网速可高达70Mbps,故排除校园网出口问题。
于是笔者又测试在路由器下的计算机和连接校园网的计算机跑iperf3测速,竟然只有不足4Mbps;为了排除路由器被管控限速导致的影响,笔者又SSH登录路由器运行iperf3进行测速:
结果却出乎意料:几乎跑满链路上限千兆。
那么,从路由器发起连接和从路由器下的计算机发起连接,不一样的地方是哪里呢?
NAT66!很明显,路由器上直接发起iperf3连接时,是直接从wan6_campus
对应的设备发出,而局域网内的设备发起连接则必然经过防火墙跨区域的NAT66转换过程!
NAT66在搞什么鬼?
我家跨上了信息高速路,但是IPv6被自己的车绊了一跤
进行抓包,容易发现,网速异常的时候存在大量的TCP重传:
这显然进一步印证了NAT66的实现存在问题。
以“openwrt nat66 slow”为关键词,上互联网搜索,很快注意到了一个GitHub issue提到了该情况:
openwrt issue #15847
而在下面,贡献者ptpt52给出了问题原因和缓解措施,并提交了修复commit #448bade(但显然,当前最新的release中还没有合入该commit)
该问题的原因是由于Linux内核当中的GRO/GSO网络卸载功能与NAT66存在兼容性问题,会导致经过NAT66的包被破坏,进而引发大量重传。缓解措施就是关闭对应网卡上的GRO/GSO功能。
1 | # 该代码关闭除了lo接口以外所有接口的GRO功能 |
关闭GRO/GSO功能后,再次测速,网速正常。
2025-04-22补充:经网友**@会打蛋花的面码**更新补充:4月15日更新的OpenWrt 24.10.1版本已经修复了IPv6 TCP GSO的问题,实测无需关闭GRO/GSO功能了。(日志:OpenWRT Releases-24.10 changelog-24.10.1)