前言
Docker 从 26.0.0 版本开始, 默认开启了容器的 IPv6, 可以看到即便是没有配置 IPv6 的网桥网络下的容器也会有 fe80 开头的 IPv6 的本地链路地址.
Docker 官方文档开启 IPv6 的配置中, 都是固定 IPv6 前缀的, 国内大环境家用都是动态前缀, 前缀变更后, 配置就要修改, 这显然是很麻烦的, 想要动态配置 IPv6 这种轮子也是搜不到的, 毕竟 Portainer 还没适配 Docker 26.0.0, 那就只能自己动手写一个了.
Github: https://github.com/lutinglt/ipv6lanrouter
Dockerhub: https://hub.docker.com/r/lutinglt/ipv6lanrouter
如果有 BUG 的话欢迎提交 Issues, 前提要确定是 BUG, 也就是要懂基本的 IPv6 通信原理.
有状态 DHCPv6 目前不打算做, 主要是 Linux 主流发行版 CLI 版本非桌面版, 以及各个主流发行版的基础镜像, 以及手机, 电视等各种智能设备, 默认都是不支持有状态 DHCPv6, 需要安装客户端, 这也是 IPv6 应用还不够广泛的证明.
(老米那么多 v4 地址, 也没什么理由大力推 v6, 其他国家显然也没那么大的 IP 地址需求).
功能
- 自动检测动态前缀, 并切换LAN口网络前缀
- 支持自动分配多个LAN口 IPv6 地址
- 支持WAN口无前缀(路由器只有 IPv6 地址, 没有分配前缀)网络的再分配
部署
新建一个 docker-compose.yml 文件, 内容参考如下
services:
ipv6lanrouter:
image: lutinglt/ipv6lanrouter:latest
container_name: ipv6lanrouter
hostname: ipv6lanrouter
restart: on-failure
networks:
wan:
lan1:
lan2:
environment:
- TZ=Asia/Shanghai
# - CHECK=3
# - LAN_MODE=docker
# - PREFIXLEN=60
# - MTU=0
# - RDNSS=*:*:*:*;*:*:*:*;
# - EXCLUDE_SUB=00;01;02;03;...;
# - EXCLUDE_NUM1=0;1;2;3;...;
# - EXCLUDE_NUM2=0;1;2;3;...;
cap_add:
- NET_ADMIN
sysctls:
- "net.ipv6.conf.all.forwarding=1"
- "net.ipv6.conf.all.proxy_ndp=1"
- "net.ipv6.conf.all.accept_ra=2"
- "net.ipv6.conf.default.forwarding=1"
- "net.ipv6.conf.default.proxy_ndp=1"
- "net.ipv6.conf.default.accept_ra=2"
networks:
wan:
external: true
name: wan
lan1:
external: true
name: lan1
lan2:
external: true
name: lan2
看名字也能知道这是一个局域网路由器, 所以 wan 和 lan 都是相对路由器来说的.
网络部分, wan 网络对应的是可以获得 IPv6 地址的网络, lan 网络对应的是不能获得 IPv6 地址的网络, wan 口有且仅有一个, 脚本里会把第一个检测到地址的口视为 wan 口, 其他地址均视为 lan 口并启动路由服务. (如果需要多WAN, 可以启动多个容器)
restart 建议设置为重启, 因为有时会有服务启动后, lan 口获得不了 IP 地址的情况, 不清楚原因, 也不打算修, 因为重启就好了, 而且无法复现(调试的时候遇到过两次).
cap_add 和 sysctls 的部分必须有, 这是路由器正常工作依赖的内核参数和权限.
如果从运营商获取的前缀是 60 位, 则不需要任何设置, 直接将网络写进文件, 然后输入
docker compose up -d
environment 部分
- TZ: 时区, 不影响程序运行, 会影响程序打印日志的时间
- CHECK: 间隔时间, 用于检测 WAN 口前缀是否变化的间隔时间
- MTU: LAN 口分配地址时, 是否告知客户端配置 MTU 值, 0 代表不下发, 交给客户端自己配置
- RDDNS: 递归 DNS 服务器, 可以理解为告知客户端DNS配置
- PREFEXLAN: WAN 口在从上级路由获取 IPv6 地址时, 上级路由获得的前缀
- LAN_MODE: LAN 口所连接的网络类型, 用于分配 IPv6 地址
PREFEXLEN && LAN_MODE
PREFEXLEN 是前缀长度, 前缀长度对应的是可以划分给LAN口网络的数量, 中国目前从运营商那获得的应该是 56-62, 大部分应该是 60, 脚本支持也是 56-64, 请注意, 这里是网络数量而不是 IP 数量, 因为 IPv6 是128位, 拥有的地址特别多, 所以只需要按网络分配就行, IPv6 地址的基本介绍可以站内搜索 技术蛋老师的 IPv6 介绍视频.
所以从运营商那获得前缀时, 如果路由器前缀显示 2000:2000:2000:2100::/56, 则表示是 56 位前缀的长度, 从 2000:2000:2000:2100::/64 到 2000:2000:2000:21ff::/64,都是属于你的网络, 不是某一个地址, 而是一个 IP 段, 为什么是 64 位可以去看视频, 这里在补充一点的是, 无状态地址的计算 EUI64 也是根据 64 位前缀来的, 且容器里用于 IPv6 地址分配的包, 也只支持到 64 位前缀. 如果路由器前缀显示 2000:2000:2000:2100::/60, 则表示是 60 位前缀的长度, 从 2000:2000:2000:2100::/64 到 2000:2000:2000:210f::/64 是属于你的网络
如果只有 IPv6 地址, 没有前缀, 表示运营商没有分配给你前缀, 此时 PREFEXLEN 要设置为 64并会涉及 LAN_MODE 的设置, LAN_MODE 默认是 Docker, 表示所有 LAN 口连接的网络都是 Docker 创建管理的网络, 因为 Docker 创建的网络分配给容器时的 MAC 地址是有规律的, 所以可以根据统一的规则继续划分网络, 并不会影响使用, ( IPv6 的无状态地址是计算出来的, 而不是路由器分配的, 有几套计算规则, Linux 目前主流发行版默认都是 EUI64 计算, Windows 则不是, 采用的是一种密钥计算出随机地址的方式, Windows 的 EUI64 计算无状态地址设置需要自行解决 )
但是如果 LAN 口连接的网络不是 Docker 创建的网络, 需要设置 LAN_MODE 为 net, 因为 LAN 网络下所有客户端获得的 IP 地址是不确定的, 所以没有办法继续划分网络, 此时只支持一个 LAN 口, 同时 LAN 口网络下的客户端和 WAN 口网络下的客户端是没有办法通信的, 因为此时路由器只是对 LAN 口网络的客户端分配 IPv6 地址, LAN口和WAN 口的客户端是在同一个局域网里, 所以不会经过路由, 不经过路由自然也就没有办法通信, 但是 LAN 口的客户端可以正常访问外网, 毕竟不在同一个网段, 自然会经过路由.
EXCLUDE_SUB
需要排除分配的网络, 如前文, 56 位前缀可以分配 00-ff, 60 位前缀可以分配 0-f, 用分号分隔
WAN: 2000:2000:2000:2100::/56
EXCLUDE_SUB: 00;01;02;fd;fe;ff
LAN: 2000:2000:2000:2103::/64 - 2000:2000:2000:21fc::/64
WAN: 2000:2000:2000:2100::/60
EXCLUDE_SUB: 0;1;2;d;e;f
LAN: 2000:2000:2000:2103::/64 - 2000:2000:2000:210c::/64
容器在分配 LAN 口地址时会排除掉 WAN 口地址
EXCLUDE_NUM1 && EXCLUDE_NUM2
方便写一整个段的排除
EXCLUDE_SUB: 00;01;02;03;04;05;10;11;12;13;14;15
等同于
EXCLUDE_NUM1: 0;1
EXCLUDE_NUM2: 0;1;2;3;4;5
与 EXCLUDE_SUB 不冲突, 两者之间可以重复
写技术类文档最难的点就是有些自己明白的点, 别人不明白时, 如何将这些点简化, 使之更为容易理解, 甚至不惜是错误的理解,( 最常用的手段就是比如, 类似, 其实技术里很多东西根本就是需要根本上建立理解的, 跟其他知识不是一个框架, 比如类似就是耍流氓, 也是程序运行跟你想的结果不一样的原因, 学习 v6 最难的点也是很多概念默认用 v4 的, 实际从我的学习来看 v4 和 v6 基本就是两个东西, 当然随着更深入的原理比如包上的话, 无非就是方法不一样, 协议的东西不一样, 但是对于开发人员的简单概念理解上, 这两个就不是一个东西 ) 如我刚开始看技术类文档给人的感觉是给看得懂的人写的, 我心思看得懂的需要看你文档吗, 你这么写给谁看呢, 这不就是看得懂的不用看, 看不懂的看了也看不懂吗, 随着自己深入后发现, 这类文档所需要的前置知识太多了, 往往是需要至少几十页才能讲明白的东西, 甚至很多都需要实战经验才能明白他解决的是什么问题, 想要每次都浓缩到一篇短短的文章里, 显然是非常不现实的, 所以如果有时候有人问问题的时候, 我基本都是建议系统性学习, 买本书看, 很多东西就明白了.
补充一个性能测试, 在BT测试中, 大概不到100个用户, 800M带宽打满, 路由器CPU单核占用不到5%, 内存占用不超过5M, 毕竟只是路由, 不是NAT (效率就是高)