Ryo_ 发表于 2022-8-22 13:16

基于路由协议的ip分流(RouterOS为例)

我的例子里做到的效果是(本文以分流中国大陆IP/非中国大陆IP为例)
1. 正常状态: ip分流,DNS无污染,中国大陆直连出去,除了少量特殊配置比如icloud啥的强制直连,剩下的走隧道
2. 异常状态: 自动切换到全部直连,DNS有污染
3. 故障恢复: 自动恢复到正常状态

实际上通过多个tun设备分别连接不同的隧道出口+细化的路由表,是可以做到更细粒度的控制的
比如亚太方向流量走HK的隧道,美洲方向流量走LA隧道,欧洲走荷兰隧道等等
如有需要请自行研究,大体框架和下面的是一样的

这个和基于L7或者Address Lists分流方案的主要区别有两点
1. 性能: 通过路由器最擅长的路由来处理,因为直接网段/接口隔离不需要使用mangle来给流量打标,且不使用L7识别,不需要破坏硬件加速转发特性
2. 故障波及范围小: 假设隧道故障,大陆IP不受影响,且未被墙的非大陆IP会在短时间后快速变为直连状态(尽管也可以通过script处理,但是如果你体验过大批量导入/删除Address Lists的卡卡卡卡卡,我猜你是不会这么选的)

前提,你要收一份对应的路由表
方法1. 参考BakaCai的博客《在家也要玩BGP 之 Mikrotik Fan Boy版》自己收全表过滤出来
方法2. 利用nchnroutes项目跑一份出来
方法3. 直接拿别人跑好的,比如我用GitHub action定时跑的这个项目
方法4. 其他现成的地址段配置转换

接下来需要一台支持路由协议(BGP/OSPF等)的主路由,和一台可以运行clash等隧道+bird的隧道端点机(openwrt或者debian等常见linux发行版都可以)
我这边的环境如下

设备及系统版本
- 主路由MikroTik AC^2(ros 6.48.6 lt)
- 隧道端点NUC5(debian 11.3)

网段
- PC/WLAN等需要透明网关的(lan桥): 192.168.1.0/24
- 直通(ether5): 192.168.255.0/24

这边把ether5这个口踢出lan桥,单独给分配192.168.255.1/24,lan桥分配192.168.1.1/24
端点机分配192.168.255.254/24
路由配置打通两个网段

/ip route
add distance=1 gateway=pppoe-out routing-mark=bypass
add distance=1 dst-address=10.0.0.0/8 gateway=lan routing-mark=bypass
add distance=1 dst-address=169.254.0.0/16 gateway=lan routing-mark=bypass
add distance=1 dst-address=172.16.0.0/12 gateway=lan routing-mark=bypass
add distance=1 dst-address=192.168.0.0/16 gateway=lan routing-mark=bypass
add distance=1 dst-address=224.0.0.0/4 gateway=lan routing-mark=bypass
add distance=1 dst-address=255.255.255.255/32 gateway=lan routing-mark=bypass
/ip route rule
add interface=lan table=main
add interface=ether5 table=bypass

两边互ping一下确认是否ok(windows防火墙可能会拦截icmp)

接下来给lan配一个dns劫持,还有dns自动切换

/ip firewall nat
add action=dst-nat chain=dstnat comment="Hijacking for DNS" dst-port=53 protocol=udp src-address=192.168.1.0/24 to-addresses=192.168.1.1 to-ports=53
/system script
add dont-require-permissions=yes name=use-default-dns owner=admin policy=ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="/ip dns set allow-remote-requests=yes servers=119.29.29.29,223.5.5.5 \r\n/ip dns cache flush"
add dont-require-permissions=yes name=use-sgw-dns owner=admin policy=ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="/ip dns set allow-remote-requests=yes servers=192.168.255.254\r\n/ip dns cache flush"

注意netwatch要在隧道端点的dns服务启动后再加(比如这个例子里的clash),或者添加后先disable,最后再回来enable,不然就半断网了(解析不了dns)
/tool netwatch
add down-script=use-default-dns host=192.168.255.254 interval=5s up-script=use-sgw-dns


接下来是路由协议的配置,我之前使用7.x版本的ros+ospf,不是很稳定,时不时有一些小毛病,这里就回退到6.x的LT版本上用bgp来跑,截至目前没有发现不正常的地方
不管是BGP还是OSPF在这个场景上作用都是一样的,就是把端点机上宣过来的路由加到main表里,如果使用OSPF需要在防火墙放行ospf协议和组播(或者使用点对点模式),bgp的话有上面的路由规则就可以了

/routing bgp instance
set default router-id=192.168.255.1
/routing bgp peer
add multihop=yes name=sgw remote-address=192.168.255.254 remote-as=65531


然后是debian的配置
软件选择bird2来跑路由协议,clash premium跑隧道(自带tun和dns,可以省下tun2socks和smartdns)

