Skip to content

Conversation

@aarongable
Copy link
Contributor

@aarongable aarongable commented Dec 5, 2025

Change the exported methods of the bdns package to have consistent arguments and return values. Specifically:

  • Split LookupHost into two more specific methods, LookupA and LookupAAAA.
  • Since each method now returns the results of a single DNS query, update all four Lookup methods to return only a single resolver, rather than a slice of resolver addresses.
  • Create a new generic "Result" type, which embeds the upstream miekg/dns.Msg type, and also helpfully extracts all the answer records of a specific type. This embedding is important for the future, since we want to extract this result's Authenticated Data bit and all CNAME hops for logging in the VA.
  • Use this new type as the return type for all four Lookup methods, removing the custom pre-processing (e.g. producing a dig-like string for CAA lookups, or filtering out Restricted IP addresses) from each method.

This unification and simplification allows us to streamline the body of bdns.exchangeOne, to reduce code duplication around incrementing metrics and clarify the retry loop's exit condition. Importantly, bdns.Exchange (which actually performs the DoH network calls) remains untouched.

As a result of the changes to LookupA and LookupAAAA, move most of LookupHost's old logic into the VA's getAddrs function. We're still doing the exact same merging and filtering of IP addresses, just within the VA rather than within the DNS abstraction layer. This also moves usage of the allowRestrictedAddrs boolean from bdns.Client to va.impl, and allows us to remove bdns.NewTest.

These interface changes require extensive test changes to match. Strip the bdns.MockClient down to almost nothing, because its guts had far too much knowledge of the desires of specific tests in a wholly different package (the VA). Instead, break the MockClient down into three much smaller fakes, and move them into the VA test files that actually need them. Have each test case explicitly specify which fake it is using, encouraging the use of smaller and more test-specific fakes in the future. Finally, use this opportunity to turn multiple linear tests into table-driven tests.

Part of #2700

@aarongable aarongable marked this pull request as ready for review December 9, 2025 00:57
@aarongable aarongable requested a review from a team as a code owner December 9, 2025 00:57
@aarongable aarongable requested a review from jprenken December 9, 2025 00:57
jprenken
jprenken previously approved these changes Dec 9, 2025
@jprenken jprenken requested review from a team and jsha and removed request for a team December 9, 2025 04:38
Copy link
Contributor

@jsha jsha left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(partial review)

bdns/dns.go Outdated
resp *dns.Msg
err error
}
ch := make(chan dnsRes, 1)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reusing this channel across multiple attempts makes the logic about writes, readers, and blocking a little less clear.

It's not totally clear to me why we fire off a goroutine here - probably it predates the availability of ExchangeContext in miekg/dns.

I'm inclined to further clean this up: delete the channel, don't spin off a goroutine, rely on net/http to honor the context deadline.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good call. Had to update the exchanger interface to add the context argument, but the result does really simplify this loop.

This does have one side effect, though: we can no longer inherently tell the difference between our own contexted getting canceled and the error coming from somewhere deeper in the stack. context.DeadlineExceeded implements the net.Error interface and sets .Timeout() to return true, so we have to explicitly indicate that DeadlineExceeded is not retryable. This could come back to bite us if some lower layer of the stack sets a tighter (e.g. 50ms shorter) deadline than we pass in, and we've previously been retrying those.

@beautifulentropy beautifulentropy self-requested a review December 10, 2025 21:07
@beautifulentropy
Copy link
Member

This is a deep and well thought out change with a lot of improvements! I'm still looking through your test changes, but I wanted to get these comments out to you as soon as possible.

// LookupTXT is a mock
func (mock *MockClient) LookupTXT(_ context.Context, hostname string) ([]string, ResolverAddrs, error) {
// Use the example account-specific label prefix derived from
// "https://example.com/acme/acct/ExampleAccount"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So stoked to move this action-at-a-distance to up-close-and-personal in the va package!

jprenken
jprenken previously approved these changes Dec 11, 2025
@aarongable aarongable merged commit be957c2 into main Dec 13, 2025
17 checks passed
@aarongable aarongable deleted the refactor-dns branch December 13, 2025 05:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants