[Rule] / [Proxy Group] / [Host] 三段的完整语法,外加模块能改的那部分 DNS 设置。
[Rule] 行语法
类型,匹配值,出口
类型,匹配值,出口,选项
FINAL,出口
AND,((类型,值),(类型,值)),出口
RULE-SET,https://example.com/list.txt,出口
字段按逗号切分,每个字段前后的空格会被去掉。第三个字段是出口,它后面的都当作选项。
匹配顺序是从上到下,第一条命中的规则决定出口,后面的不再看。 所以精确规则写在前、宽泛规则写在后。
一行只写一个匹配值,不能写 DOMAIN-SUFFIX,a.com,b.com,PROXY。多个值写多行。
行尾不能写注释,,DIRECT # 说明 会把 DIRECT # 说明 整个当成出口名。注释写在上一行。
规则类型全表
| 类型 | 匹配对象 | 取值写法 | 例子 |
|---|---|---|---|
DOMAIN |
完整域名,精确相等 | 域名,不带协议和路径 | DOMAIN,www.google.com,默认 |
DOMAIN-SUFFIX |
域名后缀 | 不带前导点。google.com 同时命中 google.com 和 a.google.com |
DOMAIN-SUFFIX,google.com,默认 |
DOMAIN-KEYWORD |
域名里含某段字符 | 任意子串 | DOMAIN-KEYWORD,google,默认 |
DOMAIN-REGEX |
域名正则 | RE2 正则,建议加 ^ $ 锚定 |
DOMAIN-REGEX,^.*\.google\.com$,默认 |
DOMAIN-WILDCARD |
域名通配 | * 任意长度,? 单字符 |
DOMAIN-WILDCARD,*.google.com,默认 |
IP-CIDR |
目标 IPv4 网段 | 带掩码,单个 IP 写 /32 |
IP-CIDR,149.154.160.0/20,默认 |
IP-CIDR6 |
目标 IPv6 网段 | 带掩码,单个 IP 写 /128 |
IP-CIDR6,2001:b28:f23d::/48,默认 |
IP6-CIDR |
同 IP-CIDR6 |
||
SRC-IP-CIDR |
来源 IP 网段 | 带掩码 | SRC-IP-CIDR,192.168.1.0/24,DIRECT |
GEOIP |
目标 IP 归属地 | 规则集名,见下文 | GEOIP,cn,DIRECT |
GEOSITE |
域名所属集合 | 规则集名,见下文 | GEOSITE,category-ads-all,REJECT |
DST-PORT |
目标端口 | 单个端口号 | DST-PORT,443,默认 |
PORT |
同 DST-PORT |
||
SRC-PORT |
来源端口 | 单个端口号 | SRC-PORT,1080,DIRECT |
PROCESS-NAME |
发起连接的进程 | 可执行文件名 | PROCESS-NAME,Google Chrome,默认 |
PROTOCOL |
传输层/应用层协议 | 见下表 | PROTOCOL,UDP,REJECT |
补充:
- 域名类的匹配值必须自己写成小写。 客户端只把被匹配到的域名转小写,规则里的值原样使用 —— 写了
DOMAIN-SUFFIX,Google.COM就永远不命中,而且没有任何报错。GEOIP/GEOSITE的名字例外,它们会被自动转小写。 IP-CIDR和IP-CIDR6内部是一回事,写对应的那个只是为了可读。裸 IP 不带掩码也能认,但写全更清楚。- IP 配置不是合法地址或网段时,内核将无法启动,不会只跳过该规则。
DOMAIN-REGEX使用无效正则表达式时也会导致相同结果。 - 端口不支持区间,
DST-PORT,80-443会让整条规则失效。多个端口写多行。 PROCESS-NAME只在 macOS 和 Windows 桌面端生效。手机端没有进程归属能力,写了不会命中。macOS 填.app里的可执行文件名(一个应用常有主程序 + 若干 Helper,都要写),Windows 填chrome.exe这样的文件名。
PROTOCOL 的取值
| 值 | 含义 |
|---|---|
TCP |
TCP 连接 |
UDP |
UDP 连接 |
QUIC |
QUIC / HTTP/3 |
HTTP |
明文 HTTP |
TLS |
TLS 连接 |
HTTPS |
同 TLS |
其它值不认,整条规则被丢弃。
明确不支持的类型
以下类型不受支持。包含这些类型的规则会被忽略,且不会显示错误或提示:
USER-AGENT、URL-REGEX、IP-ASN、DOMAIN-SET、DEST-PORT-RANGE、SUBNET、DEVICE-NAME、SCRIPT、CELLULAR-RADIO、RULE-SET-IP
上表之外的任何类型同样被跳过,同样没有提示。导入界面不会告诉你「有 N 条被跳过」,所以只用规则类型全表里列出的类型。
要按 URL 路径而不是域名来拦截,用 [URL Rewrite] 而不是 URL-REGEX。
选项
第三个字段之后的都是选项。只有 no-resolve 会被识别(大小写不敏感),写在 IP 类规则上表示不要为了匹配它去做 DNS 解析:
IP-CIDR,91.108.4.0/22,默认,no-resolve
其它选项(force-remote-dns、extended-matching、pre-matching 等)被忽略,写了不报错。
FINAL
FINAL,默认
FINAL 指定所有其他规则均未命中时使用的出口,等价于 Clash 风格的 MATCH,默认。配置多条时不会报错,最后一条生效。FINAL,REJECT 以及其他 REJECT 变体会被忽略,默认规则保持不变。
FINAL 会替换客户端的默认规则。只有需要控制所有未匹配流量时才应配置它;仅修改少量域名出口的模块不需要 FINAL。
AND / OR
多个条件组合:
AND,((DOMAIN-SUFFIX,googlevideo.com),(PROTOCOL,UDP)),REJECT
OR,((DOMAIN-SUFFIX,youtube.com),(DOMAIN-SUFFIX,youtu.be)),默认
- 子条件写在双层括号里,每个子条件用一层括号包住,子条件之间用逗号分隔。
- 子条件不包含出口,出口只写在最外层。子条件中多余的第三个字段会被当作选项忽略,且不会显示错误。
- 子条件里可以带
no-resolve。 - 子条件里任何一个类型不被支持,整条规则都会被丢弃(不会退化成部分匹配)。
- 没有
NOT。
RULE-SET
引用一份外部规则列表:
RULE-SET,https://example.com/reject.list,REJECT
- 值必须是
http://或https://开头的完整链接。 - 列表内容是每行
类型,值的纯规则(没有出口列),整份列表统一走这条写的出口。列表里能用的类型比[Rule]少,见 modules.md 的「独立规则列表」。 - 不支持裸名字,
RULE-SET,SYSTEM,DIRECT、RULE-SET,LAN,DIRECT或者引用别处定义的具名 provider 都会被跳过。 - 外部规则集的优先级高于同一模块
[Rule]段里手写的规则。
Loon 风格的 [Remote Rule] 段写法也支持:
[Remote Rule]
https://example.com/reject.list, policy=REJECT, tag=广告, enabled=true
policy 必填;tag 不填时取 policy;enabled 不填按 true。
[Remote Filter]
Loon 风格的具名筛选分组,等价于一个「用正则从全部订阅节点里筛成员」的手动分组:
[Remote Filter]
香港 = NameRegex, FilterKey="(?i)(香港|HK)"
只有 FilterKey 被当成筛选正则;第一个字段(NameRegex / NameKeyword 等)写什么都按同一种处理。自己写模块用 [Proxy Group] 就行,这一段只是为了能直接导入 Loon 的模块。
出口怎么写
规则的第三个字段、以及分组的成员,都是「出口」。解析顺序:
REJECT开头的名字 → 拦截,见下。- 任何已启用模块里
[Proxy Group]定义过的分组名,以及客户端配置里已有的出口名 → 该出口。跨模块有效:A 模块的规则可以指向 B 模块建的分组。 DIRECT(大小写不敏感)→ 直连。- 其他名称 → 使用客户端的「默认」出口。
第 2 条里的「客户端已有的出口名」包括三个内置名,规则里可以直接写:
| 名字 | 含义 |
|---|---|
默认 |
主选择器,也就是用户在节点页里选的那个。等于「走代理」 |
自动选择 |
按延迟自动挑最快的节点 |
直连 |
不走代理,与 DIRECT 等价 |
订阅自带的分组名(节点页里能看到的那些)同样可以直接写。
PROXY 可以使用,但它不是关键字。 PROXY 未被定义时会按第 4 条使用「默认」出口,结果与直接写 默认 相同。其他未定义或拼写错误的分组名也按此规则处理,且不会显示错误。建议直接使用 默认,以明确表达配置含义。
结论:走代理写 默认(写 PROXY 也行,只是配置本身看不出对错),直连写 直连 或 DIRECT;要精确控制走哪个地区,自己在 [Proxy Group] 里建一个分组,再在规则里写这个分组名。
REJECT 家族
| 写法 | 效果 |
|---|---|
REJECT |
断开连接 |
REJECT-NO-DROP |
断开连接,不静默丢弃 |
REJECT-DROP |
静默丢弃,不回任何东西 |
REJECT-200 |
回一个空的 200 |
REJECT-IMG |
回一张 1×1 PNG |
REJECT-TINYGIF |
回一张 1×1 GIF |
REJECT-DICT |
回 200 {} |
REJECT-ARRAY |
回 200 [] |
REJECT-VIDEO |
回一段空 mp4 |
后四种和 REJECT-200、REJECT-IMG、REJECT-TINYGIF 属于内容型拦截:要伪造一个 HTTP 响应,必须开着 HTTPS 解密,而且规则本身必须是 DOMAIN / DOMAIN-SUFFIX / DOMAIN-KEYWORD 三种之一。
不满足条件时(未启用解密,或者规则类型为 GEOSITE / IP-CIDR / DOMAIN-REGEX / PROCESS-NAME / AND 等),会按普通 REJECT 处理。目标仍会被拦截,但结果从返回模拟响应变为断开连接。应用可能表现为空白页面或连接错误。
REJECT、REJECT-IMG、REJECT-TINYGIF、REJECT-DICT、REJECT-ARRAY、REJECT-VIDEO 可以带 -NO-DROP 后缀。除此之外的 REJECT-* 变体(包括 REJECT-200-NO-DROP)不受支持,并按普通 REJECT 处理。不确定时请使用不带后缀的形式。
[Rule]段的-NO-DROP规则和[URL Rewrite]段的-no-drop规则不一样,后者见 mitm.md。
[Proxy Group]
分组名 = 类型, 成员1, 成员2, key=value, ...
分组类型
| 写法 | 行为 |
|---|---|
select / static |
手动选,用户在客户端里点 |
url-test / url-latency-benchmark |
定时测速,自动用最快的 |
fallback / available |
按顺序取第一个可用的 |
load-balance / round-robin / balance |
在成员间轮流分配 |
无法识别的类型会使整行配置被忽略,包括 ssid、subnet 等类型。
参数
| key | 作用 |
|---|---|
url |
测速用的探测地址。只对 url-test / fallback / load-balance 有意义 |
interval |
测速间隔,秒。常用 300 |
policy-regex-filter |
用正则从全部订阅节点里筛成员。别名:filter、include-regex、FilterKey |
exclude-regex |
从筛出来的结果里再排除掉匹配的 |
hidden |
写 hidden 或 hidden=1,这个分组不在客户端列表里显示 |
其它 key(tolerance、no-alert、include-all、timeout 等)被忽略,写了不报错。
只要写了 policy-regex-filter 或 exclude-regex,分组就自动包含全部订阅节点,不需要手写成员名。这是推荐写法:节点名变了不用改模块。
正则筛选和手写成员可以混用,例如在 url-test 分组外增加一个 fallback 分组。
例子
[Proxy Group]
香港 = url-test, policy-regex-filter=(?i)(香港|hong ?kong|HK|🇭🇰), url=http://www.gstatic.com/generate_204, interval=300
新加坡 = url-test, policy-regex-filter=(?i)(新加坡|singapore|SG|🇸🇬), exclude-regex=(?i)(试用|过期), url=http://www.gstatic.com/generate_204, interval=300
流媒体 = select, 香港, 新加坡, DIRECT
香港兜底 = fallback, 香港, 默认, url=http://www.gstatic.com/generate_204, interval=300, hidden=1
流媒体 这类手动分组的成员可以是其他分组名、DIRECT、客户端内置出口名或具体节点名。hidden=1 可隐藏仅供其他分组引用的内部分组。
正则的限制
分组筛选用的正则是 RE2,和 JavaScript 的正则不一样:
- 不支持环视:
(?=...)、(?!...)、(?<=...)、(?<!...)全部不行。 - 不支持反向引用:
\1、\2不行。 - 支持行首
(?i)表示忽略大小写。 - 支持
|分支、{2,3}量词、字符类、\d\w\s等常用写法。
使用不受支持的语法会导致内核无法启动,通常表现为节点列表为空且无法连接。这是节点列表突然为空的常见原因。需要排除节点时应使用 exclude-regex,不要使用环视。
引号
分组定义的尾部按逗号切分,但双引号里的逗号不切。所以正则里带 {2,3} 这类量词时,整个值要加引号:
测试 = url-test, policy-regex-filter="(?i)节点[0-9]{2,3}", interval=300
命名禁忌
分组名不能与已有出口重名。 发生重名时,新分组会被忽略且不会显示错误;规则仍指向原有同名出口。内核可正常运行,但新分组不会出现。
请勿使用:默认、自动选择、直连、订阅自带分组名,以及其他已启用模块定义的分组名。重复安装同一模块时,后一份同名分组也会被忽略,但不会影响内核启动。
另外两类名称会改变解析结果:
- 分组名以
REJECT开头(REJECT广告之类):出口解析第 1 步就把它当成拦截策略,这个分组永远解析不到。 - 分组名叫
DIRECT:出口解析第 2 步早于第 3 步,于是所有写DIRECT的规则都指向这个分组,而不是真直连。
成员的处理
- 成员里的
REJECT会被丢掉(分组不能选「拦截」)。 - 成员里的
DIRECT变成直连。 - 无法识别的成员名使用「默认」出口;多个无法识别的成员会合并为同一项。因此建议使用正则筛选,避免依赖未经验证的成员名。
- 分组不能为空。 未配置成员或正则筛选(
我的组 = select),或者所有成员均被忽略(广告 = select, REJECT),都会导致内核无法启动。
[Host]
域名的解析方式,优先于客户端自己的 DNS 规则。两种写法:
[Host]
# 1. 静态映射:直接回这个 IP,不问任何 DNS
example.com = 1.2.3.4
internal.corp = 10.0.0.5
dual.example.com = 1.2.3.4, 2001:db8::1
*.lab.example.com = 10.0.0.9
# 2. 指定解析器:仍然去查,只是换一台 DNS 问
*.corp.example.com = server:10.0.0.53
*.intranet.example.net = server:10.0.0.53
静态映射的值只能是 IP 字面量。一行可以写多个,逗号分隔,IPv4 / IPv6 混写。
*.x.com匹配任意子域。同一行两种混写时,静态映射优先,
server:部分忽略。指定解析器的地址也只能是 IP(可带端口
10.0.0.53:5353,可写tls://https://quic://前缀),或者server:system表示交给系统解析器。 写域名的话这条被丢掉。走这台 DNS 的域名不会被分配虚拟 IP,拿到的是真实应答 —— 内网域名解析出内网地址, 直接可用。
用它指到的 DNS 一律直连访问,不经过节点。
保留值
server:fakeip(也可写fake-ip)会为指定域名分配虚拟 IP,不在本地执行真实 解析,并由[Rule]决定出口。客户端内置规则会将部分域名判定为直连。如需让其中某个 域名使用代理出口,必须同时配置[Host]和[Rule]。仅配置[Rule]时,DNS 可能 已返回中国大陆的真实 IP,随后流量仍会经代理连接该地址,产生不必要的额外路径:[Host] weather-map2.apple.com = server:fakeip [Rule] DOMAIN,weather-map2.apple.com,PROXY它不产生任何 DNS 查询(虚拟 IP 是本地生成的),真正的解析发生在出站一侧。
DNS
[General] 的 dns-server
模块可以改直连域名用哪台 DNS 去解析 —— 换成公司 / 校园内网的解析器,内网的 split-horizon 域名才解析得对。
[General]
dns-server = 10.0.0.53, system
- 此处配置的解析器排在客户端原有解析顺序的最前面。查询失败时会继续使用原有解析器, 因此切换网络后仍可继续解析。
- 地址规则同
[Host]的server::只收 IP(可带端口和tls://https://前缀) 或system。 [General]段只认dns-server这一个键,其余键(代理端口、绕过列表、日志级别……) 照旧忽略。
不受模块控制的部分
节点和入口域名的解析不受模块影响,始终使用客户端内置的解析路径。以上配置只作用于 用户访问的目标域名。其他 DNS 行为,包括缓存、虚拟 IP 模式和区域分流判定,也由客户端控制。
其它格式的等价写法
从 Clash / Stash(.stoverride)或 Quantumult X(.snippet)导入时,下面这些字段
会被读取,语义与上面两节相同:
| 来源字段 | 等价于 |
|---|---|
dns.nameserver-policy |
[Host] 的 server: 写法 |
dns.direct-nameserver |
[General] dns-server |
dns.fake-ip-filter / fake-ip-filter+ |
这批域名不分配虚拟 IP,拿真实应答 |
dns.nameserver-policy 的值写 fakeip |
[Host] 的 server:fakeip,强制分配虚拟 IP |
QX [dns] 的 server=/域名/IP |
[Host] 的 server: 写法 |
QX [dns] 的 server=IP |
[General] dns-server |
dns: 段里的其它键(enhanced-mode、respect-rules、nameserver、fallback 等)
一律忽略。域名模式支持 +.a.com、*.a.com、.a.com、a.com 四种写法;
裸通配(单独一个 * 或 +.)不接受,那等于把所有解析都交出去;通配只能在开头,
+.stun.*.* 或 a.*.com 这种中间带星的也不接受 —— 匹配的是字面后缀,星号在中间会被
当成一个真的星号字符去比,规则永远不命中。
写法不被接受的 DNS 设置(域名模式表达不了、解析器地址写成了域名、[Host] 那行一个 IP
都没有)会在导入时提示,模块详情页的「需注意的规则」里也能逐条看到。模块其余部分照常生效,
但这几条一次都不会生效。
GeoIP / GeoSite
GEOIP,cn 和 GEOSITE,google 会转成对公开规则集目录的引用:
https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/refs/heads/sing/geo/geoip/<名字>.srs
https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/refs/heads/sing/geo/geosite/<名字>.srs
名字会被转成小写。带属性的写法(google@cn)和带否定的写法(geolocation-!cn)也是目录里的文件名,直接写即可。
常用的 GeoSite 名字:cn、google、youtube、netflix、telegram、openai、apple、microsoft、category-ads-all、geolocation-!cn。
常用的 GeoIP 名字:cn、private、telegram、google、netflix、cloudflare。
要用别的名字,先去上面那个目录确认文件存在。
名字写错不会报错
规则集在运行时下载。名称错误会导致下载返回 404,相应规则不会命中;内核仍会正常运行,且不会显示配置错误。可通过模块详情页的规则数量确认下载结果。
客户端会在导入模块时检查每个 geo 名称是否存在,无法确认的名称会显示提示。出现提示时应更正名称。
模块详情页会显示每个规则集下载的规则数量;显示 0 条表示下载未成功。