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