DNS
Name resolution is where a connection starts, and increasingly where it is configured:
an HTTPS record can carry the ALPN list, an alternative port, address hints, and
the ECH configuration. Testing that means talking to real resolvers, because no two of them
return quite the same thing.
Current results
Observed resolver answers
The matrix below is recorded by DohMatrixTest; it is evidence, not a static description of resolver policy.
Probed endpoints
Why it lives here
OkHttp's own test suite can verify that a DNS message parses. It cannot verify that
1.1.1.1 still answers an HTTPS query the way it did last month, that a
resolver on the path does not strip service metadata, or that a record's address hints point
somewhere reachable. Those are properties of the internet, checked by running against it.
Specifications
| Document | Title | Why it matters here |
|---|---|---|
| RFC 8484 | DNS Queries over HTTPS (DoH) | What okhttp-dnsoverhttps implements, and the portable way to ask for record types the platform resolver will not return. |
| RFC 9460 | Service Binding and Parameter Specification via the DNS | SVCB and HTTPS records: ALPN, port, IP hints, and AliasMode. Requested with includeServiceMetadata(true). |
| RFC 9848 | Bootstrapping TLS Encrypted ClientHello with DNS Service Bindings | The ech SvcParam — the DNS half of ECH. |
| RFC 8305 | Happy Eyeballs Version 2 | How the addresses a resolver returns are raced. Behaviour depends on getting genuinely mixed A/AAAA answers. |
| RFC 6555 | Happy Eyeballs: Success with Dual-Stack Hosts | The original dual-stack connection strategy that RFC 8305 refines. |
| RFC 1035 | Domain Names — Implementation and Specification | The wire format every DoH response is still encoded in. |
| RFC 5890 · RFC 3492 | Internationalized Domain Names, and Punycode | Hostname canonicalisation before a name is ever resolved. |
What the resolver results exercise
| Endpoint | Operator | Notes |
|---|---|---|
| https://1.1.1.1/dns-query | Cloudflare | Addressed by IP, so resolving the resolver does not itself need a resolver. Its current answer is shown in the recorded matrix above. |
| https://dns.google/dns-query | A second implementation whose recorded answer can be compared above. | |
| https://dns.quad9.net/dns-query | Quad9 | Filtering resolver; useful for checking behaviour when an answer is withheld. |
| https://dns.adguard-dns.com/dns-query | AdGuard | Filtering again, by different rules — so two filtering resolvers can disagree with each other rather than only with the unfiltered pair. |
| The platform resolver | — | On Android, AndroidDns can return service metadata directly. Off-device this is where DoH is needed instead. |
Reading the resolver matrix
The matrix on the status page asks every resolver the same handful
of names each run and records what came back. Two names are assertions — a control that
everyone must resolve, and an .invalid name that nobody may — and the rest are
recorded without judgement, because filtering is a policy rather than a defect.
sinkholed is the outcome worth looking for. A filtering resolver can withhold an
answer, or it can answer 0.0.0.0, and the second reaches a caller as a
successful lookup that then fails to connect — a far quieter failure than a resolution
error, and one that looks like a client bug from the inside.
Reading a result
DNS failures are the most environment-sensitive results the testbed produces. Before treating
one as an OkHttp bug, check whether the same query answers the same way from another network:
a CI runner's egress path, a captive resolver, or a rate limit at the resolver will all show up
as a client failure. A difference between two resolvers for the same name is a finding worth
keeping, not necessarily a bug in either — which is why a resolver that could not be reached is
recorded as unavailable rather than folded in with one that said no.