← CLI Docs

ThreatScript

Enterprise

DNS security automation — write Starlark policies that run at query time on your nameservers.

What is ThreatScript?

ThreatScript is a security DSL built on Starlark (a sandboxed Python dialect). Scripts run inside dnsscienced at query time, giving you per-query control over DNS responses — blocking, redirecting, logging, or allowing based on domain reputation, client IP, query type, and custom logic.

Sandboxed
No file access, no network calls, no eval(). Safe to run untrusted logic.
Hot-reload
Push a script and it's live immediately — no server restart needed.
Python-like
If you know Python, you already know ThreatScript syntax.

Deploy your first script

block-malware.star

def main(query):
    score = threat.score(query.domain)
    if score > 80:
        dns.nxdomain(query)
        log.alert("blocked: " + query.domain + " (score=" + str(score) + ")")
        return
    dns.allow(query)
onedns script push block-malware.star --name "Block high-risk domains"

The script is pushed to all dnsscienced nodes and begins executing on the next query.

Script anatomy

def main(query):
    # query.domain  — queried domain name (string)
    # query.type    — record type: "A", "AAAA", "MX", etc.
    # query.client  — client IP address (string)

    # Your logic here...

    dns.allow(query)    # permit the query
    # or
    dns.nxdomain(query) # respond NXDOMAIN
    # or
    dns.drop(query)     # silently drop

Every script must define a main(query) function. Execution is bounded to 2ms per query. Scripts that exceed the time limit are skipped with a logged error.

Module reference

dns — Query control

Function Description
dns.allow(query)Permit the query and pass to resolver
dns.nxdomain(query)Return NXDOMAIN response
dns.drop(query)Silently drop — no response sent
dns.blackhole(query)Return 0.0.0.0 (sinkhole)
dns.redirect(query, "upstream:53")Forward query to a specific upstream

threat — Threat intelligence

Function Description
threat.score(domain)Risk score 0–100 for a domain
threat.score_ip(ip)Risk score for a client IP address
threat.is_dga(domain)True if domain appears algorithmically generated
threat.is_tunnel(domain)True if domain shows DNS tunneling patterns

log — Logging

Function Description
log.info(msg)Informational log entry
log.warn(msg)Warning log entry
log.alert(msg)Alert-level log entry (triggers monitoring)

Example scripts

Block DGA domains

def main(query):
    if threat.is_dga(query.domain):
        dns.nxdomain(query)
        log.alert("DGA blocked: " + query.domain)
        return
    dns.allow(query)

Block DNS tunneling

def main(query):
    if query.type == "TXT" and threat.is_tunnel(query.domain):
        dns.drop(query)
        log.alert("DNS tunnel blocked from " + query.client)
        return
    dns.allow(query)

Block by client IP range

BLOCKED_CIDRS = ["192.0.2.0/24", "203.0.113.0/24"]

def main(query):
    for cidr in BLOCKED_CIDRS:
        if net.contains(cidr, query.client):
            dns.drop(query)
            return
    dns.allow(query)

Tiered threat response

def main(query):
    score = threat.score(query.domain)

    if score >= 90:
        dns.drop(query)          # highest risk: silent drop
    elif score >= 75:
        dns.nxdomain(query)      # high risk: NXDOMAIN
        log.alert("blocked " + query.domain)
    elif score >= 50:
        log.warn("suspicious: " + query.domain + " score=" + str(score))
        dns.allow(query)         # medium risk: log and allow
    else:
        dns.allow(query)

Managing scripts

# Push a script (creates or replaces by ID)
onedns script push block-malware.star

# Specify a custom ID (default: filename without .star)
onedns script push my-policy.star --id production-block

# Remove a script
onedns script delete production-block

# Check execution stats (runs, errors, blocked queries)
onedns script stats

Limits & constraints

Limit Value
Max execution time per query2ms
No file system accessScripts are fully sandboxed
No network calls from scriptsUse threat module for intel lookups
LanguageStarlark (Python subset)