Skip to Content
RulesRule Types

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:

  • TCP
  • UDP
  • HTTP
  • TLS
  • QUIC
  • STUN
  • MTPROTO

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,DIRECT

SRC-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,Telegram matches the executable file name.
  • PROCESS-NAME,Google* matches the executable file name with * and ? wildcards.
  • PROCESS-NAME,/usr/bin/ssh matches the executable’s full absolute path.
  • PROCESS-NAME,/Applications/ChatGPT.app/ matches executable paths by prefix, so it can cover all binaries inside the ChatGPT.app bundle.

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: 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 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 QUIC

AND

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-matching

Limits:

  • The target must be REJECT or REJECT-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, and AND / OR / NOT built from them. PROCESS-NAME, PROCESS-PATH, USER-AGENT, URL-REGEX, PROTOCOL and SCRIPT depend on information that only exists once the connection is open, and are rejected with pre-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.

Last updated on