From 5902b88b4a28a1af5a8f533a44c3a4d7b3342f28 Mon Sep 17 00:00:00 2001 From: Miek Gieben Date: Sun, 13 Oct 2013 11:23:14 +0100 Subject: [PATCH] Put examples in their own repository example repository is github.com:miekg/ex/dns --- README.markdown | 8 +- contrib/check-soa/check-soa.go | 159 ------------ ex/as112/as112.go | 77 ------ ex/chaos/chaos.go | 95 ------- ex/q/q.go | 437 --------------------------------- ex/reflect/reflect.go | 201 --------------- 6 files changed, 5 insertions(+), 972 deletions(-) delete mode 100644 contrib/check-soa/check-soa.go delete mode 100644 ex/as112/as112.go delete mode 100644 ex/chaos/chaos.go delete mode 100644 ex/q/q.go delete mode 100644 ex/reflect/reflect.go diff --git a/README.markdown b/README.markdown index ac934e73..14e20b45 100644 --- a/README.markdown +++ b/README.markdown @@ -59,10 +59,12 @@ correctly, the following should work: go get github.com/miekg/dns go build github.com/miekg/dns +## Examples + A short "how to use the API" is at the beginning of dns.go (this also will show -when you call `go doc github.com/miekg/dns`. Sample -programs can be found in the `ex` directory. They can also be build -with: `go build`. +when you call `go doc github.com/miekg/dns`. + +Example programs can be found in the `github.com/miekg/exdns` repository. ## Supported RFCs diff --git a/contrib/check-soa/check-soa.go b/contrib/check-soa/check-soa.go deleted file mode 100644 index 59d7c629..00000000 --- a/contrib/check-soa/check-soa.go +++ /dev/null @@ -1,159 +0,0 @@ -// Go equivalent of the "DNS & BIND" book check-soa program. -// Created by Stephane Bortzmeyer. -package main - -import ( - "errors" - "fmt" - "github.com/miekg/dns" - "os" - "strings" - "time" -) - -const ( - TIMEOUT time.Duration = 5 // seconds -) - -var ( - localm *dns.Msg - localc *dns.Client - conf *dns.ClientConfig -) - -func localQuery(qname string, qtype uint16) (*dns.Msg, error) { - localm.SetQuestion(qname, qtype) - for i := range conf.Servers { - server := conf.Servers[i] - r, _, err := localc.Exchange(localm, server+":"+conf.Port) - if r == nil || r.Rcode == dns.RcodeNameError || r.Rcode == dns.RcodeSuccess { - return r, err - } - } - return nil, errors.New("No name server to answer the question") -} - -func main() { - var err error - if len(os.Args) != 2 { - fmt.Printf("%s ZONE\n", os.Args[0]) - os.Exit(1) - } - conf, err = dns.ClientConfigFromFile("/etc/resolv.conf") - if conf == nil { - fmt.Printf("Cannot initialize the local resolver: %s\n", err) - os.Exit(1) - } - localm = new(dns.Msg) - localm.RecursionDesired = true - localm.Question = make([]dns.Question, 1) - localc = new(dns.Client) - localc.ReadTimeout = TIMEOUT * 1e9 - r, err := localQuery(dns.Fqdn(os.Args[1]), dns.TypeNS) - if r == nil { - fmt.Printf("Cannot retrieve the list of name servers for %s: %s\n", dns.Fqdn(os.Args[1]), err) - os.Exit(1) - } - if r.Rcode == dns.RcodeNameError { - fmt.Printf("No such domain %s\n", dns.Fqdn(os.Args[1])) - os.Exit(1) - } - m := new(dns.Msg) - m.RecursionDesired = false - m.Question = make([]dns.Question, 1) - c := new(dns.Client) - c.ReadTimeout = TIMEOUT * 1e9 - success := true - numNS := 0 - for _, ans := range r.Answer { - switch ans.(type) { - case *dns.NS: - nameserver := ans.(*dns.NS).Ns - numNS += 1 - ips := make([]string, 0) - fmt.Printf("%s : ", nameserver) - ra, err := localQuery(nameserver, dns.TypeA) - if ra == nil { - fmt.Printf("Error getting the IPv4 address of %s: %s\n", nameserver, err) - os.Exit(1) - } - if ra.Rcode != dns.RcodeSuccess { - fmt.Printf("Error getting the IPv4 address of %s: %s\n", nameserver, dns.RcodeToString[ra.Rcode]) - os.Exit(1) - } - for _, ansa := range ra.Answer { - switch ansa.(type) { - case *dns.A: - ips = append(ips, ansa.(*dns.A).A.String()) - } - } - raaaa, err := localQuery(nameserver, dns.TypeAAAA) - if raaaa == nil { - fmt.Printf("Error getting the IPv6 address of %s: %s\n", nameserver, err) - os.Exit(1) - } - if raaaa.Rcode != dns.RcodeSuccess { - fmt.Printf("Error getting the IPv6 address of %s: %s\n", nameserver, dns.RcodeToString[raaaa.Rcode]) - os.Exit(1) - } - for _, ansaaaa := range raaaa.Answer { - switch ansaaaa.(type) { - case *dns.AAAA: - ips = append(ips, ansaaaa.(*dns.AAAA).AAAA.String()) - } - } - if len(ips) == 0 { - success = false - fmt.Printf("No IP address for this server") - } - for _, ip := range ips { - m.Question[0] = dns.Question{dns.Fqdn(os.Args[1]), dns.TypeSOA, dns.ClassINET} - nsAddressPort := "" - if strings.ContainsAny(":", ip) { - // IPv6 address - nsAddressPort = "[" + ip + "]:53" - } else { - nsAddressPort = ip + ":53" - } - soa, _, err := c.Exchange(m, nsAddressPort) - // TODO: retry if timeout? Otherwise, one lost UDP packet and it is the end - if soa == nil { - success = false - fmt.Printf("%s (%s) ", ip, err) - goto Next - } - if soa.Rcode != dns.RcodeSuccess { - success = false - fmt.Printf("%s (%s) ", ips, dns.RcodeToString[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.SOA: - if soa.Authoritative { - // TODO: test if all name servers have the same serial ? - fmt.Printf("%s (%d) ", ips, rsoa.(*dns.SOA).Serial) - } else { - success = false - fmt.Printf("%s (not authoritative) ", ips) - } - } - } - Next: - fmt.Printf("\n") - } - } - if numNS == 0 { - 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) - } - if success { - os.Exit(0) - } - os.Exit(1) -} diff --git a/ex/as112/as112.go b/ex/as112/as112.go deleted file mode 100644 index 30302f52..00000000 --- a/ex/as112/as112.go +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright 2011 Miek Gieben. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// An AS112 blackhole DNS server. Similar to the one found in evldns. -// Also see https://www.as112.net/ - -package main - -import ( - "github.com/miekg/dns" - "log" - "os" - "os/signal" - "runtime" - "syscall" -) - -const SOA string = "@ SOA prisoner.iana.org. hostmaster.root-servers.org. 2002040800 1800 900 0604800 604800" - -func NewRR(s string) dns.RR { r, _ := dns.NewRR(s); return r } - -var zones = map[string]dns.RR{ - "10.in-addr.arpa.": NewRR("$ORIGIN 10.in-addr.arpa.\n" + SOA), - "254.169.in-addr.arpa.": NewRR("$ORIGIN 254.169.in-addr.arpa.\n" + SOA), - "168.192.in-addr.arpa.": NewRR("$ORIGIN 168.192.in-addr.arpa.\n" + SOA), - "16.172.in-addr.arpa.": NewRR("$ORIGIN 16.172.in-addr.arpa.\n" + SOA), - "17.172.in-addr.arpa.": NewRR("$ORIGIN 17.172.in-addr.arpa.\n" + SOA), - "18.172.in-addr.arpa.": NewRR("$ORIGIN 18.172.in-addr.arpa.\n" + SOA), - "19.172.in-addr.arpa.": NewRR("$ORIGIN 19.172.in-addr.arpa.\n" + SOA), - "20.172.in-addr.arpa.": NewRR("$ORIGIN 20.172.in-addr.arpa.\n" + SOA), - "21.172.in-addr.arpa.": NewRR("$ORIGIN 21.172.in-addr.arpa.\n" + SOA), - "22.172.in-addr.arpa.": NewRR("$ORIGIN 22.172.in-addr.arpa.\n" + SOA), - "23.172.in-addr.arpa.": NewRR("$ORIGIN 23.172.in-addr.arpa.\n" + SOA), - "24.172.in-addr.arpa.": NewRR("$ORIGIN 24.172.in-addr.arpa.\n" + SOA), - "25.172.in-addr.arpa.": NewRR("$ORIGIN 25.172.in-addr.arpa.\n" + SOA), - "26.172.in-addr.arpa.": NewRR("$ORIGIN 26.172.in-addr.arpa.\n" + SOA), - "27.172.in-addr.arpa.": NewRR("$ORIGIN 27.172.in-addr.arpa.\n" + SOA), - "28.172.in-addr.arpa.": NewRR("$ORIGIN 28.172.in-addr.arpa.\n" + SOA), - "29.172.in-addr.arpa.": NewRR("$ORIGIN 29.172.in-addr.arpa.\n" + SOA), - "30.172.in-addr.arpa.": NewRR("$ORIGIN 30.172.in-addr.arpa.\n" + SOA), - "31.172.in-addr.arpa.": NewRR("$ORIGIN 31.172.in-addr.arpa.\n" + SOA), -} - -func main() { - runtime.GOMAXPROCS(runtime.NumCPU() * 4) - for z, rr := range zones { - rrx := rr.(*dns.SOA) // Needed to create the actual RR, and not an reference. - dns.HandleFunc(z, func(w dns.ResponseWriter, r *dns.Msg) { - m := new(dns.Msg) - m.SetReply(r) - m.Authoritative = true - m.Ns = []dns.RR{rrx} - w.WriteMsg(m) - }) - } - go func() { - err := dns.ListenAndServe(":8053", "tcp", nil) - if err != nil { - log.Fatal("Failed to set tcp listener %s\n", err.Error()) - } - }() - go func() { - err := dns.ListenAndServe(":8053", "udp", nil) - if err != nil { - log.Fatal("Failed to set udp listener %s\n", err.Error()) - } - }() - sig := make(chan os.Signal) - signal.Notify(sig, syscall.SIGINT, syscall.SIGTERM) - for { - select { - case s := <-sig: - log.Fatalf("Signal (%d) received, stopping\n", s) - } - } -} diff --git a/ex/chaos/chaos.go b/ex/chaos/chaos.go deleted file mode 100644 index 4979f557..00000000 --- a/ex/chaos/chaos.go +++ /dev/null @@ -1,95 +0,0 @@ -// Copyright 2011 Miek Gieben. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Chaos is a small program that prints the version.bind and hostname.bind -// for each address of the nameserver given as argument. -package main - -import ( - "fmt" - "github.com/miekg/dns" - "net" - "os" -) - -func main() { - if len(os.Args) != 2 { - fmt.Printf("%s NAMESERVER\n", os.Args[0]) - os.Exit(1) - } - conf, _ := dns.ClientConfigFromFile("/etc/resolv.conf") - - m := new(dns.Msg) - m.Question = make([]dns.Question, 1) - c := new(dns.Client) - - addr := addresses(conf, c, os.Args[1]) - if len(addr) == 0 { - fmt.Printf("No address found for %s\n", os.Args[1]) - os.Exit(1) - } - for _, a := range addr { - m.Question[0] = dns.Question{"version.bind.", dns.TypeTXT, dns.ClassCHAOS} - in, rtt, _ := c.Exchange(m, a) - if in != nil && len(in.Answer) > 0 { - fmt.Printf("(time %.3d µs) %v\n", rtt/1e3, in.Answer[0]) - } - m.Question[0] = dns.Question{"hostname.bind.", dns.TypeTXT, dns.ClassCHAOS} - in, rtt, _ = c.Exchange(m, a) - if in != nil && len(in.Answer) > 0 { - fmt.Printf("(time %.3d µs) %v\n", rtt/1e3, in.Answer[0]) - } - } -} - -func do(t chan *dns.Msg, c *dns.Client, m *dns.Msg, addr string) { - go func() { - r, _, err := c.Exchange(m, addr) - if err != nil { - //print error stuff - t <- nil - } - t <- r - }() -} - -func addresses(conf *dns.ClientConfig, c *dns.Client, name string) (ips []string) { - m4 := new(dns.Msg) - m4.SetQuestion(dns.Fqdn(os.Args[1]), dns.TypeA) - m6 := new(dns.Msg) - m6.SetQuestion(dns.Fqdn(os.Args[1]), dns.TypeAAAA) - t := make(chan *dns.Msg) - defer close(t) - do(t, c, m4, net.JoinHostPort(conf.Servers[0], conf.Port)) - do(t, c, m6, net.JoinHostPort(conf.Servers[0], conf.Port)) - - i := 2 // two outstanding queries -forever: - for { - select { - case d := <-t: - i-- - if d == nil { - continue - } - if i == 0 { - break forever - } - if d.Rcode == dns.RcodeSuccess { - for _, a := range d.Answer { - switch a.(type) { - case *dns.A: - ips = append(ips, - net.JoinHostPort(a.(*dns.A).A.String(), "53")) - case *dns.AAAA: - ips = append(ips, - net.JoinHostPort(a.(*dns.AAAA).AAAA.String(), "53")) - - } - } - } - } - } - return ips -} diff --git a/ex/q/q.go b/ex/q/q.go deleted file mode 100644 index 48c183ac..00000000 --- a/ex/q/q.go +++ /dev/null @@ -1,437 +0,0 @@ -// Copyright 2011 Miek Gieben. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Q is a small utility which acts and behaves like 'dig' from BIND. -// It is meant to stay lean and mean, while having a bunch of handy -// features, like -check which checks if a packet is correctly signed (without -// checking the chain of trust). -// When using -check a comment is printed: -// -// ;+ Secure signature, miek.nl. RRSIG(SOA) validates (DNSKEY miek.nl./4155/net) -// -// which says the SOA has a valid RRSIG and it validated with the DNSKEY of miek.nl, -// which has key id 4155 and is retrieved from the server. Other values are 'disk'. -package main - -import ( - "flag" - "fmt" - "github.com/miekg/dns" - "net" - "os" - "strconv" - "strings" - "time" -) - -// TODO: serial in ixfr - -var ( - dnskey *dns.DNSKEY - short *bool -) - -func main() { - short = flag.Bool("short", false, "abbreviate long DNSSEC records") - dnssec := flag.Bool("dnssec", false, "request DNSSEC records") - query := flag.Bool("question", false, "show question") - check := flag.Bool("check", false, "check internal DNSSEC consistency") - six := flag.Bool("6", false, "use IPv6 only") - four := flag.Bool("4", false, "use IPv4 only") - anchor := flag.String("anchor", "", "use the DNSKEY in this file for interal DNSSEC consistency") - tsig := flag.String("tsig", "", "request tsig with key: [hmac:]name:key") - port := flag.Int("port", 53, "port number to use") - aa := flag.Bool("aa", false, "set AA flag in query") - ad := flag.Bool("ad", false, "set AD flag in query") - cd := flag.Bool("cd", false, "set CD flag in query") - rd := flag.Bool("rd", true, "set RD flag in query") - fallback := flag.Bool("fallback", false, "fallback to 4096 bytes bufsize and after that TCP") - tcp := flag.Bool("tcp", false, "TCP mode") - nsid := flag.Bool("nsid", false, "set edns nsid option") - client := flag.String("client", "", "set edns client-subnet option") - clientdraftcode := flag.Bool("clientdraft", false, "set edns client-subnet option using the draft option code") - //serial := flag.Int("serial", 0, "perform an IXFR with this serial") - flag.Usage = func() { - fmt.Fprintf(os.Stderr, "Usage: %s [options] [@server] [qtype] [qclass] [name ...]\n", os.Args[0]) - flag.PrintDefaults() - } - - qtype := uint16(0) - qclass := uint16(dns.ClassINET) - var qname []string - - flag.Parse() - if *anchor != "" { - f, err := os.Open(*anchor) - if err != nil { - fmt.Fprintf(os.Stderr, "Failure to open %s: %s\n", *anchor, err.Error()) - } - r, err := dns.ReadRR(f, *anchor) - if err != nil { - fmt.Fprintf(os.Stderr, "Failure to read an RR from %s: %s\n", *anchor, err.Error()) - } - if k, ok := r.(*dns.DNSKEY); !ok { - fmt.Fprintf(os.Stderr, "No DNSKEY read from %s\n", *anchor) - } else { - dnskey = k - } - } - - var nameserver string - -Flags: - for i := 0; i < flag.NArg(); i++ { - // If it starts with @ it is a nameserver - if flag.Arg(i)[0] == '@' { - nameserver = flag.Arg(i) - continue Flags - } - // First class, then type, to make ANY queries possible - // And if it looks like type, it is a type - if k, ok := dns.StringToType[strings.ToUpper(flag.Arg(i))]; ok { - qtype = k - continue Flags - } - // If it looks like a class, it is a class - if k, ok := dns.StringToClass[strings.ToUpper(flag.Arg(i))]; ok { - qclass = k - continue Flags - } - // If it starts with TYPExxx it is unknown rr - if strings.HasPrefix(flag.Arg(i), "TYPE") { - i, e := strconv.Atoi(string([]byte(flag.Arg(i))[4:])) - if e == nil { - qtype = uint16(i) - continue Flags - } - } - - // Anything else is a qname - qname = append(qname, flag.Arg(i)) - } - if len(qname) == 0 { - qname = make([]string, 1) - qname[0] = "." - qtype = dns.TypeNS - } - if qtype == 0 { - qtype = dns.TypeA - } - - if len(nameserver) == 0 { - conf, err := dns.ClientConfigFromFile("/etc/resolv.conf") - if err != nil { - fmt.Fprintln(os.Stderr, err) - os.Exit(2) - } - nameserver = "@" + conf.Servers[0] - } - - nameserver = string([]byte(nameserver)[1:]) // chop off @ - // if the nameserver is from /etc/resolv.conf the [ and ] are already - // added, thereby breaking net.ParseIP. Check for this and don't - // fully qualify such a name - if nameserver[0] == '[' && nameserver[len(nameserver)-1] == ']' { - nameserver = nameserver[1 : len(nameserver)-1] - } - if i := net.ParseIP(nameserver); i != nil { - nameserver = net.JoinHostPort(nameserver, strconv.Itoa(*port)) - } else { - nameserver = dns.Fqdn(nameserver) + ":" + strconv.Itoa(*port) - } - c := new(dns.Client) - t := new(dns.Transfer) - c.Net = "udp" - if *four { - c.Net = "udp4" - } - if *six { - c.Net = "udp6" - } - if *tcp { - c.Net = "tcp" - if *four { - c.Net = "tcp4" - } - if *six { - c.Net = "tcp6" - } - } - - m := new(dns.Msg) - m.MsgHdr.Authoritative = *aa - m.MsgHdr.AuthenticatedData = *ad - m.MsgHdr.CheckingDisabled = *cd - m.MsgHdr.RecursionDesired = *rd - m.Question = make([]dns.Question, 1) - - if *dnssec || *nsid || *client != "" { - o := new(dns.OPT) - o.Hdr.Name = "." - o.Hdr.Rrtype = dns.TypeOPT - if *dnssec { - o.SetDo() - o.SetUDPSize(dns.DefaultMsgSize) - } - if *nsid { - e := new(dns.EDNS0_NSID) - e.Code = dns.EDNS0NSID - o.Option = append(o.Option, e) - // NSD will not return nsid when the udp message size is too small - o.SetUDPSize(dns.DefaultMsgSize) - } - if *client != "" { - e := new(dns.EDNS0_SUBNET) - e.Code = dns.EDNS0SUBNET - if *clientdraftcode { - e.DraftOption = true - } - e.SourceScope = 0 - e.Address = net.ParseIP(*client) - if e.Address == nil { - fmt.Fprintf(os.Stderr, "Failure to parse IP address: %s\n", *client) - return - } - e.Family = 1 // IP4 - e.SourceNetmask = net.IPv4len * 8 - if e.Address.To4() == nil { - e.Family = 2 // IP6 - e.SourceNetmask = net.IPv6len * 8 - } - o.Option = append(o.Option, e) - } - m.Extra = append(m.Extra, o) - } - -query: - for _, v := range qname { - m.Question[0] = dns.Question{dns.Fqdn(v), qtype, qclass} - m.Id = dns.Id() - if *tsig != "" { - if algo, name, secret, ok := tsigKeyParse(*tsig); ok { - m.SetTsig(name, algo, 300, time.Now().Unix()) - c.TsigSecret = map[string]string{name: secret} - t.TsigSecret = map[string]string{name: secret} - } else { - fmt.Fprintf(os.Stderr, "TSIG key data error\n") - return - } - } - if *query { - fmt.Printf("%s", m.String()) - fmt.Printf("\n;; size: %d bytes\n\n", m.Len()) - } - if qtype == dns.TypeAXFR || qtype == dns.TypeIXFR { - env, err := t.In(m, nameserver) - if err != nil { - fmt.Printf(";; %s\n", err.Error()) - continue - } - envelope := 0 - record := 0 - for e := range env { - if e.Error != nil { - fmt.Printf(";; %s\n", e.Error.Error()) - continue query - } - for _, r := range e.RR { - fmt.Printf("%s\n", r) - } - record+=len(e.RR) - envelope++ - } - fmt.Printf("\n;; xfr size: %d records (envelopes %d)\n", record, envelope) - continue - } - r, rtt, e := c.Exchange(m, nameserver) - Redo: - if e != nil { - fmt.Printf(";; %s\n", e.Error()) - continue - } - if r.Id != m.Id { - fmt.Fprintf(os.Stderr, "Id mismatch\n") - return - } - if r.MsgHdr.Truncated && *fallback { - if c.Net != "tcp" { - if !*dnssec { - fmt.Printf(";; Truncated, trying %d bytes bufsize\n", dns.DefaultMsgSize) - o := new(dns.OPT) - o.Hdr.Name = "." - o.Hdr.Rrtype = dns.TypeOPT - o.SetUDPSize(dns.DefaultMsgSize) - m.Extra = append(m.Extra, o) - r, rtt, e = c.Exchange(m, nameserver) - *dnssec = true - goto Redo - } else { - // First EDNS, then TCP - fmt.Printf(";; Truncated, trying TCP\n") - c.Net = "tcp" - r, rtt, e = c.Exchange(m, nameserver) - goto Redo - } - } - } - if r.MsgHdr.Truncated && !*fallback { - fmt.Printf(";; Truncated\n") - } - if *check { - sigCheck(r, nameserver, *tcp) - } - if *short { - r = shortMsg(r) - } - - fmt.Printf("%v", r) - fmt.Printf("\n;; query time: %.3d µs, server: %s(%s), size: %d bytes\n", rtt/1e3, nameserver, c.Net, r.Len()) - } -} - -func tsigKeyParse(s string) (algo, name, secret string, ok bool) { - s1 := strings.SplitN(s, ":", 3) - switch len(s1) { - case 2: - return "hmac-md5.sig-alg.reg.int.", dns.Fqdn(s1[0]), s1[1], true - case 3: - switch s1[0] { - case "hmac-md5": - return "hmac-md5.sig-alg.reg.int.", dns.Fqdn(s1[1]), s1[2], true - case "hmac-sha1": - return "hmac-sha1.", dns.Fqdn(s1[1]), s1[2], true - case "hmac-sha256": - return "hmac-sha256.", dns.Fqdn(s1[1]), s1[2], true - } - } - return -} - -func sectionCheck(set []dns.RR, server string, tcp bool) { - var key *dns.DNSKEY - for _, rr := range set { - if rr.Header().Rrtype == dns.TypeRRSIG { - rrset := getRRset(set, rr.Header().Name, rr.(*dns.RRSIG).TypeCovered) - if dnskey == nil { - key = getKey(rr.(*dns.RRSIG).SignerName, rr.(*dns.RRSIG).KeyTag, server, tcp) - } else { - key = dnskey - } - if key == nil { - fmt.Printf(";? DNSKEY %s/%d not found\n", rr.(*dns.RRSIG).SignerName, rr.(*dns.RRSIG).KeyTag) - continue - } - where := "net" - if dnskey != nil { - where = "disk" - } - if err := rr.(*dns.RRSIG).Verify(key, rrset); err != nil { - fmt.Printf(";- Bogus signature, %s does not validate (DNSKEY %s/%d/%s) [%s]\n", - shortSig(rr.(*dns.RRSIG)), key.Header().Name, key.KeyTag(), where, err.Error()) - } else { - fmt.Printf(";+ Secure signature, %s validates (DNSKEY %s/%d/%s)\n", shortSig(rr.(*dns.RRSIG)), key.Header().Name, key.KeyTag(), where) - } - } - } -} - -// Check the sigs in the msg, get the signer's key (additional query), get the -// rrset from the message, check the signature(s) -func sigCheck(in *dns.Msg, server string, tcp bool) { - sectionCheck(in.Answer, server, tcp) - sectionCheck(in.Ns, server, tcp) - sectionCheck(in.Extra, server, tcp) -} - -// Return the RRset belonging to the signature with name and type t -func getRRset(l []dns.RR, name string, t uint16) []dns.RR { - l1 := make([]dns.RR, 0) - for _, rr := range l { - if strings.ToLower(rr.Header().Name) == strings.ToLower(name) && rr.Header().Rrtype == t { - l1 = append(l1, rr) - } - } - return l1 -} - -// Get the key from the DNS (uses the local resolver) and return them. -// If nothing is found we return nil -func getKey(name string, keytag uint16, server string, tcp bool) *dns.DNSKEY { - c := new(dns.Client) - if tcp { - c.Net = "tcp" - } - m := new(dns.Msg) - m.SetQuestion(name, dns.TypeDNSKEY) - m.SetEdns0(4096, true) - r, _, err := c.Exchange(m, server) - if err != nil { - return nil - } - for _, k := range r.Answer { - if k1, ok := k.(*dns.DNSKEY); ok { - if k1.KeyTag() == keytag { - return k1 - } - } - } - return nil -} - -// shorten RRSIG to "miek.nl RRSIG(NS)" -func shortSig(sig *dns.RRSIG) string { - return sig.Header().Name + " RRSIG(" + dns.TypeToString[sig.TypeCovered] + ")" -} - -// Walk trough message and short Key data and Sig data -func shortMsg(in *dns.Msg) *dns.Msg { - for i := 0; i < len(in.Answer); i++ { - in.Answer[i] = shortRR(in.Answer[i]) - } - for i := 0; i < len(in.Ns); i++ { - in.Ns[i] = shortRR(in.Ns[i]) - } - for i := 0; i < len(in.Extra); i++ { - in.Extra[i] = shortRR(in.Extra[i]) - } - return in -} - -func shortRR(r dns.RR) dns.RR { - switch t := r.(type) { - case *dns.DS: - t.Digest = "..." - case *dns.DNSKEY: - t.PublicKey = "..." - case *dns.RRSIG: - t.Signature = "..." - case *dns.NSEC3: - t.Salt = "." // Nobody cares - if len(t.TypeBitMap) > 5 { - t.TypeBitMap = t.TypeBitMap[1:5] - } - } - return r -} - -func doXfr(c *dns.Client, m *dns.Msg, nameserver string) { - /* - if t, e := c.TransferIn(m, nameserver); e == nil { - for r := range t { - if r.Error == nil { - for _, rr := range r.RR { - if *short { - rr = shortRR(rr) - } - fmt.Printf("%v\n", rr) - } - } else { - fmt.Fprintf(os.Stderr, "Failure to read XFR: %s\n", r.Error.Error()) - } - } - } else { - fmt.Fprintf(os.Stderr, "Failure to read XFR: %s\n", e.Error()) - } - */ -} diff --git a/ex/reflect/reflect.go b/ex/reflect/reflect.go deleted file mode 100644 index b41f43f7..00000000 --- a/ex/reflect/reflect.go +++ /dev/null @@ -1,201 +0,0 @@ -// Copyright 2011 Miek Gieben. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Reflect is a small name server which sends back the IP address of its client, the -// recursive resolver. -// When queried for type A (resp. AAAA), it sends back the IPv4 (resp. v6) address. -// In the additional section the port number and transport are shown. -// -// Basic use pattern: -// -// dig @localhost -p 8053 whoami.miek.nl A -// -// ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 2157 -// ;; flags: qr rd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1 -// ;; QUESTION SECTION: -// ;whoami.miek.nl. IN A -// -// ;; ANSWER SECTION: -// whoami.miek.nl. 0 IN A 127.0.0.1 -// -// ;; ADDITIONAL SECTION: -// whoami.miek.nl. 0 IN TXT "Port: 56195 (udp)" -// -// Similar services: whoami.ultradns.net, whoami.akamai.net. Also (but it -// is not their normal goal): rs.dns-oarc.net, porttest.dns-oarc.net, -// amiopen.openresolvers.org. -// -// Original version is from: Stephane Bortzmeyer . -// -// Adapted to Go (i.e. completely rewritten) by Miek Gieben . -package main - -import ( - "flag" - "fmt" - "github.com/miekg/dns" - "log" - "net" - "os" - "os/signal" - "runtime" - "runtime/pprof" - "strconv" - "strings" - "syscall" - "time" -) - -var ( - printf *bool - compress *bool - tsig *string -) - -const dom = "whoami.miek.nl." - -func handleReflect(w dns.ResponseWriter, r *dns.Msg) { - var ( - v4 bool - rr dns.RR - str string - a net.IP - ) - // TC must be done here - m := new(dns.Msg) - m.SetReply(r) - m.Compress = *compress - if ip, ok := w.RemoteAddr().(*net.UDPAddr); ok { - str = "Port: " + strconv.Itoa(ip.Port) + " (udp)" - a = ip.IP - v4 = a.To4() != nil - } - if ip, ok := w.RemoteAddr().(*net.TCPAddr); ok { - str = "Port: " + strconv.Itoa(ip.Port) + " (tcp)" - a = ip.IP - v4 = a.To4() != nil - } - - /* - if o := r.IsEdns0(); o != nil { - for _, s := range o.Option { - switch e := s.(type) { - case *dns.EDNS0_SUBNET: - log.Printf("Edns0 subnet %s", e.Address) - } - } - } - */ - - if v4 { - rr = new(dns.A) - rr.(*dns.A).Hdr = dns.RR_Header{Name: dom, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: 0} - rr.(*dns.A).A = a.To4() - } else { - rr = new(dns.AAAA) - rr.(*dns.AAAA).Hdr = dns.RR_Header{Name: dom, Rrtype: dns.TypeAAAA, Class: dns.ClassINET, Ttl: 0} - rr.(*dns.AAAA).AAAA = a - } - - t := new(dns.TXT) - t.Hdr = dns.RR_Header{Name: dom, Rrtype: dns.TypeTXT, Class: dns.ClassINET, Ttl: 0} - t.Txt = []string{str} - - switch r.Question[0].Qtype { - case dns.TypeTXT: - m.Answer = append(m.Answer, t) - m.Extra = append(m.Extra, rr) - default: - fallthrough - case dns.TypeAAAA, dns.TypeA: - m.Answer = append(m.Answer, rr) - m.Extra = append(m.Extra, t) - - case dns.TypeAXFR, dns.TypeIXFR: - c := make(chan *dns.Envelope) - tr := new(dns.Transfer) - defer close(c) - err := tr.Out(w, r, c) - if err != nil { - return - } - soa, _ := dns.NewRR(`whoami.miek.nl. 0 IN SOA linode.atoom.net. miek.miek.nl. 2009032802 21600 7200 604800 3600`) - c <- &dns.Envelope{RR: []dns.RR{soa, t, rr, soa}} - w.Hijack() - // w.Close() // Client closes connection - return - - } - - if r.IsTsig() != nil { - if w.TsigStatus() == nil { - m.SetTsig(r.Extra[len(r.Extra)-1].(*dns.TSIG).Hdr.Name, dns.HmacMD5, 300, time.Now().Unix()) - } else { - println("Status", w.TsigStatus().Error()) - } - } - if *printf { - fmt.Printf("%v\n", m.String()) - } - w.WriteMsg(m) -} - -func serve(net, name, secret string) { - switch name { - case "": - err := dns.ListenAndServe(":8053", net, nil) - if err != nil { - fmt.Printf("Failed to setup the "+net+" server: %s\n", err.Error()) - } - default: - server := &dns.Server{Addr: ":8053", Net: net, TsigSecret: map[string]string{name: secret}} - err := server.ListenAndServe() - if err != nil { - fmt.Printf("Failed to setup the "+net+" server: %s\n", err.Error()) - } - } -} - -func main() { - runtime.GOMAXPROCS(runtime.NumCPU() * 4) - cpuprofile := flag.String("cpuprofile", "", "write cpu profile to file") - printf = flag.Bool("print", false, "print replies") - compress = flag.Bool("compress", false, "compress replies") - tsig = flag.String("tsig", "", "use MD5 hmac tsig: keyname:base64") - var name, secret string - flag.Usage = func() { - flag.PrintDefaults() - } - flag.Parse() - if *tsig != "" { - a := strings.SplitN(*tsig, ":", 2) - name, secret = dns.Fqdn(a[0]), a[1] // fqdn the name, which everybody forgets... - } - if *cpuprofile != "" { - f, err := os.Create(*cpuprofile) - if err != nil { - log.Fatal(err) - } - pprof.StartCPUProfile(f) - defer pprof.StopCPUProfile() - } - - dns.HandleFunc("miek.nl.", handleReflect) - dns.HandleFunc("authors.bind.", dns.HandleAuthors) - dns.HandleFunc("authors.server.", dns.HandleAuthors) - dns.HandleFunc("version.bind.", dns.HandleVersion) - dns.HandleFunc("version.server.", dns.HandleVersion) - go serve("tcp", name, secret) - go serve("udp", name, secret) - sig := make(chan os.Signal) - signal.Notify(sig, syscall.SIGINT, syscall.SIGTERM) -forever: - for { - select { - case s := <-sig: - fmt.Printf("Signal (%d) received, stopping\n", s) - break forever - } - } -}