Skip to main content

Matcher Plugins

Matcher plugins return true or false. They are mainly used by sequence.matches.

Matcher Expression Rules

Inside sequence, quick-setup matcher expressions are usually the clearest form to start with:

- matches:
- "client_ip $lan_ip_set"
- "qtype A,28"
exec: "$forward_main"

Other quick-setup matchers can be combined in the same way:

- matches:
- "qname domain:example.com"
- "qclass IN,3"
exec: "$forward_main"

Negation:

- matches: "!has_resp"
exec: "$forward_main"

any_match

Purpose

Composes multiple matcher expressions and returns true when any one of them matches.

Example Configuration

- tag: any_policy_hit
type: any_match
args:
- "$lan_clients"
- "qtype AAAA"
- "!$blocked_qname"

Configuration Details

any_match uses an array[string] args list.

  • Type: array[string]; Required: yes; Default: none
  • Supported entries:
    • matcher tag references (for example "$match_tag")
    • quick-setup matcher expressions (for example "qname domain:example.com")
    • negated matcher expressions (for example "!has_resp" or "!$blocked_qname")
  • Runtime impact:
    • Evaluates entries in order and short-circuits on the first matched entry.
    • Returns false only when all entries fail.

Typical Uses

  • Reuse one logical OR matcher across multiple sequence rules.
  • Keep complex branching readable by moving OR conditions into one matcher.

qname

Purpose

Matches the query name in the request.

Example Configuration

- tag: match_domain
type: qname
args:
# Exact match
- "full:login.example.com"
# Suffix match
- "domain:example.com"
# Keyword match
- "keyword:cdn"
# Regex match
- "regexp:^api[0-9]+\\.example\\.net$"
# Reuse an existing domain-capable provider
- "$core_domains"
# Load rules from file
- "&/etc/oxidns/domains.txt"

Configuration Details

args is a rule list.

  • Type: array; Required: yes; Default: none
  • Supported items:
    • domain expressions, supporting full:, domain:, keyword:, regexp:, and bare domains without a prefix as domain: rules
    • provider references with domain match capability, such as domain_set or geosite
    • file references
  • Runtime impact:
    • Returns true when any question name matches any configured rule.

quick setup

- matches: "qname domain:example.com"

Typical Uses

  • Route by suffix, keyword, or regex.

question

Purpose

Matches request questions using provider implementations of contains_question.

The matcher scans every question in the current request. It returns true as soon as any question is matched by any referenced provider.

Example Configuration

- tag: match_ad
type: question
args:
- "$ad_rules"
- "$shared_domains"

Configuration Details

  • args
    • Type: array[string]; Required: yes; Default: none
    • Purpose: References providers that implement contains_question using "$provider_tag" entries.

quick setup

- matches: "question $ad_rules"

Behavior

  • Scans all questions in the request.
  • Returns true when any question is matched by any referenced provider.
  • quick setup supports the same "$provider_tag" entries.

Typical Uses

  • Let providers such as adguard_rule, domain_set, or geosite participate directly in question-level matching.
  • Branch in sequence, then hand off to black_hole, reject, or another executor.

qtype

Purpose

Matches request qtypes.

Example Configuration

This example mixes text and numeric forms. Both formats are equivalent and can be used together.

- tag: only_a_aaaa
type: qtype
args:
- "A"
- "28"

Configuration Details

  • Type: array; Required: yes; Default: none
  • Supports both enum text and decimal numeric codes; text matching is case-insensitive, and both formats can be mixed in the same list.
  • Common mappings and meanings are listed in the DNS Code Reference.
  • Unknown or future qtypes can still be matched with numeric codes.
  • Runtime impact:
    • Returns true if any question type matches the configured set.

quick setup

- matches: "qtype A,28"

Typical Uses

  • Split A, AAAA, PTR, TXT, and other query classes of traffic.

qclass

Purpose

Matches request qclasses.

Example Configuration

This example mixes text and numeric forms. Both formats are equivalent and can be used together.

- tag: in_or_ch
type: qclass
args:
- "IN"
- "3"

Configuration Details

  • Type: array; Required: yes; Default: none
  • Supports both enum text and decimal numeric codes; text matching is case-insensitive, and both formats can be mixed in the same list.
  • Common mappings and meanings are listed in the DNS Code Reference.
  • Unknown or future qclasses can still be matched with numeric codes.
  • Runtime impact:
    • Returns true if any question class matches the configured set.

quick setup

- matches: "qclass IN,3"

Typical Uses

  • Restrict handling to IN queries.

client_ip

Purpose

Matches the client source IP.

Example Configuration

