【RouterOS(ROS)】IPv4 & IPv6 自动分流设置
本文基于 ROS 7.18.2 编写
前言
IPv6 日渐普及,最近闲来无事,想着把 RouterOS 上的分流规则改为 IPv4 & IPv6,因为 IPv6 的分流设置和 IPv4 有诸多不同,在此记录一下
自动更新分流规则的脚本
左侧 System → Scripts,新建一个用于自动更新分流规则的脚本
【RouterOS(ROS)】自动更新分流规则 by 2022 之前的文章有一个适用于 IPv4 的更新脚本,我们在这里需要做一下修改,使它可以适用于 IPv4 & IPv6
这里使用的是已经制作好的 IP 列表文件
1 | # 下载 IPv4 并重命名 |
成功的话应该能在防火墙和日志中看到如下内容:
路由表设置
左侧 Routing → Tables,新建一个路由表,名字自己随便写,我这里使用的是 openwrt,路由表用于防火墙标记和指定流量出口
- FIB: 勾选
IPv4 路由设置:
左侧菜单 IP → Routes,新建一条路由规则:
- Dst.Address:0.0.0.0/0
- Gateway:旁路网关IP地址
- Distance:2 # (建议使用大于1的低优先级)
- Routing Table: 选中刚刚新建的路由表,例如 openwrt
点击Apply → OK,保存提交。
使用命令导入:/ip route add dst-address=0.0.0.0/0 gateway=192.168.1.250 distance=2 routing-table=openwrt
IPv6 路由设置:
左侧菜单 IPv6 → Routes,新建一条路由规则:
- Dst.Address:::/0
- Gateway: 旁路网关的本地链路 IPv6 地址 ,例如
fe80::be24:11ff:fe79:7afe%bridge1
[1] - Distance:2 # (建议使用大于1的低优先级)
- Routing Table: 选中刚刚新建的路由表,例如 openwrt
点击Apply → OK,保存提交。
使用命令导入:/ipv6 route add dst-address=::/0 gateway=fe80::be24:11ff:fe79:7afe%bridge1 immediate-gateway=fe80::be24:11ff:fe79:7afe%bridge1 distance=2 routing-table=openwrt
注:如果 Gateway 填写的是本地链路 IPv6 地址,如 fe80:: ,则需要在地址后面加上接口名称或者网口名称,如 bridge1,则为 fe80::be24:11ff:fe79:7afe%bridge1
,如果使用的是 ULA 地址,直接在 Gateway 处填入 ULA 地址即可,无需接口名称
防火墙设置
IPv4 防火墙规则
跳过旁路网关流量
首先我们需要对旁路网关发送来的流量进行特殊处理,使其跳过流量标记,避免路由环路
左侧 IP → Firewall → Mangle,新建一条 prerouting 规则
General
- Src.Address: 填写旁路网关的IP地址
- In.Interface: 选择桥接口名字或者网口名称,如 bridge1、ether2
Advanced
- Src.MAC Address: 填写旁路网关流量出口的 MAC 地址,和 Src.Address 二选一即可。
Action
- Action: Accept (表示通过和跳过下列的防火墙规则)
国外流量标记
再新建一条 prerouting 规则用于流量标记
General
- Dst.Address List: 目标地址列表,选择 CN 和 前面的空白方块 [!] ,表示目标地址不在 CN 列表中时才命中规则
- Src.Address List: 源地址列表,如果希望局域网内只有部分设备使用这个自动分流规则,那么可以自己去 Address List 添加一个列表,留空时为所有设备
Extra
- Dst.Address Type: 下拉选择 local,然后点击前面空白方块为 [!] ,即目标地址不属于局域网地址时才命中规则
Action
- Action: makr routing 重新标记路由
- New Routing Mark: 选择之前添加的路由表
- Passthrough: 如果下方还需要对这条流量做别的处理 ,则需要勾选
使用命令导入:
my_device 为防火墙自定义 Address List
1 | /ip firewall mangle |
注:
- 必须保证”跳过流量标记”的防火墙规则在”流量标记”规则的上方
- 如果指定了 Address List 列表内设备才进行分流,且列表中不包含旁路网关地址时,不需要跳过旁路网关流量,如我的使用环境中,有一部分流量是全局的,所以还是需要 “Bypass OpenWrt” 兜底
- 如果防火墙规则中包含了 QoS 等包标记,不想使用 Accept 时,可以删除之前的规则,改为在”国外流量标记”规则后方添加规则,给旁路网关发起的流量重新打上 main 路由标记
- 如果需要将 DNS 修改为旁路网关,需检查 NAT 规则,确保未开启 DNS 劫持
- 检查 IP 伪装规则,如果使用的是 WAN 接口伪装,需要修改为整个局域网子网段,否则需要在旁路网关防火墙处设置 IP 伪装规则
( 或参考文末”其他设置”中的处理方案 )
IPv6 防火墙规则
跳过旁路网关流量
左侧 IP → Firewall → Mangle,新建一条 prerouting 规则,IPv6 通常为动态公网单播地址,无法使用 Src.Address,需要改为 MAC 地址 Src.MAC Address
General
- In.Interface: 选择桥接口名字或者网口名称,如 bridge1、ether2
Advanced
- Src.MAC Address: 填写旁路网关流量出口的 MAC 地址
Action
- Action: Accept (表示通过和跳过下列的防火墙规则)
跳过 ICMPv6 (ND) 和 DHCPv6 的流量
IPv6 防火墙规则和 IPv4 有一些区别,除了”跳过流量标记”和”流量标记”外,还需要跳过 ICMPv6 (ND) 和 DHCPv6 的流量,否则会造成 IPv6 网络异常
这里有几种跳过流量包的方法,看个人喜好和具体需求:
- 标记国外流量标记时,勾选 [!]multicast,跳过 IPv6 组播流量
- 标记流量包
下图为标记流量包
ICMPv6(ND): protocol=58 (icmpv6)
DHCPv6:dst-port=546-547 protocol=udp
国外流量标记
IPV6 通常不需要勾选 [!]local,因为流量都是公网单播地址(GUA)
但如果没有设置上方的规则,需要勾选 [!]multicast,跳过 IPv6 组播流量
因为 GUA 一般为动态的(宽带前缀 + 设备后缀),不像 IPv4 是静态地址,IPv6 防火墙无法使用 Src.Address List,如果并非全局分流,需要每个设备一条规则,使用 MAC 地址
General
- Dst.Address List: 目标地址列表,选择 CN 和 前面的空白方块 [!] ,表示目标地址不在 CN 列表中时才命中规则
Advanced
- Src.MAC Address: 填写需要分流设备的 MAC 地址(如果你不需要全局分流)
Action
- Action: makr routing 重新标记路由
- New Routing Mark: 选择之前添加的路由表
- Passthrough: 如果下方还需要对这条流量做别的处理 ,则需要勾选
使用命令导入:
1 | /ipv6 firewall mangle |
注:
- 必须保证”跳过流量标记”的防火墙规则在”流量标记”规则的上方
- 如果指定了 MAC 地址才进行分流,旁路网关通常不会产生环路流量,这里其实不需要设置跳过旁路网关流量
- 如果防火墙规则中包含了 QoS 等包标记,不想使用 Accept 时,可以删除之前的跳过 ICMPv6 (ND) 和 DHCPv6 规则,改为使用 [!]multicast;如果是全局分流,还需要添加规则,给旁路网关发起的流量重新打上 main 路由标记
- 如果需要将 DNS 修改为旁路网关,需检查 NAT 规则,确保未开启 DNS 劫持
- 在能过获得前缀的情况下,IPv6 通常不需要开启 IP 伪装,如果错误的开启 IP 伪装,会导致外部服务器只能获取到网关 IPv6 地址,而非真实的设备 IPv6 地址
兼容安卓残疾 IPv6
IPv6 ND 设置
总所周知,安卓的 IPv6 网络功能愚蠢又弱智,既不支持 DHCPv6,也不能指定 DNS 地址,也不支持网关宣告的 fe80 本地链路 DNS 地址,只能使用 GUA 或 ULA,这给分流带来了很多不方便,所以如果你使用的是安卓设备,又不想通过防火墙拒绝 ICMPv6 (ND) 包来禁用安卓设备的 IPv6 功能的话,可以把 ND DNS 设置清空
- 删除 DNS 地址信息或使用桥接接口的 fe80:: 本地链路地址
- 如果清空了 DNS 信息,取消勾选,如果使用 fe80:: 本地链路地址,保持勾选
这样可以使安卓设备仅使用 IPv4 DNS 地址
当 ND 信息中不包含 DNS 时,可能会造成部分设备需要手动指定 DNS 才能上网,如某些单网口的 OpenWrt,谨慎使用
分发 fe80:: DNS 一般也可以实现安卓设备仅使用 IPv4 DNS,因为安卓并不支持 LLA DNS
如果你非要给安卓设备指定旁路网关的 IPv6 地址,请使用 ULA 地址,但网关离线时很难自动切换,这应该和我们使用旁路网关的初衷不一致
其他设置
其实经过上面的设置之后,基本上已经可以正常上网了,但如果 IPv6 防火墙开启了丢弃无效的转发包,部分安卓设备会因为路由标记非对称路由(?),造成 TCP 握手未完成且包被丢弃,造成 IPv6 无法上网
有以下几种解决方案:
- 直接关闭”丢弃无效的转发包”规则
- 新增一条 IPv6 伪装规则,将分流的流量出口地址伪装为 RouterOS 发出,使回程流量正常响应(反正本来就是代理流量,无所谓公网和无法嗅探真实地址)
General
- Routing Mark: 选择之前添加的路由表,表示仅处理已被标记的包
Action
- Action: masquerade 将源地址从 OpenWrt 伪装为 RouterOS,以正常响应回程包
1 | /ipv6 firewall nat |
- IPv4 其实也可以这样处理
注:
- 关于 DNS 的分配,可以使用
tools
-Netwatch
故障转移、VRRP 热备、DHCP 全局分配、DHCP Option 选项给指定设备分发(如需同时分发两个 DNS,需要转换为十六进制 HEX)等方式,这里不再详细说明
在 ROS、OpenWrt 上 设置 VRRP - RouterOS 自身代理需要 Mangle 标记 input output