写给 Geek 们的 IPv6 组网最佳实践系列:处理动态前缀造成的种种问题

2023-07-10 22:06:58 +08:00
 raysonx

本文属于《写给 Geek 们的 IPv6 组网最佳实践》系列,旨在为需要小范围 IPv6 组网(如家庭组网)的爱好者们提供最佳实践方案和常见问题解答,部分概念性内容为方便理解可能会过度简化,部分方案可能不适用企业宽带接入、大规模组网等场景。首发于 V2EX ,转载请注明出处。关于此系列的介绍,见 https://v2ex.com/t/955078#reply36 。 勘误等内容将更新在附言区。

问题描述

IPv6 下 LAN 侧每一台机器都会获得独立的公网 IPv6 地址。

目前国内绝大多数地区的家庭带宽是通过 PPPoE 虚拟拨号接入的,下发的 IPv6 前缀会在每次重新拨号后发生变化。这就需要我们重新给 LAN 侧的设备分配 IPv6 地址,以及处理前缀变化造成的种种问题,如服务发现及防火墙配置。

前缀前化导致的断网问题

举例说明

假设光猫运行在桥接模式,路由器拨号获得 IPv6 PD 前缀 2001:db8:beef:1200::/56。路由器下联一个 LAN ,指定 PD 前缀的 SLA ID 为1(也就是从2001:db8:beef:1200::/56 挑选第 1 个(从 0 开始数)/64子网),路由器会将2001:db8:beef:1201::/64 这个子前缀划为给 LAN 。正确配置的情况下所有 LAN 下的设备都将获得2001:db8:beef:1201:xxxx:xxxx:xxxx:xxxx/64 格式的地址。

此时路由器上的 PPPoE 断开后重拨,ISP 下发新的 PD 前缀 2001:db8:dead:ab00::/56。此时路由器应该向 LAN 下的所有设备宣告原前缀2001:db8:beef:1201::/64失效,并重新下发 2001:db8:dead:ab01::/64 前缀,否则 LAN 下的设备可能会因为继续使用老前缀而导网络中断。

解决方法

已经使用纯无状态分配了,但重新拨号后老前缀没有失效?

前面说了,SLAAC 可以由服务器主动通知用户设备前缀失效。但这只是协议支持。如果重新拨号后老前缀没有失效或者新前缀没有下发,说明你的路由器固件存在问题。在条件允许的情况下,换一个其他的的固件吧。

新版 OpenWRT 是没有问题的。

如果使用 VyOS 1.4 ,可以设置 set service router-advert interface eth0 prefix ::/64 deprecate-prefix,其中 eth0 是 LAN 口网卡名。

如果是在 Linux 上跑 radvd ,修改radvd.conf,端号配置中加上 DeprecatePrefix on; ,并配置脚本使 pppoe 重拨后重启 radvd 。

服务发现问题

前缀变化后,所有 LAN 侧的 IPv6 地址都会变化。如何设定 DNS 以及避免服务中断?

防火墙设定问题

如果你想在网关路由器上为每台终端设备配置防火墙规则,但又无从下手(因为终端设备没有固定的 IPv6 地址),可以使用下面的方法。

如何给我的设备设定一个固定后缀?

首先需要明确的是,在使用 SLAAC 无状态地址分配时,路由器只宣告子网的前缀,而 64 位的后缀完全由终端设备自己决定。

目前大多数新的操作系统下,一个前缀会生成两个 IPv6 地址:永久地址和临时地址。

临时地址的后缀完全是随机生成的,用于发起访问,每隔一段时间会自动变化,在一定程度保护你的隐私(防追踪)。Linux 下使用ip a命令或者 mac 系统下 ifconfig 命令,如果一个地址后面有 temporary 标记,则表明这是个临时地址。iOS 系统下,第二个无状态地址是临时地址。中文 Windows 系统下 ipconfig 命令会直接标明哪个地址是临时地址。

