fix(dns): answer the address a name actually has - #268
Merged
Conversation
Most of the registry could not be resolved by our own resolver. Every
name pointed at a host — seo.rank, chovy.hacker, alt.2600, all of them —
came back as an authoritative NOERROR with no answers, which a client is
entitled to treat as final.
That is the worst shape a failure can take. `dig` said the name existed,
nothing could reach it, and no log anywhere reported an error. google.com
resolved the whole time, so the machine looked healthy.
Two independent causes, both on the address path:
- RECORD_TYPES covered CNAME, MX and TXT only, so a published A or AAAA
record was never consulted for an address question. alt.2600 publishes
an AAAA in the registry and still answered nothing.
- targetAddress() returns null for a hostname, and nothing picked up
after it. The comment said turning a host into an address would mean
the bridge doing clearnet DNS — but it already forwards clearnet
queries upstream, so that reasoning had gone stale.
addressAnswer() replaces the old answerPolicy-then-look-for-a-CNAME pair
with one plan: target address, published A/AAAA, published CNAME, then a
CNAME synthesised from a hostname target. The cheap question is still
asked first, so a name pointed at a bare IP costs exactly one registry
call and no record fetch — the fast path every page load takes.
A bare CNAME would not have been enough. This bridge sets RA=0, so a stub
handed a dangling CNAME has been told in the same breath that nobody will
chase it; systemd-resolved reports that as a name with no address.
buildChainResponse() emits the leaf alongside it, best-effort, so a slow
upstream costs the extra record and never the answer.
DoH gets the same treatment. Its own comment said a name that resolves
over the bridge and not over DoH is the failure that endpoint exists to
remove, and it carried the identical gap.
Verified against the live registry before any test was written:
seo.rank. 30 IN CNAME dev.profullstack.com.
dev.profullstack.com. 30 IN A 67.205.189.229
alt.2600. 300 IN AAAA 2604:a880:400:d1:0:4:c3fe:1
One existing test changed rather than added to: it had recorded "a live
name pointed at a hostname is NODATA" as correct. It was the bug.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
ThreatCrush Security Scan87 finding(s) HIGH/CRITICAL: 50 | MEDIUM: 37
…and 37 more. Full results in the Security tab. Snippets are redacted; ThreatCrush never prints matched credential material. |
Merged
ralyodio
added a commit
that referenced
this pull request
Aug 3, 2026
Two resolver fixes, both of which look like working DNS from outside. #268 — a name pointed at a host answered an authoritative NOERROR with no records, which a client treats as final. seo.rank, chovy.hacker and alt.2600 were all unreachable while google.com resolved, so the machine looked healthy. RECORD_TYPES never consulted a published A or AAAA for an address question, and targetAddress() returned null for a hostname with nothing picking up after it. #267 — `dns enable` reported that a bridge already on the port "is being used as-is" and then started a second daemon anyway, which bound alongside it and took the queries the note promised to the first. Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Most of the registry could not be resolved by our own resolver. Every name pointed at a host — seo.rank, chovy.hacker, alt.2600, all of them — came back as an authoritative NOERROR with no answers, which a client is entitled to treat as final.
That is the worst shape a failure can take.
digsaid the name existed, nothing could reach it, and no log anywhere reported an error. google.com resolved the whole time, so the machine looked healthy.Two independent causes, both on the address path:
RECORD_TYPES covered CNAME, MX and TXT only, so a published A or AAAA record was never consulted for an address question. alt.2600 publishes an AAAA in the registry and still answered nothing.
targetAddress() returns null for a hostname, and nothing picked up after it. The comment said turning a host into an address would mean the bridge doing clearnet DNS — but it already forwards clearnet queries upstream, so that reasoning had gone stale.
addressAnswer() replaces the old answerPolicy-then-look-for-a-CNAME pair with one plan: target address, published A/AAAA, published CNAME, then a CNAME synthesised from a hostname target. The cheap question is still asked first, so a name pointed at a bare IP costs exactly one registry call and no record fetch — the fast path every page load takes.
A bare CNAME would not have been enough. This bridge sets RA=0, so a stub handed a dangling CNAME has been told in the same breath that nobody will chase it; systemd-resolved reports that as a name with no address. buildChainResponse() emits the leaf alongside it, best-effort, so a slow upstream costs the extra record and never the answer.
DoH gets the same treatment. Its own comment said a name that resolves over the bridge and not over DoH is the failure that endpoint exists to remove, and it carried the identical gap.
Verified against the live registry before any test was written:
One existing test changed rather than added to: it had recorded "a live name pointed at a hostname is NODATA" as correct. It was the bug.