* fix concurrent issue with cname rewrite plugin Signed-off-by: amila <amila.15@cse.mrt.ac.lk> * add nil check before deref, add AAAA type test case Signed-off-by: amila <amila.15@cse.mrt.ac.lk> --------- Signed-off-by: amila <amila.15@cse.mrt.ac.lk>
180 lines
5.7 KiB
Go
180 lines
5.7 KiB
Go
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.":
|
|
switch state.Req.Question[0].Qtype {
|
|
case dns.TypeA:
|
|
m.Answer = []dns.RR{
|
|
test.A("xyz.example.com. 3600 IN A 3.4.5.6"),
|
|
}
|
|
case dns.TypeAAAA:
|
|
m.Answer = []dns.RR{
|
|
test.AAAA("xyz.example.com. 3600 IN AAAA 3a01:7e00::f03c:91ff:fe79:234c"),
|
|
}
|
|
}
|
|
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"),
|
|
},
|
|
},
|
|
{"abc.example.com", dns.TypeAAAA,
|
|
[]dns.RR{
|
|
test.CNAME("abc.example.com. 5 IN CNAME def.example.com."),
|
|
test.AAAA("def.example.com. 5 IN AAAA 2a01:7e00::f03c:91ff:fe79:234c"),
|
|
},
|
|
[]dns.RR{
|
|
test.CNAME("abc.example.com. 5 IN CNAME xyz.example.com."),
|
|
test.AAAA("xyz.example.com. 3600 IN AAAA 3a01:7e00::f03c:91ff:fe79:234c"),
|
|
},
|
|
},
|
|
{"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
|
|
}
|
|
}
|
|
}
|