永久地址的后缀是由特定的哈希算法生成的。这个哈希由网卡的 mac 地址和一个随机数共同决定。只要你的前缀不变并且 mac 地址不变,后缀就不会变。因此适合对外提供服务。但是如果前缀变了,则后缀也会跟着变化。(当你配置了 ULA 时,因为 ULA 的前缀是不变的,所以这个 ULA 地址是静态的)。iOS 系统连接 Wi-Fi 时,默认会使用随机 mac 地址,因此后缀会经常变化,这个功能可以在 Wi-Fi 设置中关闭。

部分老系统、老的网络管理软件的永久地址仅仅是 mac 地址的变形,这种生成方式叫做 Modified EUI-64 。判断方法为,如果永久地址的后 64 位形如:xxxx:xxff:fexx:xxxx ,即中间 16 位是 ff:fe ,则该地址是使用 Modified EUI-64 生成的。在这种配置下,只要 mac 地址不变,后缀就不会变,因此可以视作固定后缀。这种生成方式会对外暴露你的 mac 地址,看你介意不介意了。

SLAAC 下的后缀可以手动指定。

比如 Linux 下可以用 ip token set ::1234 dev eth0指定后缀固定为 1234 (其中 eth0 是网卡名)。这个命令是运行时命令,无法在系统重启后保持,实际使用时需要配置到网络管理软件(如 Network Manager, systemd-networkd, ifupdown 等)中,例如:

Network Manager

nmcli c mod eth0 ipv6.token ::1234
nmcli c mod eth0 ipv6.addr-gen-mode stable-privacy

ifupdown:

iface eth0 inet6 static
        autoconf 1
        accept_ra 2
        privext 1
        post-up /sbin/ip token set ::11 dev $IFACE

systemd-networkd

[Match]
Name=eth0

[Network]
IPv6AcceptRA=true

[IPv6AcceptRA]
Token=static:::1234

本文到此结束,如果各位有各种系统下的具体兼容情况和配置命令,可以在评论中补充,我会定期更新到附言中或者放到新帖中。

7517 次点击
所在节点    宽带症候群
51 条回复
lovelylain
2023-07-14 08:46:30 +08:00
固定 ipv6 地址后缀很难确保,所以换个思路:
只通过路由器 wan 口对外提供 ipv6 服务,同时在路由器上部署 nginx ,将 ipv6 请求以 ipv4 转发到内网实际提供服务的机器,防火墙规则在 input 链里放行端口不写 ip ,完事。
JiangkaaiShenng
2023-07-14 17:36:29 +08:00
都说 SLAAC 好,可是分配要等半天
huamiao
2023-07-14 22:50:11 +08:00
@raysonx 我有个场景已经搞了 2 天了还是无法完美。不知是否能给点建议。
我使用的是 OPNSense ,2 根线做主备,都有公网 IP 。现在应用 IPv6 ,OPNSense 提供的 GUI 无法在一个接口上绑定 2 个 IPv6 配置(我不清楚其它 OS 是否也是这样,目前也还没了解过是否可以通过修改配置文件实现),所以当 WAN0 挂了之后,IPv6 流量无法走 WAN1 。
因此,目前我使用了 ULA+NPTv6 ,这样可以正常的使用 multiwan 。但这样带来一个问题,我无法从外面访问 WAN 接口(上面跑了 VPN 接入服务),ping 也无法 ping 通。
OPNSense 论坛里聊了下,应该是 NPT 在 PF (防火墙)之前生效,直接把 WAN 的地址前缀替换成 ULA 前缀了,即使这个地址实际上是不存在的。我也不清楚这算是 OPNSense 特有的问题还是其它 OS 也是这样。最终我从内网可以正常的访问互联网,但外面不能访问内网的服务。
想请教下有没有更好的方案?
cnbatch
2023-07-15 21:55:58 +08:00
@huamiao 我一样在用这个系统,对于这个问题也关注了很久。

准确来说,这主要是 OpenBSD 的锅,其次是 pfSense 的锅,随后被 OPNSense 继承。

