Skip to main content

Module dns_proxy

Module dns_proxy 

Source
Expand description

SEAM-1 / L2-04 DNS proxy — forward-only UDP proxy that enforces dnsAuthority.hostnameAllowlist at the DNS protocol layer and emits one per-query CloudEvent for every observed query.

§Phase 1 scope

  • UDP only. The single-listener proxy reads a workload query, parses the question section (see parser), evaluates the allowlist, then either forwards the bytes verbatim to the upstream do53-udp resolver or builds a REFUSED response on the spot. TCP fallback is documented as a follow-up.
  • Forward-only. No recursion, no caching. The proxy talks to a single declared upstream resolver per cell and relays the response (rcode, answers, additional records) verbatim to the workload, preserving the transaction id binding.
  • Allowlist-strict. A query whose name does not match an entry in hostname_allowlist (literal or single-leading-*. wildcard) is short-circuited with REFUSED — the upstream resolver never sees it.
  • Malformed-drop. Packets that fail parser::parse_query are dropped without a response (matching common resolver behaviour against adversarial input). The corresponding dns_query event still fires with reasonCode: malformed_query.
  • SERVFAIL on upstream timeout. When the upstream resolver fails to answer within DnsProxyConfig::upstream_timeout the proxy synthesizes a SERVFAIL response (RCODE=2) so the workload sees a deterministic error rather than hanging.

§What this module does NOT do

  • TCP fallback — workloads that get a TC (truncated) flag from upstream are expected to retry on TCP; Phase 1 forwards UDP-only and relays the truncated answer if the upstream sets TC. A real TCP listener path is a Phase 2 follow-up.
  • EDNS / DoT / DoH / DoQ upstream — Phase 1’s upstream is do53-udp only. The contract layer (DnsAuthority::resolvers[]) admits these protocols but the dataplane forwards over plain UDP.
  • No netns plumbing — the caller pre-binds the listening + upstream sockets in the cell’s network namespace and hands them to run_one_shot. This module is platform-neutral and contains no nsenter or setns calls.

§Caller responsibility

  • Pre-bind the listener socket on the address the workload’s /etc/resolv.conf points at (typically the same IP/port declared as a do53-udp resolver in dnsAuthority.resolvers[] so the existing nft accept rule lets the traffic through).
  • Pre-bind the upstream socket in the same netns; the proxy uses it for forwarding.
  • Drive the loop until shutdown.store(true) to terminate it; the listener’s read_timeout should be set to a short interval (e.g. 200ms) so the loop checks the shutdown flag promptly.

Modules§

dnssec
SEC-21 Phase 3h.1 — SEAM-1 in-netns DNS proxy DNSSEC validation.
parser
Minimal DNS message parser scoped to what the SEAM-1 / L2-04 proxy needs.
spawn
SEAM-1 Phase 2b — supervisor → cell-netns DNS proxy spawn.
upstream
SEC-21 Phase 3h.2 / T2.B Slot A6 — DoT/DoH/DoQ upstream support.

Structs§

DnsProxyConfig
Configuration for run_one_shot.
DnsProxyStats
Aggregate counters returned by run_one_shot when the loop terminates. Mirrors the cumulative state observed across a single cell run; the supervisor logs these at teardown for sanity-checking ratios.

Traits§

DnsQueryEmitter
Sink the proxy uses to publish per-query events. Trait-erased so unit tests can plug in an in-memory collector and the supervisor can adapt the production EventSink to a synchronous-fire-and-forget shape.

Functions§

run_one_shot
Run the proxy loop synchronously on the calling thread.
run_tcp_one_shot
SEAM-1 / L2-04 Phase 2 — TCP/53 listener variant of run_one_shot.