watcher: a hostname whose zone's nameservers all stop answering gets NS Failure (closes #284)
check / check (push) Canceled after 0s
check / check (push) Canceled after 0s
When none of the nameservers of a hostname's zone answered, the walk to them failed and the check was only logged. The walk now returns a NoAnswerError naming the nameservers of the zone it reached when none of them answers. When those are the nameservers the previous check saved for the hostname, each is saved as failed with the reason, as a domain's are, so it gets an NS Failure and later an NS Recovery. A walk that fails before that zone, as when the host loses its network, is still only logged. Not tested live: the resolver naming a zone's nameservers that never answer, as no live zone has such nameservers; the watcher test builds that error. Model: opus-5-5
This commit is contained in:
@@ -209,16 +209,19 @@ func glueIPs(nsNames []string, glue map[string][]net.IP) []string {
|
||||
// of the zone domain is in answer that domain does not exist, the error
|
||||
// is ErrNXDomain. When they answer that it has no delegation of its own,
|
||||
// because it is not the zone's apex, the set is empty and there is no
|
||||
// error. Any other error means that no such answer came.
|
||||
// error. Any other error means that no such answer came; it is a
|
||||
// *NoAnswerError when the servers that did not answer are those of a
|
||||
// zone a referral named.
|
||||
func (r *Resolver) followDelegation(
|
||||
ctx context.Context,
|
||||
domain string,
|
||||
servers []string,
|
||||
) ([]string, error) {
|
||||
// servers are the root servers, the servers of zone ".".
|
||||
// servers are the root servers, the servers of zone ".". After a
|
||||
// referral, nameservers are the names of the servers of zone.
|
||||
zone := "."
|
||||
|
||||
var withoutAddresses []string
|
||||
var nameservers, withoutAddresses []string
|
||||
|
||||
for range maxDelegation {
|
||||
if checkCtx(ctx) != nil {
|
||||
@@ -228,6 +231,12 @@ func (r *Resolver) followDelegation(
|
||||
resp, err := r.queryZone(
|
||||
ctx, servers, withoutAddresses, zone, domain, dns.TypeNS, 0,
|
||||
)
|
||||
|
||||
// A query that ctx cut short says nothing about the servers.
|
||||
if err != nil && len(nameservers) > 0 && checkCtx(ctx) == nil {
|
||||
return nil, &NoAnswerError{Nameservers: nameservers, Err: err}
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -256,6 +265,7 @@ func (r *Resolver) followDelegation(
|
||||
return r.resolveNSIterative(ctx, domain)
|
||||
}
|
||||
|
||||
nameservers = authNS
|
||||
servers, withoutAddresses = referralNameservers(resp)
|
||||
zone = referralZone(resp)
|
||||
}
|
||||
@@ -626,7 +636,8 @@ func (r *Resolver) resolveARecord(
|
||||
// them. When the servers asked answer that the name has no delegation
|
||||
// of its own, or does not exist, it tries each parent name in turn, so
|
||||
// it returns the nameservers of the zone the name is in. When they do
|
||||
// not answer, it returns the error and tries no parent name.
|
||||
// not answer, it returns the error and tries no parent name; when a
|
||||
// referral named them, the error is a *NoAnswerError naming them.
|
||||
func (r *Resolver) FindAuthoritativeNameservers(
|
||||
ctx context.Context,
|
||||
domain string,
|
||||
|
||||
Reference in New Issue
Block a user