因为觉得写 ruleset 太麻烦,研究了一下 GeoSite,发现其实在「正确的配置」下,只靠 GeoSite 就能满足绝大部分的分流需求。这方面的文章好像很少,写一篇分享一下折腾经验。

GeoSite 是啥

GeoSite 也是一组规则列表,很多配置文件中都有用到它,只不过用的不多。

随便找了个例子,下面的 geosite:cn,privateGEOSITE,cn 都是在引用 GeoSite 规则。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
dns:
  nameserver-policy:
    # 此处引用了 geosite 中的 cn 和 private 分组
    "geosite:cn,private":
      - https://223.5.5.5/dns-query

rules:
  # 此处也是引用 geosite 的 cn 和 private 分组
  - GEOSITE,private,DIRECT
  - GEOSITE,cn,DIRECT

和普通的规则集相比,GeoSite 有哪些不同呢?

使用简单

绝大多数工具都内置了对 GeoX 系列的支持,有些工具甚至不用特地引入,默认就给你带上了,直接写就行,就像上面的配置一样。

树形规则

GeoSite 底层是一系列小规则,这些小规则又组成更大的规则,最终汇总到几个大分组上,因此可以通过指定不同的分组来实现灵活的分流。

  graph LR
    cn --> category-games;
    cn --> category-bank;
    category-games --> mihoyo;
    category-games --> tencent-games;
    mihoyo --> mihoyo.com
    mihoyo --> mihoyogift.com

而 ruleset 只有一个层级,只能把它当成一个整体使用。

属性过过滤

GeoSite 支持 @attr 来进一步筛选分组中的规则,灵活程度更上一层楼。

比如 steam@cn 可以过滤出国内直连的 steam 域名。

又比如 jd@!cn 可以过滤出 jd 的国际域名。

GeoSite 规则现状及问题

v2fly/domain-list-community

这是目前 GeoSite 最上游项目,由 v2fly 进行维护。

它的问题在于分组规则很迷惑,很多域名会同时归属两个截然相反的规则(我也说不好算是 bug 还是 feature)。

geolocation-cngeolocation-!cn,从字面意思上看,应该分别是国内和国外域名,但实际上里面有大量重叠域名。

Note

