RouterOS路由OSPF协议+树莓派分流国外流量
跟原文作者一样,之前尝试过使用RouterOS的iptables给链接打标记的方式配置过,但不知道为什么,速度奇慢无比,直到看到通过动态路由协议的方式进行分流。
OSPF简介
OSPF (Open Shortest Path First) 是一种常用的 IGP 路由协议,相对于 BGP 这种主要是为自治域之间通信设计的协议,OSPF 的配置相对来说要简单易懂的多,而且收敛速度非常的快,适合用来在内网快速发布大量的路由。 OSPF 唯一不足的地方是一开始设计的时候没有考虑到多种协议的支持,导致 IPv6 出来后又设计了 OSPFv3 这个新的协议。因为我们希望有 IPv6 支持,所以后面会同时配置 OSPFv2 和 OSPFv3 的实例。但是相对于 IS-IS 和 iBGP 这些支持原生双栈的协议还是配置起来要简单了不少。
额外需要的信息
为了让树莓派能把国外的 IP 地址路由牵引过来,我们需要国外的 IP 段信息。注意这个跟 chnroutes 不一样,前者是中国的 IP 段,而我们需要取反获得不是中国的 IP 段,因为路由协议只能宣告哪些 IP 段应该被转发到树莓派。 在网上搜了半天无果后我自己写了一个简单的 Python 脚本可以生成符合要求的路由。项目已开源,可以在这里下载: https://github.com/dndx/nchnroutes 下载了以后 make
即可生成国外 IP 地址的路由表。注意如果树莓派上的隧道连接的是国外的 IP,那么需要从生成的 IP 段里剔除,否则隧道的流量也会被 RouterOS 发给树莓派,形成路由环路。可以参考 README.md
的说明通过 --exclude
选项把这些不应该走隧道的 IP 排除。 另外脚本支持 --next
选项,可以用来指定隧道的下一跳。 运行后会生成两个文件 routes4.conf
和 routes6.conf
,这两个文件是 BIRD 的静态路由格式,后面做 OSPF 宣告的时候会用到。 另外要注意,在树莓派上配置隧道的时候,不可以创建去往隧道的默认路由。因为我们后面需要用 BIRD 来动态的插入国外的路由走隧道。对于 WireGuard,可以用 Table = off
这个选项来不安装默认路由。
树莓派配置
建立虚拟网卡
使用go-tun2socks在树莓派中建立一个虚拟网卡,用作分流,直接下载releases即可,下载完后,使用以下命令开启虚拟网卡
1 | root@aml:~# tun2socks-linux-arm64 -tunGw 192.168.171.1 -proxyServer 127.0.0.1:10808 -tunDns 8.8.8.8,8.8.4.4 -tunName wg0 -loglevel info & |
开启转发
树莓派应该开启 IP 转发功能,编辑 /etc/sysctl.conf
把 net.ipv4.ip_forward=1
和 net.ipv6.conf.all.forwarding=1
的注释删掉,然后 sudo sysctl -p /etc/sysctl.conf
来应用设置。
IPTABLES
下一步在树莓派上配置一些基本的防火墙规则。 sudo apt install iptables-persistent
安装 iptables
规则持久化包,安装时询问是否要保存当前的规则可以选 No,因为下面我们要手动创建规则文件。 原文中,作者详细描述了IPV4与IPV6的配置注意事项,由于我这里暂时不需要IPV6,仅对IPV4进行了配置,如果有需要,可以在文章底部找到原文链接。 编辑 iptables
规则。配置文件/etc/iptables/rules.v4
如下:
1 | *filter |
执行iptables-restore < /etc/iptables/rules.v4
让配置立即生效
BIRD
下一步需要在树莓派上安装 BIRD 来与 RouterOS 建立 OSPF 邻居关系和进行路由宣告。在 Raspbian 上可以直接 sudo apt install bird
来安装。 安装好了后,BIRD 默认会自动启动。我们需要把上面生成的 routes4.conf
文件复制到 /etc/bird
目录下。然后编辑 /etc/bird/bird.conf
来导入生成的静态路由和启用 OSPF 支持:
1 | # This is a minimal configuration file, which allows the bird daemon to start |
需要根据实际情况修改以下配置: router id 192.168.169.5;
是OSPF实例的唯一标识符,要求在局域网内唯一。惯例使用树莓派的局域网IP即可。同一台机器上的 OSPFv2 和 v3 实例可以共享 router id
。 password "foobar";
这里是跟 RouterOS 握手使用的密码。选一个随机的字符串即可。 对于 IPv6,需要使用 OSPFv3,这里跳过,有需要可以在文章底部找到原文链接。 配置完成后需要reload bird 让配置生效:
1 | pi@raspberrypi:~/nchnroutes $ sudo birdc configure |
配置完后,验证树莓派的路由已经正确分流:
1 | pi@raspberrypi:~/nchnroutes $ ip r get 1.1.1.1 |
可以看到国内外的 IP 已经返回了不同的路由。也可以 traceroute
国内外的 IP 地址来验证。 至此,树莓派的配置已经完成。接下来需要在 RouterOS 上启用 OSPF 实例来收取树莓派发过来的路由。
RouterOS配置
首先需要确保 RouterOS 的 routing
package 是启用的状态。否则 OSPF 功能会不可用。
1 | [user@MikroTik] > /system package |
如果原来没有启用,启用了后需要重启才能生效:
1 | [user@MikroTik] /system package> /system reboot |
重启后,启用OSPF实例(IPv4):
1 | /routing ospf instance |
这里的 router-id
也应该设为 RouterOS 的局域网 IP 地址。不可以跟树莓派 router-id
的相同。 配置好了后,如果一切正常,树莓派应该会自动与 RouterOS 建立 OSPF 邻居关系:
1 | [admin@MikroTik] /routing ospf neighbor> print |
同时,可以看到 RouterOS 已经收到了树莓派发过来的路由:
1 | [admin@MikroTik] /ip route> print |
效果
在局域网里任何一台机器上 traceroute 114.114.114.114
和 traceroute 1.1.1.1
,可以看到前者走的是运营商的出口,而后者被转发到了树莓派后走隧道出国。 重启树莓派,模拟树莓派宕机,同时立刻在局域网里任何一台机器上 ping 一个国外的地址,可以看到一开始走的是运营商链路,树莓派重启完毕以后会自动把路由拉回到隧道:
来自 1.1.1.1 的回复: 字节=32 时间=151ms TTL=54
来自 1.1.1.1 的回复: 字节=32 时间=152ms TTL=54
来自 1.1.1.1 的回复: 字节=32 时间=160ms TTL=54
来自 1.1.1.1 的回复: 字节=32 时间=153ms TTL=54
来自 1.1.1.1 的回复: 字节=32 时间=151ms TTL=54
来自 1.1.1.1 的回复: 字节=32 时间=156ms TTL=54
来自 1.1.1.1 的回复: 字节=32 时间=151ms TTL=54
来自 1.1.1.1 的回复: 字节=32 时间=156ms TTL=54
来自 1.1.1.1 的回复: 字节=32 时间=1869ms TTL=54
来自 1.1.1.1 的回复: 字节=32 时间=7ms TTL=62
来自 1.1.1.1 的回复: 字节=32 时间=1ms TTL=62
来自 1.1.1.1 的回复: 字节=32 时间=2ms TTL=62
来自 1.1.1.1 的回复: 字节=32 时间=2ms TTL=62
来自 1.1.1.1 的回复: 字节=32 时间=13ms TTL=62
来自 1.1.1.1 的回复: 字节=32 时间=1ms TTL=62
1 | root@aml:~# curl ip.sb |