Rule Types
By writing rules, you can specify different outbound methods for connections, such as forwarding through a specific proxy or interception. Rules can match connections based on IP, domain, process name, or a combination of multiple conditions.
For each connection, the system matches rules sequentially from top to bottom.
Rules can be divided into the following types (some IP types may trigger DNS resolution):
- Domain-based
- IP or Port-based
- Protocol-based
- Logical Rules
- Other Composite Types
To write rules for URLs, refer to the HTTP Rewrite section.
You can add a no-track parameter at the end of a rule to hide connections
matched by this rule. For example, SCRIPT,quic,REJECT,no-track. This can
effectively prevent a flood of REJECT logs from cluttering the page.
Use the built-in proxies REJECT and REJECT-DROP to intercept connections.
REJECT will immediately return an error, while REJECT-DROP will silently
drop the connection to avoid a connection storm.
DOMAIN
Exact match for a domain name, e.g., DOMAIN,google.com matches google.com but not www.google.com.
DOMAIN-SUFFIX
Matches domain name suffix, e.g., DOMAIN-SUFFIX,google.com matches google.com and www.google.com.
DOMAIN-KEYWORD
Keyword matches for domain names, e.g., DOMAIN-KEYWORD,google matches google.com and google.jp.
DOMAIN-WILDCARD
Matches domain names using wildcards, supporting * and ?, e.g., DOMAIN-WILDCARD,*.google.com matches www.google.com and mail.google.com.
Here * matches any number of characters, ? matches one character.
DOMAIN-REGEX
Matches domain names using regular expressions, e.g., DOMAIN-REGEX,^.*\.google\.com$ matches www.google.com and mail.google.com.
GEOIP
Matches country codes using MaxMind GeoIP, e.g., GEOIP,CN. You can add no-resolve to avoid triggering DNS resolution.
UNKNOWN
iOS/tvOS3.6+macOS4.3+GEOIP,UNKNOWN matches destination IPs that have no country entry in the GeoIP country database, e.g., GEOIP,UNKNOWN,Proxy. UNKNOWN is case-insensitive and can be used in both individual rules and classical rule sets.
Private network addresses have no entry in the MaxMind database, so they are
matched by GEOIP,UNKNOWN. To handle LAN traffic separately, put GEOIP,LAN
before it. When the database is not loaded or fails to load, GEOIP,UNKNOWN
does not match.
Stash allows users to replace the database conforming to MaxMind GeoIP format. Users can choose a more suitable MaxMind GeoIP database according to their own needs.
IP-ASN
Matches using IP Autonomous System Number, e.g., IP-ASN,714. You can add no-resolve to avoid triggering DNS resolution.
UNKNOWN
iOS/tvOS3.6+macOS4.3+IP-ASN,UNKNOWN matches destination IPs that have no autonomous system entry in the ASN database, e.g., IP-ASN,UNKNOWN,Proxy. UNKNOWN is case-insensitive and can be used in both individual rules and classical rule sets.
Private network addresses have no entry in the MaxMind database, so they are
matched by IP-ASN,UNKNOWN. To handle LAN traffic separately, put GEOIP,LAN
before it. When the database is not loaded or fails to load, IP-ASN,UNKNOWN
does not match.
IP-CIDR / IP-CIDR6
Matches IP CIDR ranges, e.g., IP-CIDR,192.168.1.0/24. You can add no-resolve to avoid triggering DNS resolution.
NETWORK
Matches network types, e.g., tcp matches TCP protocol, udp matches UDP protocol.
PROTOCOL
PROTOCOL rules offer finer granularity than NETWORK rules. Supported protocols include:
TCPUDPHTTPTLSQUICSTUNMTPROTO
PROTOCOL,MTPROTO matches Telegram connections accepted by the built-in MTProto proxy server. BetaiOS/tvOS3.7+macOS4.4+
DST-PORT
Matches destination ports, e.g., DST-PORT,80.
SRC-IP
BetaiOS/tvOS3.7+macOS4.4+Matches the source address of a connection. The value can be a single address or a CIDR range, in IPv4 or IPv6, e.g., SRC-IP,192.168.1.110,DIRECT or SRC-IP,192.168.1.0/24,Proxy.
The source address is the address of the client that reached Stash, so this rule is most useful when several devices share one Stash instance, such as when providing a proxy to LAN devices, in gateway mode, or over a personal hotspot. It lets you assign different outbounds to different devices.
rules:
- SRC-IP,192.168.1.20,DIRECT # The TV connects directly
- SRC-IP,192.168.1.0/24,Proxy # Other LAN devices go through the proxy
- MATCH,DIRECTSRC-PORT
BetaiOS/tvOS3.7+macOS4.4+Matches the source port of a connection, e.g., SRC-PORT,52000,DIRECT.
RULE-SET
When referencing a large number of rules, use the Rule Set.
GEOSITE
domain-list-community is the domain list maintained by the v2fly community.
For example, GEOSITE,twitter matches the domains related to Twitter company:
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 data is not distributed with Stash. Stash will load domain data from github.com on first use as needed. Please ensure your current configuration can access github.com during the first use.
PROCESS-NAME
Matches by process name, e.g., PROCESS-NAME,Telegram. Effective only for local processes.
PROCESS-NAME supports several matching modes:
PROCESS-NAME,Telegrammatches the executable file name.PROCESS-NAME,Google*matches the executable file name with*and?wildcards.PROCESS-NAME,/usr/bin/sshmatches the executable’s full absolute path.PROCESS-NAME,/Applications/ChatGPT.app/matches executable paths by prefix, so it can cover all binaries inside theChatGPT.appbundle.
The trailing slash in app bundle mode is required. Without it, a path starting
with / uses full-path exact matching.
Due to Network Extension limitations, Stash iOS/tvOS (including the iOS version running on Apple silicon devices) does not support PROCESS-NAME rules, and process-related rules in the configuration will be ignored.
PROCESS-PATH
Matches by process path, e.g., PROCESS-PATH,/Applications/Telegram.app/Contents/MacOS/Telegram. Effective only for local processes.
Due to Network Extension limitations, Stash iOS/tvOS (including the iOS version running on Apple silicon devices) does not support PROCESS-PATH rules, and process-related rules in the configuration will be ignored.
SCRIPT
Matches requests through a Python expression. The expression must return a Boolean value, and any expression execution errors will be ignored.
The expression can read the following variables:
{
"network": "string", // Can be tcp or udp
"host": "string", // May be empty
"dst_ip": "string", // May be empty
"dst_port": "number",
"src_ip": "string", // Effective only in gateway mode
"src_port": "number" // Effective only in gateway mode
}The expression can call the following functions:
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:
passFor example, to intercept QUIC protocol requests, you can write:
rules:
- SCRIPT,quic,REJECT
- SCRIPT,udp-cn,ProxyToCN
script:
shortcuts: # Can be referenced in rules
quic: network == 'udp' and dst_port == 443 # Matches QUIC protocol
udp-cn: network == 'udp' and geoip(dst_ip if dst_ip != '' else resolve_ip(host)) == 'CN' # Matches UDP to CN
instagram-quic: network == 'udp' and dst_port == 443 and match_geosite('instagram') # Matches Instagram's QUICAND
When multiple rules need to be satisfied simultaneously, use the AND logical rule.
AND,((#Rule1), (#Rule2), (#Rule3)...),PROXY
In sub-rules, you can also add the no-resolve parameter to avoid triggering
DNS resolution. For example: AND,((IP-CIDR,192.168.1.110,no-resolve), (DOMAIN-SUFFIX,example.com), (DOMAIN-KEYWORD, xxx)), DIRECT
OR
When one of the rules needs to be satisfied, use the OR logical rule.
OR,((#Rule1), (#Rule2), (#Rule3)...),PROXY
NOT
Negates a rule.
NOT,((#Rule1)),PROXY
Logical rules can be combined, for example:
AND,((NOT,((GEOIP,CN))),(DOMAIN-SUFFIX,example.com)),Proxy sends
example.com through the proxy only when it does not resolve to an address
in mainland China.
USER-AGENT
Matches via User-Agent request header.
USER-AGENT,AppleNews*,PROXY
URL-REGEX
Matches links using regular expressions.
URL-REGEX,^https?:\/\/www\.amazon\.com\/(Amazon-Video|gp\/video)\/,PROXY
Rule options
Options go at the end of a rule line, comma-separated, in any order.
no-resolve
Rules that need an IP, such as IP-CIDR, GEOIP and IP-ASN, resolve a domain target before matching. With no-resolve the rule never resolves: a domain target skips it, and a target that already is an IP matches as usual.
IP-CIDR,192.168.1.0/24,DIRECT,no-resolve
no-track
Connections the rule matches stay out of the connection list; traffic statistics are unaffected. Meant for heartbeats and probes that are frequent and never worth looking at.
DOMAIN-SUFFIX,push.apple.com,DIRECT,no-track
pre-matching
BetaiOS/tvOS3.7+macOS4.4+Lets a REJECT rule take effect before a connection exists. A plain REJECT rule refuses only after the connection has reached the core, been sniffed, and possibly passed through the HTTP engine. A rule with pre-matching refuses at an earlier stage:
- DNS: an app resolving a refused name gets an empty answer, no Fake IP is assigned, and no connection is ever attempted.
- Connection setup (the system TUN on macOS, Windows and Android): the SYN is answered with a RST (
REJECT) or dropped (REJECT-DROP), with no socket spent. - First UDP datagram: answered with an ICMP port unreachable (
REJECT) or dropped (REJECT-DROP), with no session opened. - Ingress (iOS, and the proxy ports): the connection is closed before any byte is read, with no sniffing, no HTTP engine and no connection record.
Advertising and telemetry hosts are requested often and retried fast, so this is the most direct way to cut memory and CPU on iOS. A destination refused more than 100 times in 3 seconds is dropped for 10 seconds at the connection stage, so a retry storm cannot saturate the 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-matchingLimits:
- The target must be
REJECTorREJECT-DROP; any other target makes the profile fail to load. - Only rule types that can be judged before a connection exists are allowed: the domain rules,
GEOSITE,IP-CIDR,GEOIP,IP-ASN(without resolution),DST-PORT,SRC-IP,SRC-PORT,NETWORK,RULE-SET, andAND/OR/NOTbuilt from them.PROCESS-NAME,PROCESS-PATH,USER-AGENT,URL-REGEX,PROTOCOLandSCRIPTdepend on information that only exists once the connection is open, and are rejected withpre-matching.
The early stages evaluate only the rules that carry pre-matching. A rule written earlier without the option does not shelter a target: with DOMAIN,api.ads.example,DIRECT followed by DOMAIN-SUFFIX,ads.example,REJECT,pre-matching, api.ads.example is still refused at the DNS stage. Once a connection exists, normal rule matching still runs in full order, so the option only brings a refusal forward and never lets through a connection that would have been refused.
Requests refused early never appear in the connection list; the core log records one pre-matched line per target every 5 minutes. The stage field of /rules/match says at which stage a target would be refused, see HTTP API.