resolver: error from ResolveIPAddresses when no nameserver answered (closes #190)
check / check (push) Failing after 2m25s

ResolveIPAddresses now returns an error wrapping ErrNoNameserverAnswered
when every nameserver of the name's zone timed out or failed, instead of
no addresses and no error. It reads each nameserver's status as the
lookup already sets it; one answer, even NXDOMAIN, is enough for an
empty result without an error. The only caller, the nameserver address
lookup, already keeps the previous addresses on an error; its comment
no longer says the resolver hides this case.

Model: opus-5-5
This commit is contained in:
2026-10-01 21:42:48 +00:00
committed by sneak
parent 797c936c48
commit 5fab7b7417
7 changed files with 87 additions and 8 deletions
+25 -4
View File
@@ -734,7 +734,9 @@ func (r *Resolver) LookupAllRecords(
}
// ResolveIPAddresses resolves a hostname to all IPv4 and IPv6
// addresses, following CNAME chains up to MaxCNAMEDepth.
// addresses, following CNAME chains up to MaxCNAMEDepth. When no
// nameserver of the name's zone answered, it returns an error wrapping
// ErrNoNameserverAnswered rather than no addresses.
func (r *Resolver) ResolveIPAddresses(
ctx context.Context,
hostname string,
@@ -760,7 +762,10 @@ func (r *Resolver) resolveIPWithCNAME(
return nil, err
}
ips, cnameTarget := collectIPs(results)
ips, cnameTarget, err := collectIPs(results)
if err != nil {
return nil, fmt.Errorf("resolving %s: %w", hostname, err)
}
if len(ips) == 0 && cnameTarget != "" {
return r.resolveIPWithCNAME(ctx, cnameTarget, depth+1)
@@ -771,16 +776,28 @@ func (r *Resolver) resolveIPWithCNAME(
return ips, nil
}
// collectIPs returns the addresses in the nameservers' answers and the
// first CNAME target among them. It returns ErrNoNameserverAnswered when
// every nameserver timed out or failed: that is not a name with no
// addresses.
func collectIPs(
results map[string]*NameserverResponse,
) ([]string, string) {
) ([]string, string, error) {
seen := make(map[string]bool)
var ips []string
var cnameTarget string
answered := false
for _, resp := range results {
if resp.Status == StatusTimeout || resp.Status == StatusError {
continue
}
answered = true
if resp.Status == StatusNXDomain {
continue
}
@@ -804,5 +821,9 @@ func collectIPs(
}
}
return ips, cnameTarget
if !answered {
return nil, "", ErrNoNameserverAnswered
}
return ips, cnameTarget, nil
}