V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
dndx
V2EX  ›  宽带症候群

[教程] 使用 RouterOS, OSPF 和树莓派为国内外 IP 智能分流

  •  
  •   dndx · 2020-12-29 02:26:45 +08:00 · 19155 次点击
    这是一个创建于 1461 天前的主题,其中的信息可能已经有所发展或是发生改变。

    对于 RouterOS 的用户们,谈到国内外智能分流都是泪。这种 OpenWRT 可以很简单的完成的任务在 RouterOS 上基本上都需要用策略路由这种杀鸡用牛刀的方式来进行。另外,PBR 还有很多缺点,比如更新起来麻烦(一不小心 CLI 也可能搞坏路由器配置),而且没有健康检查,如果旁路由断网或者掉电 RouterOS 还是会傻傻的把流量转发过去,结果就是旁路由一挂国外 IP 全部不通。

    这篇问题记录了我在 RouterOS 上通过 OSPF 协议把国外的流量动态拉取到旁路由上的配置过程。这样也算是让 RouterOS 干最擅长的工作。而路由的动态更新也可以直接在旁路由上完成。文章里面包含了 IPv4 和 IPv6 的配置。

    根据一个月来的实验,效果非常好,中间有两次隧道断线,BIRD 都成功的检测到了故障,及时的从主路由 withdraw announcement,这样最起码国外 IP 还是通的。

    全文在此:https://idndx.com/use-routeros-ospf-and-raspberry-pi-to-create-split-routing-for-different-ip-ranges/

    这个文章只侧重了 3 层的分流,对于比如 DNS 污染就没有讨论,所以不是一个完整的解决方案。反正架设无污染的 DNS 方法网上一搜一大把,就不值得再写一遍了。

    第 1 条附言  ·  2020-12-29 03:12:45 +08:00
    除了高可用性以外,还有一个折腾的原因是 ROS 6 到现在都还不支持 IPv6 的策略路由(据说 7 里面会支持?),所以 IPv6 分流基本只有 OSPF 这一条路可走。尝试过直接在 ROS 创建静态路由,十几分钟都导入不完,所以跑路由协议几乎是唯一的办法。

    我在网上也没有看到有人发 ROS IPv6 的分流教程,估计是这个原因。
    57 条回复    2024-05-10 13:52:37 +08:00
    zro
        1
    zro  
       2020-12-29 02:46:45 +08:00
    谢谢楼主,又了解到一些知识。。

    另外借楼问一下,ROS 自带的协议,有哪个是能稳定穿墙的?谢谢~~
    dndx
        2
    dndx  
    OP
       2020-12-29 02:51:31 +08:00   ❤️ 1
    @zro 自带的肯定都不行,但是在树莓派上稍微伪装一下就可以。
    EPr2hh6LADQWqRVH
        3
    EPr2hh6LADQWqRVH  
       2020-12-29 02:56:32 +08:00 via Android
    虽然涨了一些有趣的知识但不得不说楼主你这个真是事倍功半啊。。。。
    dndx
        4
    dndx  
    OP
       2020-12-29 03:01:03 +08:00
    @avastms 相对于 PBR 的好处上面也都说了,的确是比较折腾一些,但是也能学到不少知识。另外的确可用性要比 PBR 和静态路由高一些。具体需不需这么高的可用性就看每个人各自的需求了。。。

    其实我想说那些用 PBR 的看起来也挺折腾的...虽然看起来旁路由上配置简单,但是 ROS 上的配置可就复杂多了。
    miyunda
        5
    miyunda  
       2020-12-29 07:43:17 +08:00
    图里有个 typo 。。。114
    ericbize
        6
    ericbize  
       2020-12-29 08:20:30 +08:00 via iPhone
    我是在国内的 ros 写静态路由, 把国内地址全部写进去, 然后通过 ospf 在 hk 把默认路由宣告回来。
    至于过墙, 要不就 iepl 或者是利用 udp 无状态的特性,4 台 ros 在线路稳定情况下可以稳定过墙
    sonicboy17
        7
    sonicboy17  
       2020-12-29 08:30:23 +08:00   ❤️ 1
    虽然看不懂,但是还是要战略性 mark 下
    ihipop
        8
    ihipop  
       2020-12-29 09:21:40 +08:00 via Android
    vrrp 就能解决的问题用到了 ospf 。。
    ihipop
        9
    ihipop  
       2020-12-29 09:43:38 +08:00 via Android
    @ericbize 可是 UDP 国内限速啊 ipel 一条线多少钱?
    noahzh
        10
    noahzh  
       2020-12-29 10:12:15 +08:00
    使用 WireGuard 这种 UDP 很受运营商限制,能不能搭配 v2ray 使用?
    cwbsw
        11
    cwbsw  
       2020-12-29 11:11:29 +08:00
    我想知道的是查询几万条路由的效率是否能比几万条 ipset 高?灵活性易用性上后者强太多了。
    Linkinternet
        12
    Linkinternet  
       2020-12-29 12:10:45 +08:00
    RouterOS 可以通过检测网关 脚本 netwatch 等多种检测手段
    dndx
        13
    dndx  
    OP
       2020-12-29 15:26:15 +08:00
    @cwbsw 路由器最基本的功能就是根据路由表决定下一跳,如果这个性能都做不好那也不可能有性能更好的办法了。ipset 这种要走防火墙额外处理的只会比路由表更慢。

    实际上 BGP 全表就算聚合后现在的大小也有快 50 万条路由了,10000 条跟这个比起来是小巫见大巫。用 ROS 跑 BGP 全表的人很多,要是这些都处理不了 ROS 就没法用了。

    另外 Linux 的路由表查询其实是有缓存的,并不是每个数据包都要完整的查一遍。

    http://linux-ip.net/html/routing-cache.html
    https://superuser.com/questions/419659/iptables-vs-route
    https://serverfault.com/questions/334885/use-iptables-or-null-route-for-blacklisting-about-1-million-ip-addresses
    dndx
        14
    dndx  
    OP
       2020-12-29 15:38:53 +08:00
    @noahzh 只要能 tunnel 跑 UDP 就可以,实际上我用了 udp2raw,把 UDP 包装成 TCP 。关键是要把 MTU 设对,否则一分片马上延迟爆炸。目前找到的好办法就是 `tcpdump` 配合 `ping -s` 来看封装后的 IP 包的大小。

    @ericbize 这个方法我一开始考虑过,然而 RoS 不知道为什么导入静态路由速度爆炸,后来被迫放弃。后来我在找解决方法的时候还是在网上搜到了 RoS 论坛里有人抱怨这个问题 https://forum.mikrotik.com/viewtopic.php?t=117529 才想到可以跑路由协议。不过如果有国外的 IP 路由表,那也可以在隧道另一头拉路由,这样就可以不用默认路由了。

    @ihipop VRRP 的话,因为不希望国内流量也走旁路由,所以不能满足需求

    @miyunda fixed
    noahzh
        15
    noahzh  
       2020-12-29 16:15:15 +08:00
    @dndx 这个方案是否没有办法控制哪些设备不需要分流,都走运营商,还要一个疑问,为什么这么依赖 UDP?谢谢
    stevefan1999
        16
    stevefan1999  
       2020-12-29 16:38:35 +08:00
    Route your network with OSPF~
    dndx
        17
    dndx  
    OP
       2020-12-29 16:38:40 +08:00
    @noahzh 这个是不行的,如果要按照来源来路由那就只能走 PBR 了。

    这套方案不依赖于 UDP,比如你在旁路由上跑个 ss-redir + iptables 来转发效果也是一样的。
    onion83
        18
    onion83  
       2020-12-29 16:41:27 +08:00
    思路很好我也会愿意尝试一下,不过为了解决路由闪断问题,是否可以考虑用 diff 的方法来更新,这样就没必要先全量删再全量加了,就是如何写脚本需要费点心思。

    另外 firewalls 里面有个 address list 等价于 ipset 一般配合 mangle 打标路由标识后,再配一条静态路由转到旁路由,这样静态路由表会干净些,也确保静态路由的安全避免误删断网。

    mangle 防火墙配置命令为:

    chain=prerouting action=mark-routing new-routing-mark=free passthrough=no
    dst-address-type=!local src-address-list=!bypass dst-address-list=!cn
    in-interface=bridge-core log=no log-prefix=""


    src-address-list 后跟的 bypass 是不打标签的主机列表,例如 192.168.1.1 (路由器本身) 192.168.1.254 (树莓派之类的旁路由,避免环路)

    dst-address-list 后跟的就是 cn 路由列表了 https://github.com/17mon/china_ip_list

    当然还有一些自定义路由需要脚本自己再合并一下性能:CCR1009 导入 6000 来条路由 address list 到大概 3 秒,x86 软路由 1 秒 搞定。
    noahzh
        19
    noahzh  
       2020-12-29 16:48:26 +08:00
    @onion83 同意楼上,我现在就是这么搞的,网关下线也是又感知的,楼主写了自动更新地址的脚本了吗?谢谢.
    dndx
        20
    dndx  
    OP
       2020-12-29 16:55:47 +08:00
    @onion83 是的,如果 ipset + routing mark + 监控脚本自动切路由,那效果可以达到基本一致。最大的坑就是 RoS 6 到现在也不支持 IPv6 的 PBR,所以如果想搞 IPv6 的分流就没辙了。虽然有传言 RoS 7 支持,但是看论坛里报的那个 bug 的数量。。实在是不敢用

    实际上跑 OSPF 除了一开始配置稍微麻烦点,后面更新起来和健康检查什么的都要好做的多。因为都可以在旁路由上实现,路由器上的配置就只有几行,也没有频繁修改配置的风险。

    @noahzh 更新的话,先把 https://github.com/dndx/nchnroutes/blob/main/Makefile 里面最后的几行注释去掉,然后直接在旁路由上用 root 跑了个 cron:

    ```
    0 0 * * 0 make -C /home/pi/nchnroutes
    ```

    然后 BIRD 就会自动把变更了的的 prefix 宣告给 RoS 。
    kennylam777
        21
    kennylam777  
       2020-12-29 16:58:41 +08:00
    好方法,對於正規的路由器用標準協議準沒錯,魔改還是留給樹莓派擔當
    stevefan1999
        22
    stevefan1999  
       2020-12-29 17:23:11 +08:00
    另外如果是 BGP 的 可以嘗試下 gobgp
    dndx
        23
    dndx  
    OP
       2020-12-29 17:45:08 +08:00
    @stevefan1999 要是跑 BGP,@noahzh 提到的的按照源 IP 路由的功能就能基于 BGP FlowSpec 做了,然而 Mikrotik 太懒了,到现在还没有加 FlowSpec 支持。。
    ericbize
        24
    ericbize  
       2020-12-29 18:46:03 +08:00 via iPhone
    @dndx 我都是写好一个文件, 然后在命令行 import 这样不卡啊,8000 条大概一分钟就好了
    ericbize
        25
    ericbize  
       2020-12-29 18:49:36 +08:00 via iPhone
    @ihipop 之前用阿里云 hk 跑满 30m, 广东电信 家宽。iepl 是公司的,成本大概 150/m/月
    ihipop
        26
    ihipop  
       2020-12-29 19:46:28 +08:00 via Android
    @noahzh vrrp➕DHCP 为特定设备分配 vrrp 网关
    noahzh
        27
    noahzh  
       2020-12-29 21:55:41 +08:00
    @ihipop 不同网关,那不同网关之间的互通是怎么搞定的?
    bclerdx
        28
    bclerdx  
       2020-12-30 00:01:53 +08:00
    很好的文章及科普,收藏了。多谢楼主。
    ihipop
        29
    ihipop  
       2020-12-30 08:05:39 +08:00 via Android
    @noahzh vrrp 指向旁路 旁路指向上级
    terrancesiu
        30
    terrancesiu  
       2020-12-30 09:28:40 +08:00
    我的方法,目前运行了半年了。有国内 vds 的朋友都可以照我的搞,没 vds 也可以用树莓派,n1 替代。我目前用的是 n1,放在楼道的 gpon onu 交换机那(我们这 fttb 上下行对等),用自己的第二条宽带账号拨号。
    一、n1 安装了 armbian 后,安装和配置 pppoe 、ddclient 、strongswan 、clash premium 这几个基本服务。非常重要的一点,clash 需要开启 dns 且端口是 53,并用 fakeip 模式,最后做好防火墙白名单,只开放 22 端口。
    二、routeros 通过 ikev2 vpn 拨入 n1,拿到 n1 下发的 ip 后,并和 n1 之间打 gre 隧道。然后互加对方的路由,这样 3 层就通了,最后加入一条策略路由将 198.18.0.0/16 的目的地址都交给 n1 处理。
    三、再 routeros 上做 dns fwd,将需要走 n1 的域名写入 /ip dns static 内,因为可以用正则表达式,基本上常用的流媒体,社交网络、新闻和其他的,我 30 行就解决了。转发地址为 n1 上 clash tun 的地址 198.18.0.1 。
    四、灵活运用 clash 的策略,分流不通区域的流媒体。
    五、至于其他需要依靠 ip 直接通信的应用,比如 tg 就直接将 ip 加入 ros 的策略路由表,然后在 n1 的 iptales 写 redir 到 clash 的 redir 端口。最后做个 dns 劫持,避免 chromecast 走 4 个 8.
    六、如果 n1 和 routeros 之间的 gre 速度很慢,看看 tcp mss,我改成了 1260 才正常。最后建议用 iperf3 打流测,避免瓶颈。如果 ros 的物理设备不支持 aes 解密,那么只能做未加密的 gre 隧道了。
    ttvast
        31
    ttvast  
       2020-12-30 10:06:03 +08:00
    @cwbsw
    我以前用的静态路由表,cpu 是 j1900. 宽带升级 500m 以后,测速老觉得跑不满带宽,后来发现是路由器 cpu 利用率 100%。
    后来改成了 ipset,现在 1000m 宽带,cpu 利用率也不超过 20%。

    主要是因为,ipset 使用 hash 查询, 而路由表匹配不到的话,是逐条查询。
    dndx
        32
    dndx  
    OP
       2020-12-30 14:57:04 +08:00 via iPhone
    @ttvast 这就很奇怪了,实际上 Linux 的内核路由表一开始也是哈希查询,2.6 之后为了优化前缀查询性能才改成了 trie 树。另外只有第一个数据包需要走 trie,后面往同一地址的数据包直接走路由缓存,O(1)。

    https://vincent.bernat.ch/en/blog/2017-performance-progression-ipv4-route-lookup-linux

    因为改成 ipset 也不是个小改动,CPU 100% 很有可能不是路由导致的。可以在 RoS 里跑一下 profiler 看看是什么东西用了 CPU 。

    我在 hEX 上实测的,200M 跑满测速 CPU 最高峰也只用了 10%。平均在 3-7% 之间。
    ixiaoyui
        33
    ixiaoyui  
       2020-12-30 15:11:19 +08:00
    这家用都上 OSPF 了.....
    asdgsdg98
        34
    asdgsdg98  
       2020-12-30 23:46:05 +08:00
    相比于爱快之类的系统,ROS 有什么优势吗,有人说 ROS NAT 性能更好,那为什么不用硬路由 NAT+智能网关解决呢?
    希望有人能解答
    JamesLewisLiu
        35
    JamesLewisLiu  
       2020-12-31 15:06:05 +08:00
    弱弱的问一句 能配合 OpenWRT 使用吗
    dndx
        36
    dndx  
    OP
       2020-12-31 15:24:37 +08:00
    @JamesLewisLiu 当然可以的,如果用 OpenWRT 作为主路由,只要在上面跑 OSPF 协议即可,树莓派这边的配置是一样的。

    因为 OSPF 是常见的标准协议,同理主路由可以为任何支持 OSPF 的系统,OpenWRT,Cisco IOS,JunOS 等等都应该可以。
    DopaminePlz
        37
    DopaminePlz  
       2021-01-02 08:54:23 +08:00 via Android
    楼主在诱惑我折腾家庭网络了,在骗我去学习 ospf
    oovveeaarr
        38
    oovveeaarr  
       2021-01-03 14:43:13 +08:00
    感谢 LZ 分享,LZ 做了我一直想做,但是一直懒得做的事情))
    smileawei
        39
    smileawei  
       2021-01-03 16:44:32 +08:00
    感谢提供思路。我这边用 openVPN 打隧道成功了。
    不过没用 ROS 我设置 ROS 的 mtu 总是设置不到最优,导致用 ROS 卡卡的。直接用 Linux 做了网关。
    jdwinter
        40
    jdwinter  
       2021-01-07 00:05:47 +08:00
    家用网络都上 ospf 了,我们公司还在用腾达
    chinni
        41
    chinni  
       2021-04-08 11:42:17 +08:00
    我 linux 下 bird 配置好了,route 检查也没问题了 但是我 ros 上 设置了 OSPF 后 没有得到 neighbor 。
    网络是 ROS 主路由 MikrotikAC2 做 ap,所有端口都桥一起了。 我 linux 接在 AC2 后 网段是同一个网段。
    请问会是啥问题。。。
    dndx
        42
    dndx  
    OP
       2021-04-08 12:00:44 +08:00
    @chinni 按照文章里的配置建议检查一下 `/routing ospf instance` `/routing ospf interface` `/routing ospf network` 。确保 IP 和 ID 符合实际配置。

    另外可以 `sudo bird show protocols` 看一下 BIRD 的具体状态显示的是什么。
    chinni
        43
    chinni  
       2021-04-08 13:54:33 +08:00
    @dndx
    大佬 我这里的返回贴一下。麻烦帮忙看下 方便的话 可以加我 profile 里的 tg 谢谢
    ```
    birdc show protocols
    BIRD 2.0.8 ready.
    Name Proto Table State Since Info
    kernel1 Kernel master4 up 10:54:51.242
    device1 Device --- up 10:54:51.242
    static1 Static master4 up 10:54:51.242
    ospf1 OSPF master4 up 10:54:51.242 Alone
    ```

    ```
    /routing ospf> instance print
    Flags: X - disabled, * - default
    0 * name="default" router-id=192.168.11.1 distribute-default=never
    redistribute-connected=no redistribute-static=no redistribute-rip=no
    redistribute-bgp=no redistribute-other-ospf=no metric-default=1 metric-connected=20
    metric-static=20 metric-rip=20 metric-bgp=auto metric-other-ospf=auto
    in-filter=ospf-in out-filter=ospf-out

    ```


    ```
    /routing ospf> interface print
    Flags: X - disabled, I - inactive, D - dynamic, P - passive
    # INTERFACE COST PRIORITY NETWORK-TYPE AUTHENTICATION AUTHENTICATION-KEY
    0 br-lan 10 1 broadcast none
    ```

    我这里 bird 里配置也是没有认证的所以这里是 none

    ```
    /routing ospf> network print
    Flags: X - disabled, I - invalid
    # NETWORK AREA
    0 192.168.11.0/24 backbone
    ```
    dndx
        44
    dndx  
    OP
       2021-04-09 15:55:38 +08:00 via iPhone
    BIRD 显示 Alone 说明没有找到邻居。再检查一下接口配置确认是对的。
    adoal
        45
    adoal  
       2021-06-10 00:18:01 +08:00
    ipset 的好处是可以到 dnsmasq 后面,根据 gfw2dnsmasq 转出的遇难域名列表来动态加到要走隧道的清单。当然 dnsmasq+ipset 在 ROS 上就没办法了,要 EdgeRouter 或者 OpenWRT 或者正常的 Linux 发行版。

    当然,从楼主贴的链接里看,楼主更看重的是,哪怕没遇难的外国网段,走隧道也大多比直连快一些。

    但对我等穷人来说,国外流量都走隧道的话,那首先要找又便宜又快又稳定又不会在 3 月 6 月 10 月等特殊时期卡顿的隧道……这是个大难题。国外的机子,不管是什么线路,总是会不可控的卡顿。而 UOVZ 之类的,又死贵。
    dudulangjiao
        46
    dudulangjiao  
       2021-08-31 21:41:16 +08:00
    @dndx 楼主,麻烦问一下,如果旁路由是 openwrt 的,不是树莓派的,可以用这个方案吗?
    dndx
        47
    dndx  
    OP
       2021-08-31 22:15:35 +08:00
    @dudulangjiao 可以,OpenWrt 本质上就是 Linux,BIND 这些肯定都是有包的。
    dudulangjiao
        48
    dudulangjiao  
       2021-09-03 01:09:42 +08:00 via iPhone
    @dndx 谢谢
    xuesumin
        49
    xuesumin  
       2021-09-09 13:54:30 +08:00
    下载了以后 make 即可生成国外 IP 地址的路由表。注意如果树莓派上的隧道连接的是国外的 IP,那么需要从生成的 IP 段里剔除,否则隧道的流量也会被 RouterOS 发给树莓派,形成路由环路。可以参考 README.md 的说明通过 --exclude 选项把这些不应该走隧道的 IP 排除。
    注意如果树莓派上的隧道连接的是国外的 IP ?这句话是啥意思?我旁路由是 openwrt,科学上网是机场,好多节点
    谢谢!
    dndx
        50
    dndx  
    OP
       2021-09-10 23:49:16 +08:00
    @xuesumin 如果你需要连接国外的 IP 来建立隧道,那么必须把这些 IP exclude 掉,这样这些流量不会被发往隧道,不然你的隧道连接会无法建立。
    xuesumin
        51
    xuesumin  
       2021-09-12 11:03:06 +08:00
    @dndx 明白了,谢谢!
    xxb
        52
    xxb  
       2022-04-28 16:14:55 +08:00
    不错,有空试试
    aoxiangtianji
        53
    aoxiangtianji  
       2022-06-07 22:58:09 +08:00 via Android
    @dndx 我是 ROS+openwrt 的配置,openwrt 用 openclash tun 模式建立隧道。有没有可能在 ROS 上设置,使 openwrt 走一个仅有默认路由的空路由表,来让 openclash 再分一遍流? IP 分流表总不是特别准确,而且也能达到节省隧道流量的效果。
    creepersssss
        54
    creepersssss  
       252 天前
    @dndx 希望可以更新一下,将 bird4.conf 的 export all 注释掉,OSPF 宣布机器就不会添加路由表,就可以进行二次分流了
    creepersssss
        55
    creepersssss  
       252 天前
    @xuesumin 将 bird4 的 export all 注释掉后广播机里就不会有路由,OSPF 广播机器放在 ROS 的另一个 passthrough 网段中,就不用 exclude ,也不会回环
    garryforreg420
        56
    garryforreg420  
       233 天前
    更合适的方法是 openwrt 旁路由用 fakeip 模式,域名解析全部交给 openwrt,需要分流的域名会返回 fakeip,在 routeros 上做个路由规则,把 fakeip 段路由回 openwrt,这样 routeros 完全不用搞什么动态路由了,要分流的自动交给 openwrt 上的 openclash 了。
    garryforreg420
        57
    garryforreg420  
       233 天前
    @aoxiangtianji 用 fakeip
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2360 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 27ms · UTC 15:48 · PVG 23:48 · LAX 07:48 · JFK 10:48
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.