Lookups
lookup(table, key) and lookup_ip(name, addr) are global functions in Rhai for rules that read named tables and views declared under data_sources: — exact-key CSV with lookup, longest-prefix CIDR with lookup_ip. The config, file formats, load-safety limits, and reload behavior live on Data sources; this page covers the Rhai calling surface and patterns.
Both are global functions — not methods on txn — and they read data_sources: policy tables, not the Lookup pipeline phase. See Glossary — Lookup vs lookup(table, key). Which hooks may call them is covered under Hooks and phases — phase guards.
Overview
| Function | Returns |
|---|---|
lookup(table, key) |
Exact-key CSV — the value string, or "" on miss |
lookup_ip(name, addr) |
Longest-prefix CIDR — the value string, or "" on miss |
Only names listed under data_sources: are visible to scripts — see the grant model. Both calls count toward sandbox limits (rhai.max_operations, rhai.hook_timeout_ms) like other host calls.
lookup behavior
let action = lookup("blocklist", txn.question().qname);
| Situation | Return value | Observability |
|---|---|---|
| Key found | Value cell as string | — |
| Key not in table | "" |
Silent (expected miss) |
Unknown table name (not in data_sources:) |
"" |
Warn log (milestone + periodic) and conduit_script_errors_total (reason="lookup_unknown_table") |
| Empty value cell | "" (still a “hit” if key exists — rare in practice) |
— |
Compile-time check: when the table argument is a string literal in Rhai source (for example lookup("blocklist", …)), Conduit validates the name against data_sources: at snapshot build. A typo fails conduitctl validate and reload. Dynamic table names (variable or expression) are not checked at compile time — they surface at runtime with the observability row above.
Use txn.question().qname for qname-keyed tables. On the response hook, the question is unchanged from the client query.
lookup_ip behavior
// Hit → non-empty string (value or membership marker); miss → ""
if lookup_ip("corp_nets", txn.client_ip()) != "" {
txn.set_tag("corp", true);
}
lookup_ip does a longest-prefix match over a named type: cidr view: the most-specific matching prefix wins, a hit returns a non-empty string (the trailing value, or a membership marker when the line has none), and a miss returns "". IPv4 and IPv6 are both first-class. File format and file-side semantics: Data sources — CIDR sources.
The same type: cidr views back host Client ACLs; use lookup_ip when you want the membership decision inside a rule script instead of the host ACL gate.
Patterns
Blocklist (request hook)
Script blocklist.rhai:
if lookup("blocklist", txn.question().qname) == "block" {
txn.drop_query_now();
}
Config: inline conduit.yaml beside the CSV — see Rhai policy — Blocklist drop.
Tag for observability
Script lookup-demo.rhai:
let region = lookup("geo", txn.question().qname);
if region != "" {
txn.set_tag("region", region);
}
Downstream sinks can filter on tag_required or rules can branch on txn.has_tag("region"). Walkthrough: Event export and dnstap — Tag-gated export.
Pool or egress map
let pool = lookup("routing", txn.question().qname);
if pool != "" {
txn.set_pool(pool);
} else {
txn.clear_pool();
}
List set_pool before rhai on the same rule when the script only refines pool choice and built-ins must run first — see Action order on one rule.
Runnable examples
| Script | In repository fixtures? | What it shows | Walkthrough |
|---|---|---|---|
blocklist.rhai |
Yes (tests/fixtures/rhai/) |
Drop on CSV block |
Rhai policy — Blocklist |
route-by-table.rhai |
Guide only (copy from lab YAML) | CSV qname → pool | Rhai policy — CSV pool routing |
lookup-demo.rhai |
Yes | Grant model — only configured tables | Tag for observability |
block-hits.rhai |
Yes | Lookup + user metrics | User metrics |
Limitations (current release)
- Read-only from scripts — no write-back or per-query cache invalidation.
- Rhai for rules only —
lookupandlookup_ipare available to rule scripts on the request and response hooks. - Dynamic (non-literal) table names are validated at runtime, not at compile time.
- Source types and load caps: see Data sources — Limitations.
Related topics
- Data sources —
data_sources:config, CSV / CIDR file formats, load-safety limits, reload - Host API overview — where lookups sit in the Rhai surface
- Rhai for rules — when to use scripts vs built-in selectors
- Sandbox limits — operation and timeout caps
- Event export — tags set from lookup results