大部分人更常用的是 cn 规则,它由 geolocation-cn 和 tld-cn 组成。我喜欢拆开写,这样看起来整齐一点(

steampowered.com.8686c.com 这个应该直连的域名,同时归属 geolocation-cngeolocation-!cn,一旦你这么写规则,就会因为匹配到 geolocation-!cn 而走代理浪费流量。

1
2
- GEOSITE,geolocation-!cn,PROXY
- GEOSITE,geolocation-cn,DIRECT

那是不是把 geolocation-cn 规则放到前面就行了呢?也不行,tiktok.com 也归属这两个分组,但是它应该走代理,如果先匹配到 geolocation-cn 就会变成直连。

这个看起来无解(其实并不)的问题导致很多人,甚至官方维护者,都建议使用下游规则1

Loyalsoldier/v2ray-rules-dat

这应该是目前使用最广泛的 GeoSite 分支了,其他分支基本上都是在这上面小修小补,它有两大特点:

  1. 修复了原始项目的分组问题,从geolocation-cngeolocation-!cn 剔除了 @!cn@cn 域名,防止冲突。
  2. 引入了大量其他规则作为补充。

相比默认配置的 GeoSite,这个版本绝大多数情况下确实工作得更好,但是,仍然存在一定的问题,而且恰恰也是这两点导致的。

域名分组缺失

首先,剔除掉 @cn@!cn 后,确实不会「误分流」了,但是变成「漏分流」了。因为它们既不在 geolocation-cn 中也不在 geolocation-!cn 中,如果你不用 cn 分组就匹配不到它们,很难说究竟和原版相比哪个更符合直觉。

比如域名 gstore.val.manlaxy.com,既不在 geolocation-cn 也不在 geolocation-!cn,只能用 steam@cn 来引用它 。但问题就在于——我不知道究竟哪些域名是漏网之鱼,总不能把所有 category-x@cn 分类都写一次吧……

过于宽泛的 CN 规则

可能是为了弥补第一点造成的问题,项目额外引入了 dnsmasq-china-list/accelerated-domains.china.conf 补充到了 CN 规则中。

吐槽一下,这个做法导致了 geolocation-cn + tld-cn != cn,也很反直觉,会坑到一些用户

乍一看很好,但实际上 accelerated-domains.china.conf 并不代表能国内直连的域名 ,它的收录标准(之一)是是否有中国 NS 服务器,而不是域名解析结果是否在中国,导致了一些错误的分流结果2

甚至在 dnsmasq-china-list 2023 年的一个 issue 3中,有人使用脚本进行筛选,发现这个列表中有 43% 的域名解析结果都不在中国。虽然不在中国并不意味着不能直连,但肯定是起不到到加速效果的。

仍然存在的冲突分组

继上面的问题,由于 cn 分组中添加了其他规则,又再次导致了某些域名同时出现了两个冲突的分组中。

比如 vscode.download.prss.microsoft.com,既在 geolocation-!cn 分组,也在 cn 分组中,如果没用 microsft@cn 指定它直连,就会走代理浪费流量。

正确用法

流量分流

经过一番研究之后,我认为最好还是使用原版 GeoSite 作为基础,再此基础上再搭配其他规则进行分流。

至于原版规则存在的问题,其实规避起来非常简单。使用 @cn@!cn 属性搭配如下写法,就能避免原版规则中存在的问题,实现正确的分流:

1
2
3
4
5
6
7
8
9
geox-url:
  geosite: "https://testingcf.jsdelivr.net/gh/v2fly/domain-list-community@release/dlc.dat"

rules:
  - GEOSITE,geolocation-!cn@cn,DIRECT # DIRECT 为直连分组,可以改为你自己的分组
  - GEOSITE,geolocation-!cn,PROXY     # PROXY 为代理分组,可以改为你自己的分组
  - GEOSITE,geolocation-cn@!cn,PROXY
  - GEOSITE,geolocation-cn,DIRECT
  - GEOSITE,tld-cn,DIRECT

—— geolocation-!cn 整体是国外网站,只是存在一些国内加速域名,那就先使用 @cn 筛选出这些域名进行直连,剩下的再走代理。如 alibaba.cdn.steampipe.steamcontent.com 之于 steam 分组。

—— geolocation-cn 整体是国内网站,只是存在一些只能在国外访问的域名,那就先使用 @!cn 筛选出这些域名进行代理,剩下的走直连如 jd.hk 之于 jd 分组。

由于 geolocation-!cn@cn 已经包含了诸如 steam@cn 这样的子分组规则,不需要额外设置就可以实现绝大部分域名的正确分流,劣势瞬间变成了优势。但在 Loyalsoldier 分支就无法这么写,因为它不存在 geolocation-cn@!cngeolocation-!cn@cn 分组,必须手动写 steam@cn 这样的子分组名称。

Tips

steam 直连其实还需要额外设置 steamserver.net 为直连,否则 steam 进行测速后还是会从国外 CDN 下载游戏,此时还是会走代理。4

fake-ip-filter

众所周知,fake-ip 模式有个问题,就是域名 ping 不通,这会导致一些程序错误地认为自己没有联网(比如 Windows)。

常见的解法是把 msftconnecttest.com 和 msftncsi.com 加入 fake-ip-filter,但这只解决了 Windows 的问题。

更好的方法是使用 geosite:connectivity-check 分组,这里面包含了安卓、苹果、Windows、华为、KDE、Arch Linux ……的连通性检查域名,一劳永逸。

1
2
3
4
dns:
  fake-ip-filter:
    - 'geosite:connectivity-check'
    - 'geosite:private'

DNS 分流

完美了吗?还没有。除了流量分流以外,DNS 分流也很重要。像 fonts.googleapis.com 这样的域名,虽然没有被墙,但是如果使用国外 DNS 解析,也会造成访问非常缓慢。

如果发现「明明设置了直连,但是反而更慢了?」,大概率就是没有配置 DNS 分流,导致直连的其实是国外 IP。

Clash 中的 DNS 配置策略有挺多的,这里采用最简单的一种:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
dns:
  enable: true
  ipv6: false
  enhanced-mode: fake-ip
  fake-ip-range: 198.18.0.1/16
  fake-ip-filter:
    - 'geosite:connectivity-check'
    - 'geosite:private'
  default-nameserver:
    - 223.5.5.5
  proxy-server-nameserver:
    - 223.5.5.5
  direct-nameserver:
    - https://doh.pub/dns-query
    - https://223.5.5.5/dns-query
    - https://doh.360.cn/dns-query
  nameserver:
    - 'https://8.8.8.8/dns-query#PROXY&ecs=120.76.0.0/14&ecs-override=true'

解释一下这一堆 nameserver 的作用:

default-nameserver

用来解析「DNS 服务器域名」的 DNS,需要直接使用 IP

proxy-server-nameserver

用来解析「代理服务器域名」,防止 nameserver 无法访问导致连不上代理。 比如上个月国外 DoH 大规模被墙,很多 nameserver 设置为国外 DoH,又没有设置 proxy-server-nameserver 的人就连不上代理了(我自己就是)。

direct-nameserver

「直连」域名的解析,这里用了 DoH 来防止劫持。直接用运营商的 DNS 也行,愿意自建 smartdns / adgurad home 等服务效果更好。

nameserver

用来解析没有匹配到任何「域名规则」的域名,通常是国外域名,建议使用国外 DoH 防止污染。但这个解析结果并不会用来发起连接,所以为了追求速度不使用 DoH 或直接使用国内 DNS 也行。

这里我配置得比较复杂:

  • PROXY - 查询时使用的代理接口,如果使用能直连的国外 DoH 也可以省略。
  • ecs=120.76.0.0/14&ecs-override=true - 使用 ECS 来查询,这样可以尽量避免能直连的网站解析出国外 IP。但是需要注意不是所有 DNS 都支持 ECS。

nameserver + direct-nameserver 的解析流程非常清晰,没有弯弯绕——

  flowchart TD
  Rule[匹配规则]
  Domain[匹配到域名规则]
  IP[匹配到目标 IP 规则]

  NameServer[使用 nameserver 查询]
  DirectNS[使用 direct-nameserver 重新解析]

  Proxy[发送域名给代理]
  Direct[使用 IP 直接连接]

  Rule -->  Domain
  Rule --> IP

  Domain -- 域名匹配到直连 --> DirectNS

  IP --> NameServer
  
  NameServer -- IP 匹配到直连 --> DirectNS
  DirectNS --> Direct

  NameServer -- IP 匹配到代理 --> Proxy[发送域名给代理]
  Domain -- 域名匹配到代理 --> Proxy

另一个常用方案 nameserver-policy 也可以达到同样的效果,但 nameserver-policy 的配置比较复杂,没配置好反而会适得其反。

举例来说,很多人在更新 rules 时并不会更新 nameserver-policy。比如发现 download.org 有国内节点,可以直连,于是就写下了:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
rules:
  # 插入了一条新的直连规则
  - DOMAIN,download.org,DIRECT
  - GEOSITE,geolocation-!cn,PROXY
  - GEOSITE,cn,DIRECT

dns:
  nameserver:
    - 8.8.8.8
  nameserver-policy:
    # 但是 nameserver-policy 没有增加这条规则
    'geosite:cn,private':
      - 223.5.5.5

这个写法问题在于一旦 geosite:cn 没有匹配到 download.org,clash 就会使用 nameserver 来解析,结果通常是一个国外 IP,效果适得其反。

相比之下 direct-nameserver 就简单多了,只要是直连规则,一定会使用它来解析,免去手动配置的麻烦。

引入其他规则

Loyalsoldier/v2ray-rules-dat 引入的很多规则确实很强大,比如去广告就比原版分支强多了。幸运的是 Loyalsoldier 提供了 txt 格式的域名集合,可以直接在 Clash 中导入。

例子:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
# 使用锚点简化配置
domain_rule: &domain_rule
  type: http
  behavior: domain
  format: text
  interval: 86400

ruleset:
  reject-list:
    <<: *domain_rule
    url: https://cdn.jsdelivr.net/gh/Loyalsoldier/v2ray-rules-dat@release/reject-list.txt
    path: ./v2ray-rules-dat/reject-list.txt
  china-list:
    <<: *domain_rule
    url: https://cdn.jsdelivr.net/gh/blackmatrix7/ios_rule_script@master/rule/Clash/ChinaMax/ChinaMax_Domain_For_Clash.txt
    path: ./ios_rule_script/ChinaMax_Domain_For_Clash.txt

rules:
  - RULE-SET,reject-list,REJECT
  - RULE-SET,china-list,DIRECT

尽量避免使用 classical 规则

引入第三方规则时,注意尽量不要使用 behavior 为 classical 的规则,理由如下:

1. 性能

ruleset 的 behavior 支持 domain、ipcidr 和 classical 三种。

前两种只能进行域名/IPCIDR的匹配,优化更好;后者则是支持完整语法的 clash 规则,但资源消耗更大。对于大型规则,最好是选用 domain/ipcidr 格式来降低资源占用。

2. 优化 DNS 查询

正常情况下,一个匹配到域名规则的网站应该直接走直连/代理。

但如果在域名规则之前存在不带 no-resolve 的 IP 规则,clash 会立即进行 DNS 查询。这不仅浪费时间,根据不同的配置也可能出现 DNS 泄漏风险甚至分流错误。

这里最大的坑点在于某些 classical 规则里也会有 IP 规则,没注意就可能掉坑里。

杂七杂八

GitHub - snowie2000/geoview: A handy tool to extract information from geosite/geoip

每个人都有不同的需求,因此没有什么规则是完美的。

在研究过程中,我发现 geoview 这个工具非常好用,它在查询域名时可以把属性也列出来,可以有效帮助你制定更细化的分流规则。

比如在 BT 下载时发现 tracker 竟然在走代理,但我希望它直连,于是就可以查询 tracker 域名属于哪个分组

1
2
❯ geoview -type geosite -input /etc/mihomo/GeoSite.dat -action lookup -value tracker.opentrackr.org
CATEGORY-PUBLIC-TRACKER

通过查询结果可以发现 tracker 原来不在 cn!cn 分组中,而是单独的「顶级分组」 category-public-tracker。

我顺便用脚本查询了 GeoSite 中的所有「顶级分组」,可以按需取用确保规则覆盖完全。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
2ch
annas-archive
apple-intelligence
category-ads-all
category-ai-chat-!cn
category-bank-jp
category-httpdns-cn
category-ir
category-number-verification-cn
category-pt
category-public-tracker
category-ru
category-speedtest
cn
connectivity-check
flibusta
geolocation-!cn
meduza
meta-ads
private
speedtest
test
tld-!cn
tld-opennic
tor
x