- tag: lan_clients
type: client_ip
args:
# Inline CIDR
- "192.168.0.0/16"
# Reference an IP-capable provider
- "$lan_ip_set"

Configuration Details

  • Type: array; Required: yes; Default: none
  • Supported items:
    • single IPs
    • CIDRs
    • provider references with IP match capability, such as ip_set or geoip
  • Runtime impact:
    • Returns true when the client source address matches any rule.

quick setup

- matches: "client_ip 192.168.1.0/24"

Typical Uses

  • Split policies by source subnet.

resp_ip

Purpose

Matches A and AAAA addresses in the response answers.

Example Configuration

- tag: matched_resp_ip
type: resp_ip
args:
- "100.64.0.0/10"
- "$special_targets"

Configuration Details

  • Type: array; Required: yes; Default: none
  • Supported items:
    • single IPs
    • CIDRs
    • provider references with IP match capability, such as ip_set or geoip
  • Runtime impact:
    • Returns true when any A or AAAA answer IP matches any rule.

quick setup

- matches: "resp_ip 10.0.0.0/8"

Typical Uses

  • Trigger side effects based on returned answer addresses.

ptr_ip

Purpose

Matches the IP encoded in a PTR query name.

Example Configuration

Similar to client_ip and resp_ip, it supports IP rules and IP-capable providers such as ip_set and geoip.

Configuration Details

  • Type: array; Required: yes; Default: none
  • Supported items:
    • single IPs
    • CIDRs
    • provider references with IP match capability, such as ip_set or geoip
  • Runtime impact:
    • Extracts the reverse-mapped IP from the PTR name and matches it against the configured rules.

quick setup

- matches: "ptr_ip 192.168.0.0/16"

Typical Uses

  • Separate handling for reverse-lookups of specific address spaces.

cname

Purpose

Matches CNAME targets in the response.

Example Configuration

- tag: cname_target
type: cname
args:
- "full:alias.example.com"
- "domain:example.com"
- "keyword:cdn"
- "regexp:^edge[0-9]+\\.example\\.net$"
- "$core_domains"
- "&/etc/oxidns/cnames.txt"

Configuration Details

  • Type: array; Required: yes; Default: none
  • Supported items:
    • domain expressions, supporting full:, domain:, keyword:, regexp:, and bare domains without a prefix as domain: rules
    • provider references with domain match capability, such as domain_set or geosite
    • file references
  • Runtime impact:
    • Returns true when any CNAME target in the response matches.

quick setup

- matches: "cname keyword:cdn"

Typical Uses

  • Branch on canonical names returned by upstreams.

rcode

Purpose

Matches the current response code.

Example Configuration

This example mixes text and numeric forms. Both formats are equivalent and can be used together.

- tag: failure_rcodes
type: rcode
args:
- "SERVFAIL"
- "3"

Configuration Details

  • Type: array; Required: yes; Default: none
  • Supports both enum text and decimal numeric codes; text matching is case-insensitive, and both formats can be mixed in the same list.
  • Common mappings and meanings are listed in the DNS Code Reference.
  • Unknown or future rcodes can still be matched with numeric codes.
  • Runtime impact:
    • Returns true when the response rcode matches the configured set.

quick setup

- matches: "rcode SERVFAIL,3"

Typical Uses

  • Follow-up handling for upstream failures or negative responses.

has_resp

Purpose

Matches whether a response already exists in the context.

Example Configuration

- tag: has_resp_flag
type: has_resp

Configuration Details

No standalone configuration fields.

quick setup

- matches: "has_resp"

Typical Uses

  • Guard forwarding so it only runs when no earlier plugin has answered.

has_wanted_ans

Purpose

Matches whether the response already contains wanted answers.

Example Configuration

- tag: has_wanted_answer
type: has_wanted_ans

Configuration Details

No standalone configuration fields.

quick setup

- matches: "has_wanted_ans"

Typical Uses

  • Build follow-up logic only when a meaningful answer is already present.

mark

Purpose

Matches marks already written into the DNS context.

Example Configuration

- tag: marked_100
type: mark
args:
- "100"
- "200"

Configuration Details

  • Type: array; Required: yes; Default: none
  • Supports integer mark values.
  • Multiple marks can be separated by commas or whitespace.
  • Runtime impact:
    • Returns true if any configured mark exists in the context.

quick setup

- matches: "mark 100 200"

Typical Uses

  • Branch across phases after earlier decisions set marks.

env

Purpose

Matches environment variables.

Example Configuration

- tag: env_profile_prod
type: env
args:
- "PROFILE=prod"
- "FEATURE_X"

