aboutsummaryrefslogtreecommitdiff
path: root/plugin
diff options
context:
space:
mode:
Diffstat (limited to 'plugin')
-rw-r--r--plugin/auto/README.md6
-rw-r--r--plugin/auto/auto.go2
-rw-r--r--plugin/auto/setup.go11
-rw-r--r--plugin/etcd/README.md18
-rw-r--r--plugin/etcd/etcd.go4
-rw-r--r--plugin/etcd/handler.go14
-rw-r--r--plugin/etcd/lookup_test.go4
-rw-r--r--plugin/etcd/setup.go40
-rw-r--r--plugin/etcd/setup_test.go2
-rw-r--r--plugin/etcd/stub.go81
-rw-r--r--plugin/etcd/stub_handler.go83
-rw-r--r--plugin/etcd/stub_test.go87
-rw-r--r--plugin/federation/README.md8
-rw-r--r--plugin/federation/setup.go8
-rw-r--r--plugin/file/README.md10
-rw-r--r--plugin/file/cname_test.go124
-rw-r--r--plugin/file/dname_test.go4
-rw-r--r--plugin/file/lookup.go1
-rw-r--r--plugin/file/setup.go9
-rw-r--r--plugin/file/setup_test.go4
-rw-r--r--plugin/file/zone.go2
-rw-r--r--plugin/forward/forward_test.go69
-rw-r--r--plugin/forward/lookup.go89
-rw-r--r--plugin/forward/lookup_test.go43
-rw-r--r--plugin/kubernetes/kubernetes.go2
-rw-r--r--plugin/kubernetes/setup.go8
-rw-r--r--plugin/kubernetes/setup_test.go72
-rw-r--r--plugin/pkg/upstream/upstream.go57
-rw-r--r--plugin/proxy/healthcheck_test.go60
-rw-r--r--plugin/proxy/lookup.go127
-rw-r--r--plugin/proxy/proxy_test.go27
-rw-r--r--plugin/route53/README.md56
-rw-r--r--plugin/route53/route53.go2
-rw-r--r--plugin/route53/setup.go11
-rw-r--r--plugin/secondary/README.md10
-rw-r--r--plugin/secondary/setup.go9
-rw-r--r--plugin/template/README.md19
-rw-r--r--plugin/template/setup.go8
-rw-r--r--plugin/template/setup_test.go7
39 files changed, 118 insertions, 1080 deletions
diff --git a/plugin/auto/README.md b/plugin/auto/README.md
index b2644c17b..3101366b7 100644
--- a/plugin/auto/README.md
+++ b/plugin/auto/README.md
@@ -18,7 +18,7 @@ auto [ZONES...] {
directory DIR [REGEXP ORIGIN_TEMPLATE [TIMEOUT]]
reload DURATION
no_reload
- upstream [ADDRESS...]
+ upstream
}
~~~
@@ -37,9 +37,7 @@ are used.
and reloads zone when serial changes.
* `no_reload` deprecated. Sets reload to 0.
* `upstream` defines upstream resolvers to be used resolve external names found (think CNAMEs)
- pointing to external names. **ADDRESS** can be an IP address, an IP:port or a string pointing to
- a file that is structured as /etc/resolv.conf. If no **ADDRESS** is given, CoreDNS will resolve CNAMEs
- against itself.
+ pointing to external names. CoreDNS will resolve CNAMEs against itself.
All directives from the *file* plugin are supported. Note that *auto* will load all zones found,
even though the directive might only receive queries for a specific zone. I.e:
diff --git a/plugin/auto/auto.go b/plugin/auto/auto.go
index 8cbfaf948..a09c22801 100644
--- a/plugin/auto/auto.go
+++ b/plugin/auto/auto.go
@@ -33,7 +33,7 @@ type (
// In the future this should be something like ZoneMeta that contains all this stuff.
transferTo []string
ReloadInterval time.Duration
- upstream upstream.Upstream // Upstream for looking up names during the resolution process.
+ upstream *upstream.Upstream // Upstream for looking up names during the resolution process.
duration time.Duration
}
diff --git a/plugin/auto/setup.go b/plugin/auto/setup.go
index f8356aa3d..62a4da870 100644
--- a/plugin/auto/setup.go
+++ b/plugin/auto/setup.go
@@ -155,15 +155,8 @@ func autoParse(c *caddy.Controller) (Auto, error) {
a.loader.ReloadInterval = 0
case "upstream":
- args := c.RemainingArgs()
- if len(args) == 0 {
- return a, c.ArgErr()
- }
- var err error
- a.loader.upstream, err = upstream.New(args)
- if err != nil {
- return a, err
- }
+ c.RemainingArgs() // eat remaining args
+ a.loader.upstream = upstream.New()
default:
t, _, e := parse.Transfer(c, false)
diff --git a/plugin/etcd/README.md b/plugin/etcd/README.md
index 7a85fa60d..e0e33bbfc 100644
--- a/plugin/etcd/README.md
+++ b/plugin/etcd/README.md
@@ -28,28 +28,22 @@ If you want to `round robin` A and AAAA responses look at the `loadbalance` plug
~~~
etcd [ZONES...] {
- stubzones
fallthrough [ZONES...]
path PATH
endpoint ENDPOINT...
- upstream [ADDRESS...]
+ upstream
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 plugin.
If **[ZONES...]** is omitted, then fallthrough happens for all zones for which the plugin
is authoritative. If specific zones are listed (for example `in-addr.arpa` and `ip6.arpa`), then only
queries for those zones will be subject to fallthrough.
* **PATH** the path inside etcd. Defaults to "/skydns".
* **ENDPOINT** the etcd endpoints. Defaults to "http://localhost:2379".
-* `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 plugin. If no **ADDRESS** is given, CoreDNS will resolve CNAMEs against itself.
- **ADDRESS** can be an IP address, and IP:port or a string pointing to a file that is structured
- as /etc/resolv.conf.
+* `upstream` resolve names found in etcd (think CNAMEs) If you want CoreDNS to act as a proxy for clients,
+ you'll need to add the forward plugin. CoreDNS will resolve CNAMEs against itself.
* `tls` followed by:
* no arguments, if the server certificate is signed by a system-installed CA and no client cert is needed
@@ -79,10 +73,9 @@ This is the default SkyDNS setup, with everything specified in full:
~~~ corefile
. {
etcd skydns.local {
- stubzones
path /skydns
endpoint http://localhost:2379
- upstream 8.8.8.8:53 8.8.4.4:53
+ upstream
}
prometheus
cache 160 skydns.local
@@ -98,7 +91,7 @@ when resolving external pointing CNAMEs.
. {
etcd skydns.local {
path /skydns
- upstream /etc/resolv.conf
+ upstream
}
cache 160 skydns.local
proxy . /etc/resolv.conf
@@ -125,7 +118,6 @@ need to add the zone `0.0.10.in-addr.arpa` to the list of zones. Showing a snipp
~~~
etcd skydns.local 10.0.0.0/24 {
- stubzones
...
~~~
diff --git a/plugin/etcd/etcd.go b/plugin/etcd/etcd.go
index 9b37ee458..4734fe344 100644
--- a/plugin/etcd/etcd.go
+++ b/plugin/etcd/etcd.go
@@ -12,7 +12,6 @@ import (
"github.com/coredns/coredns/plugin"
"github.com/coredns/coredns/plugin/etcd/msg"
"github.com/coredns/coredns/plugin/pkg/fall"
- "github.com/coredns/coredns/plugin/proxy"
"github.com/coredns/coredns/request"
"github.com/coredns/coredns/plugin/pkg/upstream"
@@ -35,10 +34,9 @@ type Etcd struct {
Fall fall.F
Zones []string
PathPrefix string
- Upstream upstream.Upstream // Proxy for looking up names during the resolution process
+ Upstream *upstream.Upstream
Client *etcdcv3.Client
Ctx context.Context
- Stubmap *map[string]proxy.Proxy // list of proxies for stub resolving.
endpoints []string // Stored here as well, to aid in testing.
}
diff --git a/plugin/etcd/handler.go b/plugin/etcd/handler.go
index 088993cf2..d9c6de4c9 100644
--- a/plugin/etcd/handler.go
+++ b/plugin/etcd/handler.go
@@ -14,20 +14,6 @@ func (e *Etcd) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (
opt := plugin.Options{}
state := request.Request{W: w, Req: r, Context: ctx}
- 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 plugin.Name(zone).Matches(name) {
- stub := Stub{Etcd: e, Zone: zone}
- return stub.ServeDNS(ctx, w, r)
- }
- }
- }
-
zone := plugin.Zones(e.Zones).Matches(state.Name())
if zone == "" {
return plugin.NextOrFailure(e.Name(), e.Next, ctx, w, r)
diff --git a/plugin/etcd/lookup_test.go b/plugin/etcd/lookup_test.go
index d82b4bf18..3b97fe66c 100644
--- a/plugin/etcd/lookup_test.go
+++ b/plugin/etcd/lookup_test.go
@@ -12,7 +12,6 @@ import (
"github.com/coredns/coredns/plugin/pkg/dnstest"
"github.com/coredns/coredns/plugin/pkg/tls"
"github.com/coredns/coredns/plugin/pkg/upstream"
- "github.com/coredns/coredns/plugin/proxy"
"github.com/coredns/coredns/plugin/test"
"github.com/miekg/dns"
@@ -283,9 +282,8 @@ func newEtcdPlugin() *Etcd {
tlsc, _ := tls.NewTLSConfigFromArgs()
client, _ := newEtcdClient(endpoints, tlsc)
- p := proxy.NewLookup([]string{"8.8.8.8:53"})
return &Etcd{
- Upstream: upstream.Upstream{Forward: &p},
+ Upstream: upstream.New(),
PathPrefix: "skydns",
Ctx: context.Background(),
Zones: []string{"skydns.test.", "skydns_extra.test.", "skydns_zonea.test.", "skydns_zoneb.test.", "skydns_zonec.test.", "skydns_zoned.test.", "in-addr.arpa."},
diff --git a/plugin/etcd/setup.go b/plugin/etcd/setup.go
index f753a0f1a..68d5f147d 100644
--- a/plugin/etcd/setup.go
+++ b/plugin/etcd/setup.go
@@ -9,7 +9,6 @@ import (
clog "github.com/coredns/coredns/plugin/pkg/log"
mwtls "github.com/coredns/coredns/plugin/pkg/tls"
"github.com/coredns/coredns/plugin/pkg/upstream"
- "github.com/coredns/coredns/plugin/proxy"
etcdcv3 "github.com/coreos/etcd/clientv3"
"github.com/mholt/caddy"
@@ -25,18 +24,11 @@ func init() {
}
func setup(c *caddy.Controller) error {
- e, stubzones, err := etcdParse(c)
+ e, err := etcdParse(c)
if err != nil {
return plugin.Error("etcd", err)
}
- if stubzones {
- c.OnStartup(func() error {
- e.UpdateStubZones()
- return nil
- })
- }
-
dnsserver.GetConfig(c).AddPlugin(func(next plugin.Handler) plugin.Handler {
e.Next = next
return e
@@ -45,20 +37,17 @@ func setup(c *caddy.Controller) error {
return nil
}
-func etcdParse(c *caddy.Controller) (*Etcd, bool, error) {
- stub := make(map[string]proxy.Proxy)
+func etcdParse(c *caddy.Controller) (*Etcd, error) {
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(),
- Stubmap: &stub,
}
var (
tlsConfig *tls.Config
err error
endpoints = []string{defaultEndpoint}
- stubzones = false
)
for c.Next() {
etc.Zones = c.RemainingArgs()
@@ -74,38 +63,35 @@ func etcdParse(c *caddy.Controller) (*Etcd, bool, error) {
for {
switch c.Val() {
case "stubzones":
- stubzones = true
+ // ignored, remove later.
case "fallthrough":
etc.Fall.SetZonesFromArgs(c.RemainingArgs())
case "debug":
/* it is a noop now */
case "path":
if !c.NextArg() {
- return &Etcd{}, false, c.ArgErr()
+ return &Etcd{}, c.ArgErr()
}
etc.PathPrefix = c.Val()
case "endpoint":
args := c.RemainingArgs()
if len(args) == 0 {
- return &Etcd{}, false, c.ArgErr()
+ return &Etcd{}, c.ArgErr()
}
endpoints = args
case "upstream":
- args := c.RemainingArgs()
- u, err := upstream.New(args)
- if err != nil {
- return nil, false, err
- }
- etc.Upstream = u
+ // check args != 0 and error in the future
+ c.RemainingArgs() // clear buffer
+ etc.Upstream = upstream.New()
case "tls": // cert key cacertfile
args := c.RemainingArgs()
tlsConfig, err = mwtls.NewTLSConfigFromArgs(args...)
if err != nil {
- return &Etcd{}, false, err
+ return &Etcd{}, err
}
default:
if c.Val() != "}" {
- return &Etcd{}, false, c.Errf("unknown property '%s'", c.Val())
+ return &Etcd{}, c.Errf("unknown property '%s'", c.Val())
}
}
@@ -117,14 +103,14 @@ func etcdParse(c *caddy.Controller) (*Etcd, bool, error) {
}
client, err := newEtcdClient(endpoints, tlsConfig)
if err != nil {
- return &Etcd{}, false, err
+ return &Etcd{}, err
}
etc.Client = client
etc.endpoints = endpoints
- return &etc, stubzones, nil
+ return &etc, nil
}
- return &Etcd{}, false, nil
+ return &Etcd{}, nil
}
func newEtcdClient(endpoints []string, cc *tls.Config) (*etcdcv3.Client, error) {
diff --git a/plugin/etcd/setup_test.go b/plugin/etcd/setup_test.go
index 620460cc1..0696dc3e3 100644
--- a/plugin/etcd/setup_test.go
+++ b/plugin/etcd/setup_test.go
@@ -56,7 +56,7 @@ func TestSetupEtcd(t *testing.T) {
for i, test := range tests {
c := caddy.NewTestController("dns", test.input)
- etcd, _ /*stubzones*/, err := etcdParse(c)
+ etcd, err := etcdParse(c)
if test.shouldErr && err == nil {
t.Errorf("Test %d: Expected error but found %s for input %s", i, err, test.input)
diff --git a/plugin/etcd/stub.go b/plugin/etcd/stub.go
deleted file mode 100644
index 37e426ac4..000000000
--- a/plugin/etcd/stub.go
+++ /dev/null
@@ -1,81 +0,0 @@
-package etcd
-
-import (
- "net"
- "strconv"
- "time"
-
- "github.com/coredns/coredns/plugin/etcd/msg"
- "github.com/coredns/coredns/plugin/pkg/dnsutil"
- "github.com/coredns/coredns/plugin/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.Warningf("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.Warningf("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/plugin/etcd/stub_handler.go b/plugin/etcd/stub_handler.go
deleted file mode 100644
index 1282a8263..000000000
--- a/plugin/etcd/stub_handler.go
+++ /dev/null
@@ -1,83 +0,0 @@
-package etcd
-
-import (
- "context"
- "errors"
-
- "github.com/coredns/coredns/request"
-
- "github.com/miekg/dns"
-)
-
-// 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 plugin.Handler interface.
-func (s Stub) ServeDNS(ctx context.Context, w dns.ResponseWriter, req *dns.Msg) (int, error) {
- if hasStubEdns0(req) {
- log.Warningf("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
- }
- 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/plugin/etcd/stub_test.go b/plugin/etcd/stub_test.go
deleted file mode 100644
index c01100bdf..000000000
--- a/plugin/etcd/stub_test.go
+++ /dev/null
@@ -1,87 +0,0 @@
-// +build etcd
-
-package etcd
-
-import (
- "net"
- "strconv"
- "testing"
-
- "github.com/coredns/coredns/plugin/etcd/msg"
- "github.com/coredns/coredns/plugin/pkg/dnstest"
- "github.com/coredns/coredns/plugin/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 := newEtcdPlugin()
-
- 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 := dnstest.NewRecorder(&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")},
- },
-}
diff --git a/plugin/federation/README.md b/plugin/federation/README.md
index 1bcd23af6..e65a2f6d8 100644
--- a/plugin/federation/README.md
+++ b/plugin/federation/README.md
@@ -17,16 +17,14 @@ Enabling *federation* without also having *kubernetes* is a noop.
~~~
federation [ZONES...] {
NAME DOMAIN
- upstream [ADDRESS...]
+ upstream
}
~~~
* Each **NAME** and **DOMAIN** defines federation membership. One entry for each. A duplicate
**NAME** will silently overwrite any previous value.
-* `upstream` [**ADDRESS**...] defines the upstream resolvers used for resolving the `CNAME` target
- produced by this plugin. If no **ADDRESS** is given, CoreDNS
- will resolve External Services against itself. **ADDRESS** can be an IP, an IP:port, or a path
- to a file structured like resolv.conf.
+* `upstream` [**ADDRESS**...] resolve the `CNAME` target produced by this plugin. CoreDNS
+ will resolve External Services against itself.
## Examples
diff --git a/plugin/federation/setup.go b/plugin/federation/setup.go
index 84e9aba16..0e3decf1b 100644
--- a/plugin/federation/setup.go
+++ b/plugin/federation/setup.go
@@ -64,12 +64,8 @@ func federationParse(c *caddy.Controller) (*Federation, error) {
x := c.Val()
switch x {
case "upstream":
- args := c.RemainingArgs()
- u, err := upstream.New(args)
- if err != nil {
- return nil, err
- }
- fed.Upstream = &u
+ c.RemainingArgs()
+ fed.Upstream = upstream.New()
default:
args := c.RemainingArgs()
if x := len(args); x != 1 {
diff --git a/plugin/file/README.md b/plugin/file/README.md
index 4a7cc3483..a1330ffbc 100644
--- a/plugin/file/README.md
+++ b/plugin/file/README.md
@@ -29,7 +29,7 @@ file DBFILE [ZONES... ] {
transfer to ADDRESS...
reload DURATION
no_reload
- upstream [ADDRESS...]
+ upstream
}
~~~
@@ -41,11 +41,9 @@ file DBFILE [ZONES... ] {
Value of `0` means to not scan for changes and reload. For example, `30s` checks the zonefile every 30 seconds
and reloads the zone when serial changes.
* `no_reload` deprecated. Sets reload to 0.
-* `upstream` defines upstream resolvers to be used resolve external names found (think CNAMEs)
- pointing to external names. This is only really useful when CoreDNS is configured as a proxy; for
- normal authoritative serving you don't need *or* want to use this. **ADDRESS** can be an IP
- address, an IP:port or a string pointing to a file that is structured as /etc/resolv.conf.
- If no **ADDRESS** is given, CoreDNS will resolve CNAMEs against itself.
+* `upstream` resolve external names found (think CNAMEs) pointing to external names. This is only
+ really useful when CoreDNS is configured as a proxy; for normal authoritative serving you don't
+ need *or* want to use this. CoreDNS will resolve CNAMEs against itself.
## Examples
diff --git a/plugin/file/cname_test.go b/plugin/file/cname_test.go
deleted file mode 100644
index 10eb7d934..000000000
--- a/plugin/file/cname_test.go
+++ /dev/null
@@ -1,124 +0,0 @@
-package file
-
-import (
- "context"
- "strings"
- "testing"
-
- "github.com/coredns/coredns/plugin/pkg/dnstest"
- "github.com/coredns/coredns/plugin/pkg/upstream"
- "github.com/coredns/coredns/plugin/test"
-
- "github.com/miekg/dns"
-)
-
-func TestLookupCNAMEChain(t *testing.T) {
- name := "example.org."
- zone, err := Parse(strings.NewReader(dbExampleCNAME), name, "stdin", 0)
- if err != nil {
- t.Fatalf("Expected no error when reading zone, got %q", err)
- }
-
- fm := File{Next: test.ErrorHandler(), Zones: Zones{Z: map[string]*Zone{name: zone}, Names: []string{name}}}
- ctx := context.TODO()
-
- for _, tc := range cnameTestCases {
- m := tc.Msg()
-
- rec := dnstest.NewRecorder(&test.ResponseWriter{})
- _, err := fm.ServeDNS(ctx, rec, m)
- if err != nil {
- t.Errorf("Expected no error, got %v\n", err)
- return
- }
-
- resp := rec.Msg
- test.SortAndCheck(t, resp, tc)
- }
-}
-
-var cnameTestCases = []test.Case{
- {
- Qname: "a.example.org.", Qtype: dns.TypeA,
- Answer: []dns.RR{
- test.A("a.example.org. 1800 IN A 127.0.0.1"),
- },
- },
- {
- Qname: "www3.example.org.", Qtype: dns.TypeCNAME,
- Answer: []dns.RR{
- test.CNAME("www3.example.org. 1800 IN CNAME www2.example.org."),
- },
- },
- {
- Qname: "dangling.example.org.", Qtype: dns.TypeA,
- Answer: []dns.RR{
- test.CNAME("dangling.example.org. 1800 IN CNAME foo.example.org."),
- },
- },
- {
- Qname: "www3.example.org.", Qtype: dns.TypeA,
- Answer: []dns.RR{
- test.A("a.example.org. 1800 IN A 127.0.0.1"),
- test.CNAME("www.example.org. 1800 IN CNAME a.example.org."),
- test.CNAME("www1.example.org. 1800 IN CNAME www.example.org."),
- test.CNAME("www2.example.org. 1800 IN CNAME www1.example.org."),
- test.CNAME("www3.example.org. 1800 IN CNAME www2.example.org."),
- },
- },
-}
-
-func TestLookupCNAMEExternal(t *testing.T) {
- name := "example.org."
- zone, err := Parse(strings.NewReader(dbExampleCNAME), name, "stdin", 0)
- if err != nil {
- t.Fatalf("Expected no error when reading zone, got %q", err)
- }
- zone.Upstream, _ = upstream.New([]string{"8.8.8.8:53"}) // TODO(miek): point to local instance
-
- fm := File{Next: test.ErrorHandler(), Zones: Zones{Z: map[string]*Zone{name: zone}, Names: []string{name}}}
- ctx := context.TODO()
-
- for _, tc := range exernalTestCases {
- m := tc.Msg()
-
- rec := dnstest.NewRecorder(&test.ResponseWriter{})
- _, err := fm.ServeDNS(ctx, rec, m)
- if err != nil {
- t.Errorf("Expected no error, got %v\n", err)
- return
- }
-
- resp := rec.Msg
- test.SortAndCheck(t, resp, tc)
- }
-}
-
-var exernalTestCases = []test.Case{
- {
- Qname: "external.example.org.", Qtype: dns.TypeA,
- Answer: []dns.RR{
- test.CNAME("external.example.org. 1800 CNAME www.example.net."),
- // magic 303 TTL that says: don't check TTL.
- test.A("www.example.net. 303 IN A 93.184.216.34"),
- },
- },
-}
-
-const dbExampleCNAME = `
-$TTL 30M
-$ORIGIN example.org.
-@ IN SOA linode.atoom.net. miek.miek.nl. (
- 1282630057 ; Serial
- 4H ; Refresh
- 1H ; Retry
- 7D ; Expire
- 4H ) ; Negative Cache TTL
-
-a IN A 127.0.0.1
-www3 IN CNAME www2
-www2 IN CNAME www1
-www1 IN CNAME www
-www IN CNAME a
-dangling IN CNAME foo
-external IN CNAME www.example.net.`
diff --git a/plugin/file/dname_test.go b/plugin/file/dname_test.go
index 85dc9d360..c372d14de 100644
--- a/plugin/file/dname_test.go
+++ b/plugin/file/dname_test.go
@@ -1,5 +1,8 @@
package file
+/*
+TODO(miek): move to test/ for full server testing
+
import (
"context"
"strings"
@@ -294,3 +297,4 @@ ns.example.org. 1800 IN A 127.0.0.1
RXpMdvaE6ZDwalWldLjC3h8QDywDoFdndoRY
eHOsmTvvtWWqtO6Fa5A8gmHT5HA= )
`
+*/
diff --git a/plugin/file/lookup.go b/plugin/file/lookup.go
index d15ff5b6a..d020b7788 100644
--- a/plugin/file/lookup.go
+++ b/plugin/file/lookup.go
@@ -374,7 +374,6 @@ func cnameForType(targets []dns.RR, origQtype uint16) []dns.RR {
func (z *Zone) externalLookup(state request.Request, target string, qtype uint16) []dns.RR {
m, e := z.Upstream.Lookup(state, target, qtype)
if e != nil {
- // TODO(miek): Log, or return error here?
return nil
}
if m == nil {
diff --git a/plugin/file/setup.go b/plugin/file/setup.go
index 5c371babc..e74bab7a5 100644
--- a/plugin/file/setup.go
+++ b/plugin/file/setup.go
@@ -93,7 +93,7 @@ func fileParse(c *caddy.Controller) (Zones, error) {
}
reload := 1 * time.Minute
- upstr := upstream.Upstream{}
+ upstr := upstream.New()
t := []string{}
var e error
@@ -116,11 +116,8 @@ func fileParse(c *caddy.Controller) (Zones, error) {
reload = 0
case "upstream":
- args := c.RemainingArgs()
- upstr, err = upstream.New(args)
- if err != nil {
- return Zones{}, err
- }
+ // ignore args, will be error later.
+ c.RemainingArgs() // clear buffer
default:
return Zones{}, c.Errf("unknown property '%s'", c.Val())
diff --git a/plugin/file/setup_test.go b/plugin/file/setup_test.go
index 39cadaaf2..1a3cba0e8 100644
--- a/plugin/file/setup_test.go
+++ b/plugin/file/setup_test.go
@@ -57,8 +57,8 @@ func TestFileParse(t *testing.T) {
`file ` + zoneFileName1 + ` example.net. {
upstream a
}`,
- true,
- Zones{Names: []string{}},
+ false, // OK for now as we disregard any options for the `upstream`.
+ Zones{Names: []string{"example.net."}},
},
{
`file ` + zoneFileName1 + ` example.net. {
diff --git a/plugin/file/zone.go b/plugin/file/zone.go
index e94a00f16..e323350f3 100644
--- a/plugin/file/zone.go
+++ b/plugin/file/zone.go
@@ -32,7 +32,7 @@ type Zone struct {
LastReloaded time.Time
reloadMu sync.RWMutex
reloadShutdown chan bool
- Upstream upstream.Upstream // Upstream for looking up names during the resolution process
+ Upstream *upstream.Upstream // Upstream for looking up external names during the resolution process
}
// Apex contains the apex records of a zone: SOA, NS and their potential signatures.
diff --git a/plugin/forward/forward_test.go b/plugin/forward/forward_test.go
deleted file mode 100644
index dfdde933f..000000000
--- a/plugin/forward/forward_test.go
+++ /dev/null
@@ -1,69 +0,0 @@
-package forward
-
-import (
- "testing"
-
- "github.com/coredns/coredns/plugin/pkg/dnstest"
- "github.com/coredns/coredns/plugin/pkg/transport"
- "github.com/coredns/coredns/plugin/test"
- "github.com/coredns/coredns/request"
-
- "github.com/miekg/dns"
-)
-
-func TestForward(t *testing.T) {
- s := dnstest.NewServer(func(w dns.ResponseWriter, r *dns.Msg) {
- ret := new(dns.Msg)
- ret.SetReply(r)
- ret.Answer = append(ret.Answer, test.A("example.org. IN A 127.0.0.1"))
- w.WriteMsg(ret)
- })
- defer s.Close()
-
- p := NewProxy(s.Addr, transport.DNS)
- f := New()
- f.SetProxy(p)
- defer f.Close()
-
- state := request.Request{W: &test.ResponseWriter{}, Req: new(dns.Msg)}
- state.Req.SetQuestion("example.org.", dns.TypeA)
- resp, err := f.Forward(state)
- if err != nil {
- t.Fatal("Expected to receive reply, but didn't")
- }
- // expect answer section with A record in it
- if len(resp.Answer) == 0 {
- t.Fatalf("Expected to at least one RR in the answer section, got none: %s", resp)
- }
- if resp.Answer[0].Header().Rrtype != dns.TypeA {
- t.Errorf("Expected RR to A, got: %d", resp.Answer[0].Header().Rrtype)
- }
- if resp.Answer[0].(*dns.A).A.String() != "127.0.0.1" {
- t.Errorf("Expected 127.0.0.1, got: %s", resp.Answer[0].(*dns.A).A.String())
- }
-}
-
-func TestForwardRefused(t *testing.T) {
- s := dnstest.NewServer(func(w dns.ResponseWriter, r *dns.Msg) {
- ret := new(dns.Msg)
- ret.SetReply(r)
- ret.Rcode = dns.RcodeRefused
- w.WriteMsg(ret)
- })
- defer s.Close()
-
- p := NewProxy(s.Addr, transport.DNS)
- f := New()
- f.SetProxy(p)
- defer f.Close()
-
- state := request.Request{W: &test.ResponseWriter{}, Req: new(dns.Msg)}
- state.Req.SetQuestion("example.org.", dns.TypeA)
- resp, err := f.Forward(state)
- if err != nil {
- t.Fatal("Expected to receive reply, but didn't")
- }
- if resp.Rcode != dns.RcodeRefused {
- t.Errorf("Expected rcode to be %d, got %d", dns.RcodeRefused, resp.Rcode)
- }
-}
diff --git a/plugin/forward/lookup.go b/plugin/forward/lookup.go
deleted file mode 100644
index f3eb8f34a..000000000
--- a/plugin/forward/lookup.go
+++ /dev/null
@@ -1,89 +0,0 @@
-// Package forward implements a forwarding proxy. It caches an upstream net.Conn for some time, so if the same
-// client returns the upstream's Conn will be precached. Depending on how you benchmark this looks to be
-// 50% faster than just opening a new connection for every client. It works with UDP and TCP and uses
-// inband healthchecking.
-package forward
-
-import (
- "context"
-
- "github.com/coredns/coredns/plugin/pkg/transport"
- "github.com/coredns/coredns/request"
-
- "github.com/miekg/dns"
-)
-
-// Forward forward the request in state as-is. Unlike Lookup that adds EDNS0 suffix to the message.
-// Forward may be called with a nil f, an error is returned in that case.
-func (f *Forward) Forward(state request.Request) (*dns.Msg, error) {
- if f == nil {
- return nil, ErrNoForward
- }
-
- fails := 0
- var upstreamErr error
- for _, proxy := range f.List() {
- if proxy.Down(f.maxfails) {
- fails++
- if fails < len(f.proxies) {
- continue
- }
- // All upstream proxies are dead, assume healtcheck is complete broken and randomly
- // select an upstream to connect to.
- proxy = f.List()[0]
- }
-
- ret, err := proxy.Connect(context.Background(), state, f.opts)
-
- upstreamErr = err
-
- if err != nil {
- if fails < len(f.proxies) {
- continue
- }
- break
- }
-
- // Check if the reply is correct; if not return FormErr.
- if !state.Match(ret) {
- return state.ErrorMessage(dns.RcodeFormatError), nil
- }
-
- ret = state.Scrub(ret)
- return ret, err
- }
-
- if upstreamErr != nil {
- return nil, upstreamErr
- }
-
- return nil, ErrNoHealthy
-}
-
-// Lookup will use name and type to forge a new message and will send that upstream. It will
-// set any EDNS0 options correctly so that downstream will be able to process the reply.
-// Lookup may be called with a nil f, an error is returned in that case.
-func (f *Forward) Lookup(state request.Request, name string, typ uint16) (*dns.Msg, error) {
- if f == nil {
- return nil, ErrNoForward
- }
-
- req := new(dns.Msg)
- req.SetQuestion(name, typ)
- state.SizeAndDo(req)
-
- state2 := request.Request{W: state.W, Req: req}
-
- return f.Forward(state2)
-}
-
-// NewLookup returns a Forward that can be used for plugin that need an upstream to resolve external names.
-// Note that the caller MUST run Close on the forward to stop the health checking goroutines.
-func NewLookup(addr []string) *Forward {
- f := New()
- for i := range addr {
- p := NewProxy(addr[i], transport.DNS)
- f.SetProxy(p)
- }
- return f
-}
diff --git a/plugin/forward/lookup_test.go b/plugin/forward/lookup_test.go
deleted file mode 100644
index bb3cc4143..000000000
--- a/plugin/forward/lookup_test.go
+++ /dev/null
@@ -1,43 +0,0 @@
-package forward
-
-import (
- "testing"
-
- "github.com/coredns/coredns/plugin/pkg/dnstest"
- "github.com/coredns/coredns/plugin/pkg/transport"
- "github.com/coredns/coredns/plugin/test"
- "github.com/coredns/coredns/request"
-
- "github.com/miekg/dns"
-)
-
-func TestLookup(t *testing.T) {
- s := dnstest.NewServer(func(w dns.ResponseWriter, r *dns.Msg) {
- ret := new(dns.Msg)
- ret.SetReply(r)
- ret.Answer = append(ret.Answer, test.A("example.org. IN A 127.0.0.1"))
- w.WriteMsg(ret)
- })
- defer s.Close()
-
- p := NewProxy(s.Addr, transport.DNS)
- f := New()
- f.SetProxy(p)
- defer f.Close()
-
- state := request.Request{W: &test.ResponseWriter{}, Req: new(dns.Msg)}
- resp, err := f.Lookup(state, "example.org.", dns.TypeA)
- if err != nil {
- t.Fatal("Expected to receive reply, but didn't")
- }
- // expect answer section with A record in it
- if len(resp.Answer) == 0 {
- t.Fatalf("Expected to at least one RR in the answer section, got none: %s", resp)
- }
- if resp.Answer[0].Header().Rrtype != dns.TypeA {
- t.Errorf("Expected RR to A, got: %d", resp.Answer[0].Header().Rrtype)
- }
- if resp.Answer[0].(*dns.A).A.String() != "127.0.0.1" {
- t.Errorf("Expected 127.0.0.1, got: %s", resp.Answer[0].(*dns.A).A.String())
- }
-}
diff --git a/plugin/kubernetes/kubernetes.go b/plugin/kubernetes/kubernetes.go
index 304972af3..aef1882f0 100644
--- a/plugin/kubernetes/kubernetes.go
+++ b/plugin/kubernetes/kubernetes.go
@@ -32,7 +32,7 @@ import (
type Kubernetes struct {
Next plugin.Handler
Zones []string
- Upstream upstream.Upstream
+ Upstream *upstream.Upstream
APIServerList []string
APIProxy *apiProxy
APICertAuth string
diff --git a/plugin/kubernetes/setup.go b/plugin/kubernetes/setup.go
index 06939f8f2..5ea62246f 100644
--- a/plugin/kubernetes/setup.go
+++ b/plugin/kubernetes/setup.go
@@ -241,12 +241,8 @@ func ParseStanza(c *caddy.Controller) (*Kubernetes, error) {
case "fallthrough":
k8s.Fall.SetZonesFromArgs(c.RemainingArgs())
case "upstream":
- args := c.RemainingArgs()
- u, err := upstream.New(args)
- if err != nil {
- return nil, err
- }
- k8s.Upstream = u
+ c.RemainingArgs() // eat remaining args
+ k8s.Upstream = upstream.New()
case "ttl":
args := c.RemainingArgs()
if len(args) == 0 {
diff --git a/plugin/kubernetes/setup_test.go b/plugin/kubernetes/setup_test.go
index 2bde16437..2a420e1b7 100644
--- a/plugin/kubernetes/setup_test.go
+++ b/plugin/kubernetes/setup_test.go
@@ -7,7 +7,6 @@ import (
"github.com/coredns/coredns/plugin/pkg/fall"
- "github.com/coredns/coredns/plugin/proxy"
"github.com/mholt/caddy"
meta "k8s.io/apimachinery/pkg/apis/meta/v1"
)
@@ -23,7 +22,6 @@ func TestKubernetesParse(t *testing.T) {
expectedLabelSelector string // expected label selector value
expectedPodMode string
expectedFallthrough fall.F
- expectedUpstreams []string
}{
// positive
{
@@ -36,7 +34,6 @@ func TestKubernetesParse(t *testing.T) {
"",
podModeDisabled,
fall.Zero,
- nil,
},
{
`kubernetes coredns.local test.local`,
@@ -48,7 +45,6 @@ func TestKubernetesParse(t *testing.T) {
"",
podModeDisabled,
fall.Zero,
- nil,
},
{
`kubernetes coredns.local {
@@ -61,7 +57,6 @@ func TestKubernetesParse(t *testing.T) {
"",
podModeDisabled,
fall.Zero,
- nil,
},
{
`kubernetes coredns.local {
@@ -75,7 +70,6 @@ func TestKubernetesParse(t *testing.T) {
"",
podModeDisabled,
fall.Zero,
- nil,
},
{
`kubernetes coredns.local {
@@ -89,7 +83,6 @@ func TestKubernetesParse(t *testing.T) {
"",
podModeDisabled,
fall.Zero,
- nil,
},
{
`kubernetes coredns.local {
@@ -103,7 +96,6 @@ func TestKubernetesParse(t *testing.T) {
"",
podModeDisabled,
fall.Zero,
- nil,
},
{
`kubernetes coredns.local {
@@ -117,7 +109,6 @@ func TestKubernetesParse(t *testing.T) {
"",
podModeDisabled,
fall.Zero,
- nil,
},
{
`kubernetes coredns.local {
@@ -131,7 +122,6 @@ func TestKubernetesParse(t *testing.T) {
"",
podModeDisabled,
fall.Zero,
- nil,
},
{
`kubernetes coredns.local {
@@ -145,7 +135,6 @@ func TestKubernetesParse(t *testing.T) {
"environment=prod",
podModeDisabled,
fall.Zero,
- nil,
},
{
`kubernetes coredns.local {
@@ -159,7 +148,6 @@ func TestKubernetesParse(t *testing.T) {
"application=nginx,environment in (production,qa,staging)",
podModeDisabled,
fall.Zero,
- nil,
},
{
`kubernetes coredns.local test.local {
@@ -177,7 +165,6 @@ func TestKubernetesParse(t *testing.T) {
"application=nginx,environment in (production,qa,staging)",
podModeDisabled,
fall.Root,
- nil,
},
// negative
{
@@ -192,7 +179,6 @@ func TestKubernetesParse(t *testing.T) {
"",
podModeDisabled,
fall.Zero,
- nil,
},
{
`kubernetes coredns.local {
@@ -206,7 +192,6 @@ func TestKubernetesParse(t *testing.T) {
"",
podModeDisabled,
fall.Zero,
- nil,
},
{
`kubernetes coredns.local {
@@ -220,7 +205,6 @@ func TestKubernetesParse(t *testing.T) {
"",
podModeDisabled,
fall.Zero,
- nil,
},
{
`kubernetes coredns.local {
@@ -234,7 +218,6 @@ func TestKubernetesParse(t *testing.T) {
"",
podModeDisabled,
fall.Zero,
- nil,
},
{
`kubernetes coredns.local {
@@ -248,7 +231,6 @@ func TestKubernetesParse(t *testing.T) {
"",
podModeDisabled,
fall.Zero,
- nil,
},
{
`kubernetes coredns.local {
@@ -262,7 +244,6 @@ func TestKubernetesParse(t *testing.T) {
"",
podModeDisabled,
fall.Zero,
- nil,
},
{
`kubernetes coredns.local {
@@ -276,7 +257,6 @@ func TestKubernetesParse(t *testing.T) {
"",
podModeDisabled,
fall.Zero,
- nil,
},
// pods disabled
{
@@ -291,7 +271,6 @@ func TestKubernetesParse(t *testing.T) {
"",
podModeDisabled,
fall.Zero,
- nil,
},
// pods insecure
{
@@ -306,7 +285,6 @@ func TestKubernetesParse(t *testing.T) {
"",
podModeInsecure,
fall.Zero,
- nil,
},
// pods verified
{
@@ -321,7 +299,6 @@ func TestKubernetesParse(t *testing.T) {
"",
podModeVerified,
fall.Zero,
- nil,
},
// pods invalid
{
@@ -336,7 +313,6 @@ func TestKubernetesParse(t *testing.T) {
"",
podModeVerified,
fall.Zero,
- nil,
},
// fallthrough with zones
{
@@ -351,12 +327,11 @@ func TestKubernetesParse(t *testing.T) {
"",
podModeDisabled,
fall.F{Zones: []string{"ip6.arpa.", "inaddr.arpa.", "foo.com."}},
- nil,
},
// Valid upstream
{
`kubernetes coredns.local {
- upstream 13.14.15.16:53
+ upstream
}`,
false,
"",
@@ -366,22 +341,6 @@ func TestKubernetesParse(t *testing.T) {
"",
podModeDisabled,
fall.Zero,
- []string{"13.14.15.16:53"},
- },
- // Invalid upstream
- {
- `kubernetes coredns.local {
- upstream 13.14.15.16orange
-}`,
- true,
- "not an IP address or file: \"13.14.15.16orange\"",
- -1,
- 0,
- defaultResyncPeriod,
- "",
- podModeDisabled,
- fall.Zero,
- nil,
},
// More than one Kubernetes not allowed
{
@@ -395,7 +354,6 @@ kubernetes cluster.local`,
"",
podModeDisabled,
fall.Zero,
- nil,
},
{
`kubernetes coredns.local {
@@ -409,7 +367,6 @@ kubernetes cluster.local`,
"",
podModeDisabled,
fall.Zero,
- nil,
},
{
`kubernetes coredns.local {
@@ -423,7 +380,6 @@ kubernetes cluster.local`,
"",
podModeDisabled,
fall.Zero,
- nil,
},
{
`kubernetes coredns.local {
@@ -437,7 +393,6 @@ kubernetes cluster.local`,
"",
podModeDisabled,
fall.Zero,
- nil,
},
{
`kubernetes coredns.local {
@@ -519,31 +474,6 @@ kubernetes cluster.local`,
if !k8sController.Fall.Equal(test.expectedFallthrough) {
t.Errorf("Test %d: Expected kubernetes controller to be initialized with fallthrough '%v'. Instead found fallthrough '%v' for input '%s'", i, test.expectedFallthrough, k8sController.Fall, test.input)
}
- // upstream
- var foundUpstreams *[]proxy.Upstream
- if k8sController.Upstream.Forward != nil {
- foundUpstreams = k8sController.Upstream.Forward.Upstreams
- }
- if test.expectedUpstreams == nil {
- if foundUpstreams != nil {
- t.Errorf("Test %d: Expected kubernetes controller to not be initialized with upstreams for input '%s'", i, test.input)
- }
- } else {
- if foundUpstreams == nil {
- t.Errorf("Test %d: Expected kubernetes controller to be initialized with upstreams for input '%s'", i, test.input)
- } else {
- if len(*foundUpstreams) != len(test.expectedUpstreams) {
- t.Errorf("Test %d: Expected kubernetes controller to be initialized with %d upstreams. Instead found %d upstreams for input '%s'", i, len(test.expectedUpstreams), len(*foundUpstreams), test.input)
- }
- for j, want := range test.expectedUpstreams {
- got := (*foundUpstreams)[j].Select().Name
- if got != want {
- t.Errorf("Test %d: Expected kubernetes controller to be initialized with upstream '%s'. Instead found upstream '%s' for input '%s'", i, want, got, test.input)
- }
- }
-
- }
- }
}
}
diff --git a/plugin/pkg/upstream/upstream.go b/plugin/pkg/upstream/upstream.go
index 239d3dd96..c5eba8ead 100644
--- a/plugin/pkg/upstream/upstream.go
+++ b/plugin/pkg/upstream/upstream.go
@@ -1,58 +1,35 @@
-// Package upstream abstracts a upstream lookups so that plugins
-// can handle them in an unified way.
+// Package upstream abstracts a upstream lookups so that plugins can handle them in an unified way.
package upstream
import (
+ "fmt"
+
"github.com/miekg/dns"
"github.com/coredns/coredns/core/dnsserver"
"github.com/coredns/coredns/plugin/pkg/nonwriter"
- "github.com/coredns/coredns/plugin/pkg/parse"
- "github.com/coredns/coredns/plugin/proxy"
"github.com/coredns/coredns/request"
)
-// Upstream is used to resolve CNAME targets
-type Upstream struct {
- self bool
- Forward *proxy.Proxy
-}
+// Upstream is used to resolve CNAME or other external targets via CoreDNS itself.
+type Upstream struct{}
-// New creates a new Upstream for given destination(s). If dests is empty it default to upstreaming to
-// the coredns process.
-func New(dests []string) (Upstream, error) {
- u := Upstream{}
- if len(dests) == 0 {
- u.self = true
- return u, nil
- }
- u.self = false
- ups, err := parse.HostPortOrFile(dests...)
- if err != nil {
- return u, err
- }
- p := proxy.NewLookup(ups)
- u.Forward = &p
- return u, nil
-}
+// New creates a new Upstream to resolve names using the the coredns process.
+func New() *Upstream { return &Upstream{} }
// Lookup routes lookups to our selves or forward to a remote.
-func (u Upstream) Lookup(state request.Request, name string, typ uint16) (*dns.Msg, error) {
- if u.self {
- req := new(dns.Msg)
- req.SetQuestion(name, typ)
-
- nw := nonwriter.New(state.W)
- server := state.Context.Value(dnsserver.Key{}).(*dnsserver.Server)
+func (u *Upstream) Lookup(state request.Request, name string, typ uint16) (*dns.Msg, error) {
+ server, ok := state.Context.Value(dnsserver.Key{}).(*dnsserver.Server)
+ if !ok {
+ return nil, fmt.Errorf("no full server is running")
+ }
- server.ServeDNS(state.Context, nw, req)
+ req := new(dns.Msg)
+ req.SetQuestion(name, typ)
- return nw.Msg, nil
- }
+ nw := nonwriter.New(state.W)
- if u.Forward != nil {
- return u.Forward.Lookup(state, name, typ)
- }
+ server.ServeDNS(state.Context, nw, req)
- return nil, nil
+ return nw.Msg, nil
}
diff --git a/plugin/proxy/healthcheck_test.go b/plugin/proxy/healthcheck_test.go
deleted file mode 100644
index 67f5d0f2d..000000000
--- a/plugin/proxy/healthcheck_test.go
+++ /dev/null
@@ -1,60 +0,0 @@
-package proxy
-
-import (
- "fmt"
- "net/http"
- "net/http/httptest"
- "strings"
- "sync/atomic"
- "testing"
- "time"
-
- "github.com/coredns/coredns/plugin/test"
- "github.com/coredns/coredns/request"
-
- "github.com/mholt/caddy/caddyfile"
- "github.com/miekg/dns"
-)
-
-func TestUnhealthy(t *testing.T) {
- // High HC interval, we want to test the HC after failed queries.
- config := "proxy . %s {\n health_check /healthcheck:%s 10s \nfail_timeout 100ms\n}"
-
- backend := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- r.Body.Close()
- w.Write([]byte("OK"))
- }))
- defer backend.Close()
-
- port := backend.URL[17:] // Remove all crap up to the port
- back := backend.URL[7:] // Remove http://
-
- c := caddyfile.NewDispenser("testfile", strings.NewReader(fmt.Sprintf(config, back, port)))
- upstreams, err := NewStaticUpstreams(&c)
- if err != nil {
- t.Errorf("Expected no error. Got: %s", err)
- }
- p := &Proxy{Upstreams: &upstreams}
- m := new(dns.Msg)
- m.SetQuestion("example.org.", dns.TypeA)
- state := request.Request{W: &test.ResponseWriter{}, Req: m}
-
- // Should all fail.
- for j := 0; j < failureCheck; j++ {
- if _, err := p.Forward(state); err == nil {
- t.Errorf("Expected error. Got: nil")
- }
- }
-
- fails := atomic.LoadInt32(&upstreams[0].(*staticUpstream).Hosts[0].Fails)
- if fails != 3 {
- t.Errorf("Expected %d fails, got %d", 3, fails)
- }
- // HC should be kicked off, and reset the counter to 0
- i := 0
- for fails != 0 {
- fails = atomic.LoadInt32(&upstreams[0].(*staticUpstream).Hosts[0].Fails)
- time.Sleep(100 * time.Microsecond)
- i++
- }
-}
diff --git a/plugin/proxy/lookup.go b/plugin/proxy/lookup.go
deleted file mode 100644
index 0437e8eb7..000000000
--- a/plugin/proxy/lookup.go
+++ /dev/null
@@ -1,127 +0,0 @@
-package proxy
-
-// functions other plugin might want to use to do lookup in the same style as the proxy.
-
-import (
- "context"
- "fmt"
- "net"
- "sync/atomic"
- "time"
-
- "github.com/coredns/coredns/plugin/pkg/healthcheck"
- "github.com/coredns/coredns/request"
-
- "github.com/miekg/dns"
-)
-
-// NewLookup create a new proxy with the hosts in host and a Random policy.
-func NewLookup(hosts []string) Proxy { return NewLookupWithOption(hosts, Options{}) }
-
-// NewLookupWithOption process creates a simple round robin forward with potentially forced proto for upstream.
-func NewLookupWithOption(hosts []string, opts Options) Proxy {
- p := Proxy{Next: nil}
-
- // TODO(miek): this needs to be unified with upstream.go's NewStaticUpstreams, caddy uses NewHost
- // we should copy/make something similar.
- upstream := &staticUpstream{
- from: ".",
- HealthCheck: healthcheck.HealthCheck{
- FailTimeout: 5 * time.Second,
- MaxFails: 3,
- },
- ex: newDNSExWithOption(opts),
- }
- upstream.Hosts = make([]*healthcheck.UpstreamHost, len(hosts))
-
- for i, host := range hosts {
- uh := &healthcheck.UpstreamHost{
- Name: host,
- FailTimeout: upstream.FailTimeout,
- CheckDown: checkDownFunc(upstream),
- }
-
- upstream.Hosts[i] = uh
- }
- p.Upstreams = &[]Upstream{upstream}
- return p
-}
-
-// Lookup will use name and type to forge a new message and will send that upstream. It will
-// set any EDNS0 options correctly so that downstream will be able to process the reply.
-func (p Proxy) Lookup(state request.Request, name string, typ uint16) (*dns.Msg, error) {
- req := new(dns.Msg)
- req.SetQuestion(name, typ)
- state.SizeAndDo(req)
-
- state2 := request.Request{W: state.W, Req: req}
-
- return p.lookup(state2)
-}
-
-// Forward forward the request in state as-is. Unlike Lookup that adds EDNS0 suffix to the message.
-func (p Proxy) Forward(state request.Request) (*dns.Msg, error) {
- return p.lookup(state)
-}
-
-func (p Proxy) lookup(state request.Request) (*dns.Msg, error) {
- upstream := p.match(state)
- if upstream == nil {
- return nil, errInvalidDomain
- }
- for {
- start := time.Now()
- var reply *dns.Msg
- var backendErr error
-
- // Since Select() should give us "up" hosts, keep retrying
- // hosts until timeout (or until we get a nil host).
- for time.Since(start) < tryDuration {
- host := upstream.Select()
- if host == nil {
- return nil, fmt.Errorf("%s: %s", errUnreachable, "no upstream host")
- }
-
- // duplicated from proxy.go, but with a twist, we don't write the
- // reply back to the client, we return it and there is no monitoring to update here.
-
- atomic.AddInt64(&host.Conns, 1)
-
- reply, backendErr = upstream.Exchanger().Exchange(context.TODO(), host.Name, state)
-
- atomic.AddInt64(&host.Conns, -1)
-
- if backendErr == nil {
-
- if !state.Match(reply) {
- return state.ErrorMessage(dns.RcodeFormatError), nil
- }
-
- return reply, nil
- }
-
- if oe, ok := backendErr.(*net.OpError); ok {
- if oe.Timeout() { // see proxy.go for docs.
- continue
- }
- }
-
- timeout := host.FailTimeout
- if timeout == 0 {
- timeout = defaultFailTimeout
- }
-
- atomic.AddInt32(&host.Fails, 1)
- fails := atomic.LoadInt32(&host.Fails)
-
- go func(host *healthcheck.UpstreamHost, timeout time.Duration) {
- time.Sleep(timeout)
- atomic.AddInt32(&host.Fails, -1)
- if fails%failureCheck == 0 { // Kick off healthcheck on eveyry third failure.
- host.HealthCheckURL()
- }
- }(host, timeout)
- }
- return nil, fmt.Errorf("%s: %s", errUnreachable, backendErr)
- }
-}
diff --git a/plugin/proxy/proxy_test.go b/plugin/proxy/proxy_test.go
index 3057715a4..0d29c2329 100644
--- a/plugin/proxy/proxy_test.go
+++ b/plugin/proxy/proxy_test.go
@@ -9,12 +9,7 @@ import (
"testing"
"time"
- "github.com/coredns/coredns/plugin/pkg/dnstest"
- "github.com/coredns/coredns/plugin/test"
- "github.com/coredns/coredns/request"
-
"github.com/mholt/caddy/caddyfile"
- "github.com/miekg/dns"
)
func TestStop(t *testing.T) {
@@ -75,25 +70,3 @@ func TestStop(t *testing.T) {
})
}
}
-
-func TestProxyRefused(t *testing.T) {
- s := dnstest.NewServer(func(w dns.ResponseWriter, r *dns.Msg) {
- ret := new(dns.Msg)
- ret.SetReply(r)
- ret.Rcode = dns.RcodeRefused
- w.WriteMsg(ret)
- })
- defer s.Close()
-
- p := NewLookup([]string{s.Addr})
-
- state := request.Request{W: &test.ResponseWriter{}, Req: new(dns.Msg)}
- state.Req.SetQuestion("example.org.", dns.TypeA)
- resp, err := p.Forward(state)
- if err != nil {
- t.Fatal("Expected to receive reply, but didn't")
- }
- if resp.Rcode != dns.RcodeRefused {
- t.Errorf("Expected rcode to be %d, got %d", dns.RcodeRefused, resp.Rcode)
- }
-}
diff --git a/plugin/route53/README.md b/plugin/route53/README.md
index 94fe45c81..5373e61e8 100644
--- a/plugin/route53/README.md
+++ b/plugin/route53/README.md
@@ -6,8 +6,9 @@
## Description
-The route53 plugin is useful for serving zones from resource record sets in AWS route53. This plugin
-supports all Amazon Route 53 records (https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/ResourceRecordTypes.html).
+The route53 plugin is useful for serving zones from resource record
+sets in AWS route53. This plugin supports all Amazon Route 53 records
+([https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/ResourceRecordTypes.html](https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/ResourceRecordTypes.html)).
The route53 plugin can be used when coredns is deployed on AWS or elsewhere.
## Syntax
@@ -15,33 +16,40 @@ The route53 plugin can be used when coredns is deployed on AWS or elsewhere.
~~~ txt
route53 [ZONE:HOSTED_ZONE_ID...] {
[aws_access_key AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY]
- upstream [ADDRESS...]
+ upstream
credentials PROFILE [FILENAME]
fallthrough [ZONES...]
}
~~~
-* **ZONE** the name of the domain to be accessed. When there are multiple zones with overlapping domains
- (private vs. public hosted zone), CoreDNS does the lookup in the given order here. Therefore, for a
- non-existing resource record, SOA response will be from the rightmost zone.
-* **HOSTED_ZONE_ID** the ID of the hosted zone that contains the resource record sets to be accessed.
-* **AWS_ACCESS_KEY_ID** and **AWS_SECRET_ACCESS_KEY** the AWS access key ID and secret access key
- to be used when query AWS (optional). If they are not provided, then coredns tries to access
- AWS credentials the same way as AWS CLI, e.g., environmental variables, AWS credentials file,
- instance profile credentials, etc.
-* `upstream` [**ADDRESS**...] specifies upstream resolver(s) used for resolving services that point
- to external hosts (eg. used to resolve CNAMEs). If no **ADDRESS** is given, CoreDNS will resolve
- against itself. **ADDRESS** can be an IP, an IP:port or a path to a file structured like
- resolv.conf.
-* `credentials` used for reading the credential file and setting the profile name for a given zone.
-* **PROFILE** AWS account profile name. Defaults to `default`.
-* **FILENAME** AWS credentials filename. Defaults to `~/.aws/credentials`
- are used.
-* `fallthrough` If zone matches and no record can be generated, pass request to the next plugin.
- If **[ZONES...]** is omitted, then fallthrough happens for all zones for which the plugin
- is authoritative. If specific zones are listed (for example `in-addr.arpa` and `ip6.arpa`), then only
- queries for those zones will be subject to fallthrough.
-* **ZONES** zones it should be authoritative for. If empty, the zones from the configuration block
+* **ZONE** the name of the domain to be accessed. When there are multiple zones with overlapping
+ domains (private vs. public hosted zone), CoreDNS does the lookup in the given order here.
+ Therefore, for a non-existing resource record, SOA response will be from the rightmost zone.
+
+* **HOSTED*ZONE*ID** the ID of the hosted zone that contains the resource record sets to be
+ accessed.
+
+* **AWS*ACCESS*KEY_ID** and **AWS*SECRET*ACCESS_KEY** the AWS access key ID and secret access key
+ to be used when query AWS (optional). If they are not provided, then coredns tries to access
+ AWS credentials the same way as AWS CLI, e.g., environmental variables, AWS credentials file,
+ instance profile credentials, etc.
+
+* `upstream`is used for resolving services that point to external hosts (eg. used to resolve
+ CNAMEs). CoreDNS will resolve against itself.
+
+* `credentials` used for reading the credential file and setting the profile name for a given
+ zone.
+
+* **PROFILE** AWS account profile name. Defaults to `default`.
+
+* **FILENAME** AWS credentials filename. Defaults to `~/.aws/credentials` are used.
+
+* `fallthrough` If zone matches and no record can be generated, pass request to the next plugin.
+ If **[ZONES...]** is omitted, then fallthrough happens for all zones for which the plugin is
+ authoritative. If specific zones are listed (for example `in-addr.arpa` and `ip6.arpa`), then
+ only queries for those zones will be subject to fallthrough.
+
+* **ZONES** zones it should be authoritative for. If empty, the zones from the configuration block
## Examples
diff --git a/plugin/route53/route53.go b/plugin/route53/route53.go
index 6fe8763af..537cf3212 100644
--- a/plugin/route53/route53.go
+++ b/plugin/route53/route53.go
@@ -170,7 +170,7 @@ func (h *Route53) updateZones(ctx context.Context) error {
for i, hostedZone := range z {
newZ := file.NewZone(zName, "")
- newZ.Upstream = *h.upstream
+ newZ.Upstream = h.upstream
in := &route53.ListResourceRecordSetsInput{
HostedZoneId: aws.String(hostedZone.id),
}
diff --git a/plugin/route53/setup.go b/plugin/route53/setup.go
index b293a320b..5c80a5ac9 100644
--- a/plugin/route53/setup.go
+++ b/plugin/route53/setup.go
@@ -48,7 +48,7 @@ func setup(c *caddy.Controller, f func(*credentials.Credentials) route53iface.Ro
var providers []credentials.Provider
var fall fall.F
- up, _ := upstream.New(nil)
+ up := upstream.New()
for c.Next() {
args := c.RemainingArgs()
@@ -83,12 +83,7 @@ func setup(c *caddy.Controller, f func(*credentials.Credentials) route53iface.Ro
},
})
case "upstream":
- args := c.RemainingArgs()
- var err error
- up, err = upstream.New(args)
- if err != nil {
- return c.Errf("invalid upstream: %v", err)
- }
+ c.RemainingArgs() // eats args
case "credentials":
if c.NextArg() {
sharedProvider.Profile = c.Val()
@@ -109,7 +104,7 @@ func setup(c *caddy.Controller, f func(*credentials.Credentials) route53iface.Ro
client := f(credentials.NewChainCredentials(providers))
ctx := context.Background()
- h, err := New(ctx, client, keys, &up)
+ h, err := New(ctx, client, keys, up)
if err != nil {
return c.Errf("failed to create Route53 plugin: %v", err)
}
diff --git a/plugin/secondary/README.md b/plugin/secondary/README.md
index 59ac23aea..48ba97cd3 100644
--- a/plugin/secondary/README.md
+++ b/plugin/secondary/README.md
@@ -23,18 +23,16 @@ A working syntax would be:
secondary [zones...] {
transfer from ADDRESS
transfer to ADDRESS
- upstream [ADDRESS...]
+ upstream
}
~~~
* `transfer from` specifies from which address to fetch the zone. It can be specified multiple times;
if one does not work, another will be tried.
* `transfer to` can be enabled to allow this secondary zone to be transferred again.
-* `upstream` defines upstream resolvers to be used resolve external names found (think CNAMEs)
- pointing to external names. This is only really useful when CoreDNS is configured as a proxy, for
- normal authoritative serving you don't need *or* want to use this. **ADDRESS** can be an IP
- address, and IP:port or a string pointing to a file that is structured as /etc/resolv.conf.
- If no **ADDRESS** is given, CoreDNS will resolve CNAMEs against itself.
+* `upstream` resolve external names found (think CNAMEs) pointing to external names. This is only
+ really useful when CoreDNS is configured as a proxy; for normal authoritative serving you don't
+ need *or* want to use this. CoreDNS will resolve CNAMEs against itself.
When a zone is due to be refreshed (Refresh timer fires) a random jitter of 5 seconds is
applied, before fetching. In the case of retry this will be 2 seconds. If there are any errors
diff --git a/plugin/secondary/setup.go b/plugin/secondary/setup.go
index 20dc184ca..b3ca2074f 100644
--- a/plugin/secondary/setup.go
+++ b/plugin/secondary/setup.go
@@ -49,7 +49,7 @@ func setup(c *caddy.Controller) error {
func secondaryParse(c *caddy.Controller) (file.Zones, error) {
z := make(map[string]*file.Zone)
names := []string{}
- upstr := upstream.Upstream{}
+ upstr := upstream.New()
for c.Next() {
if c.Val() == "secondary" {
@@ -78,12 +78,7 @@ func secondaryParse(c *caddy.Controller) (file.Zones, error) {
return file.Zones{}, e
}
case "upstream":
- args := c.RemainingArgs()
- var err error
- upstr, err = upstream.New(args)
- if err != nil {
- return file.Zones{}, err
- }
+ c.RemainingArgs() // eat args
default:
return file.Zones{}, c.Errf("unknown property '%s'", c.Val())
}
diff --git a/plugin/template/README.md b/plugin/template/README.md
index 17dedbfa9..bcb5b2dd7 100644
--- a/plugin/template/README.md
+++ b/plugin/template/README.md
@@ -12,14 +12,13 @@ The *template* plugin allows you to dynamically respond to queries by just writi
~~~
template CLASS TYPE [ZONE...] {
- [match REGEX...]
- [answer RR]
- [additional RR]
- [authority RR]
- [...]
- [rcode CODE]
- [upstream [ADDRESS...]]
- [fallthrough [ZONE...]]
+ match REGEX...
+ answer RR
+ additional RR
+ authority RR
+ rcode CODE
+ upstream
+ fallthrough [ZONE...]
}
~~~
@@ -30,9 +29,7 @@ template CLASS TYPE [ZONE...] {
* `answer|additional|authority` **RR** A [RFC 1035](https://tools.ietf.org/html/rfc1035#section-5) style resource record fragment
built by a [Go template](https://golang.org/pkg/text/template/) that contains the reply.
* `rcode` **CODE** A response code (`NXDOMAIN, SERVFAIL, ...`). The default is `SUCCESS`.
-* `upstream` [**ADDRESS**...] defines the upstream resolvers used for resolving CNAME.
- If no **ADDRESS** is given, CoreDNS will resolve CNAMEs against itself. **ADDRESS**
- can be an IP, an IP:port, or a path to a file structured like resolv.conf.
+* `upstream` defines the upstream resolvers used for resolving CNAMEs. CoreDNS will resolve CNAMEs against itself.
* `fallthrough` Continue with the next plugin if the zone matched but no regex matched.
If specific zones are listed (for example `in-addr.arpa` and `ip6.arpa`), then only queries for
those zones will be subject to fallthrough.
diff --git a/plugin/template/setup.go b/plugin/template/setup.go
index 841d2944f..9f122277a 100644
--- a/plugin/template/setup.go
+++ b/plugin/template/setup.go
@@ -144,12 +144,8 @@ func templateParse(c *caddy.Controller) (handler Handler, err error) {
t.fall.SetZonesFromArgs(c.RemainingArgs())
case "upstream":
- args := c.RemainingArgs()
- u, err := upstream.New(args)
- if err != nil {
- return handler, err
- }
- t.upstream = &u
+ c.RemainingArgs() // eat remaining args
+ t.upstream = upstream.New()
default:
return handler, c.ArgErr()
}
diff --git a/plugin/template/setup_test.go b/plugin/template/setup_test.go
index 7581bd306..64afac32a 100644
--- a/plugin/template/setup_test.go
+++ b/plugin/template/setup_test.go
@@ -148,13 +148,6 @@ func TestSetupParse(t *testing.T) {
}`,
false,
},
- {
- `template ANY ANY up.stream.local {
- answer "up.stream.local 5 IN CNAME up.river.local"
- upstream invalid-upstream-argument
- }`,
- true,
- },
}
for i, test := range tests {
c := caddy.NewTestController("dns", test.inputFileRules)