ADR-0017: Controlled DNS queries for the default resolver 

Status

Accepted

Date

2026-10-10

Supersedes

ADR-0005 only for its default resolver choice.

Context 

ADR-0005: Bind the checked address set directly to the connection requires a complete, validated address set bound to the connection. Its historical proposal also selects dns_get_record() and records the absence of a hard interruption contract. The current implementation explicitly controls the resolution path, response validation and query deadlines. An implicit NSS, hosts-file or search-domain fallback would introduce a different target or trust boundary.

Decision 

LibraryServiceFactory wires StaticThenDnsResolver to WireDnsQuery. Only explicit static policy entries bypass DNS; their addresses remain subject to policy. Other names are queried as exact absolute FQDNs using A, AAAA and CNAME questions. There is no implicit NSS, /etc/hosts or search-domain fallback.

The wire backend uses numeric trusted nameservers from /etc/resolv.conf, read lazily at the first DNS query. At most three nameservers are allowed. Known directives are recognized without adopting their search or NSS semantics; unknown or invalid configuration is rejected. A trusted resolver may use a private infrastructure address. This does not grant permission for HTTP connections to private endpoint addresses.

DnsPacketCodec validates the transaction ID, question, response status, types, lengths and compression bounds. Only a valid response with the TC bit set repeats the same question over length-prefixed TCP within the same query deadline. Repeated truncation or unverifiable answers do not produce a usable resolution. The resolver follows the complete CNAME chain and bounds both hops and addresses. NativeOperation converts native warnings and notices to fixed failures without exposing their text.

The default deadline is one second per nameserver and question. Positive memo entries last at most five seconds and no longer than the smallest remaining TTL in the chain; using them still requires policy validation. The complete address checks and connection pinning in ADR-0005 remain binding. This ADR replaces only its historical default choice of dns_get_record().

Alternatives considered 

  • Unbounded dns_get_record as the default backend: lacks equivalent explicit control over the query deadlines used here.
  • Implicit NSS, hosts or search domains: changes the qualified resolution path and may introduce different targets.
  • Filter dangerous addresses or continue after DNS failure: violates the complete address-set validation required by ADR-0005.
  • TCP after any UDP failure: expands fallback beyond the validated truncation case.

Consequences 

DNS has a bounded, auditable flow but remains separate network traffic to trusted resolvers. The guard does not impose a process-wide network ban. NSS-specific names need an explicit static assignment or a qualified resolver implementation.

Three nameservers, nine names in the maximum CNAME chain and three query types can theoretically take up to 81 seconds sequentially, plus local overhead. This is not a guaranteed application and HTTP deadline. An SDK timeout does not create a general resolver cancellation contract. Custom resolvers are trusted internal extensions and must preserve complete, bounded and verifiable answers.

Sources and evidence 

The implementation is in Classes/HttpGuard/WireDnsQuery.php, Classes/HttpGuard/DnsPacketCodec.php, Classes/HttpGuard/StaticThenDnsResolver.php, Classes/HttpGuard/NativeOperation.php and Classes/Service/LibraryServiceFactory.php. Current bounds and scope are documented under DNS and static resolution.

Tests/HttpGuard/Unit/Policy/WireDnsQueryTest.php maintains real local UDP-to-TCP truncation and blackhole deadline probes, numeric-server controls and lazy configuration reading. Tests/HttpGuard/Unit/Policy/WireIoBoundaryContractTest.php and Tests/HttpGuard/Unit/Policy/DnsWireBoundaryContractTest.php exercise I/O and packet boundaries. Separate target-contact controls are in Tests/HttpGuard/Integration/DnsPolicyTransportTest.php. Previously executed source-bound results are under Verification report. This ADR records inspected sources and does not establish a new test run.

Reconsideration trigger 

New resolver protocols, NSS integration, search semantics or changes to deadlines and caching require renewed trust and evidence qualification. A different backend does not remove complete address validation or the binding between the validated addresses and the connection.