Linux VPS中/120 IPv6子网路由失败及Neighbor Solicitation源地址选择疑问
咱们先梳理下你的场景和问题:你在VPS上拿到了2001:db8:X:Y::25:785c/112的IPv6段,想拆成两个/120子网——一个给eth0本地用,另一个通过tuns0路由到远程办公网。但现在远程办公网的ping没法走到公网,抓包发现VPS发的Neighbor Solicitation(NS,邻居请求)报文源地址不对,导致服务商的路由器不响应。
核心疑问
- Linux内核替远程办公网的流量向eth0发送NS时,是怎么选源地址的?
- 子网配置时我到底漏了什么?
你的现有配置信息
接口地址
# ip -6 addr list eth0 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 state UP qlen 1000 inet6 2001:db8:X:Y::25:785c/120 scope global valid_lft forever preferred_lft forever inet6 fe80::216:3cff:fe2e:4906/64 scope link noprefixroute valid_lft forever preferred_lft forever # ip -6 addr list tuns0 85: tuns0: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> mtu 1423 state UNKNOWN qlen 100 inet6 2001:db8:X:Y::25:61/120 scope global valid_lft forever preferred_lft forever inet6 fe80::2de4:df93:3c60:d6f6/64 scope link flags 800 valid_lft forever preferred_lft forever
远程办公网子网:2001:db8:X:Y::25:1000/120,办公网主机地址为2001:db8:X:Y::25:1060
路由表
# ip -6 route list unreachable ::/96 dev lo metric 1024 error -113 pref medium unreachable ::ffff:0.0.0.0/96 dev lo metric 1024 error -113 pref medium unreachable 2002:a00::/24 dev lo metric 1024 error -113 pref medium unreachable 2002:7f00::/24 dev lo metric 1024 error -113 pref medium unreachable 2002:a9fe::/32 dev lo metric 1024 error -113 pref medium unreachable 2002:ac10::/28 dev lo metric 1024 error -113 pref medium unreachable 2002:c0a8::/32 dev lo metric 1024 error -113 pref medium unreachable 2002:e000::/19 dev lo metric 1024 error -113 pref medium 2001:db8:X:Y::1 dev eth0 proto static metric 100 pref medium 2001:db8:X:Y::25:1000/120 dev tuns0 metric 1024 pref medium 2001:db8:X:Y::25:7800/120 dev eth0 proto kernel metric 256 pref medium unreachable 3ffe:ffff::/32 dev lo metric 1024 error -113 pref medium fe80::/64 dev eth0 proto kernel metric 100 pref medium fe80::/64 dev tuns0 proto kernel metric 256 pref medium default via 2001:db8:X:Y::1 dev eth0 proto static metric 100 pref medium
内核转发与防火墙
# sysctl net.ipv6.conf.{eth0,tuns0}.forwarding net.ipv6.conf.eth0.forwarding = 1 net.ipv6.conf.tuns0.forwarding = 1
# ip6tables -nvL FORWARD Chain FORWARD (policy DROP 0 packets, 0 bytes) pkts bytes target prot opt in out source destination 0 0 ACCEPT all * tuns0 ::/0 ::/0 3307 344K ACCEPT all tuns0 * ::/0 ::/0 0 0 ACCEPT all * * ::/0 ::/0 state RELATED,ESTABLISHED 3 216 ACCEPT icmpv6 eth0 * ::/0 ::/0 ipv6-icmp !type 128 code 0
症状细节
远程办公网ping公网地址(比如2606:4700::6810:85e5)全丢包,抓包eth0看到两种异常NS:
- 用eth0的链路本地地址
fe80::216:3cff:fe2e:4906做源,向组播地址ff02::1:ff00:1发送对网关2001:db8:X:Y::1的NS请求,但服务商路由器完全没响应; - 用eth0的全局地址
2001:db8:X:Y::25:785c做源,向组播地址ff02::1:ff25:1060发送对远程办公网主机的NS请求,同样没响应。
但VPS本地ping公网时,NS请求的源地址是2001:db8:X:Y::25:785c,路由器立刻回复了Neighbor Advertisement(NA,邻居通告),ping也成功了。
问题分析及解决方法
1. NS源地址选择的逻辑
Linux内核选NS源地址遵循IPv6源地址选择策略(可以用ip -6 rule查看),核心规则是:
- 当要给某个目的地址发NS时,优先选和目的地址同子网的本地地址当源;
- 如果找不到同子网的地址,就会 fallback到出口接口的链路本地地址。
你这里的问题出在:eth0的子网前缀配置成了/120,但网关2001:db8:X:Y::1属于/112前缀,不在eth0的/120子网范围内。
当远程流量过来要转发到公网时,内核需要向网关2001:db8:X:Y::1发NS,但发现eth0上的全局地址和网关不在同一个子网,就只能用链路本地地址发NS。而很多ISP的路由器会忽略来自链路本地地址的NS请求——因为它们只认属于同一个分配前缀(也就是你拿到的/112)的全局地址发来的NS。
而VPS本地ping时,内核会用eth0的全局地址作为ping的源地址,此时发NS时会复用这个源地址(它和网关同属/112前缀),所以路由器愿意响应。
2. 你遗漏的配置点
方案一:修正eth0的子网前缀(推荐)
既然服务商给你的是/112的段,你应该把eth0的地址配置在/112前缀下,而不是/120。这样网关就和eth0的地址在同一个子网里,内核发NS时会自动用eth0的全局地址当源:
# 修改eth0的地址前缀为/112 ip -6 addr change 2001:db8:X:Y::25:785c/112 dev eth0
之后远程流量转发时,内核发NS的源地址就会是eth0的全局地址,路由器会正常响应。
方案二:添加源地址策略路由(如果不想改eth0前缀)
如果因为某种原因不能修改eth0的子网前缀,可以添加一条策略路由,强制让来自远程子网的流量在转发时,用eth0的全局地址作为源:
# 添加规则:来自远程子网的流量用表100路由 ip -6 rule add from 2001:db8:X:Y::25:1000/120 lookup 100 # 在表100里添加默认路由,指定源地址为eth0的全局地址 ip -6 route add default via 2001:db8:X:Y::1 dev eth0 src 2001:db8:X:Y::25:785c table 100
这样远程子网的流量转发时,会强制使用eth0的全局地址作为源,发NS时也会用这个地址,路由器就能响应了。
3. 验证步骤
修改配置后,从远程办公网再次ping公网地址,同时在VPS上抓eth0的包:
- 查看NS请求的源地址是否变成
2001:db8:X:Y::25:785c; - 检查是否能收到服务商路由器的NA响应;
- 确认ping是否能收到回复。
备注:内容来源于stack exchange,提问作者Jaredo Mills

