跟原文作者一样,之前尝试过使用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即可,下载完后,使用以下命令开启虚拟网卡
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 & root@aml:~# ip addr add 192.168.171.1 dev wg0 root@aml:~# ip link set dev wg0 up
开启转发
树莓派应该开启 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
如下:
*filter :INPUT ACCEPT [0:0] :FORWARD DROP [0:0] :OUTPUT ACCEPT [0:0] -A FORWARD -p tcp -m tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu -A FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT -A FORWARD -i eth0 -o wg0 -j ACCEPT COMMIT *nat :PREROUTING ACCEPT [0:0] :INPUT ACCEPT [0:0] :POSTROUTING ACCEPT [0:0] :OUTPUT ACCEPT [0:0] -A POSTROUTING -o wg0 -j MASQUERADE COMMIT
执行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 支持:
# This is a minimal configuration file, which allows the bird daemon to start # but will not cause anything else to happen. # # Please refer to the documentation in the bird-doc package or BIRD User's # Guide on http://bird.network.cz/ for more information on configuring BIRD and # adding routing protocols. # Change this into your BIRD router ID. It's a world-wide unique identification # of your router, usually one of router's IPv4 addresses. router id 192.168.169.5; # The Device protocol is not a real routing protocol. It doesn't generate any # routes and it only serves as a module for getting information about network # interfaces from the kernel. protocol device { scan time 60; } # The Kernel protocol is not a real routing protocol. Instead of communicating # with other routers in the network, it performs synchronization of BIRD's # routing tables with the OS kernel. protocol kernel { metric 64; # Use explicit kernel route metric to avoid collisions # with non-BIRD routes in the kernel routing table scan time 60; import none; export all; # Actually insert routes into the kernel routing table } protocol static { include "routes4.conf"; } protocol ospf { export all; area 0.0.0.0 { interface "eth0" { authentication cryptographic; password "foobar"; }; }; }
需要根据实际情况修改以下配置:
router id 192.168.169.5;
是OSPF实例的唯一标识符,要求在局域网内唯一。惯例使用树莓派的局域网IP即可。同一台机器上的 OSPFv2 和 v3 实例可以共享 router id
。
password "foobar";
这里是跟 RouterOS 握手使用的密码。选一个随机的字符串即可。
对于 IPv6,需要使用 OSPFv3,这里跳过,有需要可以在文章底部找到原文链接。
配置完成后需要reload bird 让配置生效:
pi@raspberrypi:~/nchnroutes $ sudo birdc configure BIRD 1.6.6 ready. Reading configuration from /etc/bird/bird.conf Reconfigured
配置完后,验证树莓派的路由已经正确分流:
pi@raspberrypi:~/nchnroutes $ ip r get 1.1.1.1 1.1.1.1 dev wg0 src 192.168.88.2 uid 1000 cache pi@raspberrypi:~/nchnroutes $ ip r get 114.114.114.114 114.114.114.114 via 192.168.0.1 dev eth0 src 192.168.0.2 uid 1000 cache
可以看到国内外的 IP 已经返回了不同的路由。也可以 traceroute
国内外的 IP 地址来验证。
至此,树莓派的配置已经完成。接下来需要在 RouterOS 上启用 OSPF 实例来收取树莓派发过来的路由。
RouterOS配置
首先需要确保 RouterOS 的 routing
package 是启用的状态。否则 OSPF 功能会不可用。
[user@MikroTik] > /system package [user@MikroTik] /system package> print Flags: X - disabled # NAME VERSION SCHEDULED 0 routeros-mmips 6.48 1 system 6.48 2 ipv6 6.48 3 X wireless 6.48 4 X hotspot 6.48 5 X mpls 6.48 6 X routing 6.48 ... [user@MikroTik] /system package> enable routing [user@MikroTik] /system package> print Flags: X - disabled # NAME VERSION SCHEDULED ... 6 X routing 6.48 scheduled for enable
如果原来没有启用,启用了后需要重启才能生效:
[user@MikroTik] /system package> /system reboot Reboot, yes? [y/N]: y system will reboot shortly
重启后,启用OSPF实例(IPv4):
/routing ospf instance set [ find default=yes ] router-id=192.168.169.254 /routing ospf interface add authentication=md5 authentication-key=foobar interface=bridge_lan network-type=broadcast /routing ospf network add area=backbone network=192.168.169.0/24
这里的 router-id
也应该设为 RouterOS 的局域网 IP 地址。不可以跟树莓派 router-id
的相同。
配置好了后,如果一切正常,树莓派应该会自动与 RouterOS 建立 OSPF 邻居关系:
[admin@MikroTik] /routing ospf neighbor> print 0 instance=default router-id=192.168.169.5 address=192.168.169.5 interface=bridge1 priority=1 dr-address=192.168.169.254 backup-dr-address=192.168.169.5 state="Full" state-changes=14 ls-retransmits=0 ls-requests=0 db-summaries=0 adjacency=5h5m22s
同时,可以看到 RouterOS 已经收到了树莓派发过来的路由:
[admin@MikroTik] /ip route> print Flags: X - disabled, A - active, D - dynamic, C - connect, S - static, r - rip, b - bgp, o - ospf, m - mme, B - blackhole, U - unreachable, P - prohibit # DST-ADDRESS PREF-SRC GATEWAY DISTANCE 0 X S 0.0.0.0/0 pppoe-Unicom 1 1 ADS 0.0.0.0/0 pppoe-Telecom 1 2 ADo 1.0.0.0/24 192.168.169.5 110 3 ADo 1.0.4.0/22 192.168.169.5 110 ...
效果
在局域网里任何一台机器上 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
root@aml:~# curl ip.sb 74.12.74.5 root@aml:~# curl -s members.3322.org/dyndns/getip 39.156.69.79
链接
请问博主,使用go-tun2socks在树莓派中建立一个虚拟网卡说明看不大明白,因为我wg隧道已经建立好了,赋予了ip,跟vps联通后,ifconfig就有eth0和wg0。为什么这里还要建立一个呢?
看到后文还说到测试树莓派的分流,测试1.1.1.1的出口,看到反馈结果是dev wg0 src 192.168.88.2 uid 1000 ,也就是说wg0隧道的ip是192.168.88.2。跟之前建立的wg0不一样啊
感谢解惑。
v2ray这类应用是不会建立虚拟网卡的,所以要用go-tun2socks。当然如果应用直接建立了虚拟网卡就不需要这一步了
请问一下,树莓派本身的流量可以不走隧道吗?谢谢。
加自定义路由就行
请问博主,我通过OSPF接受路由表后,与vt的wireguard通到就断了,只要关闭OSPF wireguard隧道就通了,这种情况要怎么处理呢。
在routeros中ospf的优先级比静态路由的优先级高,可以把通道的目的地址在ospf中删除试试