aboutsummaryrefslogtreecommitdiff
path: root/plugin/dns64/dns64_test.go
diff options
context:
space:
mode:
Diffstat (limited to 'plugin/dns64/dns64_test.go')
-rw-r--r--plugin/dns64/dns64_test.go450
1 files changed, 450 insertions, 0 deletions
diff --git a/plugin/dns64/dns64_test.go b/plugin/dns64/dns64_test.go
new file mode 100644
index 000000000..fe8b77ec6
--- /dev/null
+++ b/plugin/dns64/dns64_test.go
@@ -0,0 +1,450 @@
+package dns64
+
+import (
+ "context"
+ "fmt"
+ "net"
+ "reflect"
+ "testing"
+
+ "github.com/coredns/coredns/plugin/pkg/dnstest"
+ "github.com/coredns/coredns/plugin/test"
+ "github.com/coredns/coredns/request"
+
+ "github.com/miekg/dns"
+)
+
+func To6(prefix, address string) (net.IP, error) {
+ _, pref, _ := net.ParseCIDR(prefix)
+ addr := net.ParseIP(address)
+
+ return to6(pref, addr)
+}
+
+func TestTo6(t *testing.T) {
+
+ v6, err := To6("64:ff9b::/96", "64.64.64.64")
+ if err != nil {
+ t.Error(err)
+ }
+ if v6.String() != "64:ff9b::4040:4040" {
+ t.Errorf("%d", v6)
+ }
+
+ v6, err = To6("64:ff9b::/64", "64.64.64.64")
+ if err != nil {
+ t.Error(err)
+ }
+ if v6.String() != "64:ff9b::40:4040:4000:0" {
+ t.Errorf("%d", v6)
+ }
+
+ v6, err = To6("64:ff9b::/56", "64.64.64.64")
+ if err != nil {
+ t.Error(err)
+ }
+ if v6.String() != "64:ff9b:0:40:40:4040::" {
+ t.Errorf("%d", v6)
+ }
+
+ v6, err = To6("64::/32", "64.64.64.64")
+ if err != nil {
+ t.Error(err)
+ }
+ if v6.String() != "64:0:4040:4040::" {
+ t.Errorf("%d", v6)
+ }
+}
+
+func TestResponseShould(t *testing.T) {
+ var tests = []struct {
+ resp dns.Msg
+ translateAll bool
+ expected bool
+ }{
+ // If there's an AAAA record, then no
+ {
+ resp: dns.Msg{
+ MsgHdr: dns.MsgHdr{
+ Rcode: dns.RcodeSuccess,
+ },
+ Answer: []dns.RR{
+ test.AAAA("example.com. IN AAAA ::1"),
+ },
+ },
+ expected: false,
+ },
+ // If there's no AAAA, then true
+ {
+ resp: dns.Msg{
+ MsgHdr: dns.MsgHdr{
+ Rcode: dns.RcodeSuccess,
+ },
+ Ns: []dns.RR{
+ test.SOA("example.com. IN SOA foo bar 1 1 1 1 1"),
+ },
+ },
+ expected: true,
+ },
+ // Failure, except NameError, should be true
+ {
+ resp: dns.Msg{
+ MsgHdr: dns.MsgHdr{
+ Rcode: dns.RcodeNotImplemented,
+ },
+ Ns: []dns.RR{
+ test.SOA("example.com. IN SOA foo bar 1 1 1 1 1"),
+ },
+ },
+ expected: true,
+ },
+ // NameError should be false
+ {
+ resp: dns.Msg{
+ MsgHdr: dns.MsgHdr{
+ Rcode: dns.RcodeNameError,
+ },
+ Ns: []dns.RR{
+ test.SOA("example.com. IN SOA foo bar 1 1 1 1 1"),
+ },
+ },
+ expected: false,
+ },
+ // If there's an AAAA record, but translate_all is configured, then yes
+ {
+ resp: dns.Msg{
+ MsgHdr: dns.MsgHdr{
+ Rcode: dns.RcodeSuccess,
+ },
+ Answer: []dns.RR{
+ test.AAAA("example.com. IN AAAA ::1"),
+ },
+ },
+ translateAll: true,
+ expected: true,
+ },
+ }
+
+ d := DNS64{}
+
+ for idx, tc := range tests {
+ t.Run(fmt.Sprintf("%d", idx), func(t *testing.T) {
+ d.TranslateAll = tc.translateAll
+ actual := d.responseShouldDNS64(&tc.resp)
+ if actual != tc.expected {
+ t.Fatalf("Expected %v got %v", tc.expected, actual)
+ }
+ })
+ }
+}
+
+func TestDNS64(t *testing.T) {
+ var cases = []struct {
+ // a brief summary of the test case
+ name string
+
+ // the request
+ req *dns.Msg
+
+ // the initial response from the "downstream" server
+ initResp *dns.Msg
+
+ // A response to provide
+ aResp *dns.Msg
+
+ // the expected ultimate result
+ resp *dns.Msg
+ }{
+ {
+ // no AAAA record, yes A record. Do DNS64
+ name: "standard flow",
+ req: &dns.Msg{
+ MsgHdr: dns.MsgHdr{
+ Id: 42,
+ RecursionDesired: true,
+ Opcode: dns.OpcodeQuery,
+ },
+ Question: []dns.Question{dns.Question{"example.com.", dns.TypeAAAA, dns.ClassINET}},
+ },
+ initResp: &dns.Msg{ //success, no answers
+ MsgHdr: dns.MsgHdr{
+ Id: 42,
+ Opcode: dns.OpcodeQuery,
+ RecursionDesired: true,
+ Rcode: dns.RcodeSuccess,
+ Response: true,
+ },
+ Question: []dns.Question{dns.Question{"example.com.", dns.TypeAAAA, dns.ClassINET}},
+ Ns: []dns.RR{test.SOA("example.com. 70 IN SOA foo bar 1 1 1 1 1")},
+ },
+ aResp: &dns.Msg{
+ MsgHdr: dns.MsgHdr{
+ Id: 43,
+ Opcode: dns.OpcodeQuery,
+ RecursionDesired: true,
+ Rcode: dns.RcodeSuccess,
+ Response: true,
+ },
+ Question: []dns.Question{dns.Question{"example.com.", dns.TypeA, dns.ClassINET}},
+ Answer: []dns.RR{
+ test.A("example.com. 60 IN A 192.0.2.42"),
+ test.A("example.com. 5000 IN A 192.0.2.43"),
+ },
+ },
+
+ resp: &dns.Msg{
+ MsgHdr: dns.MsgHdr{
+ Id: 42,
+ Opcode: dns.OpcodeQuery,
+ RecursionDesired: true,
+ Rcode: dns.RcodeSuccess,
+ Response: true,
+ },
+ Question: []dns.Question{dns.Question{"example.com.", dns.TypeAAAA, dns.ClassINET}},
+ Answer: []dns.RR{
+ test.AAAA("example.com. 60 IN AAAA 64:ff9b::192.0.2.42"),
+ // override RR ttl to SOA ttl, since it's lower
+ test.AAAA("example.com. 70 IN AAAA 64:ff9b::192.0.2.43"),
+ },
+ },
+ },
+ {
+ // name exists, but has neither A nor AAAA record
+ name: "a empty",
+ req: &dns.Msg{
+ MsgHdr: dns.MsgHdr{
+ Id: 42,
+ RecursionDesired: true,
+ Opcode: dns.OpcodeQuery,
+ },
+ Question: []dns.Question{dns.Question{"example.com.", dns.TypeAAAA, dns.ClassINET}},
+ },
+ initResp: &dns.Msg{ //success, no answers
+ MsgHdr: dns.MsgHdr{
+ Id: 42,
+ Opcode: dns.OpcodeQuery,
+ RecursionDesired: true,
+ Rcode: dns.RcodeSuccess,
+ Response: true,
+ },
+ Question: []dns.Question{dns.Question{"example.com.", dns.TypeAAAA, dns.ClassINET}},
+ Ns: []dns.RR{test.SOA("example.com. 3600 IN SOA foo bar 1 7200 900 1209600 86400")},
+ },
+ aResp: &dns.Msg{
+ MsgHdr: dns.MsgHdr{
+ Id: 43,
+ Opcode: dns.OpcodeQuery,
+ RecursionDesired: true,
+ Rcode: dns.RcodeSuccess,
+ Response: true,
+ },
+ Question: []dns.Question{dns.Question{"example.com.", dns.TypeA, dns.ClassINET}},
+ Ns: []dns.RR{test.SOA("example.com. 3600 IN SOA foo bar 1 7200 900 1209600 86400")},
+ },
+
+ resp: &dns.Msg{
+ MsgHdr: dns.MsgHdr{
+ Id: 42,
+ Opcode: dns.OpcodeQuery,
+ RecursionDesired: true,
+ Rcode: dns.RcodeSuccess,
+ Response: true,
+ },
+ Question: []dns.Question{dns.Question{"example.com.", dns.TypeAAAA, dns.ClassINET}},
+ Ns: []dns.RR{test.SOA("example.com. 3600 IN SOA foo bar 1 7200 900 1209600 86400")},
+ Answer: []dns.RR{}, // just to make comparison happy
+ },
+ },
+ {
+ // Query error other than NameError
+ name: "non-nxdomain error",
+ req: &dns.Msg{
+ MsgHdr: dns.MsgHdr{
+ Id: 42,
+ RecursionDesired: true,
+ Opcode: dns.OpcodeQuery,
+ },
+ Question: []dns.Question{dns.Question{"example.com.", dns.TypeAAAA, dns.ClassINET}},
+ },
+ initResp: &dns.Msg{ // failure
+ MsgHdr: dns.MsgHdr{
+ Id: 42,
+ Opcode: dns.OpcodeQuery,
+ RecursionDesired: true,
+ Rcode: dns.RcodeRefused,
+ Response: true,
+ },
+ Question: []dns.Question{dns.Question{"example.com.", dns.TypeAAAA, dns.ClassINET}},
+ },
+ aResp: &dns.Msg{
+ MsgHdr: dns.MsgHdr{
+ Id: 43,
+ Opcode: dns.OpcodeQuery,
+ RecursionDesired: true,
+ Rcode: dns.RcodeSuccess,
+ Response: true,
+ },
+ Question: []dns.Question{dns.Question{"example.com.", dns.TypeA, dns.ClassINET}},
+ Answer: []dns.RR{
+ test.A("example.com. 60 IN A 192.0.2.42"),
+ test.A("example.com. 5000 IN A 192.0.2.43"),
+ },
+ },
+
+ resp: &dns.Msg{
+ MsgHdr: dns.MsgHdr{
+ Id: 42,
+ Opcode: dns.OpcodeQuery,
+ RecursionDesired: true,
+ Rcode: dns.RcodeSuccess,
+ Response: true,
+ },
+ Question: []dns.Question{dns.Question{"example.com.", dns.TypeAAAA, dns.ClassINET}},
+ Answer: []dns.RR{
+ test.AAAA("example.com. 60 IN AAAA 64:ff9b::192.0.2.42"),
+ test.AAAA("example.com. 600 IN AAAA 64:ff9b::192.0.2.43"),
+ },
+ },
+ },
+ {
+ // nxdomain (NameError): don't even try an A request.
+ name: "nxdomain",
+ req: &dns.Msg{
+ MsgHdr: dns.MsgHdr{
+ Id: 42,
+ RecursionDesired: true,
+ Opcode: dns.OpcodeQuery,
+ },
+ Question: []dns.Question{dns.Question{"example.com.", dns.TypeAAAA, dns.ClassINET}},
+ },
+ initResp: &dns.Msg{ // failure
+ MsgHdr: dns.MsgHdr{
+ Id: 42,
+ Opcode: dns.OpcodeQuery,
+ RecursionDesired: true,
+ Rcode: dns.RcodeNameError,
+ Response: true,
+ },
+ Question: []dns.Question{dns.Question{"example.com.", dns.TypeAAAA, dns.ClassINET}},
+ Ns: []dns.RR{test.SOA("example.com. 3600 IN SOA foo bar 1 7200 900 1209600 86400")},
+ },
+ resp: &dns.Msg{
+ MsgHdr: dns.MsgHdr{
+ Id: 42,
+ Opcode: dns.OpcodeQuery,
+ RecursionDesired: true,
+ Rcode: dns.RcodeNameError,
+ Response: true,
+ },
+ Question: []dns.Question{dns.Question{"example.com.", dns.TypeAAAA, dns.ClassINET}},
+ Ns: []dns.RR{test.SOA("example.com. 3600 IN SOA foo bar 1 7200 900 1209600 86400")},
+ },
+ },
+ {
+ // AAAA record exists
+ name: "AAAA record",
+ req: &dns.Msg{
+ MsgHdr: dns.MsgHdr{
+ Id: 42,
+ RecursionDesired: true,
+ Opcode: dns.OpcodeQuery,
+ },
+ Question: []dns.Question{dns.Question{"example.com.", dns.TypeAAAA, dns.ClassINET}},
+ },
+
+ initResp: &dns.Msg{
+ MsgHdr: dns.MsgHdr{
+ Id: 42,
+ Opcode: dns.OpcodeQuery,
+ RecursionDesired: true,
+ Rcode: dns.RcodeSuccess,
+ Response: true,
+ },
+ Question: []dns.Question{dns.Question{"example.com.", dns.TypeAAAA, dns.ClassINET}},
+ Answer: []dns.RR{
+ test.AAAA("example.com. 60 IN AAAA ::1"),
+ test.AAAA("example.com. 5000 IN AAAA ::2"),
+ },
+ },
+
+ resp: &dns.Msg{
+ MsgHdr: dns.MsgHdr{
+ Id: 42,
+ Opcode: dns.OpcodeQuery,
+ RecursionDesired: true,
+ Rcode: dns.RcodeSuccess,
+ Response: true,
+ },
+ Question: []dns.Question{dns.Question{"example.com.", dns.TypeAAAA, dns.ClassINET}},
+ Answer: []dns.RR{
+ test.AAAA("example.com. 60 IN AAAA ::1"),
+ test.AAAA("example.com. 5000 IN AAAA ::2"),
+ },
+ },
+ },
+ }
+
+ _, pfx, _ := net.ParseCIDR("64:ff9b::/96")
+
+ for idx, tc := range cases {
+ t.Run(fmt.Sprintf("%d_%s", idx, tc.name), func(t *testing.T) {
+ d := DNS64{
+ Next: &fakeHandler{t, tc.initResp},
+ Prefix: pfx,
+ Upstream: &fakeUpstream{t, tc.req.Question[0].Name, tc.aResp},
+ }
+
+ rec := dnstest.NewRecorder(&test.ResponseWriter{RemoteIP: "::1"})
+ rc, err := d.ServeDNS(context.Background(), rec, tc.req)
+ if err != nil {
+ t.Fatal(err)
+ }
+ actual := rec.Msg
+ if actual.Rcode != rc {
+ t.Fatalf("ServeDNS should return real result code %q != %q", actual.Rcode, rc)
+ }
+
+ if !reflect.DeepEqual(actual, tc.resp) {
+ t.Fatalf("Final answer should match expected %q != %q", actual, tc.resp)
+ }
+ })
+ }
+}
+
+type fakeHandler struct {
+ t *testing.T
+ reply *dns.Msg
+}
+
+func (fh *fakeHandler) ServeDNS(_ context.Context, w dns.ResponseWriter, _ *dns.Msg) (int, error) {
+ if fh.reply == nil {
+ panic("fakeHandler ServeDNS with nil reply")
+ }
+ w.WriteMsg(fh.reply)
+
+ return fh.reply.Rcode, nil
+}
+func (fh *fakeHandler) Name() string {
+ return "fake"
+}
+
+type fakeUpstream struct {
+ t *testing.T
+ qname string
+ resp *dns.Msg
+}
+
+func (fu *fakeUpstream) Lookup(_ context.Context, _ request.Request, name string, typ uint16) (*dns.Msg, error) {
+ if fu.qname == "" {
+ fu.t.Fatalf("Unexpected A lookup for %s", name)
+ }
+ if name != fu.qname {
+ fu.t.Fatalf("Wrong A lookup for %s, expected %s", name, fu.qname)
+ }
+
+ if typ != dns.TypeA {
+ fu.t.Fatalf("Wrong lookup type %d, expected %d", typ, dns.TypeA)
+ }
+
+ return fu.resp, nil
+}