package cdns import ( "fmt" "net" "github.com/miekg/dns" ) func soaQuery(mychan chan SOAreply, zone string, name string, server string) { var result SOAreply var trials uint result.retrieved = false result.name = name result.address = server result.msg = "UNKNOWN" m := new(dns.Msg) if !noedns { m.SetEdns0(bufsize, !nodnssec) } m.Id = dns.Id() if recursion { m.RecursionDesired = true } else { m.RecursionDesired = false } m.Question = make([]dns.Question, 1) c := new(dns.Client) c.ReadTimeout = timeout // Seems ignored for TCP? if tcp { c.Net = "tcp" } m.Question[0] = dns.Question{Name: zone, Qtype: dns.TypeSOA, Qclass: dns.ClassINET} nsAddressPort := net.JoinHostPort(server, "53") if debug { fmt.Printf("DEBUG Querying SOA from %s\n", nsAddressPort) } for trials = 0; trials < uint(maxTrials); trials++ { soa, rtt, err := c.Exchange(m, nsAddressPort) if soa == nil { result.rtt = 0 result.msg = err.Error() } else { result.rtt = rtt if soa.Rcode != dns.RcodeSuccess { result.msg = dns.RcodeToString[soa.Rcode] break } if len(soa.Answer) == 0 { /* May happen if the server is a recursor, not authoritative, since we query with RD=0 */ result.msg = "0 answer" break } else { //nolint:revive // complex nested structure gotSoa := false for _, rsoa := range soa.Answer { switch r := rsoa.(type) { case *dns.SOA: if noauthrequired || soa.Authoritative { result.retrieved = true result.serial = r.Serial result.msg = "OK" } else { result.msg = "Not authoritative" } gotSoa = true case *dns.CNAME: /* Bad practice but common */ result.msg = "Apparently not a zone but an alias" case *dns.RRSIG: /* Ignore them. See bug #8 */ default: // TODO: a name server can send us other RR types. result.msg = fmt.Sprintf("Internal error when processing %s, unexpected record type\n", rsoa) } } if !gotSoa { result.msg = "No SOA record in reply" } break } } } mychan <- result }