Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

proposal: net: add API to override DNS servers #19268

Closed
teknoraver opened this issue Feb 24, 2017 · 23 comments

Comments

Projects
None yet
8 participants
@teknoraver
Copy link

commented Feb 24, 2017

What version of Go are you using (go version)?

go version go1.8 linux/amd64

What operating system and processor architecture are you using (go env)?

GOARCH="amd64"
GOBIN=""
GOEXE=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOOS="linux"
GOPATH="/home/matteo/go"
GORACE=""
GOROOT="/usr/lib/go-1.8"
GOTOOLDIR="/usr/lib/go-1.8/pkg/tool/linux_amd64"
GCCGO="gccgo"
CC="gcc"
GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build344172046=/tmp/go-build -gno-record-gcc-switches"
CXX="g++"
CGO_ENABLED="1"
PKG_CONFIG="pkg-config"
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"

Feature request

It could be useful to set the DNS servers used for queries, both globally or in net.Lookup*

draft implementation: https://go-review.googlesource.com/37434

@bradfitz bradfitz changed the title override DNS servers used by net.Lookup proposal: net: add API to override DNS servers Feb 24, 2017

@bradfitz bradfitz added the Proposal label Feb 24, 2017

@bradfitz

This comment has been minimized.

Copy link
Member

commented Feb 24, 2017

If we do this, why just the DNS servers? What about options? Perhaps an API to set the string contents of a /etc/resolv.conf file, which we already have a parser for?

/cc @mdempsky

@bradfitz bradfitz added this to the Proposal milestone Feb 24, 2017

@nightlyone

This comment has been minimized.

Copy link
Contributor

commented Feb 24, 2017

This will lead to hard to discover bugs in DNS configuration which can not be observed from the outside of a binary. I expect this to lead to Go binaries getting a bad reputation among people operating systems with such binaries.

Adding environment variables to achieve these effects can be observed and discovered from the outside and can implement the same API via self exec with those environment variables set.

@mdempsky

This comment has been minimized.

Copy link
Member

commented Feb 27, 2017

Perhaps an API to set the string contents of a /etc/resolv.conf file, which we already have a parser for?

I think this would be unfortunate, since /etc/resolv.conf is semi OS-specific. Also, some OSes use multiple files for config (e.g., gai.conf and nsswitch.conf on Linux).

I'd rather expose dnsConfig itself somehow, though I also worry that would limit our flexibility in supporting new OS-specific resolver behavior in the future.

@teknoraver

This comment has been minimized.

Copy link
Author

commented Feb 27, 2017

Or just expose some basic info like the DNS addresses, and allow to replace them.
Actually there is no way in Go to do a DNS query using a custom DNS.
Even some argument in net.Lookup* or functions which allows this could be usefult too

@rsc

This comment has been minimized.

Copy link
Contributor

commented Feb 27, 2017

Does the C library allow this? If so, how?

@bradfitz

This comment has been minimized.

Copy link
Member

commented Feb 27, 2017

Adding a field to net.Resolver seems like the right place if we add something. The top-level Lookup funcs use DefaultResolver.

@mdempsky

This comment has been minimized.

Copy link
Member

commented Feb 27, 2017

Does the C library allow this?

I don't see any functionality like this in glibc. If it exists, it's unlikely to be portable to other OSes.

@rsc

This comment has been minimized.

Copy link
Contributor

commented Feb 27, 2017

Actually there is no way in Go to do a DNS query using a custom DNS.

But if there's no way in C either, then I'm not too worried. There already exist third-party DNS clients for Go. https://github.com/miekg/dns in particular is very good.

I think we know how we'd do this. What's missing so far is a strong justification for adding that API complexity. Why is this important to users? In what context does it make sense to override the DNS config in Go but not other languages, or in one program but not others? Why not just always override system-wide?

@ianlancetaylor

This comment has been minimized.

Copy link
Contributor

commented Feb 28, 2017

In C, you can change the set of name servers to query by calling res_init and then changing the nscount and nsaddr_list fields of the _res global variable declared in <resolv.h>. This is not seriously documented, but programs do it, and books refer to it; e.g., the O'Reilly DNS and Bind book: http://docstore.mik.ua/orelly/networking_2ndEd/dns/ch15_02.htm .

@teknoraver

This comment has been minimized.

Copy link
Author

commented Feb 28, 2017

So it could be done with something like:

// #include <resolv.h>
import "C"
...
net.DefaultResolver.PreferGo = false