Or check only existence:

args:
- "FEATURE_X"

Configuration Details

  • Type: array; Required: yes; Default: none
  • Each item is an environment expression; all expressions must match.
  • Typical forms:
    • KEY=VALUE for exact value matching; recommended for environment variables.
    • KEY:VALUE as an equivalent rule-expression-style alias.
    • KEY
    • KEY: or KEY= for explicit existence checks.
  • Each string item in the array is parsed as one complete expression and is not split on commas or whitespace, so values such as NO_PROXY=localhost,127.0.0.1 or GREETING=hello world should be written as their own quoted array item.
  • Runtime impact:
    • Lets one config behave differently across environments without editing the policy graph itself.

quick setup

- matches: "env PROFILE=prod FEATURE_X"

Behavior

  • KEY=VALUE and KEY:VALUE require an exact match.
  • KEY checks only for existence.
  • KEY: and KEY= also check only for existence.
  • ["PROFILE", "prod"] checks that both PROFILE and prod exist; it does not mean PROFILE == prod.
  • quick setup separates expressions with whitespace; use the full args array when a value itself contains spaces.
  • Values are cached during plugin initialization and are not re-read per request.

Typical Uses

  • Toggle policy branches by deployment environment.

random

Purpose

Matches probabilistically for rollout or sampling.

Example Configuration

- tag: rollout_10p
type: random
args:
- "0.1"

Configuration Details

  • Type: number; Required: yes; Default: none
  • Meaning: Probability between 0 and 1.
  • Runtime impact:
    • Returns true according to the configured sampling ratio.

quick setup

- matches: "random 0.05"

Typical Uses

  • Gradual rollout.
  • Sampling for observability or experiments.

rate_limiter

Purpose

Matches based on per-source rate-limit state.

Example Configuration

- tag: qps_guard
type: rate_limiter
args:
qps: 20
burst: 40
mask4: 32
mask6: 48

Configuration Details

qps

  • Type: integer; Required: yes
  • Meaning: Steady-state queries per second.

burst

  • Type: integer; Required: no
  • Meaning: Burst allowance above steady-state rate.

mask4

  • Type: integer; Required: no
  • Meaning: IPv4 aggregation mask for clients.

mask6

  • Type: integer; Required: no
  • Meaning: IPv6 aggregation mask for clients.

quick setup

Prefer the full configuration so qps, burst, and mask stay explicit.

Behavior

  • Applies rate limiting per source prefix rather than only per exact IP.
  • Useful for protecting upstreams or constraining abusive traffic.

Metrics

Exported through the global GET /api/metrics endpoint:

  • ratelimit_allowed_total
  • ratelimit_rejected_total

Typical Uses

  • Query throttling.
  • Split normal traffic and over-limit traffic into different branches.

string_exp

Purpose

Matches using a string expression over request and response context.

Example Configuration

- tag: match_http_path
type: string_exp
args: "url_path prefix /dns-"

It also supports a string array:

args:
- "client_ip"
- "prefix"
- "192.168."

Configuration Details

  • string_exp args can be a string or a string array.

  • Type: string or array

  • Required: yes

  • Default: none

  • Purpose: Defines the complete string expression.

  • Expression parts:

    • data source source
    • matching operator op
    • one or more arguments
  • Runtime impact:

    • Reads values from the context according to the expression and performs string matching.

Expression Format

<source> <op> <arg...>

Supported source values:

  • qname
  • qtype
  • qclass
  • rcode
  • resp_ip
  • mark
  • client_ip
  • server_name
  • url_path
  • $ENV_KEY

Supported op values:

  • eq
  • prefix
  • suffix
  • contains
  • regexp
  • zl
Notes
  • zl means zero length and is used to determine whether a string is empty.
  • regexp supports one or more regex arguments.

quick setup

- matches: "string_exp server_name suffix .example.net"

Typical Uses

  • Perform flexible matching on DoH paths, SNI, mark sets, and response IP strings.
Notes
  • In scenarios where a dedicated matcher can be used, prefer the dedicated matcher.
  • string_exp provides greater flexibility, but the readability and maintainability of the expression are usually lower than those of dedicated plugins.

_true

Purpose

Always returns true.

Example Configuration

- tag: always_true
type: _true

Configuration Details

No standalone configuration fields.

quick setup

- matches: "_true"

Typical Uses

  • Fallback match condition.
  • Testing rule order in a sequence.

_false

Purpose

Always returns false.

Example Configuration

- tag: always_false
type: _false

Configuration Details

No standalone configuration fields.

quick setup

- matches: "_false"

Typical Uses

  • Temporarily disable a branch.