Customized DNS Resolver cannot return the proper error


(bkkgbkjb) #1

Currently, the golang’s standard package, i.e. net, allows us to customize a DNS Resolver for DNS query targeting on specific DNS Server, as specified in the Dial field as following:

type Resolver struct {
        // PreferGo controls whether Go's built-in DNS resolver is preferred
        // on platforms where it's available. It is equivalent to setting
        // GODEBUG=netdns=go, but scoped to just this resolver.
        PreferGo bool

        // StrictErrors controls the behavior of temporary errors
        // (including timeout, socket errors, and SERVFAIL) when using
        // Go's built-in resolver. For a query composed of multiple
        // sub-queries (such as an A+AAAA address lookup, or walking the
        // DNS search list), this option causes such errors to abort the
        // whole query instead of returning a partial result. This is
        // not enabled by default because it may affect compatibility
        // with resolvers that process AAAA queries incorrectly.
        StrictErrors bool

        // Dial optionally specifies an alternate dialer for use by
        // Go's built-in DNS resolver to make TCP and UDP connections
        // to DNS services. The host in the address parameter will
        // always be a literal IP address and not a host name, and the
        // port in the address parameter will be a literal port number
        // and not a service name.
        // If the Conn returned is also a PacketConn, sent and received DNS
        // messages must adhere to RFC 1035 section 4.2.1, "UDP usage".
        // Otherwise, DNS messages transmitted over Conn must adhere
        // to RFC 7766 section 5, "Transport Protocol Selection".
        // If nil, the default dialer is used.
        Dial func(ctx context.Context, network, address string) (Conn, error)
        // contains filtered or unexported fields
}

However, since this solution modifies the very-low level function, all the upper invocation chains are unaware of the customized DNS Server’ address. If we use it to query a DNS A Record, and say, which ought not to be found. The error message returned by the upper function would be misleading.

A brief example is as following:

package main

import (
	"context"
	"fmt"
	"net"
)

func main() {
	customR := net.Resolver{
		PreferGo: true,
		Dial: func(ctx context.Context, network, address string) (net.Conn, error) {
			d := net.Dialer{}
			return d.DialContext(ctx, "udp", "8.8.8.8:53")
		},
	}
	ips, err := customR.LookupHost(context.Background(), "jaslkdjlsajdla.google.com")

	fmt.Println("ips:", ips)
	fmt.Println("err:", err)
}

The above code would return: ips: [] and
err: lookup jaslkdjlsajdla.google.com on 8.8.4.4:53: no such host, instead of err: lookup jaslkdjlsajdla.google.com on 8.8.8.8:53: no such host.
In fact, the 8.8.4.4 is subject to the /etc/resolv.conf on local environment

Does anybody have better solution to make the above code return correct error instead of this misleading one?

Thanks :slight_smile:


(Jakob Borg) #2

I don’t, but I’d suggest that this is not a great way to change the resolver to use. For, amongst others, the reason you discovered.