package cdns import ( "errors" "fmt" "log" "strings" "github.com/miekg/dns" ) func localQuery(mychan chan DNSreply, qname string, qtype uint16) { if debug { 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 result.err = errors.New("no name server to answer the question") localm := new(dns.Msg) localm.Id = dns.Id() 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 } 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 } } if debug { fmt.Printf("DEBUG: end of DNS request \"%s\" / %d\n", qname, qtype) } mychan <- result }