nginx/nginx
Resolver
Active contributors: Maxim Dounin, Sergey Kandaurov, Roman Arutyunyan
Purpose
src/core/ngx_resolver.{c,h} is nginx's hand-rolled async DNS client. It exists because most of nginx's hot path runs inside a single-threaded event loop where getaddrinfo() is unacceptable — a blocking call freezes the whole worker. The resolver issues UDP DNS queries (with TCP fallback for truncated responses), caches answers, supports A / AAAA / SRV / PTR record types, and integrates with the rest of nginx through the standard event interface.
ngx_resolver.c is ~3,100 lines — large for src/core/, but justified by a feature surface that includes timeouts, retries across multiple resolvers, and a per-cycle cache.
Files
| File | Role |
|---|---|
src/core/ngx_resolver.{c,h} |
The async resolver |
Key abstractions
| Type | Role |
|---|---|
ngx_resolver_t |
Per-cycle state — UDP/TCP sockets, cache rbtrees, query queue |
ngx_resolver_ctx_t |
A pending resolve request — caller's callback, name, type |
ngx_resolver_node_t |
A cached entry (name + records + TTL deadline) |
ngx_resolve_create() |
Build a resolver from a resolver directive |
ngx_resolve_start() |
Allocate an ngx_resolver_ctx_t for a name |
ngx_resolve_name() |
Kick off resolution — calls back when answers arrive |
ngx_resolve_addr() |
Reverse PTR resolution |
ngx_resolve_name_done() |
Cancel + release a context |
How a resolution flows
sequenceDiagram
participant Caller
participant R as ngx_resolver_t
participant Cache as Cache rbtree
participant Net as UDP/TCP socket
participant DNS as Upstream DNS
Caller->>R: ngx_resolve_name(ctx, "example.com")
R->>Cache: lookup
alt cache hit (fresh)
Cache-->>R: addrs
R->>Caller: ctx->handler(ctx, addrs) (next event loop tick)
else cache miss / stale
R->>Net: send DNS query packet
R->>R: arm timer for retry
Net->>DNS: A/AAAA query
DNS-->>Net: answer
Net->>R: parse, validate
R->>Cache: insert with TTL
R->>Caller: ctx->handler(ctx, addrs)
endThe caller provides:
- The hostname (or IP for reverse).
- An
ngx_resolver_ctx_t.handlercallback. - An
ngx_resolver_ctx_t.timeoutin milliseconds. - An
ngx_resolver_ctx_t.datapointer for context.
When the answer arrives (or the timeout expires), the handler runs from the resolver's event handler. The caller's stack frame is gone by then; the resolver context is what carries forward the work.
Cache
Two rbtrees (per cycle):
- Name cache — keys by hostname, holds A and AAAA addrs.
- Address cache — keys by IP, holds reverse PTRs.
Each entry has a TTL deadline (expire) drawn from the DNS response's TTL. ngx_resolver_expire() runs from a timer to evict stale entries.
When a query is in flight, its node sits in a "waiting" state with a queue of ngx_resolver_ctx_t callers. Subsequent requests for the same name that arrive while the query is pending join the queue rather than firing a duplicate query (request collapsing).
Retries and multiple servers
resolver 8.8.8.8 1.1.1.1 valid=30s ipv6=off; configures multiple upstream resolvers. Queries round-robin across them; on timeout, the next server is tried. The valid= parameter overrides the DNS TTL (for cases where you want to cache longer than the upstream allows).
ipv6=off skips AAAA lookups entirely. ipv4=off skips A. When both A and AAAA are requested (the default), the resolver fires both queries in parallel and the callback fires when both complete (or times out).
Who uses it
- HTTP
proxy_pass http://hostname;with a literal hostname. - HTTP
resolverdirective at server scope plus dynamic upstream names. - Stream
proxy_pass hostname:port;. - Mail
auth_http http://hostname/. - OCSP stapling to fetch responses from the OCSP responder URL.
If proxy_pass http://hostname; is configured without a resolver directive in scope, hostnames are resolved once at config time (essentially a synchronous gethostbyname during reload). Adding resolver makes resolutions happen at request time.
Integration points
- Event loop — the resolver opens UDP and TCP sockets and registers them as connections. Read events drive query parsing.
- Cycle / configuration — the
resolverdirective instantiates anngx_resolver_t, attached to the per-context config. - Timers — query timeouts and cache expiry both ride on the standard timer rbtree.
Entry points for modification
Most changes here are bug fixes around edge cases (CNAME chains, DNAME, malformed answers). The DNS wire-format parser is hand-rolled and conservative — adding new record types means extending both the parser and a new variant of ngx_resolver_ctx_t. DoH (DNS over HTTPS) is not supported in mainline; the resolver speaks only RFC 1034/1035 over UDP and TCP.
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.