]>
Commit | Line | Data |
---|---|---|
ef3ee606 RG |
1 | import dns |
2 | import os | |
3 | ||
4 | from recursortests import RecursorTest | |
5 | ||
6 | class DNS64RecursorTest(RecursorTest): | |
7 | ||
8 | _confdir = 'DNS64' | |
9 | _config_template = """ | |
10 | auth-zones=example.dns64=configs/%s/example.dns64.zone | |
11 | auth-zones+=in-addr.arpa=configs/%s/in-addr.arpa.zone | |
12 | auth-zones+=ip6.arpa=configs/%s/ip6.arpa.zone | |
13 | ||
14 | dns64-prefix=64:ff9b::/96 | |
15 | """ % (_confdir, _confdir, _confdir) | |
16 | ||
503c2e3f OM |
17 | _lua_dns_script_file = """ |
18 | function nodata(dq) | |
19 | if dq.qtype == pdns.AAAA and dq.qname:equal("formerr.example.dns64") then | |
20 | dq.rcode = pdns.FORMERR | |
21 | return true | |
22 | end | |
23 | return false | |
24 | end | |
25 | """ | |
26 | ||
ef3ee606 RG |
27 | @classmethod |
28 | def generateRecursorConfig(cls, confdir): | |
29 | authzonepath = os.path.join(confdir, 'example.dns64.zone') | |
30 | with open(authzonepath, 'w') as authzone: | |
31 | authzone.write("""$ORIGIN example.dns64 | |
32 | @ 3600 IN SOA {soa} | |
33 | www 3600 IN A 192.0.2.42 | |
34 | www 3600 IN TXT "does exist" | |
35 | aaaa 3600 IN AAAA 2001:db8::1 | |
c2226112 RG |
36 | cname 3600 IN CNAME cname2.example.dns64. |
37 | cname2 3600 IN CNAME www.example.dns64. | |
503c2e3f | 38 | formerr 3600 IN A 192.0.2.43 |
ef3ee606 RG |
39 | """.format(soa=cls._SOA)) |
40 | ||
41 | authzonepath = os.path.join(confdir, 'in-addr.arpa.zone') | |
42 | with open(authzonepath, 'w') as authzone: | |
43 | authzone.write("""$ORIGIN in-addr.arpa | |
44 | @ 3600 IN SOA {soa} | |
45 | 42.2.0.192 IN PTR www.example.dns64. | |
46 | """.format(soa=cls._SOA)) | |
47 | ||
48 | authzonepath = os.path.join(confdir, 'ip6.arpa.zone') | |
49 | with open(authzonepath, 'w') as authzone: | |
50 | authzone.write("""$ORIGIN ip6.arpa | |
51 | @ 3600 IN SOA {soa} | |
52 | 1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2 IN PTR aaaa.example.dns64. | |
53 | """.format(soa=cls._SOA)) | |
54 | ||
55 | super(DNS64RecursorTest, cls).generateRecursorConfig(confdir) | |
56 | ||
57 | # this type (A) exists for this name | |
58 | def testExistingA(self): | |
59 | qname = 'www.example.dns64.' | |
60 | expected = dns.rrset.from_text(qname, 0, dns.rdataclass.IN, 'A', '192.0.2.42') | |
61 | ||
62 | query = dns.message.make_query(qname, 'A', want_dnssec=True) | |
63 | for method in ("sendUDPQuery", "sendTCPQuery"): | |
64 | sender = getattr(self, method) | |
65 | res = sender(query) | |
66 | self.assertRcodeEqual(res, dns.rcode.NOERROR) | |
67 | self.assertRRsetInAnswer(res, expected) | |
68 | ||
69 | # there is no A record, we should get a NODATA | |
70 | def testNonExistingA(self): | |
71 | qname = 'aaaa.example.dns64.' | |
72 | ||
73 | query = dns.message.make_query(qname, 'A', want_dnssec=True) | |
74 | for method in ("sendUDPQuery", "sendTCPQuery"): | |
75 | sender = getattr(self, method) | |
76 | res = sender(query) | |
77 | self.assertRcodeEqual(res, dns.rcode.NOERROR) | |
4bfebc93 | 78 | self.assertEqual(len(res.answer), 0) |
ef3ee606 RG |
79 | |
80 | # this type (AAAA) does not exist for this name but there is an A record, we should get a DNS64-wrapped AAAA | |
81 | def testNonExistingAAAA(self): | |
82 | qname = 'www.example.dns64.' | |
83 | expected = dns.rrset.from_text(qname, 0, dns.rdataclass.IN, 'AAAA', '64:ff9b::c000:22a') | |
84 | ||
85 | query = dns.message.make_query(qname, 'AAAA', want_dnssec=True) | |
86 | for method in ("sendUDPQuery", "sendTCPQuery"): | |
87 | sender = getattr(self, method) | |
88 | res = sender(query) | |
89 | self.assertRcodeEqual(res, dns.rcode.NOERROR) | |
90 | self.assertRRsetInAnswer(res, expected) | |
91 | ||
c2226112 RG |
92 | # there is a CNAME from that name to a second one, then to a name for which this type (AAAA) |
93 | # does not exist, but an A record does, so we should get a DNS64-wrapped AAAA | |
94 | def testCNAMEToA(self): | |
95 | qname = 'cname.example.dns64.' | |
96 | expectedResults = [ | |
97 | dns.rrset.from_text(qname, 0, dns.rdataclass.IN, 'CNAME', 'cname2.example.dns64.'), | |
98 | dns.rrset.from_text('cname2.example.dns64.', 0, dns.rdataclass.IN, 'CNAME', 'www.example.dns64.'), | |
99 | dns.rrset.from_text('www.example.dns64.', 0, dns.rdataclass.IN, 'AAAA', '64:ff9b::c000:22a') | |
100 | ] | |
101 | ||
102 | query = dns.message.make_query(qname, 'AAAA', want_dnssec=True) | |
103 | for method in ("sendUDPQuery", "sendTCPQuery"): | |
104 | sender = getattr(self, method) | |
105 | res = sender(query) | |
106 | self.assertRcodeEqual(res, dns.rcode.NOERROR) | |
107 | for expected in expectedResults: | |
108 | self.assertRRsetInAnswer(res, expected) | |
109 | ||
ef3ee606 | 110 | # this type (AAAA) does not exist for this name and there is no A record either, we should get a NXDomain |
c2226112 | 111 | def testNXD(self): |
ef3ee606 RG |
112 | qname = 'nxd.example.dns64.' |
113 | ||
114 | query = dns.message.make_query(qname, 'AAAA', want_dnssec=True) | |
115 | for method in ("sendUDPQuery", "sendTCPQuery"): | |
116 | sender = getattr(self, method) | |
117 | res = sender(query) | |
118 | self.assertRcodeEqual(res, dns.rcode.NXDOMAIN) | |
119 | ||
120 | # there is an AAAA record, we should get it | |
121 | def testExistingAAAA(self): | |
122 | qname = 'aaaa.example.dns64.' | |
123 | expected = dns.rrset.from_text(qname, 0, dns.rdataclass.IN, 'AAAA', '2001:db8::1') | |
124 | ||
125 | query = dns.message.make_query(qname, 'AAAA', want_dnssec=True) | |
126 | for method in ("sendUDPQuery", "sendTCPQuery"): | |
127 | sender = getattr(self, method) | |
503c2e3f OM |
128 | res = sender(query) |
129 | self.assertRcodeEqual(res, dns.rcode.NOERROR) | |
130 | self.assertRRsetInAnswer(res, expected) | |
131 | ||
a2f9c045 OM |
132 | # If the AAAA is handled by Lua code, we should not get a dns64 result |
133 | def testFormerr(self): | |
134 | qname = 'formerr.example.dns64' | |
135 | ||
136 | query = dns.message.make_query(qname, 'AAAA', want_dnssec=True) | |
137 | for method in ("sendUDPQuery", "sendTCPQuery"): | |
138 | sender = getattr(self, method) | |
139 | res = sender(query) | |
140 | self.assertRcodeEqual(res, dns.rcode.FORMERR) | |
141 | ||
142 | # If the AAAA times out, we still should get a dns64 result | |
143 | def testTimeout(self): | |
144 | qname = '8.delay1.example.' | |
145 | expected = dns.rrset.from_text(qname, 0, dns.rdataclass.IN, 'AAAA', '64:ff9b::c000:264') | |
503c2e3f OM |
146 | |
147 | query = dns.message.make_query(qname, 'AAAA', want_dnssec=True) | |
148 | for method in ("sendUDPQuery", "sendTCPQuery"): | |
149 | sender = getattr(self, method) | |
ef3ee606 RG |
150 | res = sender(query) |
151 | self.assertRcodeEqual(res, dns.rcode.NOERROR) | |
152 | self.assertRRsetInAnswer(res, expected) | |
153 | ||
154 | # there is a TXT record, we should get it | |
155 | def testExistingTXT(self): | |
156 | qname = 'www.example.dns64.' | |
157 | expected = dns.rrset.from_text(qname, 0, dns.rdataclass.IN, 'TXT', '"does exist"') | |
158 | ||
159 | query = dns.message.make_query(qname, 'TXT', want_dnssec=True) | |
160 | for method in ("sendUDPQuery", "sendTCPQuery"): | |
161 | sender = getattr(self, method) | |
162 | res = sender(query) | |
163 | self.assertRcodeEqual(res, dns.rcode.NOERROR) | |
164 | self.assertRRsetInAnswer(res, expected) | |
165 | ||
166 | # the PTR records for the DNS64 prefix should be generated | |
167 | def testNonExistingPTR(self): | |
168 | qname = 'a.2.2.0.0.0.0.c.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.b.9.f.f.4.6.0.0.ip6.arpa.' | |
169 | expectedCNAME = dns.rrset.from_text(qname, 0, dns.rdataclass.IN, 'CNAME', '42.2.0.192.in-addr.arpa.') | |
170 | expected = dns.rrset.from_text('42.2.0.192.in-addr.arpa.', 0, dns.rdataclass.IN, 'PTR', 'www.example.dns64.') | |
171 | ||
172 | query = dns.message.make_query(qname, 'PTR', want_dnssec=True) | |
173 | for method in ("sendUDPQuery", "sendTCPQuery"): | |
174 | sender = getattr(self, method) | |
175 | res = sender(query) | |
176 | print(res) | |
177 | self.assertRcodeEqual(res, dns.rcode.NOERROR) | |
178 | self.assertRRsetInAnswer(res, expectedCNAME) | |
179 | self.assertRRsetInAnswer(res, expected) | |
180 | ||
181 | # but not for other prefixes | |
182 | def testExistingPTR(self): | |
183 | qname = '1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa.' | |
184 | expected = dns.rrset.from_text(qname, 0, dns.rdataclass.IN, 'PTR', 'aaaa.example.dns64.') | |
185 | ||
186 | query = dns.message.make_query(qname, 'PTR', want_dnssec=True) | |
187 | for method in ("sendUDPQuery", "sendTCPQuery"): | |
188 | sender = getattr(self, method) | |
189 | res = sender(query) | |
190 | self.assertRcodeEqual(res, dns.rcode.NOERROR) | |
191 | self.assertRRsetInAnswer(res, expected) |