mirror of
https://github.com/coredns/coredns.git
synced 2025-11-01 02:33:14 -04:00
[rewrite] Introduce cname target rewrite rule to rewrite plugin (#6004)
* cname target rewrite part in answer sec tion Signed-off-by: amila <amila.15@cse.mrt.ac.lk> * upstream request Signed-off-by: amila <amila.15@cse.mrt.ac.lk> * fix looping issue Signed-off-by: amila <amila.15@cse.mrt.ac.lk> * support exact, prefix, suffix, substring, and regex types for cname rewrite Signed-off-by: amila <amila.15@cse.mrt.ac.lk> * support any qtype, corrected prefix, suffix, substring types behavior Signed-off-by: amila <amila.15@cse.mrt.ac.lk> * unit tests added, mocked the upstream call Signed-off-by: amila <amila.15@cse.mrt.ac.lk> * fix lint errors Signed-off-by: amila <amila.15@cse.mrt.ac.lk> * add newline to fix test issue Signed-off-by: amila <amila.15@cse.mrt.ac.lk> * add default rewrite type, add readme Signed-off-by: amila <amila.15@cse.mrt.ac.lk> * readme grammar fix Signed-off-by: amila <amila.15@cse.mrt.ac.lk> * reuse rewrite types Signed-off-by: amila <amila.15@cse.mrt.ac.lk> * comment fixed Signed-off-by: amila <amila.15@cse.mrt.ac.lk> --------- Signed-off-by: amila <amila.15@cse.mrt.ac.lk>
This commit is contained in:
163
plugin/rewrite/cname_target_test.go
Normal file
163
plugin/rewrite/cname_target_test.go
Normal file
@@ -0,0 +1,163 @@
|
||||
package rewrite
|
||||
|
||||
import (
|
||||
"context"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/coredns/coredns/plugin"
|
||||
"github.com/coredns/coredns/plugin/pkg/dnstest"
|
||||
"github.com/coredns/coredns/plugin/test"
|
||||
"github.com/coredns/coredns/request"
|
||||
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
|
||||
type MockedUpstream struct{}
|
||||
|
||||
func (u *MockedUpstream) Lookup(ctx context.Context, state request.Request, name string, typ uint16) (*dns.Msg, error) {
|
||||
m := new(dns.Msg)
|
||||
m.SetReply(state.Req)
|
||||
m.Authoritative = true
|
||||
switch state.Req.Question[0].Name {
|
||||
case "xyz.example.com.":
|
||||
m.Answer = []dns.RR{
|
||||
test.A("xyz.example.com. 3600 IN A 3.4.5.6"),
|
||||
}
|
||||
return m, nil
|
||||
case "bard.google.com.cdn.cloudflare.net.":
|
||||
m.Answer = []dns.RR{
|
||||
test.A("bard.google.com.cdn.cloudflare.net. 1800 IN A 9.7.2.1"),
|
||||
}
|
||||
return m, nil
|
||||
case "www.hosting.xyz.":
|
||||
m.Answer = []dns.RR{
|
||||
test.A("www.hosting.xyz. 500 IN A 20.30.40.50"),
|
||||
}
|
||||
return m, nil
|
||||
case "abcd.zzzz.www.pqrst.":
|
||||
m.Answer = []dns.RR{
|
||||
test.A("abcd.zzzz.www.pqrst. 120 IN A 101.20.5.1"),
|
||||
test.A("abcd.zzzz.www.pqrst. 120 IN A 101.20.5.2"),
|
||||
}
|
||||
return m, nil
|
||||
case "orders.webapp.eu.org.":
|
||||
m.Answer = []dns.RR{
|
||||
test.A("orders.webapp.eu.org. 120 IN A 20.0.0.9"),
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
return &dns.Msg{}, nil
|
||||
}
|
||||
|
||||
func TestCNameTargetRewrite(t *testing.T) {
|
||||
rules := []Rule{}
|
||||
ruleset := []struct {
|
||||
args []string
|
||||
expectedType reflect.Type
|
||||
}{
|
||||
{[]string{"continue", "cname", "exact", "def.example.com.", "xyz.example.com."}, reflect.TypeOf(&cnameTargetRule{})},
|
||||
{[]string{"continue", "cname", "prefix", "chat.openai.com", "bard.google.com"}, reflect.TypeOf(&cnameTargetRule{})},
|
||||
{[]string{"continue", "cname", "suffix", "uvw.", "xyz."}, reflect.TypeOf(&cnameTargetRule{})},
|
||||
{[]string{"continue", "cname", "substring", "efgh", "zzzz.www"}, reflect.TypeOf(&cnameTargetRule{})},
|
||||
{[]string{"continue", "cname", "regex", `(.*)\.web\.(.*)\.site\.`, `{1}.webapp.{2}.org.`}, reflect.TypeOf(&cnameTargetRule{})},
|
||||
}
|
||||
for i, r := range ruleset {
|
||||
rule, err := newRule(r.args...)
|
||||
if err != nil {
|
||||
t.Fatalf("Rule %d: FAIL, %s: %s", i, r.args, err)
|
||||
}
|
||||
if reflect.TypeOf(rule) != r.expectedType {
|
||||
t.Fatalf("Rule %d: FAIL, %s: rule type mismatch, expected %q, but got %q", i, r.args, r.expectedType, rule)
|
||||
}
|
||||
cnameTargetRule := rule.(*cnameTargetRule)
|
||||
cnameTargetRule.Upstream = &MockedUpstream{}
|
||||
rules = append(rules, rule)
|
||||
}
|
||||
doTestCNameTargetTests(rules, t)
|
||||
}
|
||||
|
||||
func doTestCNameTargetTests(rules []Rule, t *testing.T) {
|
||||
tests := []struct {
|
||||
from string
|
||||
fromType uint16
|
||||
answer []dns.RR
|
||||
expectedAnswer []dns.RR
|
||||
}{
|
||||
{"abc.example.com", dns.TypeA,
|
||||
[]dns.RR{
|
||||
test.CNAME("abc.example.com. 5 IN CNAME def.example.com."),
|
||||
test.A("def.example.com. 5 IN A 1.2.3.4"),
|
||||
},
|
||||
[]dns.RR{
|
||||
test.CNAME("abc.example.com. 5 IN CNAME xyz.example.com."),
|
||||
test.A("xyz.example.com. 3600 IN A 3.4.5.6"),
|
||||
},
|
||||
},
|
||||
{"chat.openai.com", dns.TypeA,
|
||||
[]dns.RR{
|
||||
test.CNAME("chat.openai.com. 20 IN CNAME chat.openai.com.cdn.cloudflare.net."),
|
||||
test.A("chat.openai.com.cdn.cloudflare.net. 30 IN A 23.2.1.2"),
|
||||
test.A("chat.openai.com.cdn.cloudflare.net. 30 IN A 24.6.0.8"),
|
||||
},
|
||||
[]dns.RR{
|
||||
test.CNAME("chat.openai.com. 20 IN CNAME bard.google.com.cdn.cloudflare.net."),
|
||||
test.A("bard.google.com.cdn.cloudflare.net. 1800 IN A 9.7.2.1"),
|
||||
},
|
||||
},
|
||||
{"coredns.io", dns.TypeA,
|
||||
[]dns.RR{
|
||||
test.CNAME("coredns.io. 100 IN CNAME www.hosting.uvw."),
|
||||
test.A("www.hosting.uvw. 200 IN A 7.2.3.4"),
|
||||
},
|
||||
[]dns.RR{
|
||||
test.CNAME("coredns.io. 100 IN CNAME www.hosting.xyz."),
|
||||
test.A("www.hosting.xyz. 500 IN A 20.30.40.50"),
|
||||
},
|
||||
},
|
||||
{"core.dns.rocks", dns.TypeA,
|
||||
[]dns.RR{
|
||||
test.CNAME("core.dns.rocks. 200 IN CNAME abcd.efgh.pqrst."),
|
||||
test.A("abcd.efgh.pqrst. 100 IN A 200.30.45.67"),
|
||||
},
|
||||
[]dns.RR{
|
||||
test.CNAME("core.dns.rocks. 200 IN CNAME abcd.zzzz.www.pqrst."),
|
||||
test.A("abcd.zzzz.www.pqrst. 120 IN A 101.20.5.1"),
|
||||
test.A("abcd.zzzz.www.pqrst. 120 IN A 101.20.5.2"),
|
||||
},
|
||||
},
|
||||
{"order.service.eu", dns.TypeA,
|
||||
[]dns.RR{
|
||||
test.CNAME("order.service.eu. 200 IN CNAME orders.web.eu.site."),
|
||||
test.A("orders.web.eu.site. 50 IN A 10.10.15.1"),
|
||||
},
|
||||
[]dns.RR{
|
||||
test.CNAME("order.service.eu. 200 IN CNAME orders.webapp.eu.org."),
|
||||
test.A("orders.webapp.eu.org. 120 IN A 20.0.0.9"),
|
||||
},
|
||||
},
|
||||
}
|
||||
ctx := context.TODO()
|
||||
for i, tc := range tests {
|
||||
m := new(dns.Msg)
|
||||
m.SetQuestion(tc.from, tc.fromType)
|
||||
m.Question[0].Qclass = dns.ClassINET
|
||||
m.Answer = tc.answer
|
||||
rw := Rewrite{
|
||||
Next: plugin.HandlerFunc(msgPrinter),
|
||||
Rules: rules,
|
||||
}
|
||||
rec := dnstest.NewRecorder(&test.ResponseWriter{})
|
||||
rw.ServeDNS(ctx, rec, m)
|
||||
resp := rec.Msg
|
||||
if len(resp.Answer) == 0 {
|
||||
t.Errorf("Test %d: FAIL %s (%d) Expected valid response but received %q", i, tc.from, tc.fromType, resp)
|
||||
continue
|
||||
}
|
||||
if !reflect.DeepEqual(resp.Answer, tc.expectedAnswer) {
|
||||
t.Errorf("Test %d: FAIL %s (%d) Actual are expected answer does not match, actual: %v, expected: %v",
|
||||
i, tc.from, tc.fromType, resp.Answer, tc.expectedAnswer)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user