// 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) } }