OPNSense 用的是 PF 防火墙——源自于 OpenBSD ,然后被移植到 FreeBSD ,接着由 OPNSense 作为默认防火墙使用。

OpenBSD 那边不太喜欢 IPv6 ,或者说不太喜欢 IPv6 的某些特性:IPv4 映射地址,还有 NPTv6 。
PF 原本是支持 IPv4 映射地址的,突然从某个版本开始,他们去掉了这个支持,理由是为了“安全”。
而 NPTv6 ,更是从一开始就没打算支持,OpenBSD 那群人甚至给 IPv6 弄了个内置 NAT ,就像 IPv4 那样。
但 OPNSense 等系统需要用,那怎么办?(也就是 GUI“内置”的 NPTv6 )只好搞个半自动支持,用脚本更新防火墙设置,因为 PF 本身并没有 NPT 的功能。只不过目前比较死板,只能认一个,搞成了半成品的模样。

这个 NPTv6 ,对于 BSD 系列而言,恰恰就是解决多 WAN 前缀+策略路由的关键。
PF 不支持,导致 OPNSense 也无法启用,拖了好几年都解决不了这个问题:
https://github.com/opnsense/core/issues/5284
https://github.com/opnsense/core/issues/6158
OPNSense 开发者们只能采取折衷的办法(目前正在做),那就是持续监控前缀地址,一旦发生变化了就用脚本更新设置。很可能 2024 版都没法没好。

如果不更换系统,目前唯一做法就只能等。


既然写了这么多字了,那就顺便再写一点。

其实 FreeBSD 自家的 ipfw 防火墙原本已经引入了 NPTv6 ,并且能够正常使用。可惜在最近的几个大版本当中,这个功能出了问题,用都用不了。

我在 FreeBSD 的论坛里的提问:
https://forums.freebsd.org/threads/how-to-properly-configure-nptv6.88971/
没人知道怎么解决,也没人找出是谁的代码出了 bug 。
后来我在邮件列表里问了下,同样也没人知道问题出在哪里。
我还顺带发现 ipfw 的邮件列表的“催 bug 机器人”发的提醒邮件比人类邮件还要多。

如果 ipfw 的 NPTv6 功能恢复正常,那倒是可以尝试手动启用 ipfw 单独配置 NPTv6 的部分。
huamiao
2023-07-15 23:07:43 +08:00
@cnbatch 感谢这么详细的回答。按现在的情形,也只能等着了。
dream2cast
2023-07-18 14:54:03 +08:00
@Jirajine 我目前用的 qBittorrent Docker 容器,是用 macvlan 建立一个 network 直接桥接至路由器 LAN ,docker 建立这个网络时,不用配置 IPv6 的部分(如:docker network create -d macvlan --subnet=192.168.10.0/24 --gateway=192.168.10.1 -o parent=br0 ),建立容器时,加一个参数--sysctl net.ipv6.conf.all.disable_ipv6=0 ,容器就可以通过 SLAAC 的方式直接从路由获取到 v6 地址了
xiaooloong
2023-08-08 11:28:15 +08:00
等一个楼主的 opnsense ipv6 最佳实践,想跟着做一遍。
xiaooloong
2023-08-09 09:31:47 +08:00
找到问题了: /t/880857
运营商只分配 /64 的网络,导致 wan 拿了 /64 后不能给 lan 继续分了
z5e56
2023-09-12 00:15:50 +08:00
请问有没有仅 systemd-networkd 的配置示例?使用 Debian 作为软路由拨号,最新版的 systemd (version 252) 配置方式与以前版本的并不一样,目前还没成功
phx13ye
87 天前
Network Manager 的命令是不是要改成`nmcli c show`显示的 name ,不是用 eth0 网卡名啊
sleepm
87 天前
@xiaooloong lan 设置跟踪接口 wan
重新连接 wan 后,lan 能获得一个 /60

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/955636

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX