Description
I mentioned in #12476 that I would like to detect the time it took for DNS resolution phase of the Dial process in Dialer.Dial
. The solution posted there was very hacky and adds unnecessarily to the API.
@bradfitz suggested
Perhaps
net.Dialer
could have an optionalResolver
, akin to howhttp.Client
has an optionalTransport
, orhttp.Server
has an optionalErrorLog
, etc.
This seems like an excellent idea. Here is how I propose we go about it by adding minimal complexity and preserving code compatibility.
I propose net package adds a new Resolver
interface.
type Resolver interface {
Resolve(host string, deadline time.Time) (addrs []IPAddr, err error)
}
The signature of Resolver.Resolve
is same as lookupIPDeadline
which Dial
eventually uses. Dialer
gets an optional field CustomResolver
of type Resolver
.
The Resolver
object (or nil
) gets passed around thru the resolution process.
Dialer.Dial
-> resolveAddrList
-> internetAddrList
.
internetAddrList
currently always uses lookupIPDeadline
, it would need to be changed such that if the passed custom resolver is not nil then use it, otherwise use lookupIPDeadline
.
Other functions calling resolveAddrList
or internetAddrList
would need to be modified to add an extra nil
argument . This does not break code compatibility because they are unexported functions.
Benefits of allowing a custom Resolver
- Allowing me to collect timing information as mentioned in net: I would like Dialer.Dial to provide the time it took to do DNS lookups and TCP Connect #12476
- Allowing users to implement their own DNS logic. Failovers, etc.
- Mocking for tests.
- Client side caching, pre-fetching, etc.
- In time, other packages ( like the superb github.com/miekg/dns ) could provide their own
Resolver
implementations. - Great for people like me who rely on Go to write network debugging tools.
Activity
[-]proposal: Allow passing of custom Resolver to Dialer.dial in package net[/-][+]proposal: Allow passing of custom Resolver to Dialer.Dial in package net[/+][-]proposal: Allow passing of custom Resolver to Dialer.Dial in package net[/-][+]proposal: Allow passing of custom Resolver to net.Dialer[/+]sajal commentedon Sep 9, 2015
Should I implement and submit the change for codereview? Or wait for some comments here?
bradfitz commentedon Sep 9, 2015
No need to prototype it yet. The code will be relatively easy compared to getting the design right.
I suspect that signature isn't general enough. Maybe it's good enough for a dialer, but perhaps it needs a different name.
I bet we don't want to define an interface in the net package. If anything, it could just be an optional func type on the Dialer, similar to funcs on http://golang.org/pkg/net/http/#Transport
sajal commentedon Sep 9, 2015
Perhaps call it
Lookupfunc
(or better name) and deadline-ing is handled inside net package. It might mirror signature ofnet.LookupIP
which is used by default ifLookupfunc
is nil.Anything that does a lookup could ask for optional field for
Lookupfunc
to allow user to provide their own implementation.[-]proposal: Allow passing of custom Resolver to net.Dialer[/-][+]proposal: allow net.Dialer to use custom resolver[/+][-]proposal: allow net.Dialer to use custom resolver[/-][+]proposal: net: allow Dialer to use custom resolver[/+]benburkert commentedon Nov 5, 2015
I would also like to see a
Resolver
interface but with multiple methods that match thenet.Lookup*
funcs.The timeout & deadline functionality could be configured when the resolver is created:
59 remaining items
cevatbarisyilmaz commentedon Nov 6, 2019
I pushed the commit though I didn't really test it yet (at least it didn't disrupt the current tests). Feel free to open an issue in the repo for any further things.
jmalloc commentedon Nov 6, 2019
Is there any chance that whatever approach is taken here (in the
net
package I mean) could/would allow for building a resolver that supports multicast DNS (even if it's only legacy queries)? It seems that native Go implementation does not support mDNS, and hence it is unavailable when building with CGO disabled.ncruces commentedon May 29, 2020
See github.com/ncruces/go-dns for more "prior art" on hooking into
net.Resolver.Dial
. Implemented caching, opportunistic encryption and DoH/DoS.This bit implements the strategy mentioned in the above comment (a fake
net.Conn
that you can return fromDial
). With this in place, implementing the DoH exchange is a relatively simple matter.codeskyblue commentedon May 13, 2021
I figured out the code bellow.
aojea commentedon Sep 7, 2021
@bradfitz check if this similar to what you had in mind https://go-review.googlesource.com/c/net/+/347850
ns-jisorce commentedon Dec 7, 2021
Hi @aojea Hi @bradfitz , any update on this ? Thx
TyeMcQueen commentedon Nov 16, 2022
I've prototyped a fairly simple change that significantly narrows the required customization to a single-function interface that doesn't abstract everything that Resolver does, just the part that is used by net.Dialer (and thus by net/http), namely the internetAddrList() private method.
In the net package, I add (in dial.go in my prototype):
And allow users to provide an alternate implementation for net.Dialer to use.
For maximum usefulness, it is best to also allow a *net.Resolver to be used as an InternetAddrLister so people can provide a replacement by just wrapping around the existing net.Resolver implementation (for cases where they want to do light customization rather than provide a whole custom resolution implementation).
I think this function is a very useful abstraction (and the Go authors appear to agree since this is used quite a few places) and we should just make it a public method of Resolver.
I can submit my changes but I wanted to align on the approach before doing so.
tests: add rudimentary tests for resolveIPs
tests: add rudimentary tests for resolveIPs
Allow FQDN as the control plane endpoint host