aboutsummaryrefslogtreecommitdiff
path: root/plugin
diff options
context:
space:
mode:
authorGravatar Ondřej Benkovský <ondrej.benkovsky@jamf.com> 2022-10-03 17:04:56 +0200
committerGravatar GitHub <noreply@github.com> 2022-10-03 11:04:56 -0400
commit2fa9821c7ef6ca11b37b73785a69f6968fb3bf40 (patch)
tree5720731c10ce0fb6cddeb7ce1c616c0d381aad2d /plugin
parentb9a31f2c89e12d62e89877391816ef0fac962bad (diff)
downloadcoredns-2fa9821c7ef6ca11b37b73785a69f6968fb3bf40.tar.gz
coredns-2fa9821c7ef6ca11b37b73785a69f6968fb3bf40.tar.zst
coredns-2fa9821c7ef6ca11b37b73785a69f6968fb3bf40.zip
plugin/template : add support for extended DNS errors (#5659)
* plugin/template : add support for extended DNS errors Signed-off-by: Ondřej Benkovský <ondrej.benkovsky@jamf.com>
Diffstat (limited to 'plugin')
-rw-r--r--plugin/template/README.md4
-rw-r--r--plugin/template/setup.go17
-rw-r--r--plugin/template/setup_test.go24
-rw-r--r--plugin/template/template.go12
-rw-r--r--plugin/template/template_test.go37
5 files changed, 94 insertions, 0 deletions
diff --git a/plugin/template/README.md b/plugin/template/README.md
index 5e14ae24a..1bca90662 100644
--- a/plugin/template/README.md
+++ b/plugin/template/README.md
@@ -17,6 +17,7 @@ template CLASS TYPE [ZONE...] {
additional RR
authority RR
rcode CODE
+ ederror EXTENDED_ERROR_CODE [EXTRA_REASON]
fallthrough [FALLTHROUGH-ZONE...]
}
~~~
@@ -31,6 +32,8 @@ template CLASS TYPE [ZONE...] {
in a response with an empty answer section.
* `rcode` **CODE** A response code (`NXDOMAIN, SERVFAIL, ...`). The default is `NOERROR`. Valid response code values are
per the `RcodeToString` map defined by the `miekg/dns` package in `msg.go`.
+* `ederror` **EXTENDED_ERROR_CODE** is an extended DNS error code as a number defined in `RFC8914` (0, 1, 2,..., 24).
+ **EXTRA_REASON** is an additional string explaining the reason for returning the error.
* `fallthrough` Continue with the next _template_ instance if the _template_'s **ZONE** matches a query name but no regex match.
If there is no next _template_, continue resolution with the next plugin. If **[FALLTHROUGH-ZONE...]** are listed (for example
`in-addr.arpa` and `ip6.arpa`), then only queries for those zones will be subject to fallthrough. Without
@@ -104,6 +107,7 @@ The `.invalid` domain is a reserved TLD (see [RFC 2606 Reserved Top Level DNS Na
template ANY ANY invalid {
rcode NXDOMAIN
authority "invalid. 60 {{ .Class }} SOA ns.invalid. hostmaster.invalid. (1 60 60 60 60)"
+ ederror 21 "Blocked according to RFC2606"
}
}
~~~
diff --git a/plugin/template/setup.go b/plugin/template/setup.go
index fc6b75165..56058f032 100644
--- a/plugin/template/setup.go
+++ b/plugin/template/setup.go
@@ -2,6 +2,7 @@ package template
import (
"regexp"
+ "strconv"
gotmpl "text/template"
"github.com/coredns/caddy"
@@ -123,6 +124,22 @@ func templateParse(c *caddy.Controller) (handler Handler, err error) {
}
t.rcode = rcode
+ case "ederror":
+ args := c.RemainingArgs()
+ if len(args) != 1 && len(args) != 2 {
+ return handler, c.ArgErr()
+ }
+
+ code, err := strconv.ParseUint(args[0], 10, 16)
+ if err != nil {
+ return handler, c.Errf("error parsing extended DNS error code %s, %v\n", c.Val(), err)
+ }
+ if len(args) == 2 {
+ t.ederror = &ederror{code: uint16(code), reason: args[1]}
+ } else {
+ t.ederror = &ederror{code: uint16(code)}
+ }
+
case "fallthrough":
t.fall.SetZonesFromArgs(c.RemainingArgs())
diff --git a/plugin/template/setup_test.go b/plugin/template/setup_test.go
index 9f03eebcc..345525da6 100644
--- a/plugin/template/setup_test.go
+++ b/plugin/template/setup_test.go
@@ -161,6 +161,30 @@ func TestSetupParse(t *testing.T) {
}`,
false,
},
+ {
+ `template ANY ANY invalid {
+ rcode NXDOMAIN
+ authority "invalid. 60 {{ .Class }} SOA ns.invalid. hostmaster.invalid. (1 60 60 60 60)"
+ ederror 21 "Blocked according to RFC2606"
+ }`,
+ false,
+ },
+ {
+ `template ANY ANY invalid {
+ rcode NXDOMAIN
+ authority "invalid. 60 {{ .Class }} SOA ns.invalid. hostmaster.invalid. (1 60 60 60 60)"
+ ederror invalid "Blocked according to RFC2606"
+ }`,
+ true,
+ },
+ {
+ `template ANY ANY invalid {
+ rcode NXDOMAIN
+ authority "invalid. 60 {{ .Class }} SOA ns.invalid. hostmaster.invalid. (1 60 60 60 60)"
+ ederror too many arguments
+ }`,
+ true,
+ },
}
for i, test := range tests {
c := caddy.NewTestController("dns", test.inputFileRules)
diff --git a/plugin/template/template.go b/plugin/template/template.go
index aee1e1b80..5eac81e8e 100644
--- a/plugin/template/template.go
+++ b/plugin/template/template.go
@@ -33,10 +33,16 @@ type template struct {
authority []*gotmpl.Template
qclass uint16
qtype uint16
+ ederror *ederror
fall fall.F
upstream Upstreamer
}
+type ederror struct {
+ code uint16
+ reason string
+}
+
// Upstreamer looks up targets of CNAME templates
type Upstreamer interface {
Lookup(ctx context.Context, state request.Request, name string, typ uint16) (*dns.Msg, error)
@@ -125,6 +131,12 @@ func (h Handler) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg)
msg.Ns = append(msg.Ns, rr)
}
+ if template.ederror != nil {
+ msg = msg.SetEdns0(4096, true)
+ ede := dns.EDNS0_EDE{InfoCode: template.ederror.code, ExtraText: template.ederror.reason}
+ msg.IsEdns0().Option = append(msg.IsEdns0().Option, &ede)
+ }
+
w.WriteMsg(msg)
return template.rcode, nil
}
diff --git a/plugin/template/template_test.go b/plugin/template/template_test.go
index c94deb81f..4c160988d 100644
--- a/plugin/template/template_test.go
+++ b/plugin/template/template_test.go
@@ -143,6 +143,16 @@ func TestHandler(t *testing.T) {
fall: fall.Root,
zones: []string{"."},
}
+ templateWithEDE := template{
+ rcode: dns.RcodeNameError,
+ regex: []*regexp.Regexp{regexp.MustCompile(".*")},
+ authority: []*gotmpl.Template{gotmpl.Must(newTemplate("authority", "invalid. 60 {{ .Class }} SOA ns.invalid. hostmaster.invalid. (1 60 60 60 60)"))},
+ qclass: dns.ClassANY,
+ qtype: dns.TypeANY,
+ fall: fall.Root,
+ zones: []string{"."},
+ ederror: &ederror{code: 21, reason: "Blocked due to RFC2606"},
+ }
tests := []struct {
tmpl template
@@ -442,6 +452,33 @@ func TestHandler(t *testing.T) {
"foo": "myfoo",
},
},
+ {
+ name: "EDNS error",
+ tmpl: templateWithEDE,
+ qclass: dns.ClassINET,
+ qtype: dns.TypeA,
+ qname: "test.invalid.",
+ expectedCode: dns.RcodeNameError,
+ verifyResponse: func(r *dns.Msg) error {
+ if opt := r.IsEdns0(); opt != nil {
+ matched := false
+ for _, ednsopt := range opt.Option {
+ if ede, ok := ednsopt.(*dns.EDNS0_EDE); ok {
+ if ede.InfoCode != dns.ExtendedErrorCodeNotSupported {
+ return fmt.Errorf("unexpected EDE code = %v, want %v", ede.InfoCode, dns.ExtendedErrorCodeNotSupported)
+ }
+ matched = true
+ }
+ }
+ if !matched {
+ t.Error("Error: acl.ServeDNS() missing Extended DNS Error option")
+ }
+ } else {
+ return fmt.Errorf("expected EDNS enabled")
+ }
+ return nil
+ },
+ },
}
ctx := context.TODO()