plugin/template: add upstream option (#1529)

* add upstream

* docs

* tests
This commit is contained in:
Chris O'Haver 2018-02-16 03:45:25 -05:00 committed by Miek Gieben
parent ba573c0f40
commit 2cad04ec10
4 changed files with 33 additions and 1 deletions

View file

@ -18,6 +18,7 @@ template CLASS TYPE [ZONE...] {
[authority RR] [authority RR]
[...] [...]
[rcode CODE] [rcode CODE]
[upstream [ADDRESS...]]
[fallthrough [ZONE...]] [fallthrough [ZONE...]]
} }
~~~ ~~~
@ -29,6 +30,9 @@ template CLASS TYPE [ZONE...] {
* `answer|additional|authority` **RR** A [RFC 1035](https://tools.ietf.org/html/rfc1035#section-5) style resource record fragment * `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. 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`. * `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.
* `fallthrough` Continue with the next plugin if the zone matched but no regex matched. * `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 If specific zones are listed (for example `in-addr.arpa` and `ip6.arpa`), then only queries for
those zones will be subject to fallthrough. those zones will be subject to fallthrough.

View file

@ -6,6 +6,7 @@ import (
"github.com/coredns/coredns/core/dnsserver" "github.com/coredns/coredns/core/dnsserver"
"github.com/coredns/coredns/plugin" "github.com/coredns/coredns/plugin"
"github.com/coredns/coredns/plugin/pkg/upstream"
"github.com/mholt/caddy" "github.com/mholt/caddy"
"github.com/miekg/dns" "github.com/miekg/dns"
@ -142,6 +143,13 @@ func templateParse(c *caddy.Controller) (handler Handler, err error) {
case "fallthrough": case "fallthrough":
t.fall.SetZonesFromArgs(c.RemainingArgs()) t.fall.SetZonesFromArgs(c.RemainingArgs())
case "upstream":
args := c.RemainingArgs()
u, err := upstream.NewUpstream(args)
if err != nil {
return handler, err
}
t.upstream = u
default: default:
return handler, c.ArgErr() return handler, c.ArgErr()
} }

View file

@ -133,6 +133,20 @@ func TestSetupParse(t *testing.T) {
}`, }`,
false, false,
}, },
{
`template ANY ANY up.stream.local {
answer "up.stream.local 5 IN CNAME up.river.local"
upstream
}`,
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 { for i, test := range tests {
c := caddy.NewTestController("dns", test.inputFileRules) c := caddy.NewTestController("dns", test.inputFileRules)

View file

@ -8,6 +8,7 @@ import (
"github.com/coredns/coredns/plugin" "github.com/coredns/coredns/plugin"
"github.com/coredns/coredns/plugin/pkg/fall" "github.com/coredns/coredns/plugin/pkg/fall"
"github.com/coredns/coredns/plugin/pkg/upstream"
"github.com/coredns/coredns/request" "github.com/coredns/coredns/request"
"github.com/miekg/dns" "github.com/miekg/dns"
@ -32,6 +33,7 @@ type template struct {
qclass uint16 qclass uint16
qtype uint16 qtype uint16
fall fall.F fall fall.F
upstream upstream.Upstream
} }
type templateData struct { type templateData struct {
@ -48,7 +50,7 @@ type templateData struct {
// ServeDNS implements the plugin.Handler interface. // ServeDNS implements the plugin.Handler interface.
func (h Handler) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (int, error) { func (h Handler) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (int, error) {
state := request.Request{W: w, Req: r} state := request.Request{W: w, Req: r, Context: ctx}
zone := plugin.Zones(h.Zones).Matches(state.Name()) zone := plugin.Zones(h.Zones).Matches(state.Name())
if zone == "" { if zone == "" {
@ -81,6 +83,10 @@ func (h Handler) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg)
return dns.RcodeServerFailure, err return dns.RcodeServerFailure, err
} }
msg.Answer = append(msg.Answer, rr) msg.Answer = append(msg.Answer, rr)
if rr.Header().Rrtype == dns.TypeCNAME {
up, _ := template.upstream.Lookup(state, rr.(*dns.CNAME).Target, dns.TypeA)
msg.Answer = append(msg.Answer, up.Answer...)
}
} }
for _, additional := range template.additional { for _, additional := range template.additional {
rr, err := executeRRTemplate("additional", additional, data) rr, err := executeRRTemplate("additional", additional, data)