[GH-ISSUE #1860] Empty NOERROR responses from trusted resolvers are incorrectly retried #794

Closed
opened 2026-03-16 00:16:01 +03:00 by kerem · 0 comments
Owner

Originally created by @jeff-hiner on GitHub (Dec 15, 2022).
Original GitHub issue: https://github.com/hickory-dns/hickory-dns/issues/1860

Describe the bug
Empty authoritative NOERROR responses from trusted resolvers should not be retried elsewhere.

Many domains are valid but aren't able to serve IPv6 traffic. A compliant resolver will respond to an AAAA record request for such a domain with an authoritative response: an empty answer set, and one or more SOA records describing how it was able to make the determination. This is not an error, nor does it imply that a client should ask other resolvers for a "better" answer.

This means a lookup matching this pattern will not return until every resolver in the list has been queried. In practice, a single slow or misbehaving DNS server in the list can cause these queries to take far longer than they should, even if queries are run in parallel.

To Reproduce
This is most easily demonstrated with a set of serialized servers.

Create a ResolverConfig with more than one DNS server in the list. (I use 1.1.1.1 and 1.0.0.1 but you can pick any two valid DNS servers.) Make sure the trust_nx_responses field for each resolver is true.

Build a ResolverOpts, setting its num_concurrent_reqs to 1 to serialize server hits, and server_ordering_strategy to ServerOrderingStrategy::UserProvidedOrder for repeatability.

Create an AsyncResolver with the pieces above. Successful requests should complete after receiving a response from the first resolver in the list, and not query the second resolver. Monitor DNS traffic using wireshark, and send an A record request that you know is valid. Note that no query is issued to the second resolver. Now try issuing a AAAA request with no records. m.dict.cc. works fine for this. Note that the response comes back from the first resolver, and then trust-dns queries the next server.

For extra fun, try appending an IP address to the server set that's blackholed or unreachable. Regardless of how num_concurrent_reqs is set, empty AAAA queries will wait until the bad server times out before returning a result.

Expected behavior
For records that may return empty answer sets, like HTTPS or AAAA against domains that don't host IPv6, the resolver should return the first NOERROR immediately without having to wait for responses from every resolver in the set.

System:

  • OS: any
  • Architecture: any
  • rustc version: 1.66 stable

Version:
Crate: resolver
Version: main

Additional context
Amusingly, the existing behavior is documented in NameServerConfig. But it's not correct.

Originally created by @jeff-hiner on GitHub (Dec 15, 2022). Original GitHub issue: https://github.com/hickory-dns/hickory-dns/issues/1860 **Describe the bug** Empty authoritative NOERROR responses from trusted resolvers should not be retried elsewhere. Many domains are valid but aren't able to serve IPv6 traffic. A compliant resolver will respond to an AAAA record request for such a domain with an authoritative response: an empty answer set, and one or more SOA records describing how it was able to make the determination. This is not an error, nor does it imply that a client should ask other resolvers for a "better" answer. This means a lookup matching this pattern will not return until every resolver in the list has been queried. In practice, a single slow or misbehaving DNS server in the list can cause these queries to take far longer than they should, even if queries are run in parallel. **To Reproduce** This is most easily demonstrated with a set of serialized servers. Create a `ResolverConfig` with more than one DNS server in the list. (I use `1.1.1.1` and `1.0.0.1` but you can pick any two valid DNS servers.) Make sure the `trust_nx_responses` field for each resolver is `true`. Build a `ResolverOpts`, setting its `num_concurrent_reqs` to `1` to serialize server hits, and `server_ordering_strategy` to `ServerOrderingStrategy::UserProvidedOrder` for repeatability. Create an `AsyncResolver` with the pieces above. Successful requests should complete after receiving a response from the first resolver in the list, and not query the second resolver. Monitor DNS traffic using wireshark, and send an A record request that you know is valid. Note that no query is issued to the second resolver. Now try issuing a AAAA request with no records. `m.dict.cc.` works fine for this. Note that the response comes back from the first resolver, and then `trust-dns` queries the next server. For extra fun, try appending an IP address to the server set that's blackholed or unreachable. Regardless of how `num_concurrent_reqs` is set, empty AAAA queries will wait until the bad server times out before returning a result. **Expected behavior** For records that may return empty answer sets, like HTTPS or AAAA against domains that don't host IPv6, the resolver should return the first NOERROR immediately without having to wait for responses from every resolver in the set. **System:** - OS: any - Architecture: any - rustc version: 1.66 stable **Version:** Crate: resolver Version: main **Additional context** Amusingly, the existing behavior is [documented in `NameServerConfig`](https://docs.rs/trust-dns-resolver/latest/trust_dns_resolver/config/struct.NameServerConfig.html#structfield.trust_nx_responses). But it's not correct.
kerem closed this issue 2026-03-16 00:16:06 +03:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/hickory-dns#794
No description provided.