diff options
author | 2017-09-14 09:36:06 +0100 | |
---|---|---|
committer | 2017-09-14 09:36:06 +0100 | |
commit | d8714e64e400ef873c2adc4d929a07d7890727b9 (patch) | |
tree | c9fa4c157e6af12eb1517654f8d23ca5d5619513 /middleware/etcd | |
parent | b984aa45595dc95253b91191afe7d3ee29e71b48 (diff) | |
download | coredns-d8714e64e400ef873c2adc4d929a07d7890727b9.tar.gz coredns-d8714e64e400ef873c2adc4d929a07d7890727b9.tar.zst coredns-d8714e64e400ef873c2adc4d929a07d7890727b9.zip |
Remove the word middleware (#1067)
* Rename middleware to plugin
first pass; mostly used 'sed', few spots where I manually changed
text.
This still builds a coredns binary.
* fmt error
* Rename AddMiddleware to AddPlugin
* Readd AddMiddleware to remain backwards compat
Diffstat (limited to 'middleware/etcd')
-rw-r--r-- | middleware/etcd/README.md | 109 | ||||
-rw-r--r-- | middleware/etcd/cname_test.go | 79 | ||||
-rw-r--r-- | middleware/etcd/etcd.go | 188 | ||||
-rw-r--r-- | middleware/etcd/group_test.go | 74 | ||||
-rw-r--r-- | middleware/etcd/handler.go | 97 | ||||
-rw-r--r-- | middleware/etcd/lookup_test.go | 273 | ||||
-rw-r--r-- | middleware/etcd/msg/path.go | 48 | ||||
-rw-r--r-- | middleware/etcd/msg/path_test.go | 12 | ||||
-rw-r--r-- | middleware/etcd/msg/service.go | 203 | ||||
-rw-r--r-- | middleware/etcd/msg/service_test.go | 125 | ||||
-rw-r--r-- | middleware/etcd/msg/type.go | 33 | ||||
-rw-r--r-- | middleware/etcd/msg/type_test.go | 31 | ||||
-rw-r--r-- | middleware/etcd/multi_test.go | 59 | ||||
-rw-r--r-- | middleware/etcd/other_test.go | 150 | ||||
-rw-r--r-- | middleware/etcd/setup.go | 144 | ||||
-rw-r--r-- | middleware/etcd/setup_test.go | 64 | ||||
-rw-r--r-- | middleware/etcd/stub.go | 82 | ||||
-rw-r--r-- | middleware/etcd/stub_handler.go | 86 | ||||
-rw-r--r-- | middleware/etcd/stub_test.go | 88 |
19 files changed, 0 insertions, 1945 deletions
diff --git a/middleware/etcd/README.md b/middleware/etcd/README.md deleted file mode 100644 index f7991eb7c..000000000 --- a/middleware/etcd/README.md +++ /dev/null @@ -1,109 +0,0 @@ -# etcd - -*etcd* enables reading zone data from an etcd instance. The data in etcd has to be encoded as -a [message](https://github.com/skynetservices/skydns/blob/2fcff74cdc9f9a7dd64189a447ef27ac354b725f/msg/service.go#L26) -like [SkyDNS](https://github.com/skynetservices/skydns). It should also work just like SkyDNS. - -The etcd middleware makes extensive use of the proxy middleware to forward and query other servers -in the network. - -## Syntax - -~~~ -etcd [ZONES...] -~~~ - -* **ZONES** zones etcd should be authoritative for. - -The path will default to `/skydns` the local etcd proxy (http://localhost:2379). -If no zones are specified the block's zone will be used as the zone. - -If you want to `round robin` A and AAAA responses look at the `loadbalance` middleware. - -~~~ -etcd [ZONES...] { - stubzones - fallthrough - path PATH - endpoint ENDPOINT... - upstream ADDRESS... - tls CERT KEY CACERT -} -~~~ - -* `stubzones` enables the stub zones feature. The stubzone is *only* done in the etcd tree located - under the *first* zone specified. -* `fallthrough` If zone matches but no record can be generated, pass request to the next middleware. -* **PATH** the path inside etcd. Defaults to "/skydns". -* **ENDPOINT** the etcd endpoints. Defaults to "http://localhost:2397". -* `upstream` upstream resolvers to be used resolve external names found in etcd (think CNAMEs) - pointing to external names. If you want CoreDNS to act as a proxy for clients, you'll need to add - the proxy middleware. **ADDRESS** can be an IP address, and IP:port or a string pointing to a file - that is structured as /etc/resolv.conf. -* `tls` followed by: - * no arguments, if the server certificate is signed by a system-installed CA and no client cert is needed - * a single argument that is the CA PEM file, if the server cert is not signed by a system CA and no client cert is needed - * two arguments - path to cert PEM file, the path to private key PEM file - if the server certificate is signed by a system-installed CA and a client certificate is needed - * three arguments - path to cert PEM file, path to client private key PEM file, path to CA PEM file - if the server certificate is not signed by a system-installed CA and client certificate is needed - -## Examples - -This is the default SkyDNS setup, with everying specified in full: - -~~~ -.:53 { - etcd skydns.local { - stubzones - path /skydns - endpoint http://localhost:2379 - upstream 8.8.8.8:53 8.8.4.4:53 - } - prometheus - cache 160 skydns.local - loadbalance - proxy . 8.8.8.8:53 8.8.4.4:53 -} -~~~ - -Or a setup where we use `/etc/resolv.conf` as the basis for the proxy and the upstream -when resolving external pointing CNAMEs. - -~~~ -.:53 { - etcd skydns.local { - path /skydns - upstream /etc/resolv.conf - } - cache 160 skydns.local - proxy . /etc/resolv.conf -} -~~~ - - -### Reverse zones - -Reverse zones are supported. You need to make CoreDNS aware of the fact that you are also -authoritative for the reverse. For instance if you want to add the reverse for 10.0.0.0/24, you'll -need to add the zone `0.0.10.in-addr.arpa` to the list of zones. (The fun starts with IPv6 reverse zones -in the ip6.arpa domain.) Showing a snippet of a Corefile: - -~~~ - etcd skydns.local 0.0.10.in-addr.arpa { - stubzones - ... -~~~ - -Next you'll need to populate the zone with reverse records, here we add a reverse for -10.0.0.127 pointing to reverse.skydns.local. - -~~~ -% curl -XPUT http://127.0.0.1:4001/v2/keys/skydns/arpa/in-addr/10/0/0/127 \ - -d value='{"host":"reverse.skydns.local."}' -~~~ - -Querying with dig: - -~~~ -% dig @localhost -x 10.0.0.127 +short -reverse.atoom.net. -~~~ diff --git a/middleware/etcd/cname_test.go b/middleware/etcd/cname_test.go deleted file mode 100644 index 4c39491fd..000000000 --- a/middleware/etcd/cname_test.go +++ /dev/null @@ -1,79 +0,0 @@ -// +build etcd - -package etcd - -// etcd needs to be running on http://localhost:2379 - -import ( - "testing" - - "github.com/coredns/coredns/middleware/etcd/msg" - "github.com/coredns/coredns/middleware/pkg/dnsrecorder" - "github.com/coredns/coredns/middleware/test" - - "github.com/miekg/dns" -) - -// Check the ordering of returned cname. -func TestCnameLookup(t *testing.T) { - etc := newEtcdMiddleware() - - for _, serv := range servicesCname { - set(t, etc, serv.Key, 0, serv) - defer delete(t, etc, serv.Key) - } - for _, tc := range dnsTestCasesCname { - m := tc.Msg() - - rec := dnsrecorder.New(&test.ResponseWriter{}) - _, err := etc.ServeDNS(ctxt, rec, m) - if err != nil { - t.Errorf("expected no error, got %v\n", err) - return - } - - resp := rec.Msg - if !test.Header(t, tc, resp) { - t.Logf("%v\n", resp) - continue - } - if !test.Section(t, tc, test.Answer, resp.Answer) { - t.Logf("%v\n", resp) - } - if !test.Section(t, tc, test.Ns, resp.Ns) { - t.Logf("%v\n", resp) - } - if !test.Section(t, tc, test.Extra, resp.Extra) { - t.Logf("%v\n", resp) - } - } -} - -var servicesCname = []*msg.Service{ - {Host: "cname1.region2.skydns.test", Key: "a.server1.dev.region1.skydns.test."}, - {Host: "cname2.region2.skydns.test", Key: "cname1.region2.skydns.test."}, - {Host: "cname3.region2.skydns.test", Key: "cname2.region2.skydns.test."}, - {Host: "cname4.region2.skydns.test", Key: "cname3.region2.skydns.test."}, - {Host: "cname5.region2.skydns.test", Key: "cname4.region2.skydns.test."}, - {Host: "cname6.region2.skydns.test", Key: "cname5.region2.skydns.test."}, - {Host: "endpoint.region2.skydns.test", Key: "cname6.region2.skydns.test."}, - {Host: "10.240.0.1", Key: "endpoint.region2.skydns.test."}, -} - -var dnsTestCasesCname = []test.Case{ - { - Qname: "a.server1.dev.region1.skydns.test.", Qtype: dns.TypeSRV, - Answer: []dns.RR{ - test.SRV("a.server1.dev.region1.skydns.test. 300 IN SRV 10 100 0 cname1.region2.skydns.test."), - }, - Extra: []dns.RR{ - test.CNAME("cname1.region2.skydns.test. 300 IN CNAME cname2.region2.skydns.test."), - test.CNAME("cname2.region2.skydns.test. 300 IN CNAME cname3.region2.skydns.test."), - test.CNAME("cname3.region2.skydns.test. 300 IN CNAME cname4.region2.skydns.test."), - test.CNAME("cname4.region2.skydns.test. 300 IN CNAME cname5.region2.skydns.test."), - test.CNAME("cname5.region2.skydns.test. 300 IN CNAME cname6.region2.skydns.test."), - test.CNAME("cname6.region2.skydns.test. 300 IN CNAME endpoint.region2.skydns.test."), - test.A("endpoint.region2.skydns.test. 300 IN A 10.240.0.1"), - }, - }, -} diff --git a/middleware/etcd/etcd.go b/middleware/etcd/etcd.go deleted file mode 100644 index 5ef6e0a47..000000000 --- a/middleware/etcd/etcd.go +++ /dev/null @@ -1,188 +0,0 @@ -// Package etcd provides the etcd backend middleware. -package etcd - -import ( - "encoding/json" - "fmt" - "strings" - "time" - - "github.com/coredns/coredns/middleware" - "github.com/coredns/coredns/middleware/etcd/msg" - "github.com/coredns/coredns/middleware/pkg/cache" - "github.com/coredns/coredns/middleware/pkg/singleflight" - "github.com/coredns/coredns/middleware/proxy" - "github.com/coredns/coredns/request" - - etcdc "github.com/coreos/etcd/client" - "github.com/miekg/dns" - "golang.org/x/net/context" -) - -// Etcd is a middleware talks to an etcd cluster. -type Etcd struct { - Next middleware.Handler - Fallthrough bool - Zones []string - PathPrefix string - Proxy proxy.Proxy // Proxy for looking up names during the resolution process - Client etcdc.KeysAPI - Ctx context.Context - Inflight *singleflight.Group - Stubmap *map[string]proxy.Proxy // list of proxies for stub resolving. - - endpoints []string // Stored here as well, to aid in testing. -} - -// Services implements the ServiceBackend interface. -func (e *Etcd) Services(state request.Request, exact bool, opt middleware.Options) (services []msg.Service, err error) { - services, err = e.Records(state, exact) - if err != nil { - return - } - - services = msg.Group(services) - return -} - -// Reverse implements the ServiceBackend interface. -func (e *Etcd) Reverse(state request.Request, exact bool, opt middleware.Options) (services []msg.Service, err error) { - return e.Services(state, exact, opt) -} - -// Lookup implements the ServiceBackend interface. -func (e *Etcd) Lookup(state request.Request, name string, typ uint16) (*dns.Msg, error) { - return e.Proxy.Lookup(state, name, typ) -} - -// IsNameError implements the ServiceBackend interface. -func (e *Etcd) IsNameError(err error) bool { - if ee, ok := err.(etcdc.Error); ok && ee.Code == etcdc.ErrorCodeKeyNotFound { - return true - } - return false -} - -// Records looks up records in etcd. If exact is true, it will lookup just this -// name. This is used when find matches when completing SRV lookups for instance. -func (e *Etcd) Records(state request.Request, exact bool) ([]msg.Service, error) { - name := state.Name() - - path, star := msg.PathWithWildcard(name, e.PathPrefix) - r, err := e.get(path, true) - if err != nil { - return nil, err - } - segments := strings.Split(msg.Path(name, e.PathPrefix), "/") - switch { - case exact && r.Node.Dir: - return nil, nil - case r.Node.Dir: - return e.loopNodes(r.Node.Nodes, segments, star, nil) - default: - return e.loopNodes([]*etcdc.Node{r.Node}, segments, false, nil) - } -} - -// get is a wrapper for client.Get that uses SingleInflight to suppress multiple outstanding queries. -func (e *Etcd) get(path string, recursive bool) (*etcdc.Response, error) { - - hash := cache.Hash([]byte(path)) - - resp, err := e.Inflight.Do(hash, func() (interface{}, error) { - ctx, cancel := context.WithTimeout(e.Ctx, etcdTimeout) - defer cancel() - r, e := e.Client.Get(ctx, path, &etcdc.GetOptions{Sort: false, Recursive: recursive}) - if e != nil { - return nil, e - } - return r, e - }) - if err != nil { - return nil, err - } - return resp.(*etcdc.Response), err -} - -// skydns/local/skydns/east/staging/web -// skydns/local/skydns/west/production/web -// -// skydns/local/skydns/*/*/web -// skydns/local/skydns/*/web - -// loopNodes recursively loops through the nodes and returns all the values. The nodes' keyname -// will be match against any wildcards when star is true. -func (e *Etcd) loopNodes(ns []*etcdc.Node, nameParts []string, star bool, bx map[msg.Service]bool) (sx []msg.Service, err error) { - if bx == nil { - bx = make(map[msg.Service]bool) - } -Nodes: - for _, n := range ns { - if n.Dir { - nodes, err := e.loopNodes(n.Nodes, nameParts, star, bx) - if err != nil { - return nil, err - } - sx = append(sx, nodes...) - continue - } - if star { - keyParts := strings.Split(n.Key, "/") - for i, n := range nameParts { - if i > len(keyParts)-1 { - // name is longer than key - continue Nodes - } - if n == "*" || n == "any" { - continue - } - if keyParts[i] != n { - continue Nodes - } - } - } - serv := new(msg.Service) - if err := json.Unmarshal([]byte(n.Value), serv); err != nil { - return nil, fmt.Errorf("%s: %s", n.Key, err.Error()) - } - b := msg.Service{Host: serv.Host, Port: serv.Port, Priority: serv.Priority, Weight: serv.Weight, Text: serv.Text, Key: n.Key} - if _, ok := bx[b]; ok { - continue - } - bx[b] = true - - serv.Key = n.Key - serv.TTL = e.TTL(n, serv) - if serv.Priority == 0 { - serv.Priority = priority - } - sx = append(sx, *serv) - } - return sx, nil -} - -// TTL returns the smaller of the etcd TTL and the service's -// TTL. If neither of these are set (have a zero value), a default is used. -func (e *Etcd) TTL(node *etcdc.Node, serv *msg.Service) uint32 { - etcdTTL := uint32(node.TTL) - - if etcdTTL == 0 && serv.TTL == 0 { - return ttl - } - if etcdTTL == 0 { - return serv.TTL - } - if serv.TTL == 0 { - return etcdTTL - } - if etcdTTL < serv.TTL { - return etcdTTL - } - return serv.TTL -} - -const ( - priority = 10 // default priority when nothing is set - ttl = 300 // default ttl when nothing is set - etcdTimeout = 5 * time.Second -) diff --git a/middleware/etcd/group_test.go b/middleware/etcd/group_test.go deleted file mode 100644 index 43ce4754a..000000000 --- a/middleware/etcd/group_test.go +++ /dev/null @@ -1,74 +0,0 @@ -// +build etcd - -package etcd - -import ( - "testing" - - "github.com/coredns/coredns/middleware/etcd/msg" - "github.com/coredns/coredns/middleware/pkg/dnsrecorder" - "github.com/coredns/coredns/middleware/test" - - "github.com/miekg/dns" -) - -func TestGroupLookup(t *testing.T) { - etc := newEtcdMiddleware() - - for _, serv := range servicesGroup { - set(t, etc, serv.Key, 0, serv) - defer delete(t, etc, serv.Key) - } - for _, tc := range dnsTestCasesGroup { - m := tc.Msg() - - rec := dnsrecorder.New(&test.ResponseWriter{}) - _, err := etc.ServeDNS(ctxt, rec, m) - if err != nil { - t.Errorf("expected no error, got %v\n", err) - continue - } - - resp := rec.Msg - test.SortAndCheck(t, resp, tc) - } -} - -// Note the key is encoded as DNS name, while in "reality" it is a etcd path. -var servicesGroup = []*msg.Service{ - {Host: "127.0.0.1", Key: "a.dom.skydns.test.", Group: "g1"}, - {Host: "127.0.0.2", Key: "b.sub.dom.skydns.test.", Group: "g1"}, - - {Host: "127.0.0.1", Key: "a.dom2.skydns.test.", Group: "g1"}, - {Host: "127.0.0.2", Key: "b.sub.dom2.skydns.test.", Group: ""}, - - {Host: "127.0.0.1", Key: "a.dom1.skydns.test.", Group: "g1"}, - {Host: "127.0.0.2", Key: "b.sub.dom1.skydns.test.", Group: "g2"}, -} - -var dnsTestCasesGroup = []test.Case{ - // Groups - { - // hits the group 'g1' and only includes those records - Qname: "dom.skydns.test.", Qtype: dns.TypeA, - Answer: []dns.RR{ - test.A("dom.skydns.test. 300 IN A 127.0.0.1"), - test.A("dom.skydns.test. 300 IN A 127.0.0.2"), - }, - }, - { - // One has group, the other has not... Include the non-group always. - Qname: "dom2.skydns.test.", Qtype: dns.TypeA, - Answer: []dns.RR{ - test.A("dom2.skydns.test. 300 IN A 127.0.0.1"), - test.A("dom2.skydns.test. 300 IN A 127.0.0.2"), - }, - }, - { - // The groups differ. - Qname: "dom1.skydns.test.", Qtype: dns.TypeA, - Answer: []dns.RR{ - test.A("dom1.skydns.test. 300 IN A 127.0.0.1"), - }, - }, -} diff --git a/middleware/etcd/handler.go b/middleware/etcd/handler.go deleted file mode 100644 index 7857b1955..000000000 --- a/middleware/etcd/handler.go +++ /dev/null @@ -1,97 +0,0 @@ -package etcd - -import ( - "github.com/coredns/coredns/middleware" - "github.com/coredns/coredns/middleware/pkg/dnsutil" - "github.com/coredns/coredns/request" - - "github.com/miekg/dns" - "golang.org/x/net/context" -) - -// ServeDNS implements the middleware.Handler interface. -func (e *Etcd) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (int, error) { - opt := middleware.Options{} - state := request.Request{W: w, Req: r} - - name := state.Name() - - // We need to check stubzones first, because we may get a request for a zone we - // are not auth. for *but* do have a stubzone forward for. If we do the stubzone - // handler will handle the request. - if e.Stubmap != nil && len(*e.Stubmap) > 0 { - for zone := range *e.Stubmap { - if middleware.Name(zone).Matches(name) { - stub := Stub{Etcd: e, Zone: zone} - return stub.ServeDNS(ctx, w, r) - } - } - } - - zone := middleware.Zones(e.Zones).Matches(state.Name()) - if zone == "" { - return middleware.NextOrFailure(e.Name(), e.Next, ctx, w, r) - } - - var ( - records, extra []dns.RR - err error - ) - switch state.Type() { - case "A": - records, err = middleware.A(e, zone, state, nil, opt) - case "AAAA": - records, err = middleware.AAAA(e, zone, state, nil, opt) - case "TXT": - records, err = middleware.TXT(e, zone, state, opt) - case "CNAME": - records, err = middleware.CNAME(e, zone, state, opt) - case "PTR": - records, err = middleware.PTR(e, zone, state, opt) - case "MX": - records, extra, err = middleware.MX(e, zone, state, opt) - case "SRV": - records, extra, err = middleware.SRV(e, zone, state, opt) - case "SOA": - records, err = middleware.SOA(e, zone, state, opt) - case "NS": - if state.Name() == zone { - records, extra, err = middleware.NS(e, zone, state, opt) - break - } - fallthrough - default: - // Do a fake A lookup, so we can distinguish between NODATA and NXDOMAIN - _, err = middleware.A(e, zone, state, nil, opt) - } - - if e.IsNameError(err) { - if e.Fallthrough { - return middleware.NextOrFailure(e.Name(), e.Next, ctx, w, r) - } - // Make err nil when returning here, so we don't log spam for NXDOMAIN. - return middleware.BackendError(e, zone, dns.RcodeNameError, state, nil /* err */, opt) - } - if err != nil { - return middleware.BackendError(e, zone, dns.RcodeServerFailure, state, err, opt) - } - - if len(records) == 0 { - return middleware.BackendError(e, zone, dns.RcodeSuccess, state, err, opt) - } - - m := new(dns.Msg) - m.SetReply(r) - m.Authoritative, m.RecursionAvailable, m.Compress = true, true, true - m.Answer = append(m.Answer, records...) - m.Extra = append(m.Extra, extra...) - - m = dnsutil.Dedup(m) - state.SizeAndDo(m) - m, _ = state.Scrub(m) - w.WriteMsg(m) - return dns.RcodeSuccess, nil -} - -// Name implements the Handler interface. -func (e *Etcd) Name() string { return "etcd" } diff --git a/middleware/etcd/lookup_test.go b/middleware/etcd/lookup_test.go deleted file mode 100644 index 010bd66df..000000000 --- a/middleware/etcd/lookup_test.go +++ /dev/null @@ -1,273 +0,0 @@ -// +build etcd - -package etcd - -import ( - "context" - "encoding/json" - "testing" - "time" - - "github.com/coredns/coredns/middleware/etcd/msg" - "github.com/coredns/coredns/middleware/pkg/dnsrecorder" - "github.com/coredns/coredns/middleware/pkg/singleflight" - "github.com/coredns/coredns/middleware/pkg/tls" - "github.com/coredns/coredns/middleware/proxy" - "github.com/coredns/coredns/middleware/test" - - etcdc "github.com/coreos/etcd/client" - "github.com/miekg/dns" -) - -func init() { - ctxt = context.TODO() -} - -// Note the key is encoded as DNS name, while in "reality" it is a etcd path. -var services = []*msg.Service{ - {Host: "dev.server1", Port: 8080, Key: "a.server1.dev.region1.skydns.test."}, - {Host: "10.0.0.1", Port: 8080, Key: "a.server1.prod.region1.skydns.test."}, - {Host: "10.0.0.2", Port: 8080, Key: "b.server1.prod.region1.skydns.test."}, - {Host: "::1", Port: 8080, Key: "b.server6.prod.region1.skydns.test."}, - // Unresolvable internal name. - {Host: "unresolvable.skydns.test", Key: "cname.prod.region1.skydns.test."}, - // Priority. - {Host: "priority.server1", Priority: 333, Port: 8080, Key: "priority.skydns.test."}, - // Subdomain. - {Host: "sub.server1", Port: 0, Key: "a.sub.region1.skydns.test."}, - {Host: "sub.server2", Port: 80, Key: "b.sub.region1.skydns.test."}, - {Host: "10.0.0.1", Port: 8080, Key: "c.sub.region1.skydns.test."}, - // Cname loop. - {Host: "a.cname.skydns.test", Key: "b.cname.skydns.test."}, - {Host: "b.cname.skydns.test", Key: "a.cname.skydns.test."}, - // Nameservers. - {Host: "10.0.0.2", Key: "a.ns.dns.skydns.test."}, - {Host: "10.0.0.3", Key: "b.ns.dns.skydns.test."}, - // Reverse. - {Host: "reverse.example.com", Key: "1.0.0.10.in-addr.arpa."}, // 10.0.0.1 -} - -var dnsTestCases = []test.Case{ - // SRV Test - { - Qname: "a.server1.dev.region1.skydns.test.", Qtype: dns.TypeSRV, - Answer: []dns.RR{test.SRV("a.server1.dev.region1.skydns.test. 300 SRV 10 100 8080 dev.server1.")}, - }, - // SRV Test (case test) - { - Qname: "a.SERVer1.dEv.region1.skydns.tEst.", Qtype: dns.TypeSRV, - Answer: []dns.RR{test.SRV("a.SERVer1.dEv.region1.skydns.tEst. 300 SRV 10 100 8080 dev.server1.")}, - }, - // NXDOMAIN Test - { - Qname: "doesnotexist.skydns.test.", Qtype: dns.TypeA, - Rcode: dns.RcodeNameError, - Ns: []dns.RR{ - test.SOA("skydns.test. 300 SOA ns.dns.skydns.test. hostmaster.skydns.test. 0 0 0 0 0"), - }, - }, - // A Test - { - Qname: "a.server1.prod.region1.skydns.test.", Qtype: dns.TypeA, - Answer: []dns.RR{test.A("a.server1.prod.region1.skydns.test. 300 A 10.0.0.1")}, - }, - // SRV Test where target is IP address - { - Qname: "a.server1.prod.region1.skydns.test.", Qtype: dns.TypeSRV, - Answer: []dns.RR{test.SRV("a.server1.prod.region1.skydns.test. 300 SRV 10 100 8080 a.server1.prod.region1.skydns.test.")}, - Extra: []dns.RR{test.A("a.server1.prod.region1.skydns.test. 300 A 10.0.0.1")}, - }, - // AAAA Test - { - Qname: "b.server6.prod.region1.skydns.test.", Qtype: dns.TypeAAAA, - Answer: []dns.RR{test.AAAA("b.server6.prod.region1.skydns.test. 300 AAAA ::1")}, - }, - // Multiple A Record Test - { - Qname: "server1.prod.region1.skydns.test.", Qtype: dns.TypeA, - Answer: []dns.RR{ - test.A("server1.prod.region1.skydns.test. 300 A 10.0.0.1"), - test.A("server1.prod.region1.skydns.test. 300 A 10.0.0.2"), - }, - }, - // Priority Test - { - Qname: "priority.skydns.test.", Qtype: dns.TypeSRV, - Answer: []dns.RR{test.SRV("priority.skydns.test. 300 SRV 333 100 8080 priority.server1.")}, - }, - // Subdomain Test - { - Qname: "sub.region1.skydns.test.", Qtype: dns.TypeSRV, - Answer: []dns.RR{ - test.SRV("sub.region1.skydns.test. 300 IN SRV 10 33 0 sub.server1."), - test.SRV("sub.region1.skydns.test. 300 IN SRV 10 33 80 sub.server2."), - test.SRV("sub.region1.skydns.test. 300 IN SRV 10 33 8080 c.sub.region1.skydns.test."), - }, - Extra: []dns.RR{test.A("c.sub.region1.skydns.test. 300 IN A 10.0.0.1")}, - }, - // CNAME (unresolvable internal name) - { - Qname: "cname.prod.region1.skydns.test.", Qtype: dns.TypeA, - Ns: []dns.RR{test.SOA("skydns.test. 300 SOA ns.dns.skydns.test. hostmaster.skydns.test. 0 0 0 0 0")}, - }, - // Wildcard Test - { - Qname: "*.region1.skydns.test.", Qtype: dns.TypeSRV, - Answer: []dns.RR{ - test.SRV("*.region1.skydns.test. 300 IN SRV 10 12 0 sub.server1."), - test.SRV("*.region1.skydns.test. 300 IN SRV 10 12 0 unresolvable.skydns.test."), - test.SRV("*.region1.skydns.test. 300 IN SRV 10 12 80 sub.server2."), - test.SRV("*.region1.skydns.test. 300 IN SRV 10 12 8080 a.server1.prod.region1.skydns.test."), - test.SRV("*.region1.skydns.test. 300 IN SRV 10 12 8080 b.server1.prod.region1.skydns.test."), - test.SRV("*.region1.skydns.test. 300 IN SRV 10 12 8080 b.server6.prod.region1.skydns.test."), - test.SRV("*.region1.skydns.test. 300 IN SRV 10 12 8080 c.sub.region1.skydns.test."), - test.SRV("*.region1.skydns.test. 300 IN SRV 10 12 8080 dev.server1."), - }, - Extra: []dns.RR{ - test.A("a.server1.prod.region1.skydns.test. 300 IN A 10.0.0.1"), - test.A("b.server1.prod.region1.skydns.test. 300 IN A 10.0.0.2"), - test.AAAA("b.server6.prod.region1.skydns.test. 300 IN AAAA ::1"), - test.A("c.sub.region1.skydns.test. 300 IN A 10.0.0.1"), - }, - }, - // Wildcard Test - { - Qname: "prod.*.skydns.test.", Qtype: dns.TypeSRV, - Answer: []dns.RR{ - - test.SRV("prod.*.skydns.test. 300 IN SRV 10 25 0 unresolvable.skydns.test."), - test.SRV("prod.*.skydns.test. 300 IN SRV 10 25 8080 a.server1.prod.region1.skydns.test."), - test.SRV("prod.*.skydns.test. 300 IN SRV 10 25 8080 b.server1.prod.region1.skydns.test."), - test.SRV("prod.*.skydns.test. 300 IN SRV 10 25 8080 b.server6.prod.region1.skydns.test."), - }, - Extra: []dns.RR{ - test.A("a.server1.prod.region1.skydns.test. 300 IN A 10.0.0.1"), - test.A("b.server1.prod.region1.skydns.test. 300 IN A 10.0.0.2"), - test.AAAA("b.server6.prod.region1.skydns.test. 300 IN AAAA ::1"), - }, - }, - // Wildcard Test - { - Qname: "prod.any.skydns.test.", Qtype: dns.TypeSRV, - Answer: []dns.RR{ - test.SRV("prod.any.skydns.test. 300 IN SRV 10 25 0 unresolvable.skydns.test."), - test.SRV("prod.any.skydns.test. 300 IN SRV 10 25 8080 a.server1.prod.region1.skydns.test."), - test.SRV("prod.any.skydns.test. 300 IN SRV 10 25 8080 b.server1.prod.region1.skydns.test."), - test.SRV("prod.any.skydns.test. 300 IN SRV 10 25 8080 b.server6.prod.region1.skydns.test."), - }, - Extra: []dns.RR{ - test.A("a.server1.prod.region1.skydns.test. 300 IN A 10.0.0.1"), - test.A("b.server1.prod.region1.skydns.test. 300 IN A 10.0.0.2"), - test.AAAA("b.server6.prod.region1.skydns.test. 300 IN AAAA ::1"), - }, - }, - // CNAME loop detection - { - Qname: "a.cname.skydns.test.", Qtype: dns.TypeA, - Ns: []dns.RR{test.SOA("skydns.test. 300 SOA ns.dns.skydns.test. hostmaster.skydns.test. 1407441600 28800 7200 604800 60")}, - }, - // NODATA Test - { - Qname: "a.server1.dev.region1.skydns.test.", Qtype: dns.TypeTXT, - Ns: []dns.RR{test.SOA("skydns.test. 300 SOA ns.dns.skydns.test. hostmaster.skydns.test. 0 0 0 0 0")}, - }, - // NODATA Test - { - Qname: "a.server1.dev.region1.skydns.test.", Qtype: dns.TypeHINFO, - Ns: []dns.RR{test.SOA("skydns.test. 300 SOA ns.dns.skydns.test. hostmaster.skydns.test. 0 0 0 0 0")}, - }, - // NXDOMAIN Test - { - Qname: "a.server1.nonexistent.region1.skydns.test.", Qtype: dns.TypeHINFO, Rcode: dns.RcodeNameError, - Ns: []dns.RR{test.SOA("skydns.test. 300 SOA ns.dns.skydns.test. hostmaster.skydns.test. 0 0 0 0 0")}, - }, - { - Qname: "skydns.test.", Qtype: dns.TypeSOA, - Answer: []dns.RR{test.SOA("skydns.test. 300 IN SOA ns.dns.skydns.test. hostmaster.skydns.test. 1460498836 14400 3600 604800 60")}, - }, - // NS Record Test - { - Qname: "skydns.test.", Qtype: dns.TypeNS, - Answer: []dns.RR{ - test.NS("skydns.test. 300 NS a.ns.dns.skydns.test."), - test.NS("skydns.test. 300 NS b.ns.dns.skydns.test."), - }, - Extra: []dns.RR{ - test.A("a.ns.dns.skydns.test. 300 A 10.0.0.2"), - test.A("b.ns.dns.skydns.test. 300 A 10.0.0.3"), - }, - }, - // NS Record Test - { - Qname: "a.skydns.test.", Qtype: dns.TypeNS, Rcode: dns.RcodeNameError, - Ns: []dns.RR{test.SOA("skydns.test. 300 IN SOA ns.dns.skydns.test. hostmaster.skydns.test. 1460498836 14400 3600 604800 60")}, - }, - // A Record For NS Record Test - { - Qname: "ns.dns.skydns.test.", Qtype: dns.TypeA, - Answer: []dns.RR{ - test.A("ns.dns.skydns.test. 300 A 10.0.0.2"), - test.A("ns.dns.skydns.test. 300 A 10.0.0.3"), - }, - }, - { - Qname: "skydns_extra.test.", Qtype: dns.TypeSOA, - Answer: []dns.RR{test.SOA("skydns_extra.test. 300 IN SOA ns.dns.skydns_extra.test. hostmaster.skydns_extra.test. 1460498836 14400 3600 604800 60")}, - }, - // Reverse lookup - { - Qname: "1.0.0.10.in-addr.arpa.", Qtype: dns.TypePTR, - Answer: []dns.RR{test.PTR("1.0.0.10.in-addr.arpa. 300 PTR reverse.example.com.")}, - }, -} - -func newEtcdMiddleware() *Etcd { - ctxt = context.TODO() - - endpoints := []string{"http://localhost:2379"} - tlsc, _ := tls.NewTLSConfigFromArgs() - client, _ := newEtcdClient(endpoints, tlsc) - - return &Etcd{ - Proxy: proxy.NewLookup([]string{"8.8.8.8:53"}), - PathPrefix: "skydns", - Ctx: context.Background(), - Inflight: &singleflight.Group{}, - Zones: []string{"skydns.test.", "skydns_extra.test.", "in-addr.arpa."}, - Client: client, - } -} - -func set(t *testing.T, e *Etcd, k string, ttl time.Duration, m *msg.Service) { - b, err := json.Marshal(m) - if err != nil { - t.Fatal(err) - } - path, _ := msg.PathWithWildcard(k, e.PathPrefix) - e.Client.Set(ctxt, path, string(b), &etcdc.SetOptions{TTL: ttl}) -} - -func delete(t *testing.T, e *Etcd, k string) { - path, _ := msg.PathWithWildcard(k, e.PathPrefix) - e.Client.Delete(ctxt, path, &etcdc.DeleteOptions{Recursive: false}) -} - -func TestLookup(t *testing.T) { - etc := newEtcdMiddleware() - for _, serv := range services { - set(t, etc, serv.Key, 0, serv) - defer delete(t, etc, serv.Key) - } - - for _, tc := range dnsTestCases { - m := tc.Msg() - - rec := dnsrecorder.New(&test.ResponseWriter{}) - etc.ServeDNS(ctxt, rec, m) - - resp := rec.Msg - test.SortAndCheck(t, resp, tc) - } -} - -var ctxt context.Context diff --git a/middleware/etcd/msg/path.go b/middleware/etcd/msg/path.go deleted file mode 100644 index 2184b9fcd..000000000 --- a/middleware/etcd/msg/path.go +++ /dev/null @@ -1,48 +0,0 @@ -package msg - -import ( - "path" - "strings" - - "github.com/coredns/coredns/middleware/pkg/dnsutil" - - "github.com/miekg/dns" -) - -// Path converts a domainname to an etcd path. If s looks like service.staging.skydns.local., -// the resulting key will be /skydns/local/skydns/staging/service . -func Path(s, prefix string) string { - l := dns.SplitDomainName(s) - for i, j := 0, len(l)-1; i < j; i, j = i+1, j-1 { - l[i], l[j] = l[j], l[i] - } - return path.Join(append([]string{"/" + prefix + "/"}, l...)...) -} - -// Domain is the opposite of Path. -func Domain(s string) string { - l := strings.Split(s, "/") - // start with 1, to strip /skydns - for i, j := 1, len(l)-1; i < j; i, j = i+1, j-1 { - l[i], l[j] = l[j], l[i] - } - return dnsutil.Join(l[1 : len(l)-1]) -} - -// PathWithWildcard ascts as Path, but if a name contains wildcards (* or any), the name will be -// chopped of before the (first) wildcard, and we do a highler evel search and -// later find the matching names. So service.*.skydns.local, will look for all -// services under skydns.local and will later check for names that match -// service.*.skydns.local. If a wildcard is found the returned bool is true. -func PathWithWildcard(s, prefix string) (string, bool) { - l := dns.SplitDomainName(s) - for i, j := 0, len(l)-1; i < j; i, j = i+1, j-1 { - l[i], l[j] = l[j], l[i] - } - for i, k := range l { - if k == "*" || k == "any" { - return path.Join(append([]string{"/" + prefix + "/"}, l[:i]...)...), true - } - } - return path.Join(append([]string{"/" + prefix + "/"}, l...)...), false -} diff --git a/middleware/etcd/msg/path_test.go b/middleware/etcd/msg/path_test.go deleted file mode 100644 index a9ec59713..000000000 --- a/middleware/etcd/msg/path_test.go +++ /dev/null @@ -1,12 +0,0 @@ -package msg - -import "testing" - -func TestPath(t *testing.T) { - for _, path := range []string{"mydns", "skydns"} { - result := Path("service.staging.skydns.local.", path) - if result != "/"+path+"/local/skydns/staging/service" { - t.Errorf("Failure to get domain's path with prefix: %s", result) - } - } -} diff --git a/middleware/etcd/msg/service.go b/middleware/etcd/msg/service.go deleted file mode 100644 index 9250cb634..000000000 --- a/middleware/etcd/msg/service.go +++ /dev/null @@ -1,203 +0,0 @@ -// Package msg defines the Service structure which is used for service discovery. -package msg - -import ( - "fmt" - "net" - "strings" - - "github.com/miekg/dns" -) - -// Service defines a discoverable service in etcd. It is the rdata from a SRV -// record, but with a twist. Host (Target in SRV) must be a domain name, but -// if it looks like an IP address (4/6), we will treat it like an IP address. -type Service struct { - Host string `json:"host,omitempty"` - Port int `json:"port,omitempty"` - Priority int `json:"priority,omitempty"` - Weight int `json:"weight,omitempty"` - Text string `json:"text,omitempty"` - Mail bool `json:"mail,omitempty"` // Be an MX record. Priority becomes Preference. - TTL uint32 `json:"ttl,omitempty"` - - // When a SRV record with a "Host: IP-address" is added, we synthesize - // a srv.Target domain name. Normally we convert the full Key where - // the record lives to a DNS name and use this as the srv.Target. When - // TargetStrip > 0 we strip the left most TargetStrip labels from the - // DNS name. - TargetStrip int `json:"targetstrip,omitempty"` - - // Group is used to group (or *not* to group) different services - // together. Services with an identical Group are returned in the same - // answer. - Group string `json:"group,omitempty"` - - // Etcd key where we found this service and ignored from json un-/marshalling - Key string `json:"-"` -} - -// RR returns an RR representation of s. It is in a condensed form to minimize space -// when this is returned in a DNS message. -// The RR will look like: -// 1.rails.production.east.skydns.local. 300 CH TXT "service1.example.com:8080(10,0,,false)[0,]" -// etcd Key Ttl Host:Port < see below > -// between parens: (Priority, Weight, Text (only first 200 bytes!), Mail) -// between blockquotes: [TargetStrip,Group] -// If the record is synthesised by CoreDNS (i.e. no lookup in etcd happened): -// -// TODO(miek): what to put here? -// -func (s *Service) RR() *dns.TXT { - l := len(s.Text) - if l > 200 { - l = 200 - } - t := new(dns.TXT) - t.Hdr.Class = dns.ClassCHAOS - t.Hdr.Ttl = s.TTL - t.Hdr.Rrtype = dns.TypeTXT - t.Hdr.Name = Domain(s.Key) - - t.Txt = make([]string, 1) - t.Txt[0] = fmt.Sprintf("%s:%d(%d,%d,%s,%t)[%d,%s]", - s.Host, s.Port, - s.Priority, s.Weight, s.Text[:l], s.Mail, - s.TargetStrip, s.Group) - return t -} - -// NewSRV returns a new SRV record based on the Service. -func (s *Service) NewSRV(name string, weight uint16) *dns.SRV { - host := targetStrip(dns.Fqdn(s.Host), s.TargetStrip) - - return &dns.SRV{Hdr: dns.RR_Header{Name: name, Rrtype: dns.TypeSRV, Class: dns.ClassINET, Ttl: s.TTL}, - Priority: uint16(s.Priority), Weight: weight, Port: uint16(s.Port), Target: dns.Fqdn(host)} -} - -// NewMX returns a new MX record based on the Service. -func (s *Service) NewMX(name string) *dns.MX { - host := targetStrip(dns.Fqdn(s.Host), s.TargetStrip) - - return &dns.MX{Hdr: dns.RR_Header{Name: name, Rrtype: dns.TypeMX, Class: dns.ClassINET, Ttl: s.TTL}, - Preference: uint16(s.Priority), Mx: host} -} - -// NewA returns a new A record based on the Service. -func (s *Service) NewA(name string, ip net.IP) *dns.A { - return &dns.A{Hdr: dns.RR_Header{Name: name, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: s.TTL}, A: ip} -} - -// NewAAAA returns a new AAAA record based on the Service. -func (s *Service) NewAAAA(name string, ip net.IP) *dns.AAAA { - return &dns.AAAA{Hdr: dns.RR_Header{Name: name, Rrtype: dns.TypeAAAA, Class: dns.ClassINET, Ttl: s.TTL}, AAAA: ip} -} - -// NewCNAME returns a new CNAME record based on the Service. -func (s *Service) NewCNAME(name string, target string) *dns.CNAME { - return &dns.CNAME{Hdr: dns.RR_Header{Name: name, Rrtype: dns.TypeCNAME, Class: dns.ClassINET, Ttl: s.TTL}, Target: dns.Fqdn(target)} -} - -// NewTXT returns a new TXT record based on the Service. -func (s *Service) NewTXT(name string) *dns.TXT { - return &dns.TXT{Hdr: dns.RR_Header{Name: name, Rrtype: dns.TypeTXT, Class: dns.ClassINET, Ttl: s.TTL}, Txt: split255(s.Text)} -} - -// NewPTR returns a new PTR record based on the Service. -func (s *Service) NewPTR(name string, target string) *dns.PTR { - return &dns.PTR{Hdr: dns.RR_Header{Name: name, Rrtype: dns.TypePTR, Class: dns.ClassINET, Ttl: s.TTL}, Ptr: dns.Fqdn(target)} -} - -// NewNS returns a new NS record based on the Service. -func (s *Service) NewNS(name string) *dns.NS { - host := targetStrip(dns.Fqdn(s.Host), s.TargetStrip) - return &dns.NS{Hdr: dns.RR_Header{Name: name, Rrtype: dns.TypeNS, Class: dns.ClassINET, Ttl: s.TTL}, Ns: host} -} - -// Group checks the services in sx, it looks for a Group attribute on the shortest -// keys. If there are multiple shortest keys *and* the group attribute disagrees (and -// is not empty), we don't consider it a group. -// If a group is found, only services with *that* group (or no group) will be returned. -func Group(sx []Service) []Service { - if len(sx) == 0 { - return sx - } - - // Shortest key with group attribute sets the group for this set. - group := sx[0].Group - slashes := strings.Count(sx[0].Key, "/") - length := make([]int, len(sx)) - for i, s := range sx { - x := strings.Count(s.Key, "/") - length[i] = x - if x < slashes { - if s.Group == "" { - break - } - slashes = x - group = s.Group - } - } - - if group == "" { - return sx - } - - ret := []Service{} // with slice-tricks in sx we can prolly save this allocation (TODO) - - for i, s := range sx { - if s.Group == "" { - ret = append(ret, s) - continue - } - - // Disagreement on the same level - if length[i] == slashes && s.Group != group { - return sx - } - - if s.Group == group { - ret = append(ret, s) - } - } - return ret -} - -// Split255 splits a string into 255 byte chunks. -func split255(s string) []string { - if len(s) < 255 { - return []string{s} - } - sx := []string{} - p, i := 0, 255 - for { - if i <= len(s) { - sx = append(sx, s[p:i]) - } else { - sx = append(sx, s[p:]) - break - - } - p, i = p+255, i+255 - } - - return sx -} - -// targetStrip strips "targetstrip" labels from the left side of the fully qualified name. -func targetStrip(name string, targetStrip int) string { - if targetStrip == 0 { - return name - } - - offset, end := 0, false - for i := 0; i < targetStrip; i++ { - offset, end = dns.NextLabel(name, offset) - } - if end { - // We overshot the name, use the orignal one. - offset = 0 - } - name = name[offset:] - return name -} diff --git a/middleware/etcd/msg/service_test.go b/middleware/etcd/msg/service_test.go deleted file mode 100644 index 0c19ba95b..000000000 --- a/middleware/etcd/msg/service_test.go +++ /dev/null @@ -1,125 +0,0 @@ -package msg - -import "testing" - -func TestSplit255(t *testing.T) { - xs := split255("abc") - if len(xs) != 1 && xs[0] != "abc" { - t.Errorf("Failure to split abc") - } - s := "" - for i := 0; i < 255; i++ { - s += "a" - } - xs = split255(s) - if len(xs) != 1 && xs[0] != s { - t.Errorf("failure to split 255 char long string") - } - s += "b" - xs = split255(s) - if len(xs) != 2 || xs[1] != "b" { - t.Errorf("failure to split 256 char long string: %d", len(xs)) - } - for i := 0; i < 255; i++ { - s += "a" - } - xs = split255(s) - if len(xs) != 3 || xs[2] != "a" { - t.Errorf("failure to split 510 char long string: %d", len(xs)) - } -} - -func TestGroup(t *testing.T) { - // Key are in the wrong order, but for this test it does not matter. - sx := Group( - []Service{ - {Host: "127.0.0.1", Group: "g1", Key: "b/sub/dom1/skydns/test"}, - {Host: "127.0.0.2", Group: "g2", Key: "a/dom1/skydns/test"}, - }, - ) - // Expecting to return the shortest key with a Group attribute. - if len(sx) != 1 { - t.Fatalf("failure to group zeroth set: %v", sx) - } - if sx[0].Key != "a/dom1/skydns/test" { - t.Fatalf("failure to group zeroth set: %v, wrong Key", sx) - } - - // Groups disagree, so we will not do anything. - sx = Group( - []Service{ - {Host: "server1", Group: "g1", Key: "region1/skydns/test"}, - {Host: "server2", Group: "g2", Key: "region1/skydns/test"}, - }, - ) - if len(sx) != 2 { - t.Fatalf("failure to group first set: %v", sx) - } - - // Group is g1, include only the top-level one. - sx = Group( - []Service{ - {Host: "server1", Group: "g1", Key: "a/dom/region1/skydns/test"}, - {Host: "server2", Group: "g2", Key: "a/subdom/dom/region1/skydns/test"}, - }, - ) - if len(sx) != 1 { - t.Fatalf("failure to group second set: %v", sx) - } - - // Groupless services must be included. - sx = Group( - []Service{ - {Host: "server1", Group: "g1", Key: "a/dom/region1/skydns/test"}, - {Host: "server2", Group: "g2", Key: "a/subdom/dom/region1/skydns/test"}, - {Host: "server2", Group: "", Key: "b/subdom/dom/region1/skydns/test"}, - }, - ) - if len(sx) != 2 { - t.Fatalf("failure to group third set: %v", sx) - } - - // Empty group on the highest level: include that one also. - sx = Group( - []Service{ - {Host: "server1", Group: "g1", Key: "a/dom/region1/skydns/test"}, - {Host: "server1", Group: "", Key: "b/dom/region1/skydns/test"}, - {Host: "server2", Group: "g2", Key: "a/subdom/dom/region1/skydns/test"}, - }, - ) - if len(sx) != 2 { - t.Fatalf("failure to group fourth set: %v", sx) - } - - // Empty group on the highest level: include that one also, and the rest. - sx = Group( - []Service{ - {Host: "server1", Group: "g5", Key: "a/dom/region1/skydns/test"}, - {Host: "server1", Group: "", Key: "b/dom/region1/skydns/test"}, - {Host: "server2", Group: "g5", Key: "a/subdom/dom/region1/skydns/test"}, - }, - ) - if len(sx) != 3 { - t.Fatalf("failure to group fith set: %v", sx) - } - - // One group. - sx = Group( - []Service{ - {Host: "server1", Group: "g6", Key: "a/dom/region1/skydns/test"}, - }, - ) - if len(sx) != 1 { - t.Fatalf("failure to group sixth set: %v", sx) - } - - // No group, once service - sx = Group( - []Service{ - {Host: "server1", Key: "a/dom/region1/skydns/test"}, - }, - ) - if len(sx) != 1 { - t.Fatalf("failure to group seventh set: %v", sx) - } -} diff --git a/middleware/etcd/msg/type.go b/middleware/etcd/msg/type.go deleted file mode 100644 index 7f3bfdbb9..000000000 --- a/middleware/etcd/msg/type.go +++ /dev/null @@ -1,33 +0,0 @@ -package msg - -import ( - "net" - - "github.com/miekg/dns" -) - -// HostType returns the DNS type of what is encoded in the Service Host field. We're reusing -// dns.TypeXXX to not reinvent a new set of identifiers. -// -// dns.TypeA: the service's Host field contains an A record. -// dns.TypeAAAA: the service's Host field contains an AAAA record. -// dns.TypeCNAME: the service's Host field contains a name. -// -// Note that a service can double/triple as a TXT record or MX record. -func (s *Service) HostType() (what uint16, normalized net.IP) { - - ip := net.ParseIP(s.Host) - - switch { - case ip == nil: - return dns.TypeCNAME, nil - - case ip.To4() != nil: - return dns.TypeA, ip.To4() - - case ip.To4() == nil: - return dns.TypeAAAA, ip.To16() - } - // This should never be reached. - return dns.TypeNone, nil -} diff --git a/middleware/etcd/msg/type_test.go b/middleware/etcd/msg/type_test.go deleted file mode 100644 index bad1eead0..000000000 --- a/middleware/etcd/msg/type_test.go +++ /dev/null @@ -1,31 +0,0 @@ -package msg - -import ( - "testing" - - "github.com/miekg/dns" -) - -func TestType(t *testing.T) { - tests := []struct { - serv Service - expectedType uint16 - }{ - {Service{Host: "example.org"}, dns.TypeCNAME}, - {Service{Host: "127.0.0.1"}, dns.TypeA}, - {Service{Host: "2000::3"}, dns.TypeAAAA}, - {Service{Host: "2000..3"}, dns.TypeCNAME}, - {Service{Host: "127.0.0.257"}, dns.TypeCNAME}, - {Service{Host: "127.0.0.252", Mail: true}, dns.TypeA}, - {Service{Host: "127.0.0.252", Mail: true, Text: "a"}, dns.TypeA}, - {Service{Host: "127.0.0.254", Mail: false, Text: "a"}, dns.TypeA}, - } - - for i, tc := range tests { - what, _ := tc.serv.HostType() - if what != tc.expectedType { - t.Errorf("Test %d: Expected what %v, but got %v", i, tc.expectedType, what) - } - } - -} diff --git a/middleware/etcd/multi_test.go b/middleware/etcd/multi_test.go deleted file mode 100644 index 301b2c49e..000000000 --- a/middleware/etcd/multi_test.go +++ /dev/null @@ -1,59 +0,0 @@ -// +build etcd - -package etcd - -import ( - "testing" - - "github.com/coredns/coredns/middleware/etcd/msg" - "github.com/coredns/coredns/middleware/pkg/dnsrecorder" - "github.com/coredns/coredns/middleware/test" - - "github.com/miekg/dns" -) - -func TestMultiLookup(t *testing.T) { - etc := newEtcdMiddleware() - etc.Zones = []string{"skydns.test.", "miek.nl."} - etc.Fallthrough = true - etc.Next = test.ErrorHandler() - - for _, serv := range servicesMulti { - set(t, etc, serv.Key, 0, serv) - defer delete(t, etc, serv.Key) - } - for _, tc := range dnsTestCasesMulti { - m := tc.Msg() - - rec := dnsrecorder.New(&test.ResponseWriter{}) - _, err := etc.ServeDNS(ctxt, rec, m) - if err != nil { - t.Errorf("expected no error, got %v\n", err) - return - } - - resp := rec.Msg - test.SortAndCheck(t, resp, tc) - } -} - -// Note the key is encoded as DNS name, while in "reality" it is a etcd path. -var servicesMulti = []*msg.Service{ - {Host: "dev.server1", Port: 8080, Key: "a.server1.dev.region1.skydns.test."}, - {Host: "dev.server1", Port: 8080, Key: "a.server1.dev.region1.miek.nl."}, - {Host: "dev.server1", Port: 8080, Key: "a.server1.dev.region1.example.org."}, -} - -var dnsTestCasesMulti = []test.Case{ - { - Qname: "a.server1.dev.region1.skydns.test.", Qtype: dns.TypeSRV, - Answer: []dns.RR{test.SRV("a.server1.dev.region1.skydns.test. 300 SRV 10 100 8080 dev.server1.")}, - }, - { - Qname: "a.server1.dev.region1.miek.nl.", Qtype: dns.TypeSRV, - Answer: []dns.RR{test.SRV("a.server1.dev.region1.miek.nl. 300 SRV 10 100 8080 dev.server1.")}, - }, - { - Qname: "a.server1.dev.region1.example.org.", Qtype: dns.TypeSRV, Rcode: dns.RcodeServerFailure, - }, -} diff --git a/middleware/etcd/other_test.go b/middleware/etcd/other_test.go deleted file mode 100644 index b3849b9f7..000000000 --- a/middleware/etcd/other_test.go +++ /dev/null @@ -1,150 +0,0 @@ -// +build etcd - -// tests mx and txt records - -package etcd - -import ( - "fmt" - "strings" - "testing" - - "github.com/coredns/coredns/middleware/etcd/msg" - "github.com/coredns/coredns/middleware/pkg/dnsrecorder" - "github.com/coredns/coredns/middleware/test" - - "github.com/miekg/dns" -) - -func TestOtherLookup(t *testing.T) { - etc := newEtcdMiddleware() - - for _, serv := range servicesOther { - set(t, etc, serv.Key, 0, serv) - defer delete(t, etc, serv.Key) - } - for _, tc := range dnsTestCasesOther { - m := tc.Msg() - - rec := dnsrecorder.New(&test.ResponseWriter{}) - _, err := etc.ServeDNS(ctxt, rec, m) - if err != nil { - t.Errorf("expected no error, got %v\n", err) - continue - } - - resp := rec.Msg - test.SortAndCheck(t, resp, tc) - } -} - -// Note the key is encoded as DNS name, while in "reality" it is a etcd path. -var servicesOther = []*msg.Service{ - {Host: "dev.server1", Port: 8080, Key: "a.server1.dev.region1.skydns.test."}, - - // mx - {Host: "mx.skydns.test", Priority: 50, Mail: true, Key: "a.mail.skydns.test."}, - {Host: "mx.miek.nl", Priority: 50, Mail: true, Key: "b.mail.skydns.test."}, - {Host: "a.ipaddr.skydns.test", Priority: 30, Mail: true, Key: "a.mx.skydns.test."}, - - {Host: "a.ipaddr.skydns.test", Mail: true, Key: "a.mx2.skydns.test."}, - {Host: "b.ipaddr.skydns.test", Mail: true, Key: "b.mx2.skydns.test."}, - - {Host: "a.ipaddr.skydns.test", Priority: 20, Mail: true, Key: "a.mx3.skydns.test."}, - {Host: "a.ipaddr.skydns.test", Priority: 30, Mail: true, Key: "b.mx3.skydns.test."}, - - {Host: "172.16.1.1", Key: "a.ipaddr.skydns.test."}, - {Host: "172.16.1.2", Key: "b.ipaddr.skydns.test."}, - - // txt - {Text: "abc", Key: "a1.txt.skydns.test."}, - {Text: "abc abc", Key: "a2.txt.skydns.test."}, - // txt sizes - {Text: strings.Repeat("0", 400), Key: "large400.skydns.test."}, - {Text: strings.Repeat("0", 600), Key: "large600.skydns.test."}, - {Text: strings.Repeat("0", 2000), Key: "large2000.skydns.test."}, - - // duplicate ip address - {Host: "10.11.11.10", Key: "http.multiport.http.skydns.test.", Port: 80}, - {Host: "10.11.11.10", Key: "https.multiport.http.skydns.test.", Port: 443}, -} - -var dnsTestCasesOther = []test.Case{ - // MX Tests - { - // NODATA as this is not an Mail: true record. - Qname: "a.server1.dev.region1.skydns.test.", Qtype: dns.TypeMX, - Ns: []dns.RR{ - test.SOA("skydns.test. 300 SOA ns.dns.skydns.test. hostmaster.skydns.test. 0 0 0 0 0"), - }, - }, - { - Qname: "a.mail.skydns.test.", Qtype: dns.TypeMX, - Answer: []dns.RR{test.MX("a.mail.skydns.test. 300 IN MX 50 mx.skydns.test.")}, - Extra: []dns.RR{ - test.A("a.ipaddr.skydns.test. 300 IN A 172.16.1.1"), - test.CNAME("mx.skydns.test. 300 IN CNAME a.ipaddr.skydns.test."), - }, - }, - { - Qname: "mx2.skydns.test.", Qtype: dns.TypeMX, - Answer: []dns.RR{ - test.MX("mx2.skydns.test. 300 IN MX 10 a.ipaddr.skydns.test."), - test.MX("mx2.skydns.test. 300 IN MX 10 b.ipaddr.skydns.test."), - }, - Extra: []dns.RR{ - test.A("a.ipaddr.skydns.test. 300 A 172.16.1.1"), - test.A("b.ipaddr.skydns.test. 300 A 172.16.1.2"), - }, - }, - // different priority, same host - { - Qname: "mx3.skydns.test.", Qtype: dns.TypeMX, - Answer: []dns.RR{ - test.MX("mx3.skydns.test. 300 IN MX 20 a.ipaddr.skydns.test."), - test.MX("mx3.skydns.test. 300 IN MX 30 a.ipaddr.skydns.test."), - }, - Extra: []dns.RR{ - test.A("a.ipaddr.skydns.test. 300 A 172.16.1.1"), - }, - }, - // Txt - { - Qname: "a1.txt.skydns.test.", Qtype: dns.TypeTXT, - Answer: []dns.RR{ - test.TXT("a1.txt.skydns.test. 300 IN TXT \"abc\""), - }, - }, - { - Qname: "a2.txt.skydns.test.", Qtype: dns.TypeTXT, - Answer: []dns.RR{ - test.TXT("a2.txt.skydns.test. 300 IN TXT \"abc abc\""), - }, - }, - // Large txt less than 512 - { - Qname: "large400.skydns.test.", Qtype: dns.TypeTXT, - Answer: []dns.RR{ - test.TXT(fmt.Sprintf("large400.skydns.test. 300 IN TXT \"%s\"", strings.Repeat("0", 400))), - }, - }, - // Large txt greater than 512 (UDP) - { - Qname: "large600.skydns.test.", Qtype: dns.TypeTXT, - Answer: []dns.RR{ - test.TXT(fmt.Sprintf("large600.skydns.test. 300 IN TXT \"%s\"", strings.Repeat("0", 600))), - }, - }, - // Large txt greater than 1500 (typical Ethernet) - { - Qname: "large2000.skydns.test.", Qtype: dns.TypeTXT, - Answer: []dns.RR{ - test.TXT(fmt.Sprintf("large2000.skydns.test. 300 IN TXT \"%s\"", strings.Repeat("0", 2000))), - }, - }, - // Duplicate IP address test - { - Qname: "multiport.http.skydns.test.", Qtype: dns.TypeA, - Answer: []dns.RR{test.A("multiport.http.skydns.test. 300 IN A 10.11.11.10")}, - }, -} diff --git a/middleware/etcd/setup.go b/middleware/etcd/setup.go deleted file mode 100644 index 7cbcfd2ea..000000000 --- a/middleware/etcd/setup.go +++ /dev/null @@ -1,144 +0,0 @@ -package etcd - -import ( - "crypto/tls" - - "github.com/coredns/coredns/core/dnsserver" - "github.com/coredns/coredns/middleware" - "github.com/coredns/coredns/middleware/pkg/dnsutil" - "github.com/coredns/coredns/middleware/pkg/singleflight" - mwtls "github.com/coredns/coredns/middleware/pkg/tls" - "github.com/coredns/coredns/middleware/proxy" - - etcdc "github.com/coreos/etcd/client" - "github.com/mholt/caddy" - "golang.org/x/net/context" -) - -func init() { - caddy.RegisterPlugin("etcd", caddy.Plugin{ - ServerType: "dns", - Action: setup, - }) -} - -func setup(c *caddy.Controller) error { - e, stubzones, err := etcdParse(c) - if err != nil { - return middleware.Error("etcd", err) - } - - if stubzones { - c.OnStartup(func() error { - e.UpdateStubZones() - return nil - }) - } - - dnsserver.GetConfig(c).AddMiddleware(func(next middleware.Handler) middleware.Handler { - e.Next = next - return e - }) - - return nil -} - -func etcdParse(c *caddy.Controller) (*Etcd, bool, error) { - stub := make(map[string]proxy.Proxy) - etc := Etcd{ - // Don't default to a proxy for lookups. - // Proxy: proxy.NewLookup([]string{"8.8.8.8:53", "8.8.4.4:53"}), - PathPrefix: "skydns", - Ctx: context.Background(), - Inflight: &singleflight.Group{}, - Stubmap: &stub, - } - var ( - tlsConfig *tls.Config - err error - endpoints = []string{defaultEndpoint} - stubzones = false - ) - for c.Next() { - etc.Zones = c.RemainingArgs() - if len(etc.Zones) == 0 { - etc.Zones = make([]string, len(c.ServerBlockKeys)) - copy(etc.Zones, c.ServerBlockKeys) - } - for i, str := range etc.Zones { - etc.Zones[i] = middleware.Host(str).Normalize() - } - - if c.NextBlock() { - for { - switch c.Val() { - case "stubzones": - stubzones = true - case "fallthrough": - etc.Fallthrough = true - case "debug": - /* it is a noop now */ - case "path": - if !c.NextArg() { - return &Etcd{}, false, c.ArgErr() - } - etc.PathPrefix = c.Val() - case "endpoint": - args := c.RemainingArgs() - if len(args) == 0 { - return &Etcd{}, false, c.ArgErr() - } - endpoints = args - case "upstream": - args := c.RemainingArgs() - if len(args) == 0 { - return &Etcd{}, false, c.ArgErr() - } - ups, err := dnsutil.ParseHostPortOrFile(args...) - if err != nil { - return &Etcd{}, false, err - } - etc.Proxy = proxy.NewLookup(ups) - case "tls": // cert key cacertfile - args := c.RemainingArgs() - tlsConfig, err = mwtls.NewTLSConfigFromArgs(args...) - if err != nil { - return &Etcd{}, false, err - } - default: - if c.Val() != "}" { - return &Etcd{}, false, c.Errf("unknown property '%s'", c.Val()) - } - } - - if !c.Next() { - break - } - } - - } - client, err := newEtcdClient(endpoints, tlsConfig) - if err != nil { - return &Etcd{}, false, err - } - etc.Client = client - etc.endpoints = endpoints - - return &etc, stubzones, nil - } - return &Etcd{}, false, nil -} - -func newEtcdClient(endpoints []string, cc *tls.Config) (etcdc.KeysAPI, error) { - etcdCfg := etcdc.Config{ - Endpoints: endpoints, - Transport: mwtls.NewHTTPSTransport(cc), - } - cli, err := etcdc.New(etcdCfg) - if err != nil { - return nil, err - } - return etcdc.NewKeysAPI(cli), nil -} - -const defaultEndpoint = "http://localhost:2379" diff --git a/middleware/etcd/setup_test.go b/middleware/etcd/setup_test.go deleted file mode 100644 index 833e2ba4c..000000000 --- a/middleware/etcd/setup_test.go +++ /dev/null @@ -1,64 +0,0 @@ -package etcd - -import ( - "strings" - "testing" - - "github.com/mholt/caddy" -) - -func TestSetupEtcd(t *testing.T) { - tests := []struct { - input string - shouldErr bool - expectedPath string - expectedEndpoint string - expectedErrContent string // substring from the expected error. Empty for positive cases. - }{ - // positive - { - `etcd`, false, "skydns", "http://localhost:2379", "", - }, - { - `etcd skydns.local { - endpoint localhost:300 -} -`, false, "skydns", "localhost:300", "", - }, - // negative - { - `etcd { - endpoints localhost:300 -} -`, true, "", "", "unknown property 'endpoints'", - }, - } - - for i, test := range tests { - c := caddy.NewTestController("dns", test.input) - etcd, _ /*stubzones*/, err := etcdParse(c) - - if test.shouldErr && err == nil { - t.Errorf("Test %d: Expected error but found %s for input %s", i, err, test.input) - } - - if err != nil { - if !test.shouldErr { - t.Errorf("Test %d: Expected no error but found one for input %s. Error was: %v", i, test.input, err) - continue - } - - if !strings.Contains(err.Error(), test.expectedErrContent) { - t.Errorf("Test %d: Expected error to contain: %v, found error: %v, input: %s", i, test.expectedErrContent, err, test.input) - continue - } - } - - if !test.shouldErr && etcd.PathPrefix != test.expectedPath { - t.Errorf("Etcd not correctly set for input %s. Expected: %s, actual: %s", test.input, test.expectedPath, etcd.PathPrefix) - } - if !test.shouldErr && etcd.endpoints[0] != test.expectedEndpoint { // only checks the first - t.Errorf("Etcd not correctly set for input %s. Expected: '%s', actual: '%s'", test.input, test.expectedEndpoint, etcd.endpoints[0]) - } - } -} diff --git a/middleware/etcd/stub.go b/middleware/etcd/stub.go deleted file mode 100644 index b40af6341..000000000 --- a/middleware/etcd/stub.go +++ /dev/null @@ -1,82 +0,0 @@ -package etcd - -import ( - "log" - "net" - "strconv" - "time" - - "github.com/coredns/coredns/middleware/etcd/msg" - "github.com/coredns/coredns/middleware/pkg/dnsutil" - "github.com/coredns/coredns/middleware/proxy" - "github.com/coredns/coredns/request" - - "github.com/miekg/dns" -) - -// UpdateStubZones checks etcd for an update on the stubzones. -func (e *Etcd) UpdateStubZones() { - go func() { - for { - e.updateStubZones() - time.Sleep(15 * time.Second) - } - }() -} - -// Look in .../dns/stub/<zone>/xx for msg.Services. Loop through them -// extract <zone> and add them as forwarders (ip:port-combos) for -// the stub zones. Only numeric (i.e. IP address) hosts are used. -// Only the first zone configured on e is used for the lookup. -func (e *Etcd) updateStubZones() { - zone := e.Zones[0] - - fakeState := request.Request{W: nil, Req: new(dns.Msg)} - fakeState.Req.SetQuestion(stubDomain+"."+zone, dns.TypeA) - - services, err := e.Records(fakeState, false) - if err != nil { - return - } - - stubmap := make(map[string]proxy.Proxy) - // track the nameservers on a per domain basis, but allow a list on the domain. - nameservers := map[string][]string{} - -Services: - for _, serv := range services { - if serv.Port == 0 { - serv.Port = 53 - } - ip := net.ParseIP(serv.Host) - if ip == nil { - log.Printf("[WARNING] Non IP address stub nameserver: %s", serv.Host) - continue - } - - domain := msg.Domain(serv.Key) - labels := dns.SplitDomainName(domain) - - // If the remaining name equals any of the zones we have, we ignore it. - for _, z := range e.Zones { - // Chop of left most label, because that is used as the nameserver place holder - // and drop the right most labels that belong to zone. - // We must *also* chop of dns.stub. which means cutting two more labels. - domain = dnsutil.Join(labels[1 : len(labels)-dns.CountLabel(z)-2]) - if domain == z { - log.Printf("[WARNING] Skipping nameserver for domain we are authoritative for: %s", domain) - continue Services - } - } - nameservers[domain] = append(nameservers[domain], net.JoinHostPort(serv.Host, strconv.Itoa(serv.Port))) - } - - for domain, nss := range nameservers { - stubmap[domain] = proxy.NewLookup(nss) - } - // atomic swap (at least that's what we hope it is) - if len(stubmap) > 0 { - e.Stubmap = &stubmap - } - return -} diff --git a/middleware/etcd/stub_handler.go b/middleware/etcd/stub_handler.go deleted file mode 100644 index a6b752177..000000000 --- a/middleware/etcd/stub_handler.go +++ /dev/null @@ -1,86 +0,0 @@ -package etcd - -import ( - "errors" - "log" - - "github.com/coredns/coredns/request" - - "github.com/miekg/dns" - "golang.org/x/net/context" -) - -// Stub wraps an Etcd. We have this type so that it can have a ServeDNS method. -type Stub struct { - *Etcd - Zone string // for what zone (and thus what nameservers are we called) -} - -// ServeDNS implements the middleware.Handler interface. -func (s Stub) ServeDNS(ctx context.Context, w dns.ResponseWriter, req *dns.Msg) (int, error) { - if hasStubEdns0(req) { - log.Printf("[WARNING] Forwarding cycle detected, refusing msg: %s", req.Question[0].Name) - return dns.RcodeRefused, errors.New("stub forward cycle") - } - req = addStubEdns0(req) - proxy, ok := (*s.Etcd.Stubmap)[s.Zone] - if !ok { // somebody made a mistake.. - return dns.RcodeServerFailure, nil - } - - state := request.Request{W: w, Req: req} - m, e := proxy.Forward(state) - if e != nil { - return dns.RcodeServerFailure, e - } - m.RecursionAvailable, m.Compress = true, true - state.SizeAndDo(m) - w.WriteMsg(m) - return dns.RcodeSuccess, nil -} - -// hasStubEdns0 checks if the message is carrying our special edns0 zero option. -func hasStubEdns0(m *dns.Msg) bool { - option := m.IsEdns0() - if option == nil { - return false - } - for _, o := range option.Option { - if o.Option() == ednsStubCode && len(o.(*dns.EDNS0_LOCAL).Data) == 1 && - o.(*dns.EDNS0_LOCAL).Data[0] == 1 { - return true - } - } - return false -} - -// addStubEdns0 adds our special option to the message's OPT record. -func addStubEdns0(m *dns.Msg) *dns.Msg { - option := m.IsEdns0() - // Add a custom EDNS0 option to the packet, so we can detect loops when 2 stubs are forwarding to each other. - if option != nil { - option.Option = append(option.Option, &dns.EDNS0_LOCAL{Code: ednsStubCode, Data: []byte{1}}) - return m - } - - m.Extra = append(m.Extra, ednsStub) - return m -} - -const ( - ednsStubCode = dns.EDNS0LOCALSTART + 10 - stubDomain = "stub.dns" -) - -var ednsStub = func() *dns.OPT { - o := new(dns.OPT) - o.Hdr.Name = "." - o.Hdr.Rrtype = dns.TypeOPT - o.SetUDPSize(4096) - - e := new(dns.EDNS0_LOCAL) - e.Code = ednsStubCode - e.Data = []byte{1} - o.Option = append(o.Option, e) - return o -}() diff --git a/middleware/etcd/stub_test.go b/middleware/etcd/stub_test.go deleted file mode 100644 index 5f22f42c9..000000000 --- a/middleware/etcd/stub_test.go +++ /dev/null @@ -1,88 +0,0 @@ -// +build etcd - -package etcd - -import ( - "net" - "strconv" - "testing" - - "github.com/coredns/coredns/middleware/etcd/msg" - "github.com/coredns/coredns/middleware/pkg/dnsrecorder" - "github.com/coredns/coredns/middleware/test" - - "github.com/miekg/dns" -) - -func fakeStubServerExampleNet(t *testing.T) (*dns.Server, string) { - server, addr, err := test.UDPServer("127.0.0.1:0") - if err != nil { - t.Fatalf("failed to create a UDP server: %s", err) - } - // add handler for example.net - dns.HandleFunc("example.net.", func(w dns.ResponseWriter, r *dns.Msg) { - m := new(dns.Msg) - m.SetReply(r) - m.Answer = []dns.RR{test.A("example.net. 86400 IN A 93.184.216.34")} - w.WriteMsg(m) - }) - - return server, addr -} - -func TestStubLookup(t *testing.T) { - server, addr := fakeStubServerExampleNet(t) - defer server.Shutdown() - - host, p, _ := net.SplitHostPort(addr) - port, _ := strconv.Atoi(p) - exampleNetStub := &msg.Service{Host: host, Port: port, Key: "a.example.net.stub.dns.skydns.test."} - servicesStub = append(servicesStub, exampleNetStub) - - etc := newEtcdMiddleware() - - for _, serv := range servicesStub { - set(t, etc, serv.Key, 0, serv) - defer delete(t, etc, serv.Key) - } - - etc.updateStubZones() - - for _, tc := range dnsTestCasesStub { - m := tc.Msg() - - rec := dnsrecorder.New(&test.ResponseWriter{}) - _, err := etc.ServeDNS(ctxt, rec, m) - if err != nil && m.Question[0].Name == "example.org." { - // This is OK, we expect this backend to *not* work. - continue - } - if err != nil { - t.Errorf("expected no error, got %v for %s\n", err, m.Question[0].Name) - } - resp := rec.Msg - if resp == nil { - // etcd not running? - continue - } - - test.SortAndCheck(t, resp, tc) - } -} - -var servicesStub = []*msg.Service{ - // Two tests, ask a question that should return servfail because remote it no accessible - // and one with edns0 option added, that should return refused. - {Host: "127.0.0.1", Port: 666, Key: "b.example.org.stub.dns.skydns.test."}, -} - -var dnsTestCasesStub = []test.Case{ - { - Qname: "example.org.", Qtype: dns.TypeA, Rcode: dns.RcodeServerFailure, - }, - { - Qname: "example.net.", Qtype: dns.TypeA, - Answer: []dns.RR{test.A("example.net. 86400 IN A 93.184.216.34")}, - Extra: []dns.RR{test.OPT(4096, false)}, // This will have an EDNS0 section, because *we* added our local stub forward to detect loops. - }, -} |