From da6054bb4a90274dd53f2822cba1912d26e0018f Mon Sep 17 00:00:00 2001 From: schou Date: Fri, 14 Jul 2023 08:44:30 -0400 Subject: [PATCH 1/5] plugin/forward add ignore_server_failure for masking upstream server faults Signed-off-by: schou --- man/coredns-forward.7 | 2 ++ plugin/forward/README.md | 1 + plugin/forward/forward.go | 7 +++++++ plugin/forward/setup.go | 5 +++++ 4 files changed, 15 insertions(+) diff --git a/man/coredns-forward.7 b/man/coredns-forward.7 index c6f608d248e..0d7a8a9d4b0 100644 --- a/man/coredns-forward.7 +++ b/man/coredns-forward.7 @@ -89,6 +89,8 @@ Requests that match none of these names will be passed through. an upstream to be down. If 0, the upstream will never be marked as down (nor health checked). Default is 2. .IP \(bu 4 +\fB\fCignore_server_failure\fR, squash any server failure errors returned from proxy. +.IP \(bu 4 \fB\fCexpire\fR \fBDURATION\fP, expire (cached) connections after this time, the default is 10s. .IP \(bu 4 \fB\fCtls\fR \fBCERT\fP \fBKEY\fP \fBCA\fP define the TLS properties for TLS connection. From 0 to 3 arguments can be diff --git a/plugin/forward/README.md b/plugin/forward/README.md index 7dd66f768a5..31164a92c26 100644 --- a/plugin/forward/README.md +++ b/plugin/forward/README.md @@ -63,6 +63,7 @@ forward FROM TO... { * `max_fails` is the number of subsequent failed health checks that are needed before considering an upstream to be down. If 0, the upstream will never be marked as down (nor health checked). Default is 2. +* `ignore_server_failure`, squash any server failure errors returned from proxy. * `expire` **DURATION**, expire (cached) connections after this time, the default is 10s. * `tls` **CERT** **KEY** **CA** define the TLS properties for TLS connection. From 0 to 3 arguments can be provided with the meaning as described below diff --git a/plugin/forward/forward.go b/plugin/forward/forward.go index b3df8330f13..15141bbbe0e 100644 --- a/plugin/forward/forward.go +++ b/plugin/forward/forward.go @@ -55,6 +55,9 @@ type Forward struct { // the maximum allowed (maxConcurrent) ErrLimitExceeded error + // IgnoreServerFailure passes back a success without any records if the remote server replies with an error + IgnoreServerFailure bool + tapPlugins []*dnstap.Dnstap // when dnstap plugins are loaded, we use to this to send messages out. Next plugin.Handler @@ -194,6 +197,10 @@ func (f *Forward) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg return 0, nil } + if f.IgnoreServerFailure && ret.MsgHdr.Rcode == dns.RcodeServerFailure { + ret.MsgHdr.Rcode = dns.RcodeSuccess + } + w.WriteMsg(ret) return 0, nil } diff --git a/plugin/forward/setup.go b/plugin/forward/setup.go index 916d7a7a556..e4391e69611 100644 --- a/plugin/forward/setup.go +++ b/plugin/forward/setup.go @@ -227,6 +227,11 @@ func parseBlock(c *caddy.Controller, f *Forward) error { return c.ArgErr() } f.opts.PreferUDP = true + case "ignore_server_failure": + if c.NextArg() { + return c.ArgErr() + } + f.IgnoreServerFailure = true case "tls": args := c.RemainingArgs() if len(args) > 3 { From ebf267f7e28742724e6ba024a38a22f8e58f5659 Mon Sep 17 00:00:00 2001 From: schou Date: Tue, 18 Jul 2023 13:06:01 -0400 Subject: [PATCH 2/5] Switch from a ignore_server_fail to a rewrite rcode type. Signed-off-by: schou --- man/coredns-forward.7 | 2 - plugin/forward/README.md | 1 - plugin/forward/forward.go | 7 -- plugin/forward/setup.go | 5 - plugin/rewrite/README.md | 49 ++++++++++ plugin/rewrite/rcode.go | 180 +++++++++++++++++++++++++++++++++++ plugin/rewrite/rcode_test.go | 87 +++++++++++++++++ plugin/rewrite/rewrite.go | 2 + 8 files changed, 318 insertions(+), 15 deletions(-) create mode 100644 plugin/rewrite/rcode.go create mode 100644 plugin/rewrite/rcode_test.go diff --git a/man/coredns-forward.7 b/man/coredns-forward.7 index 0d7a8a9d4b0..c6f608d248e 100644 --- a/man/coredns-forward.7 +++ b/man/coredns-forward.7 @@ -89,8 +89,6 @@ Requests that match none of these names will be passed through. an upstream to be down. If 0, the upstream will never be marked as down (nor health checked). Default is 2. .IP \(bu 4 -\fB\fCignore_server_failure\fR, squash any server failure errors returned from proxy. -.IP \(bu 4 \fB\fCexpire\fR \fBDURATION\fP, expire (cached) connections after this time, the default is 10s. .IP \(bu 4 \fB\fCtls\fR \fBCERT\fP \fBKEY\fP \fBCA\fP define the TLS properties for TLS connection. From 0 to 3 arguments can be diff --git a/plugin/forward/README.md b/plugin/forward/README.md index 31164a92c26..7dd66f768a5 100644 --- a/plugin/forward/README.md +++ b/plugin/forward/README.md @@ -63,7 +63,6 @@ forward FROM TO... { * `max_fails` is the number of subsequent failed health checks that are needed before considering an upstream to be down. If 0, the upstream will never be marked as down (nor health checked). Default is 2. -* `ignore_server_failure`, squash any server failure errors returned from proxy. * `expire` **DURATION**, expire (cached) connections after this time, the default is 10s. * `tls` **CERT** **KEY** **CA** define the TLS properties for TLS connection. From 0 to 3 arguments can be provided with the meaning as described below diff --git a/plugin/forward/forward.go b/plugin/forward/forward.go index 15141bbbe0e..b3df8330f13 100644 --- a/plugin/forward/forward.go +++ b/plugin/forward/forward.go @@ -55,9 +55,6 @@ type Forward struct { // the maximum allowed (maxConcurrent) ErrLimitExceeded error - // IgnoreServerFailure passes back a success without any records if the remote server replies with an error - IgnoreServerFailure bool - tapPlugins []*dnstap.Dnstap // when dnstap plugins are loaded, we use to this to send messages out. Next plugin.Handler @@ -197,10 +194,6 @@ func (f *Forward) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg return 0, nil } - if f.IgnoreServerFailure && ret.MsgHdr.Rcode == dns.RcodeServerFailure { - ret.MsgHdr.Rcode = dns.RcodeSuccess - } - w.WriteMsg(ret) return 0, nil } diff --git a/plugin/forward/setup.go b/plugin/forward/setup.go index e4391e69611..916d7a7a556 100644 --- a/plugin/forward/setup.go +++ b/plugin/forward/setup.go @@ -227,11 +227,6 @@ func parseBlock(c *caddy.Controller, f *Forward) error { return c.ArgErr() } f.opts.PreferUDP = true - case "ignore_server_failure": - if c.NextArg() { - return c.ArgErr() - } - f.IgnoreServerFailure = true case "tls": args := c.RemainingArgs() if len(args) > 3 { diff --git a/plugin/rewrite/README.md b/plugin/rewrite/README.md index ef938e79d34..42c28a9361e 100644 --- a/plugin/rewrite/README.md +++ b/plugin/rewrite/README.md @@ -26,6 +26,7 @@ e.g., to rewrite ANY queries to HINFO, use `rewrite type ANY HINFO`. * `edns0` - an EDNS0 option can be appended to the request as described below in the **EDNS0 Options** section. * `ttl` - the TTL value in the _response_ is rewritten. * `cname` - the CNAME target if the response has a CNAME record + * `rcode` - the response code (RCODE) value in the _response_ is rewritten. * **TYPE** this optional element can be specified for a `name` or `ttl` field. If not given type `exact` will be assumed. If options should be specified the @@ -335,6 +336,54 @@ rewrite ttl example.com. 30- rewrite ttl example.com. 30 # equivalent to rewrite ttl example.com. 30-30 ``` +### RCODE Field Rewrites + +At times, the need to rewrite a RCODE value could arise. For example, a DNS server +may respond with a SERVFAIL instead of NOERROR records when AAAA records are requested. + +In the below example, the TTL in the answers for `coredns.rocks` domain are +being set to `15`: + +This example rewrites all the *.coredns.rocks domain SERVFAIL errors to NOERROR +``` + rewrite continue { + rcode regex (.*)\.coredns\.rocks SERVFAIL NOERROR + } +``` + +The syntax for the RCODE rewrite rule is as follows. The meaning of +`exact|prefix|suffix|substring|regex` is the same as with the name rewrite rules. +An omitted type is defaulted to `exact`. + +``` +rewrite [continue|stop] rcode [exact|prefix|suffix|substring|regex] STRING OLD NEW +``` + +The values of OLD and NEW can be any of the following: + +``` + 0 NOERROR + 1 FORMERR + 2 SERVFAIL + 3 NXDOMAIN + 4 NOTIMP + 5 REFUSED + 6 YXDOMAIN + 7 YXRRSET + 8 NXRRSET + 9 NOTAUTH + 10 NOTZONE + 16 BADSIG + 17 BADKEY + 18 BADTIME + 19 BADMODE + 20 BADNAME + 21 BADALG + 22 BADTRUNC + 23 BADCOOKIE +``` + + ## EDNS0 Options Using the FIELD edns0, you can set, append, or replace specific EDNS0 options in the request. diff --git a/plugin/rewrite/rcode.go b/plugin/rewrite/rcode.go new file mode 100644 index 00000000000..0d7602cf25a --- /dev/null +++ b/plugin/rewrite/rcode.go @@ -0,0 +1,180 @@ +package rewrite + +import ( + "context" + "fmt" + "regexp" + "strconv" + "strings" + + "github.com/coredns/coredns/plugin" + "github.com/coredns/coredns/request" + + "github.com/miekg/dns" +) + +type rcodeResponseRule struct { + old int + new int +} + +func (r *rcodeResponseRule) RewriteResponse(res *dns.Msg, rr dns.RR) { + if r.old == res.MsgHdr.Rcode { + res.MsgHdr.Rcode = r.new + } +} + +type rcodeRuleBase struct { + nextAction string + response rcodeResponseRule +} + +func newRCodeRuleBase(nextAction string, old, new int) rcodeRuleBase { + return rcodeRuleBase{ + nextAction: nextAction, + response: rcodeResponseRule{old: old, new: new}, + } +} + +func (rule *rcodeRuleBase) responseRule(match bool) (ResponseRules, Result) { + if match { + return ResponseRules{&rule.response}, RewriteDone + } + return nil, RewriteIgnored +} + +// Mode returns the processing nextAction +func (rule *rcodeRuleBase) Mode() string { return rule.nextAction } + +type exactRCodeRule struct { + rcodeRuleBase + From string +} + +type prefixRCodeRule struct { + rcodeRuleBase + Prefix string +} + +type suffixRCodeRule struct { + rcodeRuleBase + Suffix string +} + +type substringRCodeRule struct { + rcodeRuleBase + Substring string +} + +type regexRCodeRule struct { + rcodeRuleBase + Pattern *regexp.Regexp +} + +// Rewrite rewrites the current request based upon exact match of the name +// in the question section of the request. +func (rule *exactRCodeRule) Rewrite(ctx context.Context, state request.Request) (ResponseRules, Result) { + return rule.responseRule(rule.From == state.Name()) +} + +// Rewrite rewrites the current request when the name begins with the matching string. +func (rule *prefixRCodeRule) Rewrite(ctx context.Context, state request.Request) (ResponseRules, Result) { + return rule.responseRule(strings.HasPrefix(state.Name(), rule.Prefix)) +} + +// Rewrite rewrites the current request when the name ends with the matching string. +func (rule *suffixRCodeRule) Rewrite(ctx context.Context, state request.Request) (ResponseRules, Result) { + return rule.responseRule(strings.HasSuffix(state.Name(), rule.Suffix)) +} + +// Rewrite rewrites the current request based upon partial match of the +// name in the question section of the request. +func (rule *substringRCodeRule) Rewrite(ctx context.Context, state request.Request) (ResponseRules, Result) { + return rule.responseRule(strings.Contains(state.Name(), rule.Substring)) +} + +// Rewrite rewrites the current request when the name in the question +// section of the request matches a regular expression. +func (rule *regexRCodeRule) Rewrite(ctx context.Context, state request.Request) (ResponseRules, Result) { + return rule.responseRule(len(rule.Pattern.FindStringSubmatch(state.Name())) != 0) +} + +// newRCodeRule creates a name matching rule based on exact, partial, or regex match +func newRCodeRule(nextAction string, args ...string) (Rule, error) { + if len(args) < 3 { + return nil, fmt.Errorf("too few (%d) arguments for a rcode rule", len(args)) + } + var oldStr, newStr string + if len(args) == 3 { + oldStr, newStr = args[1], args[2] + } + if len(args) == 4 { + oldStr, newStr = args[2], args[3] + } + old, valid := isValidRCode(oldStr) + if !valid { + return nil, fmt.Errorf("invalid matching RCODE '%s' for a rcode rule", oldStr) + } + new, valid := isValidRCode(newStr) + if !valid { + return nil, fmt.Errorf("invalid replacement RCODE '%s' for a rcode rule", newStr) + } + if len(args) == 4 { + switch strings.ToLower(args[0]) { + case ExactMatch: + return &exactRCodeRule{ + newRCodeRuleBase(nextAction, old, new), + plugin.Name(args[1]).Normalize(), + }, nil + case PrefixMatch: + return &prefixRCodeRule{ + newRCodeRuleBase(nextAction, old, new), + plugin.Name(args[1]).Normalize(), + }, nil + case SuffixMatch: + return &suffixRCodeRule{ + newRCodeRuleBase(nextAction, old, new), + plugin.Name(args[1]).Normalize(), + }, nil + case SubstringMatch: + return &substringRCodeRule{ + newRCodeRuleBase(nextAction, old, new), + plugin.Name(args[1]).Normalize(), + }, nil + case RegexMatch: + regexPattern, err := regexp.Compile(args[1]) + if err != nil { + return nil, fmt.Errorf("invalid regex pattern in a rcode rule: %s", args[1]) + } + return ®exRCodeRule{ + newRCodeRuleBase(nextAction, old, new), + regexPattern, + }, nil + default: + return nil, fmt.Errorf("rcode rule supports only exact, prefix, suffix, substring, and regex name matching") + } + } + if len(args) > 4 { + return nil, fmt.Errorf("many few arguments for a rcode rule") + } + return &exactRCodeRule{ + newRCodeRuleBase(nextAction, old, new), + plugin.Name(args[0]).Normalize(), + }, nil +} + +// validRCode returns true if v is valid RCode value. +func isValidRCode(v string) (int, bool) { + i, err := strconv.ParseUint(v, 10, 32) + // try parsing integer based rcode + if err == nil && i <= 23 { + return int(i), true + } + + for RCodeInt, RCodeStr := range dns.RcodeToString { + if strings.EqualFold(RCodeStr, v) { + return RCodeInt, true + } + } + return 0, false +} diff --git a/plugin/rewrite/rcode_test.go b/plugin/rewrite/rcode_test.go new file mode 100644 index 00000000000..05ae424a3a6 --- /dev/null +++ b/plugin/rewrite/rcode_test.go @@ -0,0 +1,87 @@ +package rewrite + +import ( + "testing" + + "github.com/coredns/coredns/plugin/test" + "github.com/coredns/coredns/request" + "github.com/miekg/dns" +) + +func TestNewRCodeRule(t *testing.T) { + tests := []struct { + next string + args []string + expectedFail bool + }{ + {"stop", []string{"srv1.coredns.rocks", "2", "0"}, false}, + {"stop", []string{"exact", "srv1.coredns.rocks", "SERVFAIL", "NOERROR"}, false}, + {"stop", []string{"prefix", "coredns.rocks", "NotAuth", "0"}, false}, + {"stop", []string{"suffix", "srv1", "SERVFAIL", "0"}, false}, + {"stop", []string{"substring", "coredns", "REFUSED", "NoError"}, false}, + {"stop", []string{"regex", `(srv1)\.(coredns)\.(rocks)`, "FORMERR", "NOERROR"}, false}, + {"continue", []string{"srv1.coredns.rocks", "2", "0"}, false}, + {"continue", []string{"exact", "srv1.coredns.rocks", "SERVFAIL", "NOERROR"}, false}, + {"continue", []string{"prefix", "coredns.rocks", "NOTAUTH", "0"}, false}, + {"continue", []string{"suffix", "srv1", "SERVFAIL", "0"}, false}, + {"continue", []string{"substring", "coredns", "REFUSED", "NOERROR"}, false}, + {"continue", []string{"regex", `(srv1)\.(coredns)\.(rocks)`, "FORMERR", "NOERROR"}, false}, + {"stop", []string{"srv1.coredns.rocks", "12345678901234567890"}, true}, + {"stop", []string{"srv1.coredns.rocks", "coredns.rocks"}, true}, + {"stop", []string{"srv1.coredns.rocks", "#1"}, true}, + {"stop", []string{"range.coredns.rocks", "1", "2"}, false}, + {"stop", []string{"ceil.coredns.rocks", "-2"}, true}, + {"stop", []string{"floor.coredns.rocks", "1-"}, true}, + {"stop", []string{"range.coredns.rocks", "2", "2"}, false}, + {"stop", []string{"invalid.coredns.rocks", "-"}, true}, + {"stop", []string{"invalid.coredns.rocks", "2-1"}, true}, + {"stop", []string{"invalid.coredns.rocks", "random"}, true}, + } + for i, tc := range tests { + failed := false + rule, err := newRCodeRule(tc.next, tc.args...) + if err != nil { + failed = true + } + if !failed && !tc.expectedFail { + continue + } + if failed && tc.expectedFail { + continue + } + t.Fatalf("Test %d: FAIL, expected fail=%t, but received fail=%t: (%s) %s, rule=%v, err=%v", i, tc.expectedFail, failed, tc.next, tc.args, rule, err) + } + for i, tc := range tests { + failed := false + tc.args = append([]string{tc.next, "rcode"}, tc.args...) + rule, err := newRule(tc.args...) + if err != nil { + failed = true + } + if !failed && !tc.expectedFail { + continue + } + if failed && tc.expectedFail { + continue + } + t.Fatalf("Test %d: FAIL, expected fail=%t, but received fail=%t: (%s) %s, rule=%v, err=%v", i, tc.expectedFail, failed, tc.next, tc.args, rule, err) + } +} + +func TestRCodeRewrite(t *testing.T) { + rule, err := newRCodeRule("stop", []string{"exact", "srv1.coredns.rocks", "SERVFAIL", "FORMERR"}...) + + m := new(dns.Msg) + m.SetQuestion("srv1.coredns.rocks.", dns.TypeA) + m.Question[0].Qclass = dns.ClassINET + m.Answer = []dns.RR{test.A("srv1.coredns.rocks. 5 IN A 10.0.0.1")} + m.MsgHdr.Rcode = dns.RcodeServerFailure + request := request.Request{Req: m} + + rcRule, _ := rule.(*exactRCodeRule) + var rr dns.RR + rcRule.response.RewriteResponse(request.Req, rr) + if request.Req.MsgHdr.Rcode != dns.RcodeFormatError { + t.Fatalf("RCode rewrite did not apply changes, request=%#v, err=%v", request.Req, err) + } +} diff --git a/plugin/rewrite/rewrite.go b/plugin/rewrite/rewrite.go index d991c7f0205..edb11813e92 100644 --- a/plugin/rewrite/rewrite.go +++ b/plugin/rewrite/rewrite.go @@ -141,6 +141,8 @@ func newRule(args ...string) (Rule, error) { return newTTLRule(mode, args[startArg:]...) case "cname": return newCNAMERule(mode, args[startArg:]...) + case "rcode": + return newRCodeRule(mode, args[startArg:]...) default: return nil, fmt.Errorf("invalid rule type %q", args[0]) } From f1fca60540528c2a4705606c1c2577d64dbb112e Mon Sep 17 00:00:00 2001 From: schou Date: Wed, 19 Jul 2023 07:17:06 -0400 Subject: [PATCH 3/5] trim down the tests Signed-off-by: schou --- plugin/rewrite/rcode_test.go | 28 ++++++---------------------- 1 file changed, 6 insertions(+), 22 deletions(-) diff --git a/plugin/rewrite/rcode_test.go b/plugin/rewrite/rcode_test.go index 05ae424a3a6..bf1c547b8c9 100644 --- a/plugin/rewrite/rcode_test.go +++ b/plugin/rewrite/rcode_test.go @@ -14,28 +14,12 @@ func TestNewRCodeRule(t *testing.T) { args []string expectedFail bool }{ - {"stop", []string{"srv1.coredns.rocks", "2", "0"}, false}, - {"stop", []string{"exact", "srv1.coredns.rocks", "SERVFAIL", "NOERROR"}, false}, - {"stop", []string{"prefix", "coredns.rocks", "NotAuth", "0"}, false}, - {"stop", []string{"suffix", "srv1", "SERVFAIL", "0"}, false}, - {"stop", []string{"substring", "coredns", "REFUSED", "NoError"}, false}, - {"stop", []string{"regex", `(srv1)\.(coredns)\.(rocks)`, "FORMERR", "NOERROR"}, false}, - {"continue", []string{"srv1.coredns.rocks", "2", "0"}, false}, - {"continue", []string{"exact", "srv1.coredns.rocks", "SERVFAIL", "NOERROR"}, false}, - {"continue", []string{"prefix", "coredns.rocks", "NOTAUTH", "0"}, false}, - {"continue", []string{"suffix", "srv1", "SERVFAIL", "0"}, false}, - {"continue", []string{"substring", "coredns", "REFUSED", "NOERROR"}, false}, - {"continue", []string{"regex", `(srv1)\.(coredns)\.(rocks)`, "FORMERR", "NOERROR"}, false}, - {"stop", []string{"srv1.coredns.rocks", "12345678901234567890"}, true}, - {"stop", []string{"srv1.coredns.rocks", "coredns.rocks"}, true}, - {"stop", []string{"srv1.coredns.rocks", "#1"}, true}, - {"stop", []string{"range.coredns.rocks", "1", "2"}, false}, - {"stop", []string{"ceil.coredns.rocks", "-2"}, true}, - {"stop", []string{"floor.coredns.rocks", "1-"}, true}, - {"stop", []string{"range.coredns.rocks", "2", "2"}, false}, - {"stop", []string{"invalid.coredns.rocks", "-"}, true}, - {"stop", []string{"invalid.coredns.rocks", "2-1"}, true}, - {"stop", []string{"invalid.coredns.rocks", "random"}, true}, + {"stop", []string{"numeric.rcode.coredns.rocks", "2", "0"}, false}, + {"stop", []string{"too.few.rcode.coredns.rocks", "2"}, true}, + {"stop", []string{"exact", "too.many.rcode.coredns.rocks", "2", "1", "0"}, true}, + {"stop", []string{"exact", "match.string.rcode.coredns.rocks", "SERVFAIL", "NOERROR"}, false}, + {"continue", []string{"regex", `(regex)\.rcode\.(coredns)\.(rocks)`, "FORMERR", "NOERROR"}, false}, + {"stop", []string{"invalid.rcode.coredns.rocks", "random", "nothing"}, true}, } for i, tc := range tests { failed := false From ba6b3c7c7684b66322088fb2a271afc6d8ad442b Mon Sep 17 00:00:00 2001 From: schou Date: Thu, 20 Jul 2023 15:28:39 -0400 Subject: [PATCH 4/5] fixing readme TTL and using map for rcode Signed-off-by: schou --- plugin/rewrite/README.md | 15 +++++++++++---- plugin/rewrite/rcode.go | 6 ++---- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/plugin/rewrite/README.md b/plugin/rewrite/README.md index 42c28a9361e..d993fa8e6bc 100644 --- a/plugin/rewrite/README.md +++ b/plugin/rewrite/README.md @@ -341,8 +341,8 @@ rewrite ttl example.com. 30 # equivalent to rewrite ttl example.com. 30-30 At times, the need to rewrite a RCODE value could arise. For example, a DNS server may respond with a SERVFAIL instead of NOERROR records when AAAA records are requested. -In the below example, the TTL in the answers for `coredns.rocks` domain are -being set to `15`: +In the below example, the rcode value the answer for `coredns.rocks` the replies with SERVFAIL +is being switched to NOERROR. This example rewrites all the *.coredns.rocks domain SERVFAIL errors to NOERROR ``` @@ -351,15 +351,22 @@ This example rewrites all the *.coredns.rocks domain SERVFAIL errors to NOERROR } ``` +The same result numeric values: +``` + rewrite continue { + rcode regex (.*)\.coredns\.rocks 2 0 + } +``` + The syntax for the RCODE rewrite rule is as follows. The meaning of `exact|prefix|suffix|substring|regex` is the same as with the name rewrite rules. An omitted type is defaulted to `exact`. ``` -rewrite [continue|stop] rcode [exact|prefix|suffix|substring|regex] STRING OLD NEW +rewrite [continue|stop] rcode [exact|prefix|suffix|substring|regex] STRING FROM TO ``` -The values of OLD and NEW can be any of the following: +The values of FROM and TO can be any of the following, text value or numeric: ``` 0 NOERROR diff --git a/plugin/rewrite/rcode.go b/plugin/rewrite/rcode.go index 0d7602cf25a..814b95fd967 100644 --- a/plugin/rewrite/rcode.go +++ b/plugin/rewrite/rcode.go @@ -171,10 +171,8 @@ func isValidRCode(v string) (int, bool) { return int(i), true } - for RCodeInt, RCodeStr := range dns.RcodeToString { - if strings.EqualFold(RCodeStr, v) { - return RCodeInt, true - } + if RCodeInt, ok := dns.StringToRcode[strings.ToUpper(v)]; ok { + return RCodeInt, true } return 0, false } From cf9f7bee67eed576e2215c3decfeb496d0ca772d Mon Sep 17 00:00:00 2001 From: schou Date: Sat, 26 Aug 2023 07:28:52 -0400 Subject: [PATCH 5/5] add newline Signed-off-by: schou --- plugin/rewrite/rcode_test.go | 1 + 1 file changed, 1 insertion(+) diff --git a/plugin/rewrite/rcode_test.go b/plugin/rewrite/rcode_test.go index bf1c547b8c9..e4026071957 100644 --- a/plugin/rewrite/rcode_test.go +++ b/plugin/rewrite/rcode_test.go @@ -5,6 +5,7 @@ import ( "github.com/coredns/coredns/plugin/test" "github.com/coredns/coredns/request" + "github.com/miekg/dns" )