aboutsummaryrefslogtreecommitdiff
path: root/plugin
diff options
context:
space:
mode:
authorGravatar Miek Gieben <miek@miek.nl> 2019-01-13 16:54:49 +0000
committerGravatar GitHub <noreply@github.com> 2019-01-13 16:54:49 +0000
commit9c16ed1d14f570f27b4ff9cb89845a3a1548a776 (patch)
tree8050afa683fdb3f2e1efa1dd2e3a35a680d689d0 /plugin
parent6b56a9c92130d50cee9bd92aaee500dbccff395f (diff)
downloadcoredns-9c16ed1d14f570f27b4ff9cb89845a3a1548a776.tar.gz
coredns-9c16ed1d14f570f27b4ff9cb89845a3a1548a776.tar.zst
coredns-9c16ed1d14f570f27b4ff9cb89845a3a1548a776.zip
Default to upstream to self (#2436)
* Default to upstream to self This is a backwards incompatible change. This is a massive (cleanup) PR where we default to resolving external names by the coredns process itself, instead of directly forwarding them to some upstream. This ignores any arguments `upstream` may have had and makes it depend on proxy/forward configuration in the Corefile. This allows resolved upstream names to be cached and we have better healthchecking of the upstreams. It also means there is only one way to resolve names, by either using the proxy or forward plugin. The proxy/forward lookup.go functions have been removed. This also lessen the dependency on proxy, meaning deprecating proxy will become easier. Some tests have been removed as well, or moved to the top-level test directory as they now require a full coredns process instead of just the plugin. For the etcd plugin, the entire StubZone resolving is *dropped*! This was a hacky (but working) solution to say the least. If someone cares deeply it can be brought back (maybe)? The pkg/upstream is now very small and almost does nothing. Also the New() function was changed to return a pointer to upstream.Upstream. It also returns only one parameter, so any stragglers using it will encounter a compile error. All documentation has been adapted. This affected the following plugins: * etcd * file * auto * secondary * federation * template * route53 A followup PR will make any upstream directives with arguments an error, right now they are ignored. Signed-off-by: Miek Gieben <miek@miek.nl> * Fix etcd build - probably still fails unit test Signed-off-by: Miek Gieben <miek@miek.nl> * Slightly smarter lookup check in upstream Signed-off-by: Miek Gieben <miek@miek.nl> * Compilez Signed-off-by: Miek Gieben <miek@miek.nl>
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)