Understanding Rule Types: DOMAIN, IP-CIDR, GEOIP, PROCESS-NAME and RULE-SET Please publish the content exactly as provided. Keep both in-body links dofollow and do not add any other outbound links.

Open somebody else’s routing configuration and the rules: block is usually the longest thing in it. Hundreds of lines, all shaped alike, all apparently doing something slightly different. It looks intimidating until you realise there are only about a dozen distinct types, and each asks one simple question about a connection.

The complexity is not in the individual lines. It is in their order, and in knowing which question is cheap to ask and which one quietly forces the engine into extra work before it can answer.

What follows is a reference to the types you will actually use: syntax for each, what it costs to evaluate, and the ordering conventions that fall out of those costs — plus how to read the connections log to find out which line actually fired.

Anatomy of a Rule Line

Every rule is a comma-separated line with two or three fields:

TYPE,PAYLOAD,TARGET[,OPTION]

TYPE names the test. PAYLOAD is what it tests against — a domain, a network prefix, a country code, a process name. TARGET is where matching traffic goes: DIRECTREJECT, a node, or usually a policy group. The optional fourth field carries modifiers, of which no-resolve is the one that matters.

The last rule in every list is the catch-all:

  - MATCH,PROXY

MATCH takes no payload and matches everything. Without it, a connection that falls off the bottom of the list has no policy at all. Treat it as mandatory.

Evaluation Is Top-Down and Stops at the First Hit

The engine walks the list downward, testing each rule against the connection’s metadata, and the first match wins outright. Nothing below it is looked at. Two consequences follow, and most configuration bugs come from ignoring one of them.

The first is specificity: a broad rule placed above a narrow one swallows it. If DOMAIN-SUFFIX,google.com,PROXY sits above DOMAIN,drive.google.com,DIRECT, the second line is unreachable — it will never fire, because the suffix rule already claimed the traffic. Narrow first, broad after.

The second is about cost, and it is less obvious. Rule types are not equally cheap:

  • Free — port, source IP and process rules read metadata the engine already has from the moment the connection was accepted.
  • Cheap — domain rules are string comparisons against a hostname that was in the request itself.
  • Expensive — IP-based rules need a destination address. When the request arrived as a hostname, the engine has to resolve it before the rule can be evaluated at all.

That is the whole reason domain rules belong above IP rules — not because string comparison is faster, but because reaching an IP rule can trigger a DNS lookup for a request a domain rule further down would have handled without one.

The Three Domain Rules

These three cover the overwhelming majority of real routing decisions, and confusing them is the most common beginner error.

DOMAIN — exact match only

  - DOMAIN,api.example.com,PROXY

Matches that hostname and nothing else — not subdomains, not the bare domain. Use it to route one specific endpoint differently from everything around it.

DOMAIN-SUFFIX — the domain and everything under it

  - DOMAIN-SUFFIX,example.com,PROXY

Matches example.comapi.example.com and cdn.static.example.com. This is the workhorse. It is label-aware, not a plain string suffix, so it will not match notexample.com.

DOMAIN-KEYWORD — substring anywhere

  - DOMAIN-KEYWORD,analytics,REJECT

Matches if the string appears anywhere in the hostname. Blunt in equal measure — a keyword rule for ads will happily catch downloads.example.com. Keep these few, specific and low in the list.

Some builds also offer DOMAIN-REGEX for patterns the three above cannot express, such as ^ad[0-9]{1,3}\.. It is the most expensive of the family, so avoid it unless a pattern truly requires one.

Hostname testedDOMAIN, example.comDOMAIN-SUFFIX, example.comDOMAIN-KEYWORD, exampleexample.commatchmatchmatchapi.example.comnomatchmatchnotexample.comnonomatchexample.co.uknonomatch

IP Rules and the no-resolve Flag

IP rules test the destination address against a network prefix.

  - IP-CIDR,192.168.0.0/16,DIRECT,no-resolve
  - IP-CIDR,10.0.0.0/8,DIRECT,no-resolve
  - IP-CIDR6,fc00::/7,DIRECT,no-resolve
  - IP-ASN,13335,PROXY,no-resolve

Related types read other parts of the tuple: SRC-IP-CIDR matches the machine that opened the connection, which is how you give one LAN device its own policy, while DST-PORT and SRC-PORT match ports.

Now the important part. When a connection arrives as a hostname, there is no destination IP yet, and an IP rule cannot be tested without one — so by default the engine resolves the hostname on the spot just to answer the question, even if a rule twenty lines down would have matched the domain instead.

The no-resolve flag says: evaluate this rule only if an IP is already known, otherwise skip it. That single option prevents a whole class of problems.

  • Lookups that should not have happened. A hostname you meant to route through a proxy gets resolved locally first, exposing it to whichever resolver the machine is using.
  • Latency you cannot see. Every unnecessary resolution adds a round trip in front of the connection.
  • Broken fake-IP setups, which depend on domain rules matching before anything asks for a real address.

The practical rule: put no-resolve on every IP rule that appears above your domain rules, particularly the private-network block near the top of the list. Leave it off only for IP rules that sit near the bottom, after domain matching has already had its chance. Watching the effect of this in a live connections view is the quickest way to understand it, and a desktop client such as clash-vergerev.co shows the matched rule alongside each connection so you can see exactly which line pulled a resolution forward.

GEOIP and GEOSITE

These two look similar and work completely differently.

  - GEOIP,CN,DIRECT,no-resolve
  - GEOIP,PRIVATE,DIRECT,no-resolve
  - GEOSITE,category-ads-all,REJECT

GEOIP takes a two-letter country code and tests the destination address against a bundled IP-to-country database, an MMDB or DAT file the client refreshes periodically. Because it tests an address, it is an IP rule wearing a different hat, and it wants no-resolve when placed high.

GEOSITE takes a category name and tests the domain against a curated list of hostnames grouped by service or purpose. It is a domain rule, it is cheap, and it triggers no lookup. Both databases live on disk and are versioned, so if a rule that used to work suddenly stops, check for an out-of-date database before rewriting anything.

PROCESS-NAME and Per-App Routing

Process rules match on the program that opened the connection rather than where it is going.

  - PROCESS-NAME,ssh,DIRECT
  - PROCESS-NAME,Docker Desktop,DIRECT
  - PROCESS-NAME,steam.exe,Gaming
  - PROCESS-PATH,/usr/local/bin/kubectl,DIRECT

This type solves problems nothing else can. A backup agent talking to a hundred rotating endpoints cannot be pinned down by domain, and a container runtime reaching a local registry does not announce itself in the hostname. Naming the process sidesteps both.

Three caveats. Names are platform-specific — steam.exe on Windows, steam elsewhere. Looking up socket ownership generally needs TUN mode or elevated permissions to work reliably. And the rule is free to evaluate only if that lookup succeeded, so keep process rules near the top.

Per-app routing is also where a graphical rules viewer earns its keep. Seeing your clash rules listed in the exact order the engine will evaluate them makes it immediately obvious when a process rule has been buried under a broader domain rule you forgot was there.

RULE-SET and Remote Providers

Rather than pasting five thousand ad domains into your file, you reference a list maintained elsewhere.

rule-providers:
  ads:
    type: http
    behavior: domain
    format: yaml
    url: "https://example.org/lists/ads.yaml"
    path: ./ruleset/ads.yaml
    interval: 86400

  private-nets:
    type: file
    behavior: ipcidr
    path: ./ruleset/private.yaml

rules:
  - RULE-SET,ads,REJECT
  - RULE-SET,private-nets,DIRECT,no-resolve

Three fields decide how a provider behaves. type is http for a remote list or file for a local one. interval is the refresh period in seconds, so a daily list is 86400. And behavior tells the engine what kind of entries to expect:

  • domain — hostnames only. Matched cheaply, no resolution.
  • ipcidr — network prefixes only. Carries the same resolution concerns as any IP rule.
  • classical — full rule lines of mixed types inside the file, the most flexible and the slowest to evaluate.

Getting behavior wrong is a common failure: a domain list declared classical loads without complaint and matches nothing. If a rule set seems inert, check that field first, then confirm the file at path exists.

Providers are also what make a large configuration maintainable. A file that is mostly a dozen RULE-SET lines plus a handful of personal exceptions is one you can still read a year later, which is the real argument for building around external lists rather than hand-maintaining thousands of entries.

A Sane Default Ordering

Putting the cost model into practice gives a fairly standard skeleton:

  1. Process rules — free, and they should outrank anything destination-based.
  2. Private and loopback ranges, with no-resolve.
  3. Personal exceptions — DOMAIN lines overriding the lists below.
  4. Reject lists — ad and tracker rule sets, matched on domain.
  5. Service routing — DOMAIN-SUFFIX and GEOSITE rules.
  6. Keyword rules — few, and deliberately late.
  7. IP and GEOIP rules — last resort, now safe to resolve.
  8. MATCH — the catch-all.

For the rare case this ordering cannot express, logical rules combine tests with ANDOR and NOT, as in AND,((DOMAIN-SUFFIX,example.com),(DST-PORT,443)),PROXY. They are harder to debug, so use them sparingly.

Finding Out Which Rule Matched

When something routes the wrong way, stop reading the file and read the log. The connections view lists every active flow with its destination, the process that opened it, the chain of groups and nodes it took, and the rule that selected that chain. A short procedure resolves most cases:

  1. Reproduce the traffic with the connections view open, filtered by the hostname or process involved.
  2. Read the rule column on the offending entry. That is the line that fired — not the line you expected to fire.
  3. Find that line in your file and look above it. The culprit is nearly always a broader rule higher up.
  4. If an IP or GEOIP rule matched but you wrote a domain rule for that host, your domain rule is below it. Move it up and add no-resolve.
  5. Reload and reproduce again. Existing connections keep their original decision, so always test with a fresh one.

The rules viewer, which lists the parsed set in evaluation order, is the companion to this. If a line you wrote is missing there, it failed to parse — usually a stray space after a comma, or a target that matches no group.

Common Questions

Does a long rule list slow down connections?

Barely, if it is ordered sensibly. Domain and metadata tests are fast. What costs real time is a resolution triggered by an IP rule placed too high — one badly positioned line hurts more than a thousand well-ordered ones.

Why does my DOMAIN rule never match?

Usually because a DOMAIN-SUFFIX or RULE-SET line above already covers that host. Check the rule column in the connections log, then move your specific rule above whatever claimed it.

Should I put no-resolve on every IP rule?

On every one above your domain rules, yes. For IP rules at the very bottom, resolution is expected, and the flag would simply stop them matching hostname-based traffic at all.

How often do remote rule sets update?

Whenever interval says, in seconds from the last successful fetch; daily is typical for ad lists. If a fetch fails, the cached copy at path keeps being used, so an upstream outage does not break your routing.

Putting the List Together

Rule types are individually simple. Domain rules ask about a name, IP rules about an address, process rules about which program is talking, and rule sets are the first two supplied in bulk from elsewhere.

What turns that into a working configuration is order: specific before general, cheap before expensive, and no-resolve on anything IP-shaped above your domain matching. Get those three habits right and a list of several thousand rules stays predictable.

Leave a Comment

Your email address will not be published. Required fields are marked *