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//xx for msg.Services. Loop through them -// extract 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) - - server.ServeDNS(state.Context, nw, req) - - return nw.Msg, nil +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") } - if u.Forward != nil { - return u.Forward.Lookup(state, name, typ) - } + req := new(dns.Msg) + req.SetQuestion(name, typ) - return nil, nil + nw := nonwriter.New(state.W) + + server.ServeDNS(state.Context, nw, req) + + 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) diff --git a/test/auto_test.go b/test/auto_test.go index c45aed4fa..9380ea78a 100644 --- a/test/auto_test.go +++ b/test/auto_test.go @@ -7,10 +7,6 @@ import ( "testing" "time" - "github.com/coredns/coredns/plugin/proxy" - "github.com/coredns/coredns/plugin/test" - "github.com/coredns/coredns/request" - "github.com/miekg/dns" ) @@ -34,10 +30,9 @@ func TestAuto(t *testing.T) { } defer i.Stop() - p := proxy.NewLookup([]string{udp}) - state := request.Request{W: &test.ResponseWriter{}, Req: new(dns.Msg)} - - resp, err := p.Lookup(state, "www.example.org.", dns.TypeA) + m := new(dns.Msg) + m.SetQuestion("www.example.org.", dns.TypeA) + resp, err := dns.Exchange(m, udp) if err != nil { t.Fatal("Expected to receive reply, but didn't") } @@ -52,7 +47,7 @@ func TestAuto(t *testing.T) { time.Sleep(1500 * time.Millisecond) // wait for it to be picked up - resp, err = p.Lookup(state, "www.example.org.", dns.TypeA) + resp, err = dns.Exchange(m, udp) if err != nil { t.Fatal("Expected to receive reply, but didn't") } @@ -64,7 +59,7 @@ func TestAuto(t *testing.T) { os.Remove(filepath.Join(tmpdir, "db.example.org")) time.Sleep(1100 * time.Millisecond) // wait for it to be picked up - resp, err = p.Lookup(state, "www.example.org.", dns.TypeA) + resp, err = dns.Exchange(m, udp) if err != nil { t.Fatal("Expected to receive reply, but didn't") } @@ -99,10 +94,9 @@ func TestAutoNonExistentZone(t *testing.T) { } defer i.Stop() - p := proxy.NewLookup([]string{udp}) - state := request.Request{W: &test.ResponseWriter{}, Req: new(dns.Msg)} - - resp, err := p.Lookup(state, "example.org.", dns.TypeA) + m := new(dns.Msg) + m.SetQuestion("example.org.", dns.TypeA) + resp, err := dns.Exchange(m, udp) if err != nil { t.Fatal("Expected to receive reply, but didn't") } @@ -145,12 +139,9 @@ func TestAutoAXFR(t *testing.T) { time.Sleep(1100 * time.Millisecond) // wait for it to be picked up - p := proxy.NewLookup([]string{udp}) m := new(dns.Msg) m.SetAxfr("example.org.") - state := request.Request{W: &test.ResponseWriter{}, Req: m} - - resp, err := p.Lookup(state, "example.org.", dns.TypeAXFR) + resp, err := dns.Exchange(m, udp) if err != nil { t.Fatal("Expected to receive reply, but didn't") } diff --git a/test/cache_test.go b/test/cache_test.go index 30f119839..1bb600492 100644 --- a/test/cache_test.go +++ b/test/cache_test.go @@ -3,9 +3,7 @@ package test import ( "testing" - "github.com/coredns/coredns/plugin/proxy" "github.com/coredns/coredns/plugin/test" - "github.com/coredns/coredns/request" "github.com/miekg/dns" ) @@ -40,21 +38,20 @@ func TestLookupCache(t *testing.T) { } defer i.Stop() - p := proxy.NewLookup([]string{udp}) - state := request.Request{W: &test.ResponseWriter{}, Req: new(dns.Msg)} - t.Run("Long TTL", func(t *testing.T) { - testCase(t, state, p, "example.org.", 2, 10) + testCase(t, "example.org.", udp, 2, 10) }) t.Run("Short TTL", func(t *testing.T) { - testCase(t, state, p, "short.example.org.", 1, 5) + testCase(t, "short.example.org.", udp, 1, 5) }) } -func testCase(t *testing.T, state request.Request, p proxy.Proxy, name string, expectAnsLen int, expectTTL uint32) { - resp, err := p.Lookup(state, name, dns.TypeA) +func testCase(t *testing.T, name, addr string, expectAnsLen int, expectTTL uint32) { + m := new(dns.Msg) + m.SetQuestion(name, dns.TypeA) + resp, err := dns.Exchange(m, addr) if err != nil { t.Fatal("Expected to receive reply, but didn't") } diff --git a/test/ds_file_test.go b/test/ds_file_test.go index 2b2be5795..c0843e98e 100644 --- a/test/ds_file_test.go +++ b/test/ds_file_test.go @@ -3,9 +3,7 @@ package test import ( "testing" - "github.com/coredns/coredns/plugin/proxy" mtest "github.com/coredns/coredns/plugin/test" - "github.com/coredns/coredns/request" "github.com/miekg/dns" ) @@ -47,11 +45,10 @@ func TestLookupDS(t *testing.T) { } defer i.Stop() - p := proxy.NewLookup([]string{udp}) - state := request.Request{W: &mtest.ResponseWriter{}, Req: new(dns.Msg)} - for _, tc := range dsTestCases { - resp, err := p.Lookup(state, tc.Qname, tc.Qtype) + m := new(dns.Msg) + m.SetQuestion(tc.Qname, tc.Qtype) + resp, err := dns.Exchange(m, udp) if err != nil || resp == nil { t.Fatalf("Expected to receive reply, but didn't for %s %d", tc.Qname, tc.Qtype) } diff --git a/test/etcd_cache_test.go b/test/etcd_cache_test.go index df670e107..eb4774a8c 100644 --- a/test/etcd_cache_test.go +++ b/test/etcd_cache_test.go @@ -7,9 +7,6 @@ import ( "testing" "github.com/coredns/coredns/plugin/etcd/msg" - "github.com/coredns/coredns/plugin/proxy" - "github.com/coredns/coredns/plugin/test" - "github.com/coredns/coredns/request" "github.com/miekg/dns" ) @@ -38,16 +35,15 @@ func TestEtcdCache(t *testing.T) { defer delete(ctx, t, etc, serv.Key) } - p := proxy.NewLookup([]string{udp}) - state := request.Request{W: &test.ResponseWriter{}, Req: new(dns.Msg)} - - resp, err := p.Lookup(state, "b.example.skydns.test.", dns.TypeA) + m := new(dns.Msg) + m.SetQuestion("b.example.skydns.test.", dns.TypeA) + resp, err := dns.Exchange(m, udp) if err != nil { t.Errorf("Expected to receive reply, but didn't: %s", err) } checkResponse(t, resp) - resp, err = p.Lookup(state, "b.example.skydns.test.", dns.TypeA) + resp, err = dns.Exchange(m, udp) if err != nil { t.Errorf("Expected to receive reply, but didn't: %s", err) } diff --git a/test/etcd_test.go b/test/etcd_test.go index 134b2e63b..2b90c3a6c 100644 --- a/test/etcd_test.go +++ b/test/etcd_test.go @@ -10,9 +10,6 @@ import ( "github.com/coredns/coredns/plugin/etcd" "github.com/coredns/coredns/plugin/etcd/msg" - "github.com/coredns/coredns/plugin/proxy" - "github.com/coredns/coredns/plugin/test" - "github.com/coredns/coredns/request" etcdcv3 "github.com/coreos/etcd/clientv3" "github.com/miekg/dns" @@ -38,7 +35,7 @@ func TestEtcdStubAndProxyLookup(t *testing.T) { stubzones path /skydns endpoint http://localhost:2379 - upstream 8.8.8.8:53 8.8.4.4:53 + upstream fallthrough } proxy . 8.8.8.8:53 @@ -58,9 +55,9 @@ func TestEtcdStubAndProxyLookup(t *testing.T) { defer delete(ctx, t, etc, serv.Key) } - p := proxy.NewLookup([]string{udp}) // use udp port from the server - state := request.Request{W: &test.ResponseWriter{}, Req: new(dns.Msg)} - resp, err := p.Lookup(state, "example.com.", dns.TypeA) + m := new(dns.Msg) + m.SetQuestion("example.com.", dns.TypeA) + resp, err := dns.Exchange(m, udp) if err != nil { t.Fatalf("Expected to receive reply, but didn't: %v", err) } diff --git a/test/example_test.go b/test/example_test.go index 484cc67d7..852143fe8 100644 --- a/test/example_test.go +++ b/test/example_test.go @@ -11,6 +11,5 @@ short.example.org. 1 IN A 127.0.0.3 *.w.example.org. IN TXT "Wildcard" a.b.c.w.example.org. IN TXT "Not a wildcard" cname.example.org. IN CNAME www.example.net. - service.example.org. IN SRV 8080 10 10 example.org. ` diff --git a/test/file_cname_proxy_test.go b/test/file_cname_proxy_test.go index 6d086e091..e6f41ee97 100644 --- a/test/file_cname_proxy_test.go +++ b/test/file_cname_proxy_test.go @@ -3,10 +3,6 @@ package test import ( "testing" - "github.com/coredns/coredns/plugin/proxy" - "github.com/coredns/coredns/plugin/test" - "github.com/coredns/coredns/request" - "github.com/miekg/dns" ) @@ -30,10 +26,9 @@ func TestZoneExternalCNAMELookupWithoutProxy(t *testing.T) { } defer i.Stop() - p := proxy.NewLookup([]string{udp}) - state := request.Request{W: &test.ResponseWriter{}, Req: new(dns.Msg)} - - resp, err := p.Lookup(state, "cname.example.org.", dns.TypeA) + m := new(dns.Msg) + m.SetQuestion("cname.example.org.", dns.TypeA) + resp, err := dns.Exchange(m, udp) if err != nil { t.Fatalf("Expected to receive reply, but didn't: %s", err) } @@ -52,11 +47,12 @@ func TestZoneExternalCNAMELookupWithProxy(t *testing.T) { } defer rm() - // Corefile with for example without proxy section. - corefile := `example.org:0 { - file ` + name + ` { - upstream 8.8.8.8 + // Corefile with for example proxy section. + corefile := `.:0 { + file ` + name + ` example.org { + upstream } + proxy . 8.8.8.8 8.8.4.4 } ` i, udp, _, err := CoreDNSServerAndPorts(corefile) @@ -65,10 +61,9 @@ func TestZoneExternalCNAMELookupWithProxy(t *testing.T) { } defer i.Stop() - p := proxy.NewLookup([]string{udp}) - state := request.Request{W: &test.ResponseWriter{}, Req: new(dns.Msg)} - - resp, err := p.Lookup(state, "cname.example.org.", dns.TypeA) + m := new(dns.Msg) + m.SetQuestion("cname.example.org.", dns.TypeA) + resp, err := dns.Exchange(m, udp) if err != nil { t.Fatalf("Expected to receive reply, but didn't: %s", err) } diff --git a/test/file_reload_test.go b/test/file_reload_test.go index 2f07d9a8e..b0d6c6656 100644 --- a/test/file_reload_test.go +++ b/test/file_reload_test.go @@ -6,9 +6,6 @@ import ( "time" "github.com/coredns/coredns/plugin/file" - "github.com/coredns/coredns/plugin/proxy" - "github.com/coredns/coredns/plugin/test" - "github.com/coredns/coredns/request" "github.com/miekg/dns" ) @@ -39,10 +36,9 @@ example.net:0 { } defer i.Stop() - p := proxy.NewLookup([]string{udp}) - state := request.Request{W: &test.ResponseWriter{}, Req: new(dns.Msg)} - - resp, err := p.Lookup(state, "example.org.", dns.TypeA) + m := new(dns.Msg) + m.SetQuestion("example.org.", dns.TypeA) + resp, err := dns.Exchange(m, udp) if err != nil { t.Fatalf("Expected to receive reply, but didn't: %s", err) } @@ -55,7 +51,7 @@ example.net:0 { time.Sleep(2 * time.Second) // reload time - resp, err = p.Lookup(state, "example.org.", dns.TypeA) + resp, err = dns.Exchange(m, udp) if err != nil { t.Fatal("Expected to receive reply, but didn't") } diff --git a/test/file_srv_additional_test.go b/test/file_srv_additional_test.go index 106ae7faa..9ac74d8a3 100644 --- a/test/file_srv_additional_test.go +++ b/test/file_srv_additional_test.go @@ -3,10 +3,6 @@ package test import ( "testing" - "github.com/coredns/coredns/plugin/proxy" - "github.com/coredns/coredns/plugin/test" - "github.com/coredns/coredns/request" - "github.com/miekg/dns" ) @@ -30,10 +26,9 @@ func TestZoneSRVAdditional(t *testing.T) { } defer i.Stop() - p := proxy.NewLookup([]string{udp}) - state := request.Request{W: &test.ResponseWriter{}, Req: new(dns.Msg)} - - resp, err := p.Lookup(state, "service.example.org.", dns.TypeSRV) + m := new(dns.Msg) + m.SetQuestion("service.example.org.", dns.TypeSRV) + resp, err := dns.Exchange(m, udp) if err != nil { t.Fatalf("Expected to receive reply, but didn't: %s", err) } diff --git a/test/hosts_file_test.go b/test/hosts_file_test.go index 8e017aafa..b0e2ae23b 100644 --- a/test/hosts_file_test.go +++ b/test/hosts_file_test.go @@ -3,10 +3,6 @@ package test import ( "testing" - "github.com/coredns/coredns/plugin/proxy" - "github.com/coredns/coredns/plugin/test" - "github.com/coredns/coredns/request" - "github.com/miekg/dns" ) @@ -24,10 +20,9 @@ func TestHostsInlineLookup(t *testing.T) { } defer i.Stop() - p := proxy.NewLookup([]string{udp}) - state := request.Request{W: &test.ResponseWriter{}, Req: new(dns.Msg)} - - resp, err := p.Lookup(state, "example.org.", dns.TypeA) + m := new(dns.Msg) + m.SetQuestion("example.org.", dns.TypeA) + resp, err := dns.Exchange(m, udp) if err != nil { t.Fatal("Expected to receive reply, but didn't") } diff --git a/test/proxy_health_test.go b/test/proxy_health_test.go index 11ae1a4ee..620d8b274 100644 --- a/test/proxy_health_test.go +++ b/test/proxy_health_test.go @@ -3,36 +3,9 @@ package test import ( "testing" - "github.com/coredns/coredns/plugin/proxy" - "github.com/coredns/coredns/plugin/test" - "github.com/coredns/coredns/request" - "github.com/miekg/dns" ) -func TestProxyErratic(t *testing.T) { - corefile := `example.org:0 { - erratic { - drop 2 - } - } -` - - backend, udp, _, err := CoreDNSServerAndPorts(corefile) - if err != nil { - t.Fatalf("Could not get CoreDNS serving instance: %s", err) - } - defer backend.Stop() - - p := proxy.NewLookup([]string{udp}) - state := request.Request{W: &test.ResponseWriter{}, Req: new(dns.Msg)} - - // We do one lookup that should not time out. - // After this the backend is marked unhealthy anyway. So basically this - // tests that it times out. - p.Lookup(state, "example.org.", dns.TypeA) -} - func TestProxyThreeWay(t *testing.T) { // Run 3 CoreDNS server, 2 upstream ones and a proxy. 1 Upstream is unhealthy after 1 query, but after // that we should still be able to send to the other one. diff --git a/test/proxy_http_health_test.go b/test/proxy_http_health_test.go deleted file mode 100644 index bda5a0f90..000000000 --- a/test/proxy_http_health_test.go +++ /dev/null @@ -1,86 +0,0 @@ -package test - -import ( - "io" - "net" - "net/http" - "net/http/httptest" - "net/url" - "testing" - - "github.com/coredns/coredns/plugin/proxy" - "github.com/coredns/coredns/plugin/test" - "github.com/coredns/coredns/request" - "github.com/miekg/dns" -) - -func TestProxyWithHTTPCheckOK(t *testing.T) { - healthCheckServer := httptest.NewServer(http.HandlerFunc( - func(w http.ResponseWriter, r *http.Request) { - w.WriteHeader(http.StatusOK) - io.WriteString(w, "OK\n") - })) - defer healthCheckServer.Close() - - healthCheckURL, err := url.Parse(healthCheckServer.URL) - if err != nil { - t.Fatal(err) - } - // TODO: use URL.Port() (Go 1.8+) once we've deprecated Go 1.7 support - var healthCheckPort string - if _, healthCheckPort, err = net.SplitHostPort(healthCheckURL.Host); err != nil { - healthCheckPort = "80" - } - - name, rm, err := test.TempFile(".", exampleOrg) - if err != nil { - t.Fatalf("Failed to create zone: %s", err) - } - defer rm() - - // We have to bind to 127.0.0.1 because the server started by - // httptest.NewServer does, and the IP addresses of the backend - // DNS and HTTP servers must match. - authoritativeCorefile := `example.org:0 { - bind 127.0.0.1 - file ` + name + ` -} -` - - authoritativeInstance, authoritativeAddr, _, err := CoreDNSServerAndPorts(authoritativeCorefile) - if err != nil { - t.Fatalf("Could not get CoreDNS authoritative instance: %s", err) - } - defer authoritativeInstance.Stop() - - proxyCorefile := `example.org:0 { - proxy . ` + authoritativeAddr + ` { - health_check /health:` + healthCheckPort + ` 1s - - } -} -` - - proxyInstance, proxyAddr, _, err := CoreDNSServerAndPorts(proxyCorefile) - if err != nil { - t.Fatalf("Could not get CoreDNS proxy instance: %s", err) - } - defer proxyInstance.Stop() - - p := proxy.NewLookup([]string{proxyAddr}) - state := request.Request{W: &test.ResponseWriter{}, Req: new(dns.Msg)} - resp, err := p.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/test/proxy_test.go b/test/proxy_test.go index 87a05a21e..50e5dae46 100644 --- a/test/proxy_test.go +++ b/test/proxy_test.go @@ -3,9 +3,7 @@ package test import ( "testing" - "github.com/coredns/coredns/plugin/proxy" "github.com/coredns/coredns/plugin/test" - "github.com/coredns/coredns/request" "github.com/miekg/dns" ) @@ -29,46 +27,9 @@ func TestLookupProxy(t *testing.T) { } defer i.Stop() - p := proxy.NewLookup([]string{udp}) - state := request.Request{W: &test.ResponseWriter{}, Req: new(dns.Msg)} - resp, err := p.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()) - } -} - -func TestLookupDnsWithForcedTcp(t *testing.T) { - t.Parallel() - name, rm, err := test.TempFile(".", exampleOrg) - if err != nil { - t.Fatalf("Failed to create zone: %s", err) - } - defer rm() - - corefile := `example.org:0 { - file ` + name + ` -} -` - - i, _, tcp, err := CoreDNSServerAndPorts(corefile) - if err != nil { - t.Fatalf("Could not get CoreDNS serving instance: %s", err) - } - defer i.Stop() - - p := proxy.NewLookupWithOption([]string{tcp}, proxy.Options{ForceTCP: true}) - state := request.Request{W: &test.ResponseWriter{}, Req: new(dns.Msg)} - resp, err := p.Lookup(state, "example.org.", dns.TypeA) + m := new(dns.Msg) + m.SetQuestion("example.org.", dns.TypeA) + resp, err := dns.Exchange(m, udp) if err != nil { t.Fatal("Expected to receive reply, but didn't") } @@ -108,13 +69,12 @@ func BenchmarkProxyLookup(b *testing.B) { } defer i.Stop() - p := proxy.NewLookup([]string{udp}) - state := request.Request{W: &test.ResponseWriter{}, Req: new(dns.Msg)} + m := new(dns.Msg) + m.SetQuestion("example.org.", dns.TypeA) b.ResetTimer() for i := 0; i < b.N; i++ { - _, err := p.Lookup(state, "example.org.", dns.TypeA) - if err != nil { + if _, err := dns.Exchange(m, udp); err != nil { b.Fatal("Expected to receive reply, but didn't") } } diff --git a/test/reverse_test.go b/test/reverse_test.go index 962601a28..f77891172 100644 --- a/test/reverse_test.go +++ b/test/reverse_test.go @@ -3,10 +3,6 @@ package test import ( "testing" - "github.com/coredns/coredns/plugin/proxy" - "github.com/coredns/coredns/plugin/test" - "github.com/coredns/coredns/request" - "github.com/miekg/dns" ) @@ -26,9 +22,9 @@ func TestReverseCorefile(t *testing.T) { t.Fatalf("Could not get UDP listening port") } - p := proxy.NewLookup([]string{udp}) - state := request.Request{W: &test.ResponseWriter{}, Req: new(dns.Msg)} - resp, err := p.Lookup(state, "17.0.0.10.in-addr.arpa.", dns.TypePTR) + m := new(dns.Msg) + m.SetQuestion("17.0.0.10.in-addr.arpa.", dns.TypePTR) + resp, err := dns.Exchange(m, udp) if err != nil { t.Fatal("Expected to receive reply, but didn't") } diff --git a/test/secondary_test.go b/test/secondary_test.go index 18bfd8f15..bb013bbaf 100644 --- a/test/secondary_test.go +++ b/test/secondary_test.go @@ -3,9 +3,7 @@ package test import ( "testing" - "github.com/coredns/coredns/plugin/proxy" "github.com/coredns/coredns/plugin/test" - "github.com/coredns/coredns/request" "github.com/miekg/dns" ) @@ -25,10 +23,9 @@ func TestEmptySecondaryZone(t *testing.T) { } defer i.Stop() - p := proxy.NewLookup([]string{udp}) - state := request.Request{W: &test.ResponseWriter{}, Req: new(dns.Msg)} - - resp, err := p.Lookup(state, "www.example.org.", dns.TypeA) + m := new(dns.Msg) + m.SetQuestion("www.example.org.", dns.TypeA) + resp, err := dns.Exchange(m, udp) if err != nil { t.Fatal("Expected to receive reply, but didn't") } diff --git a/test/wildcard_test.go b/test/wildcard_test.go index b04affe6b..60e019e83 100644 --- a/test/wildcard_test.go +++ b/test/wildcard_test.go @@ -3,9 +3,7 @@ package test import ( "testing" - "github.com/coredns/coredns/plugin/proxy" "github.com/coredns/coredns/plugin/test" - "github.com/coredns/coredns/request" "github.com/miekg/dns" ) @@ -29,11 +27,10 @@ func TestLookupWildcard(t *testing.T) { } defer i.Stop() - p := proxy.NewLookup([]string{udp}) - state := request.Request{W: &test.ResponseWriter{}, Req: new(dns.Msg)} - for _, lookup := range []string{"a.w.example.org.", "a.a.w.example.org."} { - resp, err := p.Lookup(state, lookup, dns.TypeTXT) + m := new(dns.Msg) + m.SetQuestion(lookup, dns.TypeTXT) + resp, err := dns.Exchange(m, udp) if err != nil || resp == nil { t.Fatalf("Expected to receive reply, but didn't for %s", lookup) } @@ -64,7 +61,9 @@ func TestLookupWildcard(t *testing.T) { } for _, lookup := range []string{"w.example.org.", "a.w.example.org.", "a.a.w.example.org."} { - resp, err := p.Lookup(state, lookup, dns.TypeSRV) + m := new(dns.Msg) + m.SetQuestion(lookup, dns.TypeSRV) + resp, err := dns.Exchange(m, udp) if err != nil || resp == nil { t.Fatal("Expected to receive reply, but didn't", lookup) }