Merge branch 'master' of github.com:miekg/dns

This commit is contained in:
Miek Gieben 2012-11-09 10:47:45 +01:00
commit fbe3e80256
2 changed files with 46 additions and 59 deletions

3
dns.go
View File

@ -61,7 +61,8 @@
// c := new(Client) // c := new(Client)
// in, err := c.Exchange(m1, "127.0.0.1:53") // in, err := c.Exchange(m1, "127.0.0.1:53")
// //
// An asynchronous query is also possible, see client.Do and client.DoRtt. // An asynchronous query is also possible, see client.Do or client.DoRtt, when
// you are interested in the round trip time of the exchange.
// //
// From a birds eye view a dns message consists out of four sections. // From a birds eye view a dns message consists out of four sections.
// The question section: in.Question, the answer section: in.Answer, // The question section: in.Question, the answer section: in.Answer,

View File

@ -1,3 +1,4 @@
// Go equivalent of the "DNS & BIND" book check-soa program.
package main package main
import ( import (
@ -19,18 +20,12 @@ var (
conf *dns.ClientConfig conf *dns.ClientConfig
) )
func localQuery(qname string, qtype uint16) (r *dns.Msg, err error) { func localQuery(qname string, qtype uint16) (*dns.Msg, error) {
localm.Question[0] = dns.Question{qname, qtype, dns.ClassINET} localm.SetQuestion(qname, qtype)
for serverIndex := range conf.Servers { for i := range conf.Servers {
server := conf.Servers[serverIndex] server := conf.Servers[i]
r, err := localc.Exchange(localm, server+":"+conf.Port) r, err := localc.Exchange(localm, server+":"+conf.Port)
if r == nil { if r == nil || r.Rcode == dns.RcodeNameError || r.Rcode == dns.RcodeSuccess {
return r, err
}
if r.Rcode == dns.RcodeNameError {
return r, err
}
if r.Rcode == dns.RcodeSuccess {
return r, err return r, err
} }
} }
@ -38,17 +33,11 @@ func localQuery(qname string, qtype uint16) (r *dns.Msg, err error) {
} }
func main() { func main() {
var ( var err error
err error
)
if len(os.Args) != 2 { if len(os.Args) != 2 {
fmt.Printf("%s ZONE\n", os.Args[0]) fmt.Printf("%s ZONE\n", os.Args[0])
os.Exit(1) os.Exit(1)
} }
zone := os.Args[1]
if zone[len(zone)-1] != '.' {
zone += "."
}
conf, err = dns.ClientConfigFromFile("/etc/resolv.conf") conf, err = dns.ClientConfigFromFile("/etc/resolv.conf")
if conf == nil { if conf == nil {
fmt.Printf("Cannot initialize the local resolver: %s\n", err) fmt.Printf("Cannot initialize the local resolver: %s\n", err)
@ -59,13 +48,13 @@ func main() {
localm.Question = make([]dns.Question, 1) localm.Question = make([]dns.Question, 1)
localc = new(dns.Client) localc = new(dns.Client)
localc.ReadTimeout = TIMEOUT * 1e9 localc.ReadTimeout = TIMEOUT * 1e9
r, err := localQuery(zone, dns.TypeNS) r, err := localQuery(dns.Fqdn(os.Args[1]), dns.TypeNS)
if r == nil { if r == nil {
fmt.Printf("Cannot retrieve the list of name servers for %s: %s\n", zone, err) fmt.Printf("Cannot retrieve the list of name servers for %s: %s\n", dns.Fqdn(os.Args[1]), err)
os.Exit(1) os.Exit(1)
} }
if r.Rcode == dns.RcodeNameError { if r.Rcode == dns.RcodeNameError {
fmt.Printf("No such domain %s\n", zone) fmt.Printf("No such domain %s\n", dns.Fqdn(os.Args[1]))
os.Exit(1) os.Exit(1)
} }
m := new(dns.Msg) m := new(dns.Msg)
@ -75,8 +64,7 @@ func main() {
c.ReadTimeout = TIMEOUT * 1e9 c.ReadTimeout = TIMEOUT * 1e9
success := true success := true
numNS := 0 numNS := 0
for i := range r.Answer { for _, ans := range r.Answer {
ans := r.Answer[i]
switch ans.(type) { switch ans.(type) {
case *dns.RR_NS: case *dns.RR_NS:
nameserver := ans.(*dns.RR_NS).Ns nameserver := ans.(*dns.RR_NS).Ns
@ -92,8 +80,7 @@ func main() {
fmt.Printf("Error getting the IPv4 address of %s: %s\n", nameserver, dns.Rcode_str[ra.Rcode]) fmt.Printf("Error getting the IPv4 address of %s: %s\n", nameserver, dns.Rcode_str[ra.Rcode])
os.Exit(1) os.Exit(1)
} }
for j := range ra.Answer { for _, ansa := range ra.Answer {
ansa := ra.Answer[j]
switch ansa.(type) { switch ansa.(type) {
case *dns.RR_A: case *dns.RR_A:
ips = append(ips, ansa.(*dns.RR_A).A.String()) ips = append(ips, ansa.(*dns.RR_A).A.String())
@ -108,8 +95,7 @@ func main() {
fmt.Printf("Error getting the IPv6 address of %s: %s\n", nameserver, dns.Rcode_str[raaaa.Rcode]) fmt.Printf("Error getting the IPv6 address of %s: %s\n", nameserver, dns.Rcode_str[raaaa.Rcode])
os.Exit(1) os.Exit(1)
} }
for j := range raaaa.Answer { for _, ansaaaa := range raaaa.Answer {
ansaaaa := raaaa.Answer[j]
switch ansaaaa.(type) { switch ansaaaa.(type) {
case *dns.RR_AAAA: case *dns.RR_AAAA:
ips = append(ips, ansaaaa.(*dns.RR_AAAA).AAAA.String()) ips = append(ips, ansaaaa.(*dns.RR_AAAA).AAAA.String())
@ -119,54 +105,54 @@ func main() {
success = false success = false
fmt.Printf("No IP address for this server") fmt.Printf("No IP address for this server")
} }
for j := range ips { for _, ip := range ips {
m.Question[0] = dns.Question{zone, dns.TypeSOA, dns.ClassINET} m.Question[0] = dns.Question{dns.Fqdn(os.Args[1]), dns.TypeSOA, dns.ClassINET}
nsAddressPort := "" nsAddressPort := ""
if strings.ContainsAny(":", ips[j]) { if strings.ContainsAny(":", ip) {
/* IPv6 address */ // IPv6 address
nsAddressPort = "[" + ips[j] + "]:53" nsAddressPort = "[" + ip + "]:53"
} else { } else {
nsAddressPort = ips[j] + ":53" nsAddressPort = ip + ":53"
} }
soa, err := c.Exchange(m, nsAddressPort) soa, err := c.Exchange(m, nsAddressPort)
/* TODO: retry if timeout? Otherwise, one lost UDP packet and it is the end ... */ // TODO: retry if timeout? Otherwise, one lost UDP packet and it is the end
if soa == nil { if soa == nil {
success = false success = false
fmt.Printf("%s (%s) ", ips[j], err) fmt.Printf("%s (%s) ", ip, err)
} else { goto Next
if soa.Rcode != dns.RcodeSuccess { }
success = false if soa.Rcode != dns.RcodeSuccess {
fmt.Printf("%s (%s) ", ips[j], dns.Rcode_str[soa.Rcode]) success = false
fmt.Printf("%s (%s) ", ips, dns.Rcode_str[soa.Rcode])
goto Next
}
if len(soa.Answer) == 0 { // May happen if the server is a recursor, not authoritative, since we query with RD=0
success = false
fmt.Printf("%s (0 answer) ", ip)
goto Next
}
rsoa := soa.Answer[0]
switch rsoa.(type) {
case *dns.RR_SOA:
if soa.MsgHdr.Authoritative {
// TODO: test if all name servers have the same serial ?
fmt.Printf("%s (%d) ", ips, rsoa.(*dns.RR_SOA).Serial)
} else { } else {
if len(soa.Answer) == 0 { /* May happen if the server is a recursor, not authoritative, since we query with RD=0 */ success = false
success = false fmt.Printf("%s (not authoritative) ", ips)
fmt.Printf("%s (0 answer) ", ips[j])
} else {
rsoa := soa.Answer[0]
switch rsoa.(type) {
case *dns.RR_SOA:
if soa.MsgHdr.Authoritative {
/* TODO: test if all name servers have the same serial ? */
fmt.Printf("%s (%d) ", ips[j], rsoa.(*dns.RR_SOA).Serial)
} else {
success = false
fmt.Printf("%s (not authoritative) ", ips[j])
}
}
}
} }
} }
} }
Next:
fmt.Printf("\n") fmt.Printf("\n")
} }
} }
if numNS == 0 { if numNS == 0 {
fmt.Printf("No NS records for \"%s\". It is probably a CNAME to a domain but not a zone\n", zone) fmt.Printf("No NS records for \"%s\". It is probably a CNAME to a domain but not a zone\n", dns.Fqdn(os.Args[1]))
os.Exit(1) os.Exit(1)
} }
if success { if success {
os.Exit(0) os.Exit(0)
} else {
os.Exit(1)
} }
os.Exit(1)
} }