// Test program to experiment the IETF draft draft-ietf-dnsop-rrserial (hereafter "the draft").
// Depends on godns .
// If you don't know Go:
// go get github.com/miekg/dns
// go build test-rrserial.go
package main
import (
"encoding/binary"
"fmt"
"github.com/miekg/dns"
"os"
"strings"
)
const otype = 65024
func print_rrserial(msg *dns.Msg) {
opt := msg.IsEdns0()
for _, v := range opt.Option {
switch v := v.(type) {
case *dns.EDNS0_LOCAL:
if v.Option() == otype {
serial := binary.BigEndian.Uint32(v.Data)
fmt.Printf("EDNS rrserial found, \"%d\"\n", serial)
}
default:
continue
}
}
}
func main() {
if len(os.Args) != 3 && len(os.Args) != 4 {
fmt.Printf("%s SERVER QNAME [QTYPE]\n", os.Args[0])
os.Exit(1)
}
ns := os.Args[1]
qname := dns.Fqdn(os.Args[2])
qtype := dns.TypeAAAA
ok := true
if len(os.Args) == 4 {
if qtype, ok = dns.StringToType[strings.ToUpper(os.Args[3])]; ok {
// Good value
} else {
fmt.Printf("%s is not a known record type\n", strings.ToUpper(os.Args[3]))
os.Exit(1)
}
}
m := new(dns.Msg)
m.Question = make([]dns.Question, 1)
c := new(dns.Client)
o := new(dns.OPT)
o.Hdr.Name = "."
o.Hdr.Rrtype = dns.TypeOPT
o.SetUDPSize(4096)
e := new(dns.EDNS0_LOCAL)
e.Code = otype
e.Data = []byte{}
o.Option = append(o.Option, e)
m.Extra = append(m.Extra, o)
m.Question[0] = dns.Question{qname, qtype, dns.ClassINET}
in, _, err := c.Exchange(m, ns+":53")
if err == nil && in != nil {
if in.Rcode == dns.RcodeRefused {
fmt.Printf("Query refused (may be %s is a resolver, we do not ask for recursion)\n", ns)
os.Exit(1)
} else if in.Rcode == dns.RcodeFormatError {
fmt.Printf("%s claims our format is incorrect, it is wrong\n", ns)
os.Exit(1)
} else if in.Rcode == dns.RcodeNameError {
fmt.Printf("%s not found\n", qname)
gotSoa := false
serial := uint32(0)
for _, rsoa := range in.Ns {
switch rsoa.(type) {
case *dns.SOA:
serial = rsoa.(*dns.SOA).Serial
gotSoa = true
default:
continue
}
}
if !gotSoa {
fmt.Printf("No SOA in the answer :-(\n")
os.Exit(1)
} else {
fmt.Printf("Serial number in SOA %d\n", serial)
}
os.Exit(0)
} else if in.Rcode == dns.RcodeServerFailure {
fmt.Printf("Server failure\n")
print_rrserial(in)
os.Exit(1)
} else if in.Rcode != dns.RcodeSuccess {
fmt.Printf("Wrong return code %d\n", in.Rcode)
os.Exit(1)
}
if len(in.Answer) > 0 {
for _, rec := range in.Answer {
fmt.Printf("%s\n", rec)
}
} else if len(in.Answer) == 0 {
fmt.Printf("Empty answer received\n")
}
print_rrserial(in)
} else {
if err != nil {
fmt.Printf("Error in query: %s\n", err)
} else if in == nil {
fmt.Printf("No answer received\n")
}
os.Exit(1)
}
}