Commit graph

1 commit

Author SHA1 Message Date
Local Dev
83a8fff021 resolver: echo EDNS OPT record so strict clients stop failing
Root cause of the "Firefox 'Server Not Found' (github)" and Node
`getaddrinfo EAI_FAIL` reports against the shipped daemon: reply() in
bnsd.js built responses from scratch and never copied the query's EDNS0
OPT record from the additional section. RFC 6891 §6.1.1 requires the
response to echo OPT when the query carried one; strict clients (glibc
getaddrinfo, Firefox with TRR off) treat the missing OPT as FORMERR and
surface EAI_FAIL / "Server Not Found". Lenient clients (nslookup, Chrome
async-dns) tolerate the loss, which is why the bug looked flaky.

The prior commit (ef19db1) extracted src/lib/dns-server.js as a testable
surface but left bnsd.js still calling the old inline helpers. This
finishes the migration:

- src/lib/dns-server.js:
  - buildReply() now walks the additional section, finds the OPT RR by
    name=root/type=41, and appends it to the response. When the query
    had no OPT, none is fabricated (RFC 6891 §7). Preserves RD and
    opcode from the query rather than hardcoding 0x8580.
  - parseQuestion() rejects QDCOUNT != 1 and truncated labels early,
    and skipName() tolerates DNS compression pointers per RFC 1035
    §4.1.4 so the OPT walker doesn't trip on a compressed name.
  - forwardQuery() accepts "host" (default port 53) or "host:port" so
    it can be tested off port 53.

- src/daemon/bnsd.js: replaces the inline helpers with imports; the
  icann-first branch keeps its rcode-inspecting callback via a small
  forwardInspect() wrapper around the Promise-based forwardQuery.

- test/dns-server.test.mjs (new): 14 tests. Includes parseQuestion
  cases (plain / EDNS / bad QDCOUNT / truncated), buildReply invariants
  (OPT echoed / OPT never fabricated / RD preserved / NODATA still
  echoes OPT), full dns.Resolver round-trips against an in-process
  server (A / AAAA-NODATA / forward-to-mock-upstream), and two pinned
  regression tests that copy the OLD reply() verbatim and assert its
  OPT-dropping behavior so a future regression is caught immediately.

- AriadneResolver/ariadne-resolver/{src/daemon/bnsd.js, src/lib/dns-server.js}:
  synced from Argus so the packaged installer picks up the fix.

Pre-existing failures in test/portfolio-index.test.mjs (require is not
defined at src/lib/chain.js:54) are unrelated and predate this work.
2026-08-02 01:19:09 +02:00