C.res_init()
C.__res_state().nscount = 1
C.__res_state().nsaddr_list[0].sin_addr.s_addr = 0xDEDE43D0 // resolver1.opendns.com

net.LookupIP("example.com")
@bradfitz

This comment has been minimized.

Copy link
Member

commented Feb 28, 2017

PreferGo = false doesn't do what you think. False is the default (zero) value. That boolean only prefers Go. It doesn't prefer C if false.

@teknoraver

This comment has been minimized.

Copy link
Author

commented Feb 28, 2017

ok, so it could be done with that snippet and GODEBUG=netdns=cgo

@rsc

This comment has been minimized.

Copy link
Contributor

commented Mar 6, 2017

If we do implement this, let's make it force use of the pure Go resolver and not try to implement in C by scribbling over C library data structures.

What I wrote above is still true:

What's missing so far is a strong justification for adding that API complexity. Why is this important to users? In what context does it make sense to override the DNS config in Go but not other languages, or in one program but not others? Why not just always override system-wide?

@teknoraver

This comment has been minimized.

Copy link
Author

commented Mar 6, 2017

The context is: sending a DNS request to a specific server instead of the system one,
without having to create and send the packet by hand (and parse the reply as well)

@rsc

This comment has been minimized.

Copy link
Contributor

commented Mar 6, 2017

@teknoraver That's not context. That's a restatement of the feature. It doesn't answer any of the questions in my previous two replies.

@rsc

This comment has been minimized.

Copy link
Contributor

commented Mar 13, 2017

Still waiting on context. In addition to:

What's missing so far is a strong justification for adding that API complexity. Why is this important to users? In what context does it make sense to override the DNS config in Go but not other languages, or in one program but not others? Why not just always override system-wide?

I also wonder when that's appropriate but https://github.com/miekg/dns is not the answer instead.

@teknoraver

This comment has been minimized.

Copy link
Author

commented Mar 13, 2017

I needed to do a DNS query to a custom server, I tought that changing the configured servers could be an option,
but maybe adding API to do lookup using a server is better

@rsc

This comment has been minimized.

Copy link
Contributor

commented Apr 3, 2017

It sounds like this proposal is maybe a little too specific, but @bradfitz points out pending CL https://go-review.googlesource.com/c/37260 that would enable this and some other kinds of overrides. Maybe that CL should be turned into a separate proposal issue and this one closed?

@teknoraver

This comment has been minimized.

Copy link
Author

commented Apr 3, 2017

ok I agree with the custom Dialer

@rsc

This comment has been minimized.

Copy link
Contributor

commented Apr 10, 2017

Declining because (1) there doesn't seem to be a compelling use case and (2) apparently #19910 will be good enough.

@rsc rsc closed this Apr 10, 2017

@artooro

This comment has been minimized.

Copy link

commented Nov 17, 2017

Hey guys, I know this issue is closed but I'm having a hard time figuring out how #19910 helps with this.

I am trying to do the following.

func GoogleDNSDialer(ctx context.Context, network, address string) (net.Conn, error) {
	d := net.Dialer{}
	return d.DialContext(ctx, "udp", "8.8.8.8:53")
}

r := net.Resolver{
	Dial: GoogleDNSDialer,
}
ctx := context.Background()
ipaddr, err := r.LookupIPAddr(ctx, "www.example.com")
if err != nil {
	panic(err)
}
fmt.Println("DNS Result", ipaddr)

Yet r.LookupIPAddr isn't using the custom dialer and is still using the default resolver from resolvconf.

@ianlancetaylor

This comment has been minimized.

Copy link
Contributor

commented Nov 17, 2017

@artooro We don't use the issue tracker for questions, especially not on closed bugs. Please use a forum. See https://golang.org/wiki/Questions . Thanks.

When I try setting the Dial field in net.Resolver, it is used. When you ask on the forum, please provide a complete example.

@artooro

This comment has been minimized.

Copy link

commented Nov 17, 2017

@ianlancetaylor sorry will do that going forward. But just in case anyone searches and finds this, turns out all I had to do was set PreferGo to true making the code:

r := net.Resolver{
	PreferGo: true,
	Dial: GoogleDNSDialer,
}

It wasn't obvious from the docs that PreferGo needed to be set in order for Dial to be used.

@golang golang locked and limited conversation to collaborators Nov 17, 2018

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
You can’t perform that action at this time.