aboutsummaryrefslogtreecommitdiff
path: root/plugin/template/template_test.go
diff options
context:
space:
mode:
Diffstat (limited to 'plugin/template/template_test.go')
-rw-r--r--plugin/template/template_test.go245
1 files changed, 197 insertions, 48 deletions
diff --git a/plugin/template/template_test.go b/plugin/template/template_test.go
index 0e1470644..a815e8c7c 100644
--- a/plugin/template/template_test.go
+++ b/plugin/template/template_test.go
@@ -7,80 +7,100 @@ import (
"testing"
"github.com/coredns/coredns/plugin/test"
+ "github.com/mholt/caddy"
gotmpl "text/template"
"github.com/coredns/coredns/plugin/pkg/dnstest"
+ "github.com/coredns/coredns/plugin/pkg/fall"
"github.com/miekg/dns"
)
func TestHandler(t *testing.T) {
rcodeFallthrough := 3841 // reserved for private use, used to indicate a fallthrough
exampleDomainATemplate := template{
- class: dns.ClassINET,
- qtype: dns.TypeA,
- regex: []*regexp.Regexp{regexp.MustCompile("(^|[.])ip-10-(?P<b>[0-9]*)-(?P<c>[0-9]*)-(?P<d>[0-9]*)[.]example[.]$")},
- answer: []*gotmpl.Template{gotmpl.Must(gotmpl.New("answer").Parse("{{ .Name }} 60 IN A 10.{{ .Group.b }}.{{ .Group.c }}.{{ .Group.d }}"))},
+ regex: []*regexp.Regexp{regexp.MustCompile("(^|[.])ip-10-(?P<b>[0-9]*)-(?P<c>[0-9]*)-(?P<d>[0-9]*)[.]example[.]$")},
+ answer: []*gotmpl.Template{gotmpl.Must(gotmpl.New("answer").Parse("{{ .Name }} 60 IN A 10.{{ .Group.b }}.{{ .Group.c }}.{{ .Group.d }}"))},
+ qclass: dns.ClassANY,
+ qtype: dns.TypeANY,
+ fthrough: fall.F{Zones: []string{"."}},
+ zones: []string{"."},
}
exampleDomainANSTemplate := template{
- class: dns.ClassINET,
- qtype: dns.TypeA,
regex: []*regexp.Regexp{regexp.MustCompile("(^|[.])ip-10-(?P<b>[0-9]*)-(?P<c>[0-9]*)-(?P<d>[0-9]*)[.]example[.]$")},
answer: []*gotmpl.Template{gotmpl.Must(gotmpl.New("answer").Parse("{{ .Name }} 60 IN A 10.{{ .Group.b }}.{{ .Group.c }}.{{ .Group.d }}"))},
additional: []*gotmpl.Template{gotmpl.Must(gotmpl.New("additional").Parse("ns0.example. IN A 203.0.113.8"))},
authority: []*gotmpl.Template{gotmpl.Must(gotmpl.New("authority").Parse("example. IN NS ns0.example.com."))},
+ qclass: dns.ClassANY,
+ qtype: dns.TypeANY,
+ fthrough: fall.F{Zones: []string{"."}},
+ zones: []string{"."},
}
exampleDomainMXTemplate := template{
- class: dns.ClassINET,
- qtype: dns.TypeMX,
regex: []*regexp.Regexp{regexp.MustCompile("(^|[.])ip-10-(?P<b>[0-9]*)-(?P<c>[0-9]*)-(?P<d>[0-9]*)[.]example[.]$")},
answer: []*gotmpl.Template{gotmpl.Must(gotmpl.New("answer").Parse("{{ .Name }} 60 MX 10 {{ .Name }}"))},
additional: []*gotmpl.Template{gotmpl.Must(gotmpl.New("additional").Parse("{{ .Name }} 60 IN A 10.{{ .Group.b }}.{{ .Group.c }}.{{ .Group.d }}"))},
+ qclass: dns.ClassANY,
+ qtype: dns.TypeANY,
+ fthrough: fall.F{Zones: []string{"."}},
+ zones: []string{"."},
}
invalidDomainTemplate := template{
- class: dns.ClassANY,
- qtype: dns.TypeANY,
- regex: []*regexp.Regexp{regexp.MustCompile("[.]invalid[.]$")},
- rcode: dns.RcodeNameError,
- answer: []*gotmpl.Template{gotmpl.Must(gotmpl.New("answer").Parse("invalid. 60 {{ .Class }} SOA a.invalid. b.invalid. (1 60 60 60 60)"))},
+ regex: []*regexp.Regexp{regexp.MustCompile("[.]invalid[.]$")},
+ rcode: dns.RcodeNameError,
+ answer: []*gotmpl.Template{gotmpl.Must(gotmpl.New("answer").Parse("invalid. 60 {{ .Class }} SOA a.invalid. b.invalid. (1 60 60 60 60)"))},
+ qclass: dns.ClassANY,
+ qtype: dns.TypeANY,
+ fthrough: fall.F{Zones: []string{"."}},
+ zones: []string{"."},
}
rcodeServfailTemplate := template{
- class: dns.ClassANY,
- qtype: dns.TypeANY,
- regex: []*regexp.Regexp{regexp.MustCompile(".*")},
- rcode: dns.RcodeServerFailure,
+ regex: []*regexp.Regexp{regexp.MustCompile(".*")},
+ rcode: dns.RcodeServerFailure,
+ qclass: dns.ClassANY,
+ qtype: dns.TypeANY,
+ fthrough: fall.F{Zones: []string{"."}},
+ zones: []string{"."},
}
brokenTemplate := template{
- class: dns.ClassINET,
- qtype: dns.TypeA,
- regex: []*regexp.Regexp{regexp.MustCompile("[.]example[.]$")},
- answer: []*gotmpl.Template{gotmpl.Must(gotmpl.New("answer").Parse("{{ .Name }} 60 IN TXT \"{{ index .Match 2 }}\""))},
+ regex: []*regexp.Regexp{regexp.MustCompile("[.]example[.]$")},
+ answer: []*gotmpl.Template{gotmpl.Must(gotmpl.New("answer").Parse("{{ .Name }} 60 IN TXT \"{{ index .Match 2 }}\""))},
+ qclass: dns.ClassANY,
+ qtype: dns.TypeANY,
+ fthrough: fall.F{Zones: []string{"."}},
+ zones: []string{"."},
}
nonRRTemplate := template{
- class: dns.ClassINET,
- qtype: dns.TypeA,
- regex: []*regexp.Regexp{regexp.MustCompile("[.]example[.]$")},
- answer: []*gotmpl.Template{gotmpl.Must(gotmpl.New("answer").Parse("{{ .Name }}"))},
+ regex: []*regexp.Regexp{regexp.MustCompile("[.]example[.]$")},
+ answer: []*gotmpl.Template{gotmpl.Must(gotmpl.New("answer").Parse("{{ .Name }}"))},
+ qclass: dns.ClassANY,
+ qtype: dns.TypeANY,
+ fthrough: fall.F{Zones: []string{"."}},
+ zones: []string{"."},
}
nonRRAdditionalTemplate := template{
- class: dns.ClassINET,
- qtype: dns.TypeA,
regex: []*regexp.Regexp{regexp.MustCompile("[.]example[.]$")},
additional: []*gotmpl.Template{gotmpl.Must(gotmpl.New("answer").Parse("{{ .Name }}"))},
+ qclass: dns.ClassANY,
+ qtype: dns.TypeANY,
+ fthrough: fall.F{Zones: []string{"."}},
+ zones: []string{"."},
}
nonRRAuthoritativeTemplate := template{
- class: dns.ClassINET,
- qtype: dns.TypeA,
regex: []*regexp.Regexp{regexp.MustCompile("[.]example[.]$")},
authority: []*gotmpl.Template{gotmpl.Must(gotmpl.New("authority").Parse("{{ .Name }}"))},
+ qclass: dns.ClassANY,
+ qtype: dns.TypeANY,
+ fthrough: fall.F{Zones: []string{"."}},
+ zones: []string{"."},
}
tests := []struct {
tmpl template
qname string
+ name string
qclass uint16
qtype uint16
- name string
expectedCode int
expectedErr string
verifyResponse func(*dns.Msg) error
@@ -88,8 +108,6 @@ func TestHandler(t *testing.T) {
{
name: "RcodeServFail",
tmpl: rcodeServfailTemplate,
- qclass: dns.ClassANY,
- qtype: dns.TypeANY,
qname: "test.invalid.",
expectedCode: dns.RcodeServerFailure,
verifyResponse: func(r *dns.Msg) error {
@@ -222,22 +240,6 @@ func TestHandler(t *testing.T) {
},
},
{
- name: "ExampleDomainMismatchType",
- tmpl: exampleDomainATemplate,
- qclass: dns.ClassINET,
- qtype: dns.TypeMX,
- qname: "ip-10-95-12-8.example.",
- expectedCode: rcodeFallthrough,
- },
- {
- name: "ExampleDomainMismatchClass",
- tmpl: exampleDomainATemplate,
- qclass: dns.ClassCHAOS,
- qtype: dns.TypeA,
- qname: "ip-10-95-12-8.example.",
- expectedCode: rcodeFallthrough,
- },
- {
name: "ExampleInvalidNXDOMAIN",
tmpl: invalidDomainTemplate,
qclass: dns.ClassINET,
@@ -261,6 +263,7 @@ func TestHandler(t *testing.T) {
for _, tr := range tests {
handler := Handler{
Next: test.NextHandler(rcodeFallthrough, nil),
+ Zones: []string{"."},
Templates: []template{tr.tmpl},
}
req := &dns.Msg{
@@ -292,3 +295,149 @@ func TestHandler(t *testing.T) {
}
}
}
+
+// TestMultiSection verfies that a corefile with mutliple but different template sections works
+func TestMultiSection(t *testing.T) {
+ rcodeFallthrough := 3841 // reserved for private use, used to indicate a fallthrough
+ ctx := context.TODO()
+
+ multisectionConfig := `
+ # Implicit section (see c.ServerBlockKeys)
+ # test.:8053 {
+
+ # REFUSE IN A for the server zone (test.)
+ template IN A {
+ rcode REFUSED
+ }
+ # Fallthrough everyting IN TXT for test.
+ template IN TXT {
+ match "$^"
+ rcode SERVFAIL
+ fallthrough
+ }
+ # Answer CH TXT *.coredns.invalid. / coredns.invalid.
+ template CH TXT coredns.invalid {
+ answer "{{ .Name }} 60 CH TXT \"test\""
+ }
+ # Anwser example. ip templates and fallthrough otherwise
+ template IN A example {
+ match ^ip-10-(?P<b>[0-9]*)-(?P<c>[0-9]*)-(?P<d>[0-9]*)[.]example[.]$
+ answer "{{ .Name }} 60 IN A 10.{{ .Group.b }}.{{ .Group.c }}.{{ .Group.d }}"
+ fallthrough
+ }
+ # Answer MX record requests for ip templates in example. and never fall through
+ template IN MX example {
+ match ^ip-10-(?P<b>[0-9]*)-(?P<c>[0-9]*)-(?P<d>[0-9]*)[.]example[.]$
+ answer "{{ .Name }} 60 IN MX 10 {{ .Name }}"
+ additional "{{ .Name }} 60 IN A 10.{{ .Group.b }}.{{ .Group.c }}.{{ .Group.d }}"
+ }
+ `
+ c := caddy.NewTestController("dns", multisectionConfig)
+ c.ServerBlockKeys = []string{"test.:8053"}
+
+ handler, err := templateParse(c)
+ if err != nil {
+ t.Fatalf("TestMultiSection could not parse config: %v", err)
+ }
+
+ handler.Next = test.NextHandler(rcodeFallthrough, nil)
+
+ rec := dnstest.NewRecorder(&test.ResponseWriter{})
+
+ // Asking for test. IN A -> REFUSED
+
+ req := &dns.Msg{Question: []dns.Question{{Name: "some.test.", Qclass: dns.ClassINET, Qtype: dns.TypeA}}}
+ code, err := handler.ServeDNS(ctx, rec, req)
+ if err != nil {
+ t.Fatalf("TestMultiSection expected no error resolving some.test. A, got: %v", err)
+ }
+ if code != dns.RcodeRefused {
+ t.Fatalf("TestMultiSection expected response code REFUSED got: %v", code)
+ }
+
+ // Asking for test. IN TXT -> fallthrough
+
+ req = &dns.Msg{Question: []dns.Question{{Name: "some.test.", Qclass: dns.ClassINET, Qtype: dns.TypeTXT}}}
+ code, err = handler.ServeDNS(ctx, rec, req)
+ if err != nil {
+ t.Fatalf("TestMultiSection expected no error resolving some.test. TXT, got: %v", err)
+ }
+ if code != rcodeFallthrough {
+ t.Fatalf("TestMultiSection expected response code fallthrough got: %v", code)
+ }
+
+ // Asking for coredns.invalid. CH TXT -> TXT "test"
+
+ req = &dns.Msg{Question: []dns.Question{{Name: "coredns.invalid.", Qclass: dns.ClassCHAOS, Qtype: dns.TypeTXT}}}
+ code, err = handler.ServeDNS(ctx, rec, req)
+ if err != nil {
+ t.Fatalf("TestMultiSection expected no error resolving coredns.invalid. TXT, got: %v", err)
+ }
+ if code != dns.RcodeSuccess {
+ t.Fatalf("TestMultiSection expected success response for coredns.invalid. TXT got: %v", code)
+ }
+ if len(rec.Msg.Answer) != 1 {
+ t.Fatalf("TestMultiSection expected one answer for coredns.invalid. TXT got: %v", rec.Msg.Answer)
+ }
+ if rec.Msg.Answer[0].Header().Rrtype != dns.TypeTXT || rec.Msg.Answer[0].(*dns.TXT).Txt[0] != "test" {
+ t.Fatalf("TestMultiSection a \"test\" answer for coredns.invalid. TXT got: %v", rec.Msg.Answer[0])
+ }
+
+ // Asking for an ip template in example
+
+ req = &dns.Msg{Question: []dns.Question{{Name: "ip-10-11-12-13.example.", Qclass: dns.ClassINET, Qtype: dns.TypeA}}}
+ code, err = handler.ServeDNS(ctx, rec, req)
+ if err != nil {
+ t.Fatalf("TestMultiSection expected no error resolving ip-10-11-12-13.example. IN A, got: %v", err)
+ }
+ if code != dns.RcodeSuccess {
+ t.Fatalf("TestMultiSection expected success response ip-10-11-12-13.example. IN A got: %v, %v", code, dns.RcodeToString[code])
+ }
+ if len(rec.Msg.Answer) != 1 {
+ t.Fatalf("TestMultiSection expected one answer for ip-10-11-12-13.example. IN A got: %v", rec.Msg.Answer)
+ }
+ if rec.Msg.Answer[0].Header().Rrtype != dns.TypeA {
+ t.Fatalf("TestMultiSection an A RR answer for ip-10-11-12-13.example. IN A got: %v", rec.Msg.Answer[0])
+ }
+
+ // Asking for an MX ip template in example
+
+ req = &dns.Msg{Question: []dns.Question{{Name: "ip-10-11-12-13.example.", Qclass: dns.ClassINET, Qtype: dns.TypeMX}}}
+ code, err = handler.ServeDNS(ctx, rec, req)
+ if err != nil {
+ t.Fatalf("TestMultiSection expected no error resolving ip-10-11-12-13.example. IN MX, got: %v", err)
+ }
+ if code != dns.RcodeSuccess {
+ t.Fatalf("TestMultiSection expected success response ip-10-11-12-13.example. IN MX got: %v, %v", code, dns.RcodeToString[code])
+ }
+ if len(rec.Msg.Answer) != 1 {
+ t.Fatalf("TestMultiSection expected one answer for ip-10-11-12-13.example. IN MX got: %v", rec.Msg.Answer)
+ }
+ if rec.Msg.Answer[0].Header().Rrtype != dns.TypeMX {
+ t.Fatalf("TestMultiSection an A RR answer for ip-10-11-12-13.example. IN MX got: %v", rec.Msg.Answer[0])
+ }
+
+ // Test that something.example. A does fall through but something.example. MX does not
+
+ req = &dns.Msg{Question: []dns.Question{{Name: "something.example.", Qclass: dns.ClassINET, Qtype: dns.TypeA}}}
+ code, err = handler.ServeDNS(ctx, rec, req)
+ if err != nil {
+ t.Fatalf("TestMultiSection expected no error resolving something.example. IN A, got: %v", err)
+ }
+ if code != rcodeFallthrough {
+ t.Fatalf("TestMultiSection expected a fall through resolving something.example. IN A, got: %v, %v", code, dns.RcodeToString[code])
+ }
+
+ req = &dns.Msg{Question: []dns.Question{{Name: "something.example.", Qclass: dns.ClassINET, Qtype: dns.TypeMX}}}
+ code, err = handler.ServeDNS(ctx, rec, req)
+ if err != nil {
+ t.Fatalf("TestMultiSection expected no error resolving something.example. IN MX, got: %v", err)
+ }
+ if code == rcodeFallthrough {
+ t.Fatalf("TestMultiSection expected no fall through resolving something.example. IN MX")
+ }
+ if code != dns.RcodeNameError {
+ t.Fatalf("TestMultiSection expected NXDOMAIN resolving something.example. IN MX, got %v, %v", code, dns.RcodeToString[code])
+ }
+
+}