规则类型
通过编写规则,您可以指定不同连接的出站方式,例如通过某个代理转发或拦截。规则可以根据连接的 IP、域名、进程名或组合多个条件进行匹配。
对于每一条连接,系统会按照从上到下的顺序依次匹配规则。
规则可以分为以下几种类型(其中 IP 类型可能会触发 DNS 解析):
- 基于域名
- 基于 IP 或端口
- 基于协议
- 逻辑规则
- 其他复合类型
如需针对 URL 编写规则,请参阅 HTTP 重写 章节。
在规则末尾可添加 no-track 参数来隐藏匹配到此规则的连接,例如
SCRIPT,quic,REJECT,no-track。这能有效避免大量 REJECT 记录充斥页面。
可使用 REJECT 和 REJECT-DROP 这两个内置代理来拦截连接。REJECT
会立即返回错误,而 REJECT-DROP 会静默丢弃连接,以避免产生连接风暴。
DOMAIN
完全匹配域名,例如 DOMAIN,google.com 匹配 google.com,但不匹配 www.google.com。
DOMAIN-SUFFIX
匹配域名后缀,例如 DOMAIN-SUFFIX,google.com 匹配 google.com 和 www.google.com。
DOMAIN-KEYWORD
关键词匹配域名,例如 DOMAIN-KEYWORD,google 匹配 google.com 和 google.jp。
DOMAIN-WILDCARD
使用通配符匹配域名,支持 * 和 ?,例如 DOMAIN-WILDCARD,*.google.com 匹配 www.google.com 和 mail.google.com。
其中 * 匹配任意数量的字符,? 匹配一个字符。
DOMAIN-REGEX
使用正则表达式匹配域名,例如 DOMAIN-REGEX,^.*\.google\.com$ 匹配 www.google.com 和 mail.google.com。
GEOIP
通过 MaxMind GeoIP 匹配国家代码,例如 GEOIP,CN。可添加 no-resolve 以避免触发 DNS 解析。
UNKNOWN
iOS/tvOS3.6+macOS4.3+GEOIP,UNKNOWN 匹配在 GeoIP 国家库中没有对应国家条目的目标 IP,例如 GEOIP,UNKNOWN,Proxy。UNKNOWN 大小写不敏感,既可用于单条规则,也可作为 classical 类型规则集中的规则。
私有网络地址在 MaxMind 数据库中没有对应条目,因此会被 GEOIP,UNKNOWN
命中。如需单独处理内网流量,请将 GEOIP,LAN
写在其之前。数据库未加载或加载失败时,GEOIP,UNKNOWN 不会匹配。
Stash 允许用户替换符合 MaxMind GeoIP 格式的数据库。用户可根据自身需求选择更适合的 MaxMind GeoIP 数据库。
IP-ASN
通过 IP 自治系统编号匹配,例如 IP-ASN,714。可添加 no-resolve 以避免触发 DNS 解析。
UNKNOWN
iOS/tvOS3.6+macOS4.3+IP-ASN,UNKNOWN 匹配在 ASN 库中没有对应自治系统条目的目标 IP,例如 IP-ASN,UNKNOWN,Proxy。UNKNOWN 大小写不敏感,既可用于单条规则,也可作为 classical 类型规则集中的规则。
私有网络地址在 MaxMind 数据库中没有对应条目,因此会被 IP-ASN,UNKNOWN
命中。如需单独处理内网流量,请将 GEOIP,LAN
写在其之前。数据库未加载或加载失败时,IP-ASN,UNKNOWN 不会匹配。
IP-CIDR / IP-CIDR6
IP CIDR 范围匹配,例如 IP-CIDR,192.168.1.0/24。可添加 no-resolve 以避免触发 DNS 解析。
NETWORK
匹配网络类型,例如 tcp 匹配 TCP 协议,udp 匹配 UDP 协议。
PROTOCOL
PROTOCOL 规则比 NETWORK 规则提供更细粒度的判断。支持的协议包括:
TCPUDPHTTPTLSQUICSTUNMTPROTO
PROTOCOL,MTPROTO 匹配由内置 MTProto 代理服务器接入的 Telegram 连接。BetaiOS/tvOS3.7+macOS4.4+
DST-PORT
目标端口匹配,例如 DST-PORT,80。
SRC-IP
BetaiOS/tvOS3.7+macOS4.4+按连接的来源地址匹配,可以写单个地址或 CIDR 网段,IPv4 与 IPv6 均支持,例如 SRC-IP,192.168.1.110,DIRECT 或 SRC-IP,192.168.1.0/24,Proxy。
来源地址是接入 Stash 的客户端地址,因此这条规则在为局域网设备提供代理、网关模式或个人热点等多台设备共用一个 Stash 的场景下最有用,可以为不同设备指定不同出站。
rules:
- SRC-IP,192.168.1.20,DIRECT # 电视直连
- SRC-IP,192.168.1.0/24,Proxy # 其余局域网设备走代理
- MATCH,DIRECTSRC-PORT
BetaiOS/tvOS3.7+macOS4.4+按连接的来源端口匹配,例如 SRC-PORT,52000,DIRECT。
RULE-SET
引用大量规则时,请使用 规则集合。
GEOSITE
domain-list-community 是由 v2fly 社区维护的域名列表。
例如 GEOSITE,twitter 匹配 Twitter 公司相关域名:
ads-twitter.com @ads cms-twdigitalassets.com periscope.tv pscp.tv t.co tellapart.com tweetdeck.com twimg.com twitpic.com twitter.biz twitter.com twitter.jp twitter.map.fastly.net twittercommunity.com twitterflightschool.com twitterinc.com twitteroauth.com twitterstat.us twtrdns.net twttr.com twttr.net twvid.com vine.co x.com
domain-list-community 数据不随 Stash 分发,Stash 会在首次使用时从 github.com 按需加载域名数据。首次使用请确保当前配置能正常访问 github.com。
PROCESS-NAME
进程名称匹配,例如 PROCESS-NAME,Telegram。仅对本机进程有效。
PROCESS-NAME 支持多种匹配模式:
PROCESS-NAME,Telegram匹配可执行文件名称。PROCESS-NAME,Google*使用*与?通配符匹配可执行文件名称。PROCESS-NAME,/usr/bin/ssh精确匹配可执行文件的完整绝对路径。PROCESS-NAME,/Applications/ChatGPT.app/按可执行文件路径前缀匹配,可覆盖ChatGPT.app应用包内的所有二进制文件。
App bundle 模式必须保留末尾的 /。如果以 / 开头但不以 / 结尾,则使用完整路径精确匹配。
由于 Network Extension 的限制,Stash iOS/tvOS(包括运行于 Apple silicon 设备上的 iOS 版)不支持 PROCESS-NAME 规则,配置中的进程相关规则将被忽略。
PROCESS-PATH
进程路径匹配,例如 PROCESS-PATH,/Applications/Telegram.app/Contents/MacOS/Telegram。仅对本机进程有效。
由于 Network Extension 的限制,Stash iOS/tvOS(包括运行于 Apple silicon 设备上的 iOS 版)不支持 PROCESS-PATH 规则,配置中的进程相关规则将被忽略。
SCRIPT
通过 Python 表达式匹配请求。表达式必须返回 Boolean 值,执行错误的表达式会被忽略。
表达式可读取以下变量:
{
"network": "string", // 可以是 tcp 或 udp
"host": "string", // 可能为空
"dst_ip": "string", // 可能为空
"dst_port": "number",
"src_ip": "string", // 仅在网关模式下有效
"src_port": "number" // 仅在网关模式下有效
}表达式可调用以下函数:
def resolve_ip(host: str) -> str:
pass
def in_cidr(ip: str, cidr: str) -> bool:
pass
def geoip(ip: str) -> str:
pass
def ipasn(ip: str) -> int:
pass
def match_provider(name: str) -> bool:
pass
def match_geosite(name: str) -> bool:
pass例如,需要拦截 QUIC 协议的请求,可以这样写:
rules:
- SCRIPT,quic,REJECT
- SCRIPT,udp-cn,ProxyToCN
script:
shortcuts: # 可在 rule 中引用
quic: network == 'udp' and dst_port == 443 # 匹配 QUIC 协议
udp-cn: network == 'udp' and geoip(dst_ip if dst_ip != '' else resolve_ip(host)) == 'CN' # 匹配发往 CN 的 UDP
instagram-quic: network == 'udp' and dst_port == 443 and match_geosite('instagram') # 匹配 Instagram 的 QUICAND
当需要同时满足多个规则时,可以使用 AND 逻辑规则。
AND,((#Rule1), (#Rule2), (#Rule3)...),PROXY
在子规则中,也可以添加 no-resolve 参数来避免触发 DNS
解析。例如:AND,((IP-CIDR,192.168.1.110,no-resolve), (DOMAIN-SUFFIX,example.com), (DOMAIN-KEYWORD, xxx)), DIRECT
OR
当需要满足其中一个规则时,可以使用 OR 逻辑规则。
OR,((#Rule1), (#Rule2), (#Rule3)...),PROXY
NOT
对规则取反。
NOT,((#Rule1)),PROXY
逻辑规则可以组合使用,例如:AND,((NOT,((GEOIP,CN))),(DOMAIN-SUFFIX,example.com)),Proxy
表示访问 example.com 且解析结果不在中国大陆时走代理。
USER-AGENT
通过 User-Agent 请求标头进行匹配。
USER-AGENT,AppleNews*,PROXY
URL-REGEX
使用正则表达式匹配链接。
URL-REGEX,^https?:\/\/www\.amazon\.com\/(Amazon-Video|gp\/video)\/,PROXY
规则选项
规则行末尾可以追加选项,多个选项用逗号分隔,顺序不限。
no-resolve
IP-CIDR、GEOIP、IP-ASN 这类需要 IP 的规则,遇到域名目标时会先发起 DNS 解析。加上 no-resolve 后不再为该规则解析,域名目标直接跳过它;已经有 IP 的目标照常匹配。
IP-CIDR,192.168.1.0/24,DIRECT,no-resolve
no-track
命中的连接不记入连接列表,流量统计照常。适合心跳、探测这类高频而无需查看的请求。
DOMAIN-SUFFIX,push.apple.com,DIRECT,no-track
pre-matching
BetaiOS/tvOS3.7+macOS4.4+让 REJECT 规则在连接建立之前生效。普通的 REJECT 规则要等连接进入核心、完成嗅探、必要时还要经过 HTTP 引擎之后才会拒绝;带 pre-matching 的规则会提前到更早的阶段:
- DNS 阶段:应用解析被拒域名时直接得到空应答,不分配 Fake IP,连接根本不会发起。
- 建连阶段(macOS、Windows、Android 的系统 TUN):SYN 包直接回 RST(
REJECT)或被丢弃(REJECT-DROP),不占用套接字。 - UDP 首包:回 ICMP 端口不可达(
REJECT)或丢弃(REJECT-DROP),不建立会话。 - 入口阶段(iOS 以及代理端口):连接在读取任何数据之前关闭,不嗅探、不进 HTTP 引擎、不记入连接列表。
广告、统计类域名的请求量大、重试快,这是 iOS 下减少内存和 CPU 占用最直接的手段。同一目标 3 秒内被拒绝超过 100 次后,建连阶段会改为丢弃 10 秒,避免客户端的重试风暴占满 CPU。
rules:
- DOMAIN-SUFFIX,ads.example,REJECT,pre-matching
- RULE-SET,advertising,REJECT-DROP,pre-matching
- AND,((DOMAIN-KEYWORD,track),(DST-PORT,443)),REJECT,pre-matching限制:
- 目标只能是
REJECT或REJECT-DROP,其它目标会使配置加载失败。 - 只能使用在连接建立前就能判断的规则类型:域名类规则、
GEOSITE、IP-CIDR、GEOIP、IP-ASN(不触发解析)、DST-PORT、SRC-IP、SRC-PORT、NETWORK、RULE-SET,以及由它们组成的AND/OR/NOT。PROCESS-NAME、PROCESS-PATH、USER-AGENT、URL-REGEX、PROTOCOL、SCRIPT依赖连接建立后才有的信息,带pre-matching会报错。
提前阶段只评估带 pre-matching 的规则。写在它前面、但不带该选项的规则不会保护被它命中的目标:例如先写 DOMAIN,api.ads.example,DIRECT,再写 DOMAIN-SUFFIX,ads.example,REJECT,pre-matching,api.ads.example 仍会在 DNS 阶段被拒绝。连接一旦建立,正常的规则匹配仍按完整顺序进行,所以该选项只会让拒绝提前,不会放行任何本应被拒的连接。
被提前拒绝的请求不会出现在连接列表,核心日志每个目标每 5 分钟记一条 pre-matched 记录。/rules/match 接口的 stage 字段会说明某个目标会在哪个阶段被拒绝,见 HTTP API。