aboutsummaryrefslogtreecommitdiff
path: root/middleware/etcd
diff options
context:
space:
mode:
authorGravatar Miek Gieben <miek@miek.nl> 2017-09-14 09:36:06 +0100
committerGravatar GitHub <noreply@github.com> 2017-09-14 09:36:06 +0100
commitd8714e64e400ef873c2adc4d929a07d7890727b9 (patch)
treec9fa4c157e6af12eb1517654f8d23ca5d5619513 /middleware/etcd
parentb984aa45595dc95253b91191afe7d3ee29e71b48 (diff)
downloadcoredns-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.md109
-rw-r--r--middleware/etcd/cname_test.go79
-rw-r--r--middleware/etcd/etcd.go188
-rw-r--r--middleware/etcd/group_test.go74
-rw-r--r--middleware/etcd/handler.go97
-rw-r--r--middleware/etcd/lookup_test.go273
-rw-r--r--middleware/etcd/msg/path.go48
-rw-r--r--middleware/etcd/msg/path_test.go12
-rw-r--r--middleware/etcd/msg/service.go203
-rw-r--r--middleware/etcd/msg/service_test.go125
-rw-r--r--middleware/etcd/msg/type.go33
-rw-r--r--middleware/etcd/msg/type_test.go31
-rw-r--r--middleware/etcd/multi_test.go59
-rw-r--r--middleware/etcd/other_test.go150
-rw-r--r--middleware/etcd/setup.go144
-rw-r--r--middleware/etcd/setup_test.go64
-rw-r--r--middleware/etcd/stub.go82
-rw-r--r--middleware/etcd/stub_handler.go86
-rw-r--r--middleware/etcd/stub_test.go88
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.
- },
-}