dns.client — Lilush API

←index

← dns

Overview

High-level DNS resolver with caching, CNAME following, search list expansion, server failover, retry, and response validation. Ties together dns.message, dns.name, dns.cache, and dns.transport.* into a single resolve() call.

Functions

NameSignature
parse_resolv_confparse_resolv_conf(path) -> config, err
resolver:resolveresolver:resolve(qname, qtype) -> records, err
resolver:queryresolver:query(raw_bytes) -> msg, err
resolver:closeresolver:close()
newnew(cfg) -> resolver, err

parse_resolv_conf(path) -> config, err

Parse /etc/resolv.conf and return a config table

Reads and parses a resolv.conf file, returning a table suitable for passing to (or merging into) dns.client.new() configuration.

Parsed directives:

Fields are only present in the result when found in the file, allowing the caller to merge with their own defaults. Server entries have no port since standard resolv.conf has no port syntax; the transport default applies.

path defaults to "/etc/resolv.conf".

local dns_client = require("dns.client")

-- Use system resolvers
local sys = dns_client.parse_resolv_conf()
local r = dns_client.new(sys)

-- Merge with overrides
local sys = dns_client.parse_resolv_conf()
sys.timeout = 3
sys.use_tls = true
local r = dns_client.new(sys)

resolver:resolve(qname, qtype) -> records, err

Resolve a domain name to records of the specified type

Resolves qname by querying upstream servers with retry, failover, and optional caching. Follows CNAME chains (depth limit 10) and applies search list expansion based on ndots.

qtype is a record type as a string ("A", "AAAA", "MX") or number (1, 28, 15). String matching is case-insensitive.

Returns a list of matching answer records on success, each with name, type, class, ttl, and rdata fields. Returns nil, err on failure (NXDOMAIN, timeout, no servers, etc.).

local answers, err = resolver:resolve("example.com", "A")
if not answers then
    print("error: " .. err)
else
    for _, rr in ipairs(answers) do
        print(rr.rdata.address, "TTL", rr.ttl)
    end
end

-- MX records
local mx, err = resolver:resolve("gmail.com", "MX")
if mx then
    for _, rr in ipairs(mx) do
        print(rr.rdata.preference, rr.rdata.exchange)
    end
end

resolver:query(raw_bytes) -> msg, err

Send a pre-encoded DNS query and return the decoded response

Lower-level query interface. Sends raw_bytes as a DNS message to configured servers with retry and failover, returns the decoded response message table. No caching, no CNAME following, no response validation beyond successful decode.

resolver:close()

Close the resolver and release transport resources

new(cfg) -> resolver, err

Create a new DNS resolver

Configuration fields:

local dns_client = require("dns.client")
local dns_cache = require("dns.cache")

-- Simple resolver
local r = dns_client.new({ servers = { "1.1.1.1", "8.8.8.8" } })
local answers, err = r:resolve("example.com", "A")

-- Per-server port
local r = dns_client.new({
    servers = { { host = "127.0.0.1", port = 5353 }, "8.8.8.8" },
})

-- From system resolv.conf
local sys = dns_client.parse_resolv_conf()
local r = dns_client.new(sys)

-- DNS-over-TLS
local r = dns_client.new({
    servers = { "1.1.1.1" },
    use_tls = true,
})