resolver: a nameserver is asked at each of its addresses in turn (closes #285)
check / check (push) Canceled after 0s

A nameserver's queries went only to the first IPv4 address its name
resolves to, so one unreachable address made it fail whenever that
address came first in the answer. Each record type is now asked at the
addresses one at a time until one gives a usable reply, and the next
type is asked first at the address that gave it. A type that fails is
logged with the reason at each address, and a nameserver is reported as
timed out only when every query timed out; one given no address has
failed. The README's DNS Resolution Strategy says which addresses are
asked.

Model: opus-5-5
This commit is contained in:
2026-10-15 11:37:47 +00:00
committed by sneak
parent b79726acc6
commit 0059d96780
7 changed files with 260 additions and 91 deletions
+18 -12
View File
@@ -133,18 +133,19 @@ notification endpoint set, changes show only on the dashboard; see
- Queries **each** authoritative nameserver independently for **all** record
types: A, AAAA, CNAME, MX, TXT, SRV, CAA, NS.
- Each record type is a query of its own. When a nameserver answers some types
but the query for another gets no usable reply (no reply after two tries, an
error reply such as SERVFAIL, a referral, or a reply too large for UDP whose
retry over TCP fails), the failure is logged with the reason, and the type is
listed in the nameserver's `failedTypes` and keeps the records saved for the
nameserver by the previous check. On that check those records are not compared
with the other nameservers', so no record change or inconsistency is reported
for the type; on the next check they are compared with the nameserver's answer
as usual. When the previous check did not know the type's records either,
because the nameserver was new or failing then or the type was already listed
in `unknownTypes`, the type is also listed in `unknownTypes` and left out of
every comparison until it answers. A nameserver none of whose queries got a
usable reply has failed (see NS query failure below).
but the query for another gets no usable reply at any of its addresses (no
reply after two tries, an error reply such as SERVFAIL, a referral, or a reply
too large for UDP whose retry over TCP fails), the failure is logged with the
reason, and the type is listed in the nameserver's `failedTypes` and keeps the
records saved for the nameserver by the previous check. On that check those
records are not compared with the other nameservers', so no record change or
inconsistency is reported for the type; on the next check they are compared
with the nameserver's answer as usual. When the previous check did not know
the type's records either, because the nameserver was new or failing then or
the type was already listed in `unknownTypes`, the type is also listed in
`unknownTypes` and left out of every comparison until it answers. A nameserver
none of whose queries got a usable reply has failed (see NS query failure
below).
- Stores results **per nameserver**. The state for a hostname is not a merged
view — it is a map from nameserver to record set.
- DNS names inside record values (CNAME, MX, SRV and NS targets) are stored in
@@ -549,6 +550,11 @@ name's nameservers and in the lookup of a nameserver's own address. Such a
lookup can need others in turn; lookups go at most three deep, one inside
another, so delegations that point at each other still end.
In step 4 each record type is asked at the IPv4 addresses the nameserver's name
resolves to, one at a time, until one gives a usable reply; the next type is
asked first at that address. A type's query fails only when none of them gives
one, and the nameserver has failed only when that is so for every type.
This approach ensures:
- Independence from any upstream resolver's cache or filtering.