Rule Types
By writing rules, you can specify the outbound handling for different connections, such as forwarding or intercepting through a specific proxy. Rules can match based on the IP, domain name, process name, or a combination of multiple conditions.
For each connection, the system always matches rules from top to bottom.
Rules can be divided into the following types, among which the IP type may trigger DNS resolution:
- Based on Domain Name
- Based on IP
- Other Composite Types
Want to write rules for URLs? Please read the HTTP Rewrite chapter.
You can add the no-track
parameter at the end of a rule to hide connections
that match this rule, such as SCRIPT,quic,REJECT,no-track
. This is effective
for avoiding a large number of REJECT records cluttering the page.
You can use the built-in proxies REJECT
and REJECT-DROP
to intercept
connections. REJECT
will immediately return an error, while REJECT-DROP
will silently discard the connection to avoid generating connection storms.
DOMAIN
Exact match of domain names, e.g., DOMAIN,google.com
matches google.com
but does not match www.google.com
.
DOMAIN-SUFFIX
Matches domain suffixes, e.g., DOMAIN-SUFFIX,google.com
matches both google.com
and www.google.com
.
DOMAIN-KEYWORD
Keyword matches domain names, e.g., DOMAIN-KEYWORD,google
matches both google.com
and google.jp
.
GEOIP
Matches country codes through MaxMind GeoIP, e.g., GEOIP,CN
. You can add no-resolve
to avoid triggering DNS resolution.
Stash allows users to replace databases that are compliant with MaxMind GeoIP format. Users can choose a MaxMind GeoIP database that better fits their requirements.
IP-ASN
Matches based on IP Autonomous System Numbers, e.g., IP-ASN,714
. You can add no-resolve
to avoid triggering DNS resolution.
IP-CIDR / IP-CIDR6
IP CIDR range matching, e.g., IP-CIDR,192.168.1.0/24
. You can add no-resolve
to avoid triggering DNS resolution.
DST-PORT
Matches target ports, e.g., DST-PORT,80
.
RULE-SET
When referencing a large number of rules, please use Rule Sets.
GEOSITE
domain-list-community (opens in a new tab) is a domain list maintained by the v2fly community.
For example, GEOSITE,twitter
matches domains related to Twitter (opens in a new tab):
ads-twitter.com cms-twdigitalassets.com periscope.tv pscp.tv t.co tellapart.com tweetdeck.com twimg.com twitpic.com twitter.biz twitter.com twitter.jp twittercommunity.com twitterflightschool.com twitterinc.com twitteroauth.com twitterstat.us twtrdns.net twttr.com twttr.net twvid.com vine.co x.com
The domain-list-community data is not distributed with Stash; Stash will load domain data from github.com on demand during the first use. Please ensure that your current configuration has connectivity to github.com during the first usage.
PROCESS-NAME
Matches process names, e.g., PROCESS-NAME,Telegram
. Only valid for local processes.
Due to limitations with the Network Extension, Stash iOS/tvOS (including the iOS version running on Apple silicon devices) does not support PROCESS-NAME rules, and any process-related rules in the configuration will be ignored.
PROCESS-PATH
Matches process paths, e.g., PROCESS-PATH,/Applications/Telegram.app/Contents/MacOS/Telegram
. Only valid for local processes.
Due to limitations with the Network Extension, Stash iOS/tvOS (including the iOS version running on Apple silicon devices) does not support PROCESS-PATH rules, and any process-related rules in the configuration will be ignored.
SCRIPT
Matches requests using Python expressions. The expression must return a Boolean value, and expressions that result in errors will be ignored.
Expressions can read the following variables:
{
"network": "string", // could be tcp or udp
"host": "string", // may be empty
"dst_ip": "string", // may be empty
"dst_port": "number",
"src_ip": "string", // only valid in gateway mode
"src_port": "number" // only valid in gateway mode
}
Expressions 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:
pass
For example, to intercept QUIC protocol requests, you can write:
rules:
- SCRIPT,quic,REJECT
- SCRIPT,udp-cn,ProxyToCN
script:
shortcuts: # can be referenced in rule
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 going to CN
instagram-quic: network == 'udp' and dst_port == 443 and match_geosite('instagram') # matches Instagram's QUIC