diff options
-rw-r--r-- | plugin/rewrite/class.go | 5 | ||||
-rw-r--r-- | plugin/rewrite/edns0.go | 20 | ||||
-rw-r--r-- | plugin/rewrite/name.go | 65 | ||||
-rw-r--r-- | plugin/rewrite/reverter.go | 44 | ||||
-rw-r--r-- | plugin/rewrite/rewrite.go | 9 | ||||
-rw-r--r-- | plugin/rewrite/rewrite_test.go | 17 | ||||
-rw-r--r-- | plugin/rewrite/setup.go | 7 | ||||
-rw-r--r-- | plugin/rewrite/type.go | 5 |
8 files changed, 161 insertions, 11 deletions
diff --git a/plugin/rewrite/class.go b/plugin/rewrite/class.go index ca86430d2..2e54f515c 100644 --- a/plugin/rewrite/class.go +++ b/plugin/rewrite/class.go @@ -41,3 +41,8 @@ func (rule *classRule) Rewrite(w dns.ResponseWriter, r *dns.Msg) Result { 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{} +} diff --git a/plugin/rewrite/edns0.go b/plugin/rewrite/edns0.go index a71c14a53..7ea6f7917 100644 --- a/plugin/rewrite/edns0.go +++ b/plugin/rewrite/edns0.go @@ -78,6 +78,11 @@ func (rule *edns0NsidRule) Mode() string { return rule.mode } +// GetResponseRule return a rule to rewrite the response with. Currently not implemented. +func (rule *edns0NsidRule) GetResponseRule() ResponseRule { + return ResponseRule{} +} + // Rewrite will alter the request EDNS0 local options func (rule *edns0LocalRule) Rewrite(w dns.ResponseWriter, r *dns.Msg) Result { result := RewriteIgnored @@ -115,6 +120,11 @@ func (rule *edns0LocalRule) Mode() string { return rule.mode } +// GetResponseRule return a rule to rewrite the response with. Currently not implemented. +func (rule *edns0LocalRule) GetResponseRule() ResponseRule { + return ResponseRule{} +} + // newEdns0Rule creates an EDNS0 rule of the appropriate type based on the args func newEdns0Rule(mode string, args ...string) (Rule, error) { if len(args) < 2 { @@ -312,6 +322,11 @@ func (rule *edns0VariableRule) Mode() string { return rule.mode } +// GetResponseRule return a rule to rewrite the response with. Currently not implemented. +func (rule *edns0VariableRule) GetResponseRule() ResponseRule { + return ResponseRule{} +} + func isValidVariable(variable string) bool { switch variable { case @@ -423,6 +438,11 @@ 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{} +} + // These are all defined actions. const ( Replace = "replace" diff --git a/plugin/rewrite/name.go b/plugin/rewrite/name.go index 102c8ad09..6d7a02632 100644 --- a/plugin/rewrite/name.go +++ b/plugin/rewrite/name.go @@ -37,6 +37,7 @@ type regexNameRule struct { NextAction string Pattern *regexp.Regexp Replacement string + ResponseRule } const ( @@ -113,9 +114,6 @@ func newNameRule(nextAction string, args ...string) (Rule, error) { if len(args) < 2 { return nil, fmt.Errorf("too few arguments for a name rule") } - if len(args) > 3 { - return nil, fmt.Errorf("exceeded the number of arguments for a name rule") - } if len(args) == 3 { switch strings.ToLower(args[0]) { case ExactMatch: @@ -131,11 +129,45 @@ func newNameRule(nextAction string, args ...string) (Rule, error) { if err != nil { return nil, fmt.Errorf("Invalid regex pattern in a name rule: %s", args[1]) } - return ®exNameRule{nextAction, regexPattern, plugin.Name(args[2]).Normalize()}, nil + return ®exNameRule{nextAction, regexPattern, plugin.Name(args[2]).Normalize(), ResponseRule{}}, nil default: return nil, fmt.Errorf("A name rule supports only exact, prefix, suffix, substring, and regex name matching") } } + if len(args) == 7 { + if strings.ToLower(args[0]) == RegexMatch { + if args[3] != "answer" { + return nil, fmt.Errorf("exceeded the number of arguments for a regex name rule") + } + switch strings.ToLower(args[4]) { + case "name": + default: + return nil, fmt.Errorf("exceeded the number of arguments for a regex name rule") + } + regexPattern, err := regexp.Compile(args[1]) + if err != nil { + return nil, fmt.Errorf("Invalid regex pattern in a name rule: %s", args) + } + responseRegexPattern, err := regexp.Compile(args[5]) + if err != nil { + return nil, fmt.Errorf("Invalid regex pattern in a name rule: %s", args) + } + return ®exNameRule{ + nextAction, + regexPattern, + plugin.Name(args[2]).Normalize(), + ResponseRule{ + Active: true, + Pattern: responseRegexPattern, + Replacement: plugin.Name(args[6]).Normalize(), + }, + }, nil + } + return nil, fmt.Errorf("the rewrite of response is supported only for name regex rule") + } + if len(args) > 3 && len(args) != 7 { + return nil, fmt.Errorf("exceeded the number of arguments for a name rule") + } return &nameRule{nextAction, plugin.Name(args[0]).Normalize(), plugin.Name(args[1]).Normalize()}, nil } @@ -159,3 +191,28 @@ func (rule *substringNameRule) Mode() string { func (rule *regexNameRule) Mode() string { return rule.NextAction } + +// GetResponseRule return a rule to rewrite the response with. Currently not implemented. +func (rule *nameRule) GetResponseRule() ResponseRule { + return ResponseRule{} +} + +// GetResponseRule return a rule to rewrite the response with. Currently not implemented. +func (rule *prefixNameRule) GetResponseRule() ResponseRule { + return ResponseRule{} +} + +// GetResponseRule return a rule to rewrite the response with. Currently not implemented. +func (rule *suffixNameRule) GetResponseRule() ResponseRule { + return ResponseRule{} +} + +// GetResponseRule return a rule to rewrite the response with. Currently not implemented. +func (rule *substringNameRule) GetResponseRule() ResponseRule { + return ResponseRule{} +} + +// GetResponseRule return a rule to rewrite the response with. +func (rule *regexNameRule) GetResponseRule() ResponseRule { + return rule.ResponseRule +} diff --git a/plugin/rewrite/reverter.go b/plugin/rewrite/reverter.go index 400fb5fff..1ad65536e 100644 --- a/plugin/rewrite/reverter.go +++ b/plugin/rewrite/reverter.go @@ -1,27 +1,61 @@ package rewrite -import "github.com/miekg/dns" +import ( + "github.com/miekg/dns" + "regexp" + "strconv" + "strings" +) + +// ResponseRule contains a rule to rewrite a response with. +type ResponseRule struct { + Active bool + Pattern *regexp.Regexp + Replacement string +} // ResponseReverter reverses the operations done on the question section of a packet. // This is need because the client will otherwise disregards the response, i.e. // dig will complain with ';; Question section mismatch: got miek.nl/HINFO/IN' type ResponseReverter struct { dns.ResponseWriter - original dns.Question + originalQuestion dns.Question + ResponseRewrite bool + ResponseRules []ResponseRule } // NewResponseReverter returns a pointer to a new ResponseReverter. func NewResponseReverter(w dns.ResponseWriter, r *dns.Msg) *ResponseReverter { return &ResponseReverter{ - ResponseWriter: w, - original: r.Question[0], + ResponseWriter: w, + originalQuestion: r.Question[0], } } // WriteMsg records the status code and calls the // underlying ResponseWriter's WriteMsg method. func (r *ResponseReverter) WriteMsg(res *dns.Msg) error { - res.Question[0] = r.original + res.Question[0] = r.originalQuestion + if r.ResponseRewrite { + for _, rr := range res.Answer { + name := rr.(*dns.A).Hdr.Name + for _, rule := range r.ResponseRules { + regexGroups := rule.Pattern.FindStringSubmatch(name) + if len(regexGroups) == 0 { + continue + } + s := rule.Replacement + for groupIndex, groupValue := range regexGroups { + groupIndexStr := "{" + strconv.Itoa(groupIndex) + "}" + if strings.Contains(s, groupIndexStr) { + s = strings.Replace(s, groupIndexStr, groupValue, -1) + } + } + name = s + } + rr.(*dns.A).Hdr.Name = name + } + } return r.ResponseWriter.WriteMsg(res) } diff --git a/plugin/rewrite/rewrite.go b/plugin/rewrite/rewrite.go index 4e31cb7d5..bd715ad4f 100644 --- a/plugin/rewrite/rewrite.go +++ b/plugin/rewrite/rewrite.go @@ -45,6 +45,11 @@ func (rw Rewrite) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg for _, rule := range rw.Rules { switch result := rule.Rewrite(w, r); result { case RewriteDone: + respRule := rule.GetResponseRule() + if respRule.Active == true { + 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) @@ -70,8 +75,10 @@ func (rw Rewrite) Name() string { return "rewrite" } type Rule interface { // Rewrite rewrites the current request. Rewrite(dns.ResponseWriter, *dns.Msg) Result - // Mode returns the processing mode stop or continue + // Mode returns the processing mode stop or continue. Mode() string + // GetResponseRule returns the rule to rewrite response with, if any. + GetResponseRule() ResponseRule } func newRule(args ...string) (Rule, error) { diff --git a/plugin/rewrite/rewrite_test.go b/plugin/rewrite/rewrite_test.go index e2770da0e..0119b8602 100644 --- a/plugin/rewrite/rewrite_test.go +++ b/plugin/rewrite/rewrite_test.go @@ -36,6 +36,13 @@ func TestNewRule(t *testing.T) { {[]string{"name", "substring", "a.com", "b.com"}, false, reflect.TypeOf(&substringNameRule{})}, {[]string{"name", "regex", "([a])\\.com", "new-{1}.com"}, false, reflect.TypeOf(®exNameRule{})}, {[]string{"name", "regex", "([a]\\.com", "new-{1}.com"}, true, nil}, + {[]string{"name", "regex", "(dns)\\.(core)\\.(rocks)", "{2}.{1}.{3}", "answer", "name", "(core)\\.(dns)\\.(rocks)", "{2}.{1}.{3}"}, false, reflect.TypeOf(®exNameRule{})}, + {[]string{"name", "regex", "(adns)\\.(core)\\.(rocks)", "{2}.{1}.{3}", "answer", "name", "(core)\\.(adns)\\.(rocks)", "{2}.{1}.{3}", "too.long", "way.too.long"}, true, nil}, + {[]string{"name", "regex", "(bdns)\\.(core)\\.(rocks)", "{2}.{1}.{3}", "NoAnswer", "name", "(core)\\.(bdns)\\.(rocks)", "{2}.{1}.{3}"}, true, nil}, + {[]string{"name", "regex", "(cdns)\\.(core)\\.(rocks)", "{2}.{1}.{3}", "answer", "ttl", "(core)\\.(cdns)\\.(rocks)", "{2}.{1}.{3}"}, true, nil}, + {[]string{"name", "regex", "(ddns)\\.(core)\\.(rocks)", "{2}.{1}.{3}", "answer", "name", "\xecore\\.(ddns)\\.(rocks)", "{2}.{1}.{3}"}, true, nil}, + {[]string{"name", "regex", "\xedns\\.(core)\\.(rocks)", "{2}.{1}.{3}", "answer", "name", "(core)\\.(edns)\\.(rocks)", "{2}.{1}.{3}"}, true, nil}, + {[]string{"name", "substring", "fcore.dns.rocks", "dns.fcore.rocks", "answer", "name", "(fcore)\\.(dns)\\.(rocks)", "{2}.{1}.{3}"}, true, nil}, {[]string{"name", "substring", "a.com", "b.com", "c.com"}, true, nil}, {[]string{"type"}, true, nil}, {[]string{"type", "a"}, true, nil}, @@ -152,6 +159,8 @@ func TestRewrite(t *testing.T) { rules := []Rule{} r, _ := newNameRule("stop", "from.nl.", "to.nl.") rules = append(rules, r) + r, _ = newNameRule("stop", "regex", "(core)\\.(dns)\\.(rocks)\\.(nl)", "{2}.{1}.{3}.{4}", "answer", "name", "(dns)\\.(core)\\.(rocks)\\.(nl)", "{2}.{1}.{3}.{4}") + rules = append(rules, r) r, _ = newNameRule("stop", "exact", "from.exact.nl.", "to.nl.") rules = append(rules, r) r, _ = newNameRule("stop", "prefix", "prefix", "to") @@ -203,6 +212,7 @@ func TestRewrite(t *testing.T) { {"a.nl.", dns.TypeANY, dns.ClassCHAOS, "a.nl.", dns.TypeANY, dns.ClassINET}, // class gets rewritten twice because of continue/stop logic: HS to CH, CH to IN {"a.nl.", dns.TypeANY, 4, "a.nl.", dns.TypeANY, dns.ClassINET}, + {"core.dns.rocks.nl.", dns.TypeA, dns.ClassINET, "dns.core.rocks.nl.", dns.TypeA, dns.ClassINET}, } ctx := context.TODO() @@ -224,6 +234,13 @@ func TestRewrite(t *testing.T) { if resp.Question[0].Qclass != tc.toC { t.Errorf("Test %d: Expected Class to be '%d' but was '%d'", i, tc.toC, resp.Question[0].Qclass) } + if tc.fromT == dns.TypeA && tc.toT == dns.TypeA { + if len(resp.Answer) > 0 { + if resp.Answer[0].(*dns.A).Hdr.Name != tc.to { + t.Errorf("Test %d: Expected Answer Name to be %q but was %q", i, tc.to, resp.Answer[0].(*dns.A).Hdr.Name) + } + } + } } } diff --git a/plugin/rewrite/setup.go b/plugin/rewrite/setup.go index 5954a3300..c5d76feec 100644 --- a/plugin/rewrite/setup.go +++ b/plugin/rewrite/setup.go @@ -3,7 +3,6 @@ package rewrite import ( "github.com/coredns/coredns/core/dnsserver" "github.com/coredns/coredns/plugin" - "github.com/mholt/caddy" ) @@ -32,6 +31,12 @@ func rewriteParse(c *caddy.Controller) ([]Rule, error) { for c.Next() { args := c.RemainingArgs() + if len(args) < 2 { + // Handles rules out of nested instructions, i.e. the ones enclosed in curly brackets + for c.NextBlock() { + args = append(args, c.Val()) + } + } rule, err := newRule(args...) if err != nil { return nil, err diff --git a/plugin/rewrite/type.go b/plugin/rewrite/type.go index 22a545675..ec36b0b0a 100644 --- a/plugin/rewrite/type.go +++ b/plugin/rewrite/type.go @@ -42,3 +42,8 @@ func (rule *typeRule) Rewrite(w dns.ResponseWriter, r *dns.Msg) Result { 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{} +} |