Rewrite SRV targets and additional names in response (#4287)

* Rewrite plugin - rewrite SRV targets and names in response answer and additional records

Signed-off-by: Nic Colledge <nic@njcolledge.net>

* Added README content to describe new behaviour

Signed-off-by: Nic Colledge <nic@njcolledge.net>

* Added more record types to rewrite handling based on PR/Issue feedback

Signed-off-by: Nic Colledge <nic@njcolledge.net>

* Updated README.md for plugin

Signed-off-by: Nic Colledge <nic@njcolledge.net>

* Updated unit tests.
Small refactor of getTarget... function.

Signed-off-by: Nic Colledge <nic@njcolledge.net>

* Refactor to add response value rewrite as answer value option

Signed-off-by: Nic Colledge <nic@njcolledge.net>

* Removed TODO comment, added test for NAPTR record.

Signed-off-by: Nic Colledge <nic@njcolledge.net>
This commit is contained in:
slick-nic
2021-02-23 09:12:40 +00:00
committed by GitHub
parent fe2b5f630d
commit 0103931263
10 changed files with 322 additions and 130 deletions

View File

@@ -151,26 +151,37 @@ ftp-us-west-1.coredns.rocks. 0 IN A 10.20.20.20
ftp-us-west-1.coredns.rocks. 0 IN A 10.30.30.30
```
It is also possible to rewrite other values returned in the DNS response records
(e.g. the server names returned in `SRV` and `MX` records). This can be enabled by adding
the `answer value` to a name regex rule as specified below. `answer value` takes a
regular expression and a rewrite name as parameters and works in the same way as the
`answer name` rule.
Note that names in the `AUTHORITY SECTION` and `ADDITIONAL SECTION` will also be
rewritten following the specified rules. The names returned by the following
record types: `CNAME`, `DNAME`, `SOA`, `SRV`, `MX`, `NAPTR`, `NS` will be rewritten
if the `answer value` rule is specified.
The syntax for the rewrite of DNS request and response is as follows:
```
rewrite [continue|stop] {
name regex STRING STRING
answer name STRING STRING
[answer value STRING STRING]
}
```
Note that the above syntax is strict. For response rewrites, only `name`
rules are allowed to match the question section, and only by match type
`regex`. The answer rewrite must be after the name, as in the
syntax example. There must only be two lines (a `name` followed by an
`answer`) in the brackets; additional rules are not supported.
syntax example.
An alternate syntax for rewriting a DNS request and response is as
follows:
```
rewrite [continue|stop] name regex STRING STRING answer name STRING STRING
rewrite [continue|stop] name regex STRING STRING answer name STRING STRING [answer value STRING STRING]
```
When using `exact` name rewrite rules, the answer gets rewritten automatically,

View File

@@ -43,5 +43,5 @@ func (rule *classRule) Rewrite(ctx context.Context, state request.Request) Resul
// Mode returns the processing mode.
func (rule *classRule) Mode() string { return rule.NextAction }
// GetResponseRule return a rule to rewrite the response with. Currently not implemented.
func (rule *classRule) GetResponseRule() ResponseRule { return ResponseRule{} }
// GetResponseRules return rules to rewrite the response with. Currently not implemented.
func (rule *classRule) GetResponseRules() []ResponseRule { return []ResponseRule{} }

View File

@@ -73,8 +73,8 @@ func (rule *edns0NsidRule) Rewrite(ctx context.Context, state request.Request) R
// Mode returns the processing mode.
func (rule *edns0NsidRule) Mode() string { return rule.mode }
// GetResponseRule returns a rule to rewrite the response with. Currently not implemented.
func (rule *edns0NsidRule) GetResponseRule() ResponseRule { return ResponseRule{} }
// GetResponseRules returns rules to rewrite the response with. Currently not implemented.
func (rule *edns0NsidRule) GetResponseRules() []ResponseRule { return []ResponseRule{} }
// Rewrite will alter the request EDNS0 local options.
func (rule *edns0LocalRule) Rewrite(ctx context.Context, state request.Request) Result {
@@ -103,8 +103,8 @@ func (rule *edns0LocalRule) Rewrite(ctx context.Context, state request.Request)
// Mode returns the processing mode.
func (rule *edns0LocalRule) Mode() string { return rule.mode }
// GetResponseRule returns a rule to rewrite the response with. Currently not implemented.
func (rule *edns0LocalRule) GetResponseRule() ResponseRule { return ResponseRule{} }
// GetResponseRules returns a rule to rewrite the response with. Currently not implemented.
func (rule *edns0LocalRule) GetResponseRules() []ResponseRule { return []ResponseRule{} }
// newEdns0Rule creates an EDNS0 rule of the appropriate type based on the args
func newEdns0Rule(mode string, args ...string) (Rule, error) {
@@ -253,8 +253,8 @@ func (rule *edns0VariableRule) Rewrite(ctx context.Context, state request.Reques
// Mode returns the processing mode.
func (rule *edns0VariableRule) Mode() string { return rule.mode }
// GetResponseRule returns a rule to rewrite the response with. Currently not implemented.
func (rule *edns0VariableRule) GetResponseRule() ResponseRule { return ResponseRule{} }
// GetResponseRules returns rules to rewrite the response with. Currently not implemented.
func (rule *edns0VariableRule) GetResponseRules() []ResponseRule { return []ResponseRule{} }
func isValidVariable(variable string) bool {
switch variable {
@@ -362,8 +362,8 @@ func (rule *edns0SubnetRule) Rewrite(ctx context.Context, state request.Request)
// Mode returns the processing mode
func (rule *edns0SubnetRule) Mode() string { return rule.mode }
// GetResponseRule return a rule to rewrite the response with. Currently not implemented.
func (rule *edns0SubnetRule) GetResponseRule() ResponseRule { return ResponseRule{} }
// GetResponseRules return rules to rewrite the response with. Currently not implemented.
func (rule *edns0SubnetRule) GetResponseRules() []ResponseRule { return []ResponseRule{} }
// These are all defined actions.
const (

View File

@@ -40,7 +40,7 @@ type regexNameRule struct {
NextAction string
Pattern *regexp.Regexp
Replacement string
ResponseRule
ResponseRules []ResponseRule
}
const (
@@ -113,7 +113,6 @@ func (rule *regexNameRule) Rewrite(ctx context.Context, state request.Request) R
// newNameRule creates a name matching rule based on exact, partial, or regex match
func newNameRule(nextAction string, args ...string) (Rule, error) {
var matchType, rewriteQuestionFrom, rewriteQuestionTo string
var rewriteAnswerField, rewriteAnswerFrom, rewriteAnswerTo string
if len(args) < 2 {
return nil, fmt.Errorf("too few arguments for a name rule")
}
@@ -140,8 +139,9 @@ func newNameRule(nextAction string, args ...string) (Rule, error) {
}
}
if len(args) > 3 && len(args) != 7 {
return nil, fmt.Errorf("response rewrites must consist only of a name rule with 3 arguments and an answer rule with 3 arguments")
//if len(args) > 3 && len(args) != 7 {
if len(args) > 3 && (len(args) - 3) % 4 != 0 {
return nil, fmt.Errorf("response rewrites must consist only of a name rule with 3 arguments and one or more answer rules with 3 arguments each")
}
if len(args) < 7 {
@@ -190,47 +190,39 @@ func newNameRule(nextAction string, args ...string) (Rule, error) {
nextAction,
rewriteQuestionFromPattern,
rewriteQuestionTo,
ResponseRule{
[]ResponseRule{{
Type: "name",
},
}},
}, nil
default:
return nil, fmt.Errorf("name rule supports only exact, prefix, suffix, substring, and regex name matching, received: %s", matchType)
}
}
if len(args) == 7 {
//if len(args) == 7 {
if (len(args) - 3) % 4 == 0 {
if matchType == RegexMatch {
if args[3] != "answer" {
return nil, fmt.Errorf("exceeded the number of arguments for a regex name rule")
}
rewriteQuestionFromPattern, err := isValidRegexPattern(rewriteQuestionFrom, rewriteQuestionTo)
if err != nil {
return nil, err
}
rewriteAnswerField = strings.ToLower(args[4])
switch rewriteAnswerField {
case "name":
default:
return nil, fmt.Errorf("exceeded the number of arguments for a regex name rule")
}
rewriteAnswerFrom = args[5]
rewriteAnswerTo = args[6]
rewriteAnswerFromPattern, err := isValidRegexPattern(rewriteAnswerFrom, rewriteAnswerTo)
rewriteQuestionTo = plugin.Name(args[2]).Normalize()
responseRuleCount := (len(args) - 3) / 4
responseRules := make([]ResponseRule, responseRuleCount)
for i := 0; i < responseRuleCount; i ++ {
startIdx := 3 + (i * 4)
responseRule, err := newResponseRule(args[startIdx:startIdx + 4])
if err != nil {
return nil, err
}
rewriteQuestionTo = plugin.Name(args[2]).Normalize()
rewriteAnswerTo = plugin.Name(args[6]).Normalize()
responseRules[i] = *responseRule
}
return &regexNameRule{
nextAction,
rewriteQuestionFromPattern,
rewriteQuestionTo,
ResponseRule{
Active: true,
Type: "name",
Pattern: rewriteAnswerFromPattern,
Replacement: rewriteAnswerTo,
},
responseRules,
}, nil
}
return nil, fmt.Errorf("the rewrite of response is supported only for name regex rule")
@@ -238,6 +230,34 @@ func newNameRule(nextAction string, args ...string) (Rule, error) {
return nil, fmt.Errorf("the rewrite rule is invalid: %s", args)
}
// newResponseRule creates a new "answer name" or "answer value" response rule.
func newResponseRule(args []string) (responseRule *ResponseRule, err error){
if args[0] != "answer" {
return nil, fmt.Errorf("exceeded the number of arguments for a regex name rule")
}
rewriteAnswerField := strings.ToLower(args[1])
switch rewriteAnswerField {
case "name":
case "value":
default:
return nil, fmt.Errorf("exceeded the number of arguments for a regex name rule")
}
rewriteAnswerFrom := args[2]
rewriteAnswerTo := args[3]
rewriteAnswerFromPattern, err := isValidRegexPattern(rewriteAnswerFrom, rewriteAnswerTo)
if err != nil {
return nil, err
}
rewriteAnswerTo = plugin.Name(args[3]).Normalize()
return &ResponseRule{
Active: true,
Type: rewriteAnswerField,
Pattern: rewriteAnswerFromPattern,
Replacement: rewriteAnswerTo,
}, nil
}
// Mode returns the processing nextAction
func (rule *exactNameRule) Mode() string { return rule.NextAction }
func (rule *prefixNameRule) Mode() string { return rule.NextAction }
@@ -245,20 +265,20 @@ func (rule *suffixNameRule) Mode() string { return rule.NextAction }
func (rule *substringNameRule) Mode() string { return rule.NextAction }
func (rule *regexNameRule) Mode() string { return rule.NextAction }
// GetResponseRule returns a rule to rewrite the response with. Currently not implemented.
func (rule *exactNameRule) GetResponseRule() ResponseRule { return rule.ResponseRule }
// GetResponseRules returns rules to rewrite the response with. Currently not implemented.
func (rule *exactNameRule) GetResponseRules() []ResponseRule { return []ResponseRule{rule.ResponseRule} }
// GetResponseRule returns a rule to rewrite the response with. Currently not implemented.
func (rule *prefixNameRule) GetResponseRule() ResponseRule { return ResponseRule{} }
// GetResponseRules returns rules to rewrite the response with. Currently not implemented.
func (rule *prefixNameRule) GetResponseRules() []ResponseRule { return []ResponseRule{} }
// GetResponseRule returns a rule to rewrite the response with. Currently not implemented.
func (rule *suffixNameRule) GetResponseRule() ResponseRule { return ResponseRule{} }
// GetResponseRules returns rules to rewrite the response with. Currently not implemented.
func (rule *suffixNameRule) GetResponseRules() []ResponseRule { return []ResponseRule{} }
// GetResponseRule returns a rule to rewrite the response with. Currently not implemented.
func (rule *substringNameRule) GetResponseRule() ResponseRule { return ResponseRule{} }
// GetResponseRules returns rules to rewrite the response with. Currently not implemented.
func (rule *substringNameRule) GetResponseRules() []ResponseRule { return []ResponseRule{} }
// GetResponseRule returns a rule to rewrite the response with.
func (rule *regexNameRule) GetResponseRule() ResponseRule { return rule.ResponseRule }
// GetResponseRules returns rules to rewrite the response with.
func (rule *regexNameRule) GetResponseRules() []ResponseRule { return rule.ResponseRules }
// hasClosingDot returns true if s has a closing dot at the end.
func hasClosingDot(s string) bool {

View File

@@ -42,44 +42,114 @@ func (r *ResponseReverter) WriteMsg(res1 *dns.Msg) error {
res.Question[0] = r.originalQuestion
if r.ResponseRewrite {
for _, rr := range res.Ns {
rewriteResourceRecord(res, rr, r)
}
for _, rr := range res.Answer {
rewriteResourceRecord(res, rr, r)
}
for _, rr := range res.Extra {
rewriteResourceRecord(res, rr, r)
}
}
return r.ResponseWriter.WriteMsg(res)
}
func rewriteResourceRecord(res *dns.Msg, rr dns.RR, r *ResponseReverter) {
var (
isNameRewritten bool
isTTLRewritten bool
isValueRewritten bool
name = rr.Header().Name
ttl = rr.Header().Ttl
value string
)
for _, rule := range r.ResponseRules {
if rule.Type == "" {
rule.Type = "name"
}
switch rule.Type {
case "name":
regexGroups := rule.Pattern.FindStringSubmatch(name)
if len(regexGroups) == 0 {
continue
rewriteString(rule, &name, &isNameRewritten)
case "value":
value = getRecordValueForRewrite(rr)
if value != "" {
rewriteString(rule, &value, &isValueRewritten)
}
s := rule.Replacement
for groupIndex, groupValue := range regexGroups {
groupIndexStr := "{" + strconv.Itoa(groupIndex) + "}"
s = strings.Replace(s, groupIndexStr, groupValue, -1)
}
name = s
isNameRewritten = true
case "ttl":
ttl = rule.TTL
isTTLRewritten = true
}
}
if isNameRewritten {
rr.Header().Name = name
}
if isTTLRewritten {
rr.Header().Ttl = ttl
}
if isValueRewritten {
setRewrittenRecordValue(rr, value)
}
}
return r.ResponseWriter.WriteMsg(res)
func getRecordValueForRewrite(rr dns.RR) (name string) {
switch rr.Header().Rrtype {
case dns.TypeSRV:
return rr.(*dns.SRV).Target
case dns.TypeMX:
return rr.(*dns.MX).Mx
case dns.TypeCNAME:
return rr.(*dns.CNAME).Target
case dns.TypeNS:
return rr.(*dns.NS).Ns
case dns.TypeDNAME:
return rr.(*dns.DNAME).Target
case dns.TypeNAPTR:
return rr.(*dns.NAPTR).Replacement
case dns.TypeSOA:
return rr.(*dns.SOA).Ns
default:
return ""
}
}
func setRewrittenRecordValue(rr dns.RR, value string) {
switch rr.Header().Rrtype {
case dns.TypeSRV:
rr.(*dns.SRV).Target = value
case dns.TypeMX:
rr.(*dns.MX).Mx = value
case dns.TypeCNAME:
rr.(*dns.CNAME).Target = value
case dns.TypeNS:
rr.(*dns.NS).Ns = value
case dns.TypeDNAME:
rr.(*dns.DNAME).Target = value
case dns.TypeNAPTR:
rr.(*dns.NAPTR).Replacement = value
case dns.TypeSOA:
rr.(*dns.SOA).Ns = value
}
}
func rewriteString(rule ResponseRule, str *string, isStringRewritten *bool) {
regexGroups := rule.Pattern.FindStringSubmatch(*str)
if len(regexGroups) == 0 {
return
}
s := rule.Replacement
for groupIndex, groupValue := range regexGroups {
groupIndexStr := "{" + strconv.Itoa(groupIndex) + "}"
s = strings.Replace(s, groupIndexStr, groupValue, -1)
}
*isStringRewritten = true
*str = s
}
// Write is a wrapper that records the size of the message that gets written.

View File

@@ -68,3 +68,90 @@ func doReverterTests(rules []Rule, t *testing.T) {
}
}
}
var valueTests = []struct {
from string
fromType uint16
answer []dns.RR
extra []dns.RR
to string
toType uint16
noRevert bool
expectValue string
expectAnswerType uint16
expectAddlName string
}{
{"my.domain.uk", dns.TypeSRV, []dns.RR{test.SRV("my.cluster.local. 5 IN SRV 0 100 100 srv1.my.cluster.local.")}, []dns.RR{test.A("srv1.my.cluster.local. 5 IN A 10.0.0.1")}, "my.domain.uk", dns.TypeSRV, false, "srv1.my.domain.uk.", dns.TypeSRV, "srv1.my.domain.uk."},
{"my.domain.uk", dns.TypeSRV, []dns.RR{test.SRV("my.cluster.local. 5 IN SRV 0 100 100 srv1.my.cluster.local.")}, []dns.RR{test.A("srv1.my.cluster.local. 5 IN A 10.0.0.1")}, "my.cluster.local.", dns.TypeSRV, true, "srv1.my.cluster.local.", dns.TypeSRV, "srv1.my.cluster.local."},
{"my.domain.uk", dns.TypeANY, []dns.RR{test.CNAME("my.cluster.local. 3600 IN CNAME cname.cluster.local.")}, []dns.RR{test.A("cname.cluster.local. 5 IN A 10.0.0.1")}, "my.domain.uk", dns.TypeANY, false, "cname.domain.uk.", dns.TypeCNAME, "cname.domain.uk."},
{"my.domain.uk", dns.TypeANY, []dns.RR{test.CNAME("my.cluster.local. 3600 IN CNAME cname.cluster.local.")}, []dns.RR{test.A("cname.cluster.local. 5 IN A 10.0.0.1")}, "my.cluster.local.", dns.TypeANY, true, "cname.cluster.local.", dns.TypeCNAME, "cname.cluster.local."},
{"my.domain.uk", dns.TypeANY, []dns.RR{test.DNAME("my.cluster.local. 3600 IN DNAME dname.cluster.local.")}, []dns.RR{test.A("dname.cluster.local. 5 IN A 10.0.0.1")}, "my.domain.uk", dns.TypeANY, false, "dname.domain.uk.", dns.TypeDNAME, "dname.domain.uk."},
{"my.domain.uk", dns.TypeANY, []dns.RR{test.DNAME("my.cluster.local. 3600 IN DNAME dname.cluster.local.")}, []dns.RR{test.A("dname.cluster.local. 5 IN A 10.0.0.1")}, "my.cluster.local.", dns.TypeANY, true, "dname.cluster.local.", dns.TypeDNAME, "dname.cluster.local."},
{"my.domain.uk", dns.TypeMX, []dns.RR{test.MX("my.cluster.local. 3600 IN MX 1 mx1.cluster.local.")}, []dns.RR{test.A("mx1.cluster.local. 5 IN A 10.0.0.1")}, "my.domain.uk", dns.TypeMX, false, "mx1.domain.uk.", dns.TypeMX, "mx1.domain.uk."},
{"my.domain.uk", dns.TypeMX, []dns.RR{test.MX("my.cluster.local. 3600 IN MX 1 mx1.cluster.local.")}, []dns.RR{test.A("mx1.cluster.local. 5 IN A 10.0.0.1")}, "my.cluster.local.", dns.TypeMX, true, "mx1.cluster.local.", dns.TypeMX, "mx1.cluster.local."},
{"my.domain.uk", dns.TypeANY, []dns.RR{test.NS("my.cluster.local. 3600 IN NS ns1.cluster.local.")}, []dns.RR{test.A("ns1.cluster.local. 5 IN A 10.0.0.1")}, "my.domain.uk", dns.TypeANY, false, "ns1.domain.uk.", dns.TypeNS, "ns1.domain.uk."},
{"my.domain.uk", dns.TypeANY, []dns.RR{test.NS("my.cluster.local. 3600 IN NS ns1.cluster.local.")}, []dns.RR{test.A("ns1.cluster.local. 5 IN A 10.0.0.1")}, "my.cluster.local.", dns.TypeANY, true, "ns1.cluster.local.", dns.TypeNS, "ns1.cluster.local."},
{"my.domain.uk", dns.TypeSOA, []dns.RR{test.SOA("my.cluster.local. 1800 IN SOA ns1.cluster.local. admin.cluster.local. 1502165581 14400 3600 604800 14400")}, []dns.RR{test.A("ns1.cluster.local. 5 IN A 10.0.0.1")}, "my.domain.uk", dns.TypeSOA, false, "ns1.domain.uk.", dns.TypeSOA, "ns1.domain.uk."},
{"my.domain.uk", dns.TypeSOA, []dns.RR{test.SOA("my.cluster.local. 1800 IN SOA ns1.cluster.local. admin.cluster.local. 1502165581 14400 3600 604800 14400")}, []dns.RR{test.A("ns1.cluster.local. 5 IN A 10.0.0.1")}, "my.cluster.local.", dns.TypeSOA, true, "ns1.cluster.local.", dns.TypeSOA, "ns1.cluster.local."},
{"my.domain.uk", dns.TypeNAPTR, []dns.RR{test.NAPTR("my.cluster.local. 100 IN NAPTR 100 10 \"S\" \"SIP+D2U\" \"!^.*$!sip:customer-service@example.com!\" _sip._udp.cluster.local.")}, []dns.RR{test.A("ns1.cluster.local. 5 IN A 10.0.0.1")}, "my.domain.uk", dns.TypeNAPTR, false, "_sip._udp.domain.uk.", dns.TypeNAPTR, "ns1.domain.uk."},
{"my.domain.uk", dns.TypeNAPTR, []dns.RR{test.NAPTR("my.cluster.local. 100 IN NAPTR 100 10 \"S\" \"SIP+D2U\" \"!^.*$!sip:customer-service@example.com!\" _sip._udp.cluster.local.")}, []dns.RR{test.A("ns1.cluster.local. 5 IN A 10.0.0.1")}, "my.cluster.local.", dns.TypeNAPTR, true, "_sip._udp.cluster.local.", dns.TypeNAPTR, "ns1.cluster.local."},
}
func TestValueResponseReverter(t *testing.T) {
rules := []Rule{}
r, _ := newNameRule("stop", "regex", `(.*)\.domain\.uk`, "{1}.cluster.local", "answer", "name", `(.*)\.cluster\.local`, "{1}.domain.uk", "answer", "value", `(.*)\.cluster\.local`, "{1}.domain.uk")
rules = append(rules, r)
doValueReverterTests(rules, t)
rules = []Rule{}
r, _ = newNameRule("continue", "regex", `(.*)\.domain\.uk`, "{1}.cluster.local", "answer", "name", `(.*)\.cluster\.local`, "{1}.domain.uk", "answer", "value", `(.*)\.cluster\.local`, "{1}.domain.uk")
rules = append(rules, r)
doValueReverterTests(rules, t)
}
func doValueReverterTests(rules []Rule, t *testing.T) {
ctx := context.TODO()
for i, tc := range valueTests {
m := new(dns.Msg)
m.SetQuestion(tc.from, tc.fromType)
m.Question[0].Qclass = dns.ClassINET
m.Answer = tc.answer
m.Extra = tc.extra
rw := Rewrite{
Next: plugin.HandlerFunc(msgPrinter),
Rules: rules,
noRevert: tc.noRevert,
}
rec := dnstest.NewRecorder(&test.ResponseWriter{})
rw.ServeDNS(ctx, rec, m)
resp := rec.Msg
if resp.Question[0].Name != tc.to {
t.Errorf("Test %d: Expected Name to be %q but was %q", i, tc.to, resp.Question[0].Name)
}
if resp.Question[0].Qtype != tc.toType {
t.Errorf("Test %d: Expected Type to be '%d' but was '%d'", i, tc.toType, resp.Question[0].Qtype)
}
if len(resp.Answer) <= 0 || resp.Answer[0].Header().Rrtype != tc.expectAnswerType {
t.Error("Unexpected Answer Record Type / No Answers")
return
}
value := getRecordValueForRewrite(resp.Answer[0])
if value != tc.expectValue {
t.Errorf("Test %d: Expected Target to be '%s' but was '%s'", i, tc.expectValue, value)
}
if len(resp.Extra) <= 0 || resp.Extra[0].Header().Rrtype != dns.TypeA {
t.Error("Unexpected Additional Record Type / No Additional Records")
return
}
if resp.Extra[0].Header().Name != tc.expectAddlName {
t.Errorf("Test %d: Expected Extra Name to be %q but was %q", i, tc.expectAddlName, resp.Extra[0].Header().Name)
}
}
}

View File

@@ -49,11 +49,12 @@ func (rw Rewrite) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg
state.Req.Question[0] = wr.originalQuestion
return dns.RcodeServerFailure, err
}
respRule := rule.GetResponseRule()
for _, respRule := range rule.GetResponseRules() {
if respRule.Active {
wr.ResponseRewrite = true
wr.ResponseRules = append(wr.ResponseRules, respRule)
}
}
if rule.Mode() == Stop {
if rw.noRevert {
return plugin.NextOrFailure(rw.Name(), rw.Next, ctx, w, r)
@@ -78,8 +79,8 @@ type Rule interface {
Rewrite(ctx context.Context, state request.Request) Result
// Mode returns the processing mode stop or continue.
Mode() string
// GetResponseRule returns the rule to rewrite response with, if any.
GetResponseRule() ResponseRule
// GetResponseRules returns rules to rewrite response with, if any.
GetResponseRules() []ResponseRule
}
func newRule(args ...string) (Rule, error) {

View File

@@ -15,31 +15,31 @@ import (
type exactTTLRule struct {
NextAction string
From string
ResponseRule
ResponseRules []ResponseRule
}
type prefixTTLRule struct {
NextAction string
Prefix string
ResponseRule
ResponseRules []ResponseRule
}
type suffixTTLRule struct {
NextAction string
Suffix string
ResponseRule
ResponseRules []ResponseRule
}
type substringTTLRule struct {
NextAction string
Substring string
ResponseRule
ResponseRules []ResponseRule
}
type regexTTLRule struct {
NextAction string
Pattern *regexp.Regexp
ResponseRule
ResponseRules []ResponseRule
}
// Rewrite rewrites the current request based upon exact match of the name
@@ -108,41 +108,41 @@ func newTTLRule(nextAction string, args ...string) (Rule, error) {
return &exactTTLRule{
nextAction,
plugin.Name(args[1]).Normalize(),
ResponseRule{
[]ResponseRule{{
Active: true,
Type: "ttl",
TTL: ttl,
},
}},
}, nil
case PrefixMatch:
return &prefixTTLRule{
nextAction,
plugin.Name(args[1]).Normalize(),
ResponseRule{
[]ResponseRule{{
Active: true,
Type: "ttl",
TTL: ttl,
},
}},
}, nil
case SuffixMatch:
return &suffixTTLRule{
nextAction,
plugin.Name(args[1]).Normalize(),
ResponseRule{
[]ResponseRule{{
Active: true,
Type: "ttl",
TTL: ttl,
},
}},
}, nil
case SubstringMatch:
return &substringTTLRule{
nextAction,
plugin.Name(args[1]).Normalize(),
ResponseRule{
[]ResponseRule{{
Active: true,
Type: "ttl",
TTL: ttl,
},
}},
}, nil
case RegexMatch:
regexPattern, err := regexp.Compile(args[1])
@@ -152,11 +152,11 @@ func newTTLRule(nextAction string, args ...string) (Rule, error) {
return &regexTTLRule{
nextAction,
regexPattern,
ResponseRule{
[]ResponseRule{{
Active: true,
Type: "ttl",
TTL: ttl,
},
}},
}, nil
default:
return nil, fmt.Errorf("ttl rule supports only exact, prefix, suffix, substring, and regex name matching")
@@ -168,11 +168,11 @@ func newTTLRule(nextAction string, args ...string) (Rule, error) {
return &exactTTLRule{
nextAction,
plugin.Name(args[0]).Normalize(),
ResponseRule{
[]ResponseRule{{
Active: true,
Type: "ttl",
TTL: ttl,
},
}},
}, nil
}
@@ -183,29 +183,29 @@ func (rule *suffixTTLRule) Mode() string { return rule.NextAction }
func (rule *substringTTLRule) Mode() string { return rule.NextAction }
func (rule *regexTTLRule) Mode() string { return rule.NextAction }
// GetResponseRule returns a rule to rewrite the response with. Currently not implemented.
func (rule *exactTTLRule) GetResponseRule() ResponseRule {
return rule.ResponseRule
// GetResponseRules returns rules to rewrite the response with. Currently not implemented.
func (rule *exactTTLRule) GetResponseRules() []ResponseRule {
return rule.ResponseRules
}
// GetResponseRule returns a rule to rewrite the response with. Currently not implemented.
func (rule *prefixTTLRule) GetResponseRule() ResponseRule {
return rule.ResponseRule
// GetResponseRules returns rules to rewrite the response with. Currently not implemented.
func (rule *prefixTTLRule) GetResponseRules() []ResponseRule {
return rule.ResponseRules
}
// GetResponseRule returns a rule to rewrite the response with. Currently not implemented.
func (rule *suffixTTLRule) GetResponseRule() ResponseRule {
return rule.ResponseRule
// GetResponseRules returns rules to rewrite the response with. Currently not implemented.
func (rule *suffixTTLRule) GetResponseRules() []ResponseRule {
return rule.ResponseRules
}
// GetResponseRule returns a rule to rewrite the response with. Currently not implemented.
func (rule *substringTTLRule) GetResponseRule() ResponseRule {
return rule.ResponseRule
// GetResponseRules returns rules to rewrite the response with. Currently not implemented.
func (rule *substringTTLRule) GetResponseRules() []ResponseRule {
return rule.ResponseRules
}
// GetResponseRule returns a rule to rewrite the response with.
func (rule *regexTTLRule) GetResponseRule() ResponseRule {
return rule.ResponseRule
// GetResponseRules returns rules to rewrite the response with.
func (rule *regexTTLRule) GetResponseRules() []ResponseRule {
return rule.ResponseRules
}
// validTTL returns true if v is valid TTL value.

View File

@@ -44,5 +44,5 @@ func (rule *typeRule) Rewrite(ctx context.Context, state request.Request) Result
// Mode returns the processing mode.
func (rule *typeRule) Mode() string { return rule.nextAction }
// GetResponseRule return a rule to rewrite the response with. Currently not implemented.
func (rule *typeRule) GetResponseRule() ResponseRule { return ResponseRule{} }
// GetResponseRules return rules to rewrite the response with. Currently not implemented.
func (rule *typeRule) GetResponseRules() []ResponseRule { return []ResponseRule{} }

View File

@@ -99,6 +99,9 @@ func DNSKEY(rr string) *dns.DNSKEY { r, _ := dns.NewRR(rr); return r.(*dns.DNSKE
// DS returns a DS record from rr. It panics on errors.
func DS(rr string) *dns.DS { r, _ := dns.NewRR(rr); return r.(*dns.DS) }
// NAPTR returns a NAPTR record from rr. It panics on errors.
func NAPTR(rr string) *dns.NAPTR { r, _ := dns.NewRR(rr); return r.(*dns.NAPTR) }
// OPT returns an OPT record with UDP buffer size set to bufsize and the DO bit set to do.
func OPT(bufsize int, do bool) *dns.OPT {
o := new(dns.OPT)