替换你的clash订阅地址,按需修改external-controller/external-ui
/etc/clash/config.yaml
dns:
enable: true
ipv6: true
listen: 0.0.0.0:53
enhanced-mode: redir-host
use-hosts: true
default-nameserver:
    - 119.29.29.29
    - 223.5.5.5
nameserver:
    - 119.29.29.29
    - 223.5.5.5
fallback:
    - https://dns.google/dns-query
    - https://cloudflare-dns.com/dns-query
    - https://1.1.1.1/dns-query
    - https://8.8.8.8/dns-query
    - https://8.8.4.4/dns-query
fallback-filter:
    geoip: true
    ipcidr:
      - 240.0.0.0/4
tun:
    enable: true
    stack: system
    auto-detect-interface: true
port: 7890
socks-port: 7891
redir-port: 7893
allow-lan: true
mode: Rule
log-level: silent
external-controller: '0.0.0.0:8080'

proxy-groups:
- name: PROXY
    type: select
    use:
      - subscribe

proxy-providers:
subscribe:
    type: http
    url: 替换成你的clash订阅地址
    interval: 86400
    path: ./proxy/subscribe.yaml
    health-check:
      enable: false
      interval: 600
      # lazy: true
      url: http://www.gstatic.com/generate_204

rule-providers:
icloud:
    type: http
    behavior: domain
    url: "https://cdn.jsdelivr.net/gh/Loyalsoldier/clash-rules@release/icloud.txt"
    path: ./ruleset/icloud.yaml
    interval: 86400

apple:
    type: http
    behavior: domain
    url: "https://cdn.jsdelivr.net/gh/Loyalsoldier/clash-rules@release/apple.txt"
    path: ./ruleset/apple.yaml
    interval: 86400

google:
    type: http
    behavior: domain
    url: "https://cdn.jsdelivr.net/gh/Loyalsoldier/clash-rules@release/google.txt"
    path: ./ruleset/google.yaml
    interval: 86400

proxy:
    type: http
    behavior: domain
    url: "https://cdn.jsdelivr.net/gh/Loyalsoldier/clash-rules@release/proxy.txt"
    path: ./ruleset/proxy.yaml
    interval: 86400

direct:
    type: http
    behavior: domain
    url: "https://cdn.jsdelivr.net/gh/Loyalsoldier/clash-rules@release/direct.txt"
    path: ./ruleset/direct.yaml
    interval: 86400

private:
    type: http
    behavior: domain
    url: "https://cdn.jsdelivr.net/gh/Loyalsoldier/clash-rules@release/private.txt"
    path: ./ruleset/private.yaml
    interval: 86400

telegramcidr:
    type: http
    behavior: ipcidr
    url: "https://cdn.jsdelivr.net/gh/Loyalsoldier/clash-rules@release/telegramcidr.txt"
    path: ./ruleset/telegramcidr.yaml
    interval: 86400

cncidr:
    type: http
    behavior: ipcidr
    url: "https://cdn.jsdelivr.net/gh/Loyalsoldier/clash-rules@release/cncidr.txt"
    path: ./ruleset/cncidr.yaml
    interval: 86400

lancidr:
    type: http
    behavior: ipcidr
    url: "https://cdn.jsdelivr.net/gh/Loyalsoldier/clash-rules@release/lancidr.txt"
    path: ./ruleset/lancidr.yaml
    interval: 86400

applications:
    type: http
    behavior: classical
    url: "https://cdn.jsdelivr.net/gh/Loyalsoldier/clash-rules@release/applications.txt"
    path: ./ruleset/applications.yaml
    interval: 86400

rules:
- PROCESS-NAME,clash,DIRECT
- RULE-SET,applications,DIRECT
- RULE-SET,private,DIRECT
- RULE-SET,icloud,DIRECT
- RULE-SET,apple,DIRECT
- RULE-SET,google,DIRECT
- RULE-SET,proxy,PROXY
- RULE-SET,direct,DIRECT
- RULE-SET,lancidr,DIRECT
- RULE-SET,cncidr,DIRECT
- RULE-SET,telegramcidr,PROXY
- GEOIP,LAN,DIRECT
- GEOIP,CN,DIRECT
- MATCH,PROXY

最好用yacd之类接进去确认一下GLOBAL是不是direct
如果有smartdns或者dnsmasq会变得很麻烦,需要解决端口冲突问题改成解析链,再加上对应的PROCESS-NAME DIRECT规则,总之不建议开这些

/etc/bird/bird.conf
log syslog all;

router id 192.168.255.254;

protocol device {
      scan time 60;
}

protocol kernel {
      ipv4 {
            import none;
            export all;
      };
}

protocol static {
      ipv4;
      include "routes4.conf";
}

protocol bgp {
      local as 65531;
      neighbor 192.168.255.1 as 65530;
      source address 192.168.255.254;
      ipv4 {
                import none;
                export all;
      };
}

crontab添加2条定时刷新路由

0 2 * * * curl -s https://api.xn--7ovq92diups1e.com/ncr?device=utun -o /etc/bird/routes4.conf
0 3 */1 * * /etc/init.d/bird reload

手动执行一次初始化

curl -s https://api.xn--7ovq92diups1e.com/ncr?device=utun -o /etc/bird/routes4.conf

就可以启动clash和bird2的服务了(以及使能前面的netwatch)

再加一个健康检查脚本,访问Google异常并且重试失败后关闭bird和icmp响应,触发ros自动切换

/root/check.sh
#!/usr/bin/bash
COUNT=0
MAX_COUNT=3
while [ $COUNT -lt $MAX_COUNT ]
do
      SER=0
      NET=0
      if [ $(curl --connect-timeout 5 --interface utun -w "%{http_code}" -s https://www.google.com/generate_204) -eq 204 ];then
                NET=1
      fi
      if /etc/init.d/bird status|grep Active|grep -q running;then
                SER=1
      fi
      if [ $NET -eq 1 ] && [ $SER -eq 0 ];then
                /etc/init.d/bird start
                echo 0 >/proc/sys/net/ipv4/icmp_echo_ignore_all
                exit 0
      fi
      if [ $NET -eq 0 ] && [ $SER -eq 1 ];then
                let COUNT+=1
                if [ $COUNT -eq $MAX_COUNT ];then
                        /etc/init.d/bird stop
                        echo 1 >/proc/sys/net/ipv4/icmp_echo_ignore_all
                fi
                continue
      fi
      exit 0
done

crontab添加规则

* * * * * /root/check.sh

测试一下

可见访问国外ip和国内ip已经不一样了,分流完成

老饭 发表于 2022-8-22 13:46

还是mangle灵活一点,可以指定端口爬梯,这样只翻80443 953之类的,不用担心bt和游戏之类的流量乱跑

blanksign 发表于 2022-8-22 13:51

有哭的时候。

多崎作 发表于 2022-8-22 14:42

最近也想研究下,先mark

Ryo_ 发表于 2022-8-22 14:46

老饭 发表于 2022-8-22 13:46
还是mangle灵活一点,可以指定端口爬梯,这样只翻80443 953之类的,不用担心bt和游戏之类的流量乱跑 ...

主要是mangle开了之后NAT的硬件加速就寄了,端口规则可以加到clash里,只对特定DST-PORT,其他direct就可以了

Darcychiu 发表于 2022-8-22 14:47

不推荐用nchnroutes,用ASN分流

Ryo_ 发表于 2022-8-22 14:54

Darcychiu 发表于 2022-8-22 14:47
不推荐用nchnroutes,用ASN分流

有条件自己收表ASN过滤肯定是最稳的,但是其他论坛看其实还有不少人是一周一更新的状态....
nchnroutes起码不至于滞后这么多

xenosccc 发表于 2022-8-22 14:57

mark下。学习下。

老饭 发表于 2022-8-22 16:00

Ryo_ 发表于 2022-8-22 14:46
主要是mangle开了之后NAT的硬件加速就寄了,端口规则可以加到clash里,只对特定DST-PORT,其他direct就可以 ...

我是CHR,没有nat硬件加速[傻笑]

XHY 发表于 2022-8-22 17:45

不懂搞成这样的意义,尤其是用了Clash的情况下

Ryo_ 发表于 2022-8-22 19:03

XHY 发表于 2022-8-22 17:45
不懂搞成这样的意义,尤其是用了Clash的情况下

你要是不嫌吵,主路直接用一台Juniper SRX的防火墙(比如比较入门便宜的240),可以配出来和这个一样的组网
这种组网下网络的稳定性可靠性可以做的很高,隧道炸了影响也小

xenosccc 发表于 2022-9-1 22:59

本帖最后由 xenosccc 于 2022-9-2 14:34 编辑

小白请教下“proxy-groups:
- name: PROXY
    type: select
    use:
      - subscribe

proxy-providers:
subscribe:
    type: http
    url: 替换成你的clash订阅地址
    interval: 86400
    path: ./proxy/subscribe.yaml
    health-check:
      enable: false
      interval: 600
      # lazy: true
      url: http://www.gstatic.com/generate_204”

aitkots 发表于 2022-9-2 10:05

[傻笑] 高手高手

leviz 发表于 2022-9-2 11:03

学习下ros的ip分流方法,收藏

Ryo_ 发表于 2022-9-2 14:12

xenosccc 发表于 2022-9-1 22:59
小白请教下“proxy-groups:
- name: PROXY
    type: select


订阅 就是yaml的链接,顺便最近最好别在CHH讨论这个...你看下版头锁定贴

xenosccc 发表于 2022-9-2 14:35

本帖最后由 xenosccc 于 2022-9-2 15:03 编辑

Ryo_ 发表于 2022-9-2 14:12
订阅 就是yaml的链接,顺便最近最好别在CHH讨论这个...你看下版头锁定贴

已编辑了。[生病]

sanquans 发表于 2022-9-5 13:49

来学习 不知道如何是好 各种分流都折腾过了 各种问题 后来改用option来指定网关和dns了

tunluan 发表于 2022-9-5 15:22

Darcychiu 发表于 2022-8-22 14:47
不推荐用nchnroutes,用ASN分流

如果没有喂到嘴里的教程,可能需要考完ccnp才能折腾吧~

Ryo_ 发表于 2022-9-5 15:56

tunluan 发表于 2022-9-5 15:22
如果没有喂到嘴里的教程,可能需要考完ccnp才能折腾吧~

其实细化ASN分流如果把隧道端点换成ISP接入点, 不就是 IDC 机房 BGP 多线接入那套东西吗[偷笑]

guitengyue 发表于 2022-9-17 14:24

我那个ospf,还没搞定apple系列的问题
具体表现为:
1. appstore有时候进不去
2. homekit 在外面无法使用

dns用的smartdns,默认配置。。。。不知掉咋设置

guitengyue 发表于 2022-9-17 15:15

我这边就是死活无法放行openwrt的流量
openwrt也是单独和ros另外一个网卡连的
添加了bypass放行的表,但是就是出不去,一直进入死循

guitengyue 发表于 2022-9-17 15:43

本帖最后由 guitengyue 于 2022-9-17 15:49 编辑

/ip route
add distance=1 gateway=pppoe-out routing-mark=bypass
我这条一加,整个系统就不能fq了
而且这条应该是这样的吧?dst-address必须要添加?
add distance=1 dst-address=0.0.0.0/0 gateway=pppoe-out routing-mark=bypass

Ryo_ 发表于 2022-9-18 23:08

guitengyue 发表于 2022-9-17 15:43
/ip route
add distance=1 gateway=pppoe-out routing-mark=bypass
我这条一加,整个系统就不能fq了


完整展开应该是
add disabled=no distance=1 dst-address=0.0.0.0/0 gateway=pppoe-out pref-src=0.0.0.0 routing-table=bypass scope=30 suppress-hw-offload=no target-scope=10

正常不写应该也会自动给你加的

guitengyue 发表于 2022-9-18 23:11

Ryo_ 发表于 2022-9-18 23:08
完整展开应该是
add disabled=no distance=1 dst-address=0.0.0.0/0 gateway=pppoe-out pref-src=0.0.0.0 ...

嗯,就是这样的,加了就直接不行了,你博客里面也留言了,搞不定
今天整回去用了ip分流方案

Ryo_ 发表于 2022-9-18 23:58

guitengyue 发表于 2022-9-18 23:11
嗯,就是这样的,加了就直接不行了,你博客里面也留言了,搞不定
今天整回去用了ip分流方案 ...

建议尝试一下通过socks5接clash能不能正常访问,确认下是clash出去的方向有问题还是main表收到的路由有问题,如果ospf在ros报错可能是组播的毛病,可以试着把ospf换成点对点模式或者直接bgp来跑

guitengyue 发表于 2022-9-19 21:13

Ryo_ 发表于 2022-9-18 23:58
建议尝试一下通过socks5接clash能不能正常访问,确认下是clash出去的方向有问题还是main表收到的路由有问 ...

我用的是ros+openwrt(bird+passwall)
clash没用过,用你博客教程照抄后,ubuntu中的bird运行后提示这个,ospf1: Bad HELLO packet from nbr 192.168.1.1 on ens192 - prefix length mismatch (23)
弄不下去了。。。牺牲0.1s的体验算了,还是用回ip分流了[睡觉]

spiral 发表于 2022-9-28 01:49

Mark,我先在虚拟机里模拟部署一遍再上真机。

chengwanyu 发表于 2022-10-13 17:33

请问下,pt网站怎么处理,都是国外ip,还都是变化的?

Ryo_ 发表于 2022-10-21 16:10

chengwanyu 发表于 2022-10-13 17:33
请问下,pt网站怎么处理,都是国外ip,还都是变化的?

我目前是对特定端口进来的流量直接走另一个路由表放行出去,然后把下载机之类的挂在这个端口下
这么别扭的做法主要是为了保留ROS的NAT加速,如果不是因为这个的话直接在mangle表按照原地址打route marking就可以了

chengwanyu 发表于 2022-10-21 21:30

直接在mangle表按照原地址打route marking就可以了这个求解 怎么做的,,不太懂
页: [1] 2
查看完整版本: 基于路由协议的ip分流(RouterOS为例)