整理了国内网络环境下IPv6的相关问题和解决方法
PPPoE
PPPoE(Point-to-Point Protocol over Ethernet)是一种网络连接协议,通过和运营商建立虚拟隧道实现互联网访问。拨号成功后,所有的数据都将在这个协议中传输,因此在传输的以太网数据包中,协议本身会占用一部分,和“真正”要传输的数据一起发送。
MTU和MSS
起因是发现在路由器上设置好IPv6后,手机上的其他App都能正常使用,唯独微信表情出现转圈情况。经过一通搜索,发现是跟拨号时设置的MTU有关。
在我的路由器上,PPPoE默认的MTU为1492,修改为1480(实际应该只要设置MSS就行),问题得到解决。
顺便根据 #参考1 手动设置IPv6的MSS以提高网络效率。
原理
MTU(Maximum transmission unit))是链路上能通过的数据包(包含IP头包)的最大尺寸(以太网一般为1500 字节)。一种情况是超过这个大小的包会被分片,造成传输效率下降;另一种情况是终端设备设置了不要分片(DF标记),中间设备收到超过大小的包会通知终端设备发一个小一点的包,但是很多设备忽略这个通知,只能等超时重传。而IPv6 不支持分片(数据包都带 DF 标记),可能无法正常传输消息。
MSS (maximum segment size) Clamping 决定单个 TCP 包的最大尺寸。路由器可以通过嗅探 TCP 握手包,把 MSS 值改小,使最后发送的包大小(MSS+TCP 头+IP 头)不超过限定值。
PPPoE隧道需要占用8个字节,所以MTU应当设置成1492以下(1500-8)以保证通过以太网的包不超过1500字节。IPv4 包头和TCP 包头各占用20字节,所以将MSS设置成1452以下(1492-20-20)可以避免被拆分或超时丢包。IPv6包头占用40字节,所以IPv6下的MSS应该设置成1432以下(1492-40-20)。
设置方法
MTU的设置一般在路由器PPPOE拨号设置界面。
MSS的设置则较为复杂,需要路由器支持这一功能。
基于Linux的路由器
# 自动MSS,假设PPPOE虚接口是pppoe0 iptables -t mangle -A POSTROUTING -p tcp --tcp-flags SYN,RST SYN -o pppoe0 -j TCPMSS --clamp-mss-to-pmtu ip6tables -t mangle -A POSTROUTING -p tcp --tcp-flags SYN,RST SYN -o pppoe0 -j TCPMSS --clamp-mss-to-pmtu # 手动指定MSS,假设PPPOE虚接口是pppoe0 $ iptables -t mangle -A POSTROUTING -p tcp --tcp-flags SYN,RST SYN -o pppoe0 -j TCPMSS --set-mss 1452 $ ip6tables -t mangle -A POSTROUTING -p tcp --tcp-flags SYN,RST SYN -o pppoe0 -j TCPMSS --set-mss 1432
RouterOS
/ipv6 firewall mangle add chain=forward out-interface=pppoe-out1 protocol=tcp tcp-flags=syn action=change-mss new-mss=1420
UBNT Edgerouter
set firewall options mss-clamp6 interface-type pppoe set firewall options mss-clamp6 mss 1420
前缀失效问题
PPPoE断开重播后,运营商下发的IPv6的前缀地址会发生变化,而对于网络内各个客户端,DHCPv6模式分配的地址租期未到,IPv6的地址没有得到更新,会造成一段时间的断网。
解决办法是关闭 DHCPv6 服务,改用 SLAAC 无状态分配,路由器会在网络发生变化时通知客户端,由客户端自行生成地址。
详细说明见 #参考5 。
EdgeOS需要加一点特技,见 EdgeOS在PPPoE下正确处理IPv6地址变动
DNS
目前IPv6路由优化感觉还是没那么靠谱,出国线路也是经常各种绕,有些大厂的网站都没有支持IPv6。
我是作为一种辅助,PT加速以及直连MTP,不用来访问网站,因此是把DNS关闭的。