使用Gentoo Linux手搓路由器之四 -- 支持 IPv6
家庭网络环境下(slaac
)的 Linux 路由器 IPv6 的配置
先说大概有内种方案吧
NAT
模式: 同IPv4
的NAT
一样。这个没有什么好说的,失去IPv6
的意义,直接不考虑。Relay
模式。这个就是现在OpenWRT
玩家采用的方案。 系统中自带的odhcpd
是支持 ra, nd, dhcpv6relay
。 我看网上有人说不稳定,但是也没有啥证据。 可惜Linux
没有这个东西,我在网上也找了相关文章,没有找到资料。Github
上有一个历史悠久的代码 Menci/magpie 通过抓包实现的Relay
我试着编译,报错太多了,Fix 难度太大了,直接不考虑。
Bridge
模式。 原理大概就是创建一个网桥brlan
(这是个名字,可以改的),把WAN
和LAN
放到一起,仅让IPv6
的数据包通过这个网桥,IPv4
的数据包依然走原来的NAT
- 基于桥接的中继(
Relay
)
- 基于桥接的中继(
创建网桥
- 在
netifrc
中创建1vim /etc/conf.d/net 2### 加入创建网桥的配置 3bridge_brlan="enp1s0f0 enp1s0f1" # enp1s0f1 为 WAN, enp1s0f0 为 LAN 口
- 或者使用脚本创建
1brctl addif brlan wan
脚本创建有一个麻烦,就是不好重复执行脚本,我一般把 iptables 写在脚本里,因为网络配置的需要会经常修改脚本重复执行,所以我会把创建网桥的工作放在
netifrc
启动的时候。
禁止IPv4
的数据包通过网桥
1ebtables -t broute -A BROUTING -p ! IPv6 -i ${WAN} --logical-in brlan -j DROP
2ebtables -t filter -A OUTPUT -p ! IPv6 --logical-out ${LAN} -o ${WAN} -j DROP
这里要使用到
ebtables
, 网桥更底层, iptables 无法控制。第一条规则: 在 broute 链上 DROP 的数据包并不真正的DROP, 而是使得这个数据包不经过网桥, 原样发到发到原来的接口上。 这样就不会影响到原来的 IPv4 的 NAT 配置。而 IPv6 的数据包会直接经过网桥与 LAN 侧的主机互通了。 第二条规则在 filter 链上, 将 brlan 要发往 WAN 的 非IPv6 的数据包全部丢弃,是为了使得 brlan 在 IPv4 泛洪时不会将 IPv4 的数据包发往 WAN
如果做到这里,你已经可以正常使用 IPv6 了,可是这样会带来一些问题。如:网桥是工作在三层以下,也就是说 IPv6 的流量不会经过路由器的三层,无法配置路由规则和防火墙。
基于网桥的 Relay
因 WAN 和 LAN 在同一个网桥上进去连通的, 所以 NDP, NS,NA 的数据包默认就能正确的被送达。这就相当于实现了一个 NDP Relay。(与手动实现的中继有一点不同,就是这种情况是在同一个网桥内部,桥会直接双向发送 slaac和NDP包,不会改变 MAC 地址, 在 WAN 和 LAN 看来, 他们是直接互通的)。 所以考虑 ICMPv6 的数据包直接网桥通过,而非 ICMPv6 的数据包让它经过三层路由。
BTW: 如果是 WAN 是光猫拨号,且光猫的 DHCPD 无法关闭的情况下,需要在增加一条规则,禁止光猫的DHCPD被广播到 LAN
1ebtables -t broute -A BROUTING -p IPv4 --ip-protocol UDP --ip-source 192.168.1.0/24 --ip-destination-port 67:68 -j DROP
2## --ip-source 就是光猫的 dhcpd 的网段
基于桥接的 Relay
1ebtables -t nat -A PREROUTING -p IPv6 --logical-in ${LAN} --ip6-proto ipv6-icmp --ip6-icmp-type router-solicitation -j ACCEPT
2ebtables -t nat -A PREROUTING -p IPv6 --logical-in ${LAN} --ip6-proto ipv6-icmp --ip6-icmp-type router-advertisement -j ACCEPT
3ebtables -t nat -A PREROUTING -p IPv6 --logical-in ${LAN} --ip6-proto ipv6-icmp --ip6-icmp-type neighbour-solicitation -j ACCEPT
4ebtables -t nat -A PREROUTING -p IPv6 --logical-in ${LAN} --ip6-proto ipv6-icmp --ip6-icmp-type neighbour-advertisement -j ACCEPT
5ebtables -t nat -A PREROUTING -p IPv6 --logical-in ${LAN} -j redirect
前四条规则是让 ICMPv6 的 slaac 和 NDP 数据包通过网桥, 实现 slaac 和 ndp的中继。 第五条规则是让 非 slaac 和 NDP 且由 brlan 进入的 IPv6 的数据包不经过网桥,而是将他们的 MAC 地址改为 brlan,使的这些数据在路由器的 brlan 口上被接收到。 所以需要增加 brlan 到 brlan 的转发
- 内核参数
1# net.ipv6.conf.all.forwarding=1 2sysctl -w net.ipv6.conf.all.forwarding=1
- 转发规则
1ip6tables -t filter -A FORWARD -i ${LAN} -o ${LAN} -j ACCEPT
这样就可以使用防火墙去处理 IPv6 的数据包了
几个内核的参数
参数名 | 用法 |
---|---|
net.ipv6.conf.all.disable_ipv6 | 是否禁用 IPv6, 0 禁用, 1 开启 |
net.ipv6.conf.all.forwarding | 是否开启转发 0 不开启, 1 开启, 2意思是强制开启转发同时不要自动禁用基于Router Advertisements的Stateless Address Autoconfiguration(如果禁用了的话,远程机器就会把这台设备当作路由器而不是主机,而地址自动配置只会给主机配置,不会给路由器配置)。 |
net.ipv6.conf.all.accept_ra | 接受RA,0 不接受 1 接受(当forwarding禁止时接受) 2 任何情况下都接受(本文作为网关的情况下应该是2,路由器本身也需要IPv6地址的) |
net.ipv6.conf.all.max_addresses | 故名思义,最大地址数量. 0 不限制,>0 最大值 |
net.ipv6.conf.all.mtu | mtu 值, 一般不需要调整,是否需要调整请查看 《家用宽带IPv6开启后上网变慢的问题》 |
net.ipv6.conf.brlan.use_tempaddr | 0 不使用临时地址,1 生成临时地址 2 生成临时地址,并在使用过程中优先使用临时址 (显然2更加保护隐私) |
内核参数配置注意点:
如果使用 accept_ra 来配置 Client 端的 IPv6 地址,如果仅仅是使用 net.ipv6.conf.all.accept_ra
和 net.ipv6.conf.default.accept_ra
这两个参数来控制,是指当路由器发送RA的时候系统会根据 RA 的内容来完成地址配置。但是有一种情况,就是客户机本身的变化是需要实现获取RA来调整自身的配置与路由器的网络配置对齐。这个时候需要使用 net.ipv6.conf.${eth?}.accept_ra
来指定网卡,比如网卡被重启,客户机会主动发送 RS 来获取 RA。
使用 tcpdump
抓取 RS / RA
1tcpdump -i ${eth?} -vvvvn icmp6 and 'ip6[40] = 133 or ip6[40] = 134'
Posts in this series
- 使用Gentoo Linux手搓路由器之四 -- 支持 IPv6
- 使用 Gentoo Linux 手搓路由器之三 -- 国内访问加速
- 使用 Gentoo Linux 手搓路由器之二 -- 透明代理
- IPTV单线复用——在Linux系统上配置
- 使用 Gentoo Linux 搭建简单路由器并支持IPTV功能