// nameList returns a list of names for sequential DNS queries.
func (conf *dnsConfig) nameList(name string) []string {
- if avoidDNS(name) {
- return nil
- }
-
// Check name length (see isDomainName).
l := len(name)
rooted := l > 0 && name[l-1] == '.'
// If name is rooted (trailing dot), try only that name.
if rooted {
+ if avoidDNS(name) {
+ return nil
+ }
return []string{name}
}
// Build list of search choices.
names := make([]string, 0, 1+len(conf.search))
// If name has enough dots, try unsuffixed first.
- if hasNdots {
+ if hasNdots && !avoidDNS(name) {
names = append(names, name)
}
// Try suffixes that are not too long (see isDomainName).
for _, suffix := range conf.search {
- if l+len(suffix) <= 254 {
- names = append(names, name+suffix)
+ fqdn := name + suffix
+ if !avoidDNS(fqdn) && len(fqdn) <= 254 {
+ names = append(names, fqdn)
}
}
// Try unsuffixed, if not tried first above.
- if !hasNdots {
+ if !hasNdots && !avoidDNS(name) {
names = append(names, name)
}
return names
"path/filepath"
"reflect"
"runtime"
+ "slices"
"strings"
"sync"
"sync/atomic"
}
}
+func TestNameListAvoidDNS(t *testing.T) {
+ c := &dnsConfig{search: []string{"go.dev.", "onion."}}
+ got := c.nameList("www")
+ if !slices.Equal(got, []string{"www.", "www.go.dev."}) {
+ t.Fatalf(`nameList("www") = %v, want "www.", "www.go.dev."`, got)
+ }
+
+ got = c.nameList("www.onion")
+ if !slices.Equal(got, []string{"www.onion.go.dev."}) {
+ t.Fatalf(`nameList("www.onion") = %v, want "www.onion.go.dev."`, got)
+ }
+}
+
var fakeDNSServerSuccessful = fakeDNSServer{rh: func(_, _ string, q dnsmessage.Message, _ time.Time) (dnsmessage.Message, error) {
r := dnsmessage.Message{
Header: dnsmessage.Header{
func TestLookupTorOnion(t *testing.T) {
defer dnsWaitGroup.Wait()
r := Resolver{PreferGo: true, Dial: fakeDNSServerSuccessful.DialContext}
- addrs, err := r.LookupIPAddr(context.Background(), "foo.onion")
+ addrs, err := r.LookupIPAddr(context.Background(), "foo.onion.")
if err != nil {
t.Fatalf("lookup = %v; want nil", err)
}