fix(dns): retry configurable resolvers
Все проверки выполнены успешно
CI / test (push) Successful in 2m32s
Docker / Build and publish worker image (push) Successful in 20m9s

Treat resolver transport failures as inconclusive checks so they do not open outage alerts.
Этот коммит содержится в:
Gleb Tv
2026-07-16 19:30:02 +03:00
родитель fd1a010e31
Коммит 579a14b403
6 изменённых файлов: 82 добавлений и 41 удалений

Просмотреть файл

@@ -4,7 +4,6 @@ import (
"errors"
"fmt"
"log"
"strings"
"github.com/miekg/dns"
)
@@ -14,7 +13,6 @@ func localQuery(mychan chan DNSreply, qname string, qtype uint16) {
fmt.Printf("DEBUG: start of DNS request \"%s\" / %d\n", qname, qtype)
}
var result DNSreply
var trials uint
result.qname = qname
result.qtype = qtype
result.r = nil
@@ -24,41 +22,29 @@ func localQuery(mychan chan DNSreply, qname string, qtype uint16) {
localm.RecursionDesired = true
localm.Question = make([]dns.Question, 1)
localm.SetEdns0(bufsize, false) // Even if no EDNS requested, see #9 May be we should retry without it if timeout?
localc := new(dns.Client)
localc.ReadTimeout = timeout
localm.Question[0] = dns.Question{Name: qname, Qtype: qtype, Qclass: dns.ClassINET}
Tests:
for trials = 0; trials < uint(maxTrials); trials++ {
for serverIndex := range conf.Servers {
server := conf.Servers[serverIndex]
result.nameserver = server
// Brackets around the server address are necessary for IPv6 name servers
// Brackets required for IPv6; do not use net.JoinHostPort (see check-soa commit 3e4edb1)
r, rtt, err := localc.Exchange(localm, "["+server+"]:"+conf.Port)
if r == nil {
result.r = nil
result.err = err
log.Println(err.Error())
if strings.Contains(err.Error(), "timeout") {
// Try another resolver
continue
}
// We give in
break Tests
for _, server := range conf.Servers {
result.nameserver = server
localc := &dns.Client{ReadTimeout: timeout}
// Brackets are required for IPv6; do not use net.JoinHostPort (see check-soa commit 3e4edb1).
r, rtt, err := localc.Exchange(localm, "["+server+"]:"+conf.Port)
if err != nil || r == nil {
result.r = nil
result.err = err
if err != nil {
log.Println(err)
}
result.rtt = rtt
if r.Rcode == dns.RcodeSuccess {
// TODO: NODATA (NOERROR/ANSWER=0) are silently ignored (e.g. name exists but no IP address)
// TODO: for rcodes like SERVFAIL, trying another resolver could make sense
result.r = r
result.err = nil
break Tests
}
// All the other codes are errors
result.r = r
result.err = errors.New(dns.RcodeToString[r.Rcode])
break Tests
continue
}
result.rtt = rtt
if r.Rcode == dns.RcodeSuccess {
result.r = r
result.err = nil
break
}
result.r = r
result.err = errors.New(dns.RcodeToString[r.Rcode])
break
}
if debug {
fmt.Printf("DEBUG: end of DNS request \"%s\" / %d\n", qname, qtype)