]>
git.ipfire.org Git - thirdparty/pdns.git/blob - regression-tests.recursor-dnssec/test_Lua.py
1 import clientsubnetoption
8 from twisted
.internet
.protocol
import DatagramProtocol
9 from twisted
.internet
import reactor
11 from recursortests
import RecursorTest
13 class GettagRecursorTest(RecursorTest
):
14 _confdir
= 'LuaGettag'
15 _config_template
= """
17 gettag-needs-edns-options=yes
19 _lua_dns_script_file
= """
20 function gettag(remote, ednssubnet, localip, qname, qtype, ednsoptions, tcp)
25 -- make sure we can pass data around to the other hooks
26 data['canary'] = 'from-gettag'
28 -- test that the remote addr is valid
29 if remote:toString() ~= '127.0.0.1' then
30 pdnslog("invalid remote")
31 table.insert(tags, 'invalid remote '..remote:toString())
35 -- test that the local addr is valid
36 if localip:toString() ~= '127.0.0.1' then
37 pdnslog("invalid local")
38 table.insert(tags, 'invalid local '..localip:toString())
42 if not ednssubnet:empty() then
43 table.insert(tags, 'edns-subnet-'..ednssubnet:toString())
46 for k,v in pairs(ednsoptions) do
47 table.insert(tags, 'ednsoption-'..k..'-count-'..v:count())
49 local values = v:getValues()
50 for j,l in pairs(values) do
53 -- check that the old interface (before 4.2.0) still works
55 if l:len() ~= v.size then
56 table.insert(tags, 'size obtained via the old edns option interface does not match')
58 value = v:getContent()
60 table.insert(tags, 'content obtained via the old edns option interface does not match')
64 table.insert(tags, 'ednsoption-'..k..'-total-len-'..len)
68 table.insert(tags, 'gettag-tcp')
71 -- test that tags are passed to other hooks
72 table.insert(tags, qname:toString())
73 table.insert(tags, 'gettag-qtype-'..qtype)
78 function preresolve(dq)
80 -- test that we are getting the tags set by gettag()
81 -- and also getting the correct qname
83 for _, tag in pairs(dq:getPolicyTags()) do
84 if dq.qname:equal(tag) then
87 dq:addAnswer(pdns.TXT, '"'..tag..'"')
91 pdnslog("not valid tag found")
92 dq.rcode = pdns.REFUSED
96 if dq.data['canary'] ~= 'from-gettag' then
97 pdnslog("did not get any data from gettag")
98 dq.rcode = pdns.REFUSED
102 if dq.qtype == pdns.A then
103 dq:addAnswer(pdns.A, '192.0.2.1')
104 elseif dq.qtype == pdns.AAAA then
105 dq:addAnswer(pdns.AAAA, '2001:db8::1')
116 confdir
= os
.path
.join('configs', cls
._confdir
)
117 cls
.createConfigDir(confdir
)
118 cls
.generateRecursorConfig(confdir
)
119 cls
.startRecursor(confdir
, cls
._recursorPort
)
122 def tearDownClass(cls
):
123 cls
.tearDownRecursor()
125 def assertResponseMatches(self
, query
, expectedRRs
, response
):
126 expectedResponse
= dns
.message
.make_response(query
)
128 if query
.flags
& dns
.flags
.RD
:
129 expectedResponse
.flags |
= dns
.flags
.RA
130 if query
.flags
& dns
.flags
.CD
:
131 expectedResponse
.flags |
= dns
.flags
.CD
133 expectedResponse
.answer
= expectedRRs
134 print(expectedResponse
)
136 self
.assertEquals(response
, expectedResponse
)
141 dns
.rrset
.from_text(name
, 0, dns
.rdataclass
.IN
, 'A', '192.0.2.1'),
142 dns
.rrset
.from_text_list(name
, 0, dns
.rdataclass
.IN
, 'TXT', [ name
, 'gettag-qtype-1'])
144 query
= dns
.message
.make_query(name
, 'A', want_dnssec
=True)
145 query
.flags |
= dns
.flags
.CD
146 res
= self
.sendUDPQuery(query
)
147 self
.assertResponseMatches(query
, expected
, res
)
150 name
= 'gettag-tcpa.lua.'
152 dns
.rrset
.from_text(name
, 0, dns
.rdataclass
.IN
, 'A', '192.0.2.1'),
153 dns
.rrset
.from_text_list(name
, 0, dns
.rdataclass
.IN
, 'TXT', [ name
, 'gettag-qtype-1', 'gettag-tcp'])
155 query
= dns
.message
.make_query(name
, 'A', want_dnssec
=True)
156 query
.flags |
= dns
.flags
.CD
157 res
= self
.sendTCPQuery(query
)
158 self
.assertResponseMatches(query
, expected
, res
)
161 name
= 'gettag-aaaa.lua.'
163 dns
.rrset
.from_text(name
, 0, dns
.rdataclass
.IN
, 'AAAA', '2001:db8::1'),
164 dns
.rrset
.from_text_list(name
, 0, dns
.rdataclass
.IN
, 'TXT', [ name
, 'gettag-qtype-28'])
166 query
= dns
.message
.make_query(name
, 'AAAA', want_dnssec
=True)
167 query
.flags |
= dns
.flags
.CD
168 res
= self
.sendUDPQuery(query
)
169 self
.assertResponseMatches(query
, expected
, res
)
171 def testSubnet(self
):
172 name
= 'gettag-subnet.lua.'
173 subnet
= '192.0.2.255'
175 ecso
= clientsubnetoption
.ClientSubnetOption(subnet
, subnetMask
)
177 dns
.rrset
.from_text(name
, 0, dns
.rdataclass
.IN
, 'A', '192.0.2.1'),
178 dns
.rrset
.from_text_list(name
, 0, dns
.rdataclass
.IN
, 'TXT', [name
, 'gettag-qtype-1', 'edns-subnet-' + subnet
+ '/' + str(subnetMask
),
179 'ednsoption-8-count-1', 'ednsoption-8-total-len-8']),
181 query
= dns
.message
.make_query(name
, 'A', want_dnssec
=True, options
=[ecso
])
182 query
.flags |
= dns
.flags
.CD
183 res
= self
.sendUDPQuery(query
)
184 self
.assertResponseMatches(query
, expected
, res
)
186 def testEDNSOptions(self
):
187 name
= 'gettag-ednsoptions.lua.'
188 subnet
= '192.0.2.255'
190 ecso
= clientsubnetoption
.ClientSubnetOption(subnet
, subnetMask
)
191 eco1
= cookiesoption
.CookiesOption(b
'deadbeef', b
'deadbeef')
192 eco2
= cookiesoption
.CookiesOption(b
'deadc0de', b
'deadc0de')
195 dns
.rrset
.from_text(name
, 0, dns
.rdataclass
.IN
, 'A', '192.0.2.1'),
196 dns
.rrset
.from_text_list(name
, 0, dns
.rdataclass
.IN
, 'TXT', [name
, 'gettag-qtype-1', 'edns-subnet-' + subnet
+ '/' + str(subnetMask
),
197 'ednsoption-10-count-2', 'ednsoption-10-total-len-32',
198 'ednsoption-8-count-1', 'ednsoption-8-total-len-8'
201 query
= dns
.message
.make_query(name
, 'A', want_dnssec
=True, options
=[eco1
,ecso
,eco2
])
202 query
.flags |
= dns
.flags
.CD
203 res
= self
.sendUDPQuery(query
)
204 self
.assertResponseMatches(query
, expected
, res
)
206 hooksReactorRunning
= False
208 class UDPHooksResponder(DatagramProtocol
):
210 def datagramReceived(self
, datagram
, address
):
211 request
= dns
.message
.from_wire(datagram
)
213 response
= dns
.message
.make_response(request
)
214 response
.flags |
= dns
.flags
.AA
216 if request
.question
[0].name
== dns
.name
.from_text('nxdomain.luahooks.example.'):
217 soa
= dns
.rrset
.from_text('luahooks.example.', 86400, dns
.rdataclass
.IN
, 'SOA', 'ns.luahooks.example. hostmaster.luahooks.example. 1 3600 3600 3600 1')
218 response
.authority
.append(soa
)
219 response
.set_rcode(dns
.rcode
.NXDOMAIN
)
221 elif request
.question
[0].name
== dns
.name
.from_text('nodata.luahooks.example.'):
222 soa
= dns
.rrset
.from_text('luahooks.example.', 86400, dns
.rdataclass
.IN
, 'SOA', 'ns.luahooks.example. hostmaster.luahooks.example. 1 3600 3600 3600 1')
223 response
.authority
.append(soa
)
225 elif request
.question
[0].name
== dns
.name
.from_text('postresolve.luahooks.example.'):
226 answer
= dns
.rrset
.from_text('postresolve.luahooks.example.', 3600, dns
.rdataclass
.IN
, 'A', '192.0.2.1')
227 response
.answer
.append(answer
)
229 self
.transport
.write(response
.to_wire(), address
)
231 class LuaHooksRecursorTest(RecursorTest
):
232 _confdir
= 'LuaHooks'
233 _config_template
= """
234 forward-zones=luahooks.example=%s.23
235 log-common-errors=yes
237 """ % (os
.environ
['PREFIX'])
238 _lua_dns_script_file
= """
240 allowedips = newNMG()
241 allowedips:addMask("%s.0/24")
243 function ipfilter(remoteip, localip, dh)
244 -- allow only 127.0.0.1 and AD=0
245 if allowedips:match(remoteip) and not dh:getAD() then
253 if dq.qtype == pdns.AAAA and dq.qname == newDN("nodata.luahooks.example.") then
254 dq:addAnswer(pdns.AAAA, "2001:DB8::1")
261 function nxdomain(dq)
262 if dq.qtype == pdns.A and dq.qname == newDN("nxdomain.luahooks.example.") then
264 dq:addAnswer(pdns.A, "192.0.2.1")
271 function postresolve(dq)
272 if dq.qtype == pdns.A and dq.qname == newDN("postresolve.luahooks.example.") then
273 local records = dq:getRecords()
274 for k,v in pairs(records) do
275 if v.type == pdns.A and v:getContent() == "192.0.2.1" then
276 v:changeContent("192.0.2.42")
280 dq:setRecords(records)
287 function preoutquery(dq)
288 if dq.remoteaddr:equal(newCA("%s.23")) and dq.qname == newDN("preout.luahooks.example.") and dq.qtype == pdns.A then
289 dq.rcode = -3 -- "kill"
296 """ % (os
.environ
['PREFIX'], os
.environ
['PREFIX'])
299 def startResponders(cls
):
300 global hooksReactorRunning
301 print("Launching responders..")
303 address
= cls
._PREFIX
+ '.23'
306 if not hooksReactorRunning
:
307 reactor
.listenUDP(port
, UDPHooksResponder(), interface
=address
)
308 hooksReactorRunning
= True
310 if not reactor
.running
:
311 cls
._UDPResponder
= threading
.Thread(name
='UDP Hooks Responder', target
=reactor
.run
, args
=(False,))
312 cls
._UDPResponder
.setDaemon(True)
313 cls
._UDPResponder
.start()
319 cls
.startResponders()
321 confdir
= os
.path
.join('configs', cls
._confdir
)
322 cls
.createConfigDir(confdir
)
324 cls
.generateRecursorConfig(confdir
)
325 cls
.startRecursor(confdir
, cls
._recursorPort
)
327 print("Launching tests..")
330 def tearDownClass(cls
):
331 cls
.tearDownRecursor()
333 def testNoData(self
):
334 expected
= dns
.rrset
.from_text('nodata.luahooks.example.', 3600, dns
.rdataclass
.IN
, 'AAAA', '2001:DB8::1')
335 query
= dns
.message
.make_query('nodata.luahooks.example.', 'AAAA', 'IN')
336 res
= self
.sendUDPQuery(query
)
338 self
.assertRcodeEqual(res
, dns
.rcode
.NOERROR
)
339 self
.assertRRsetInAnswer(res
, expected
)
341 def testVanillaNXD(self
):
342 #expected = dns.rrset.from_text('nxdomain.luahooks.example.', 3600, dns.rdataclass.IN, 'A', '192.0.2.1')
343 query
= dns
.message
.make_query('nxdomain.luahooks.example.', 'AAAA', 'IN')
344 res
= self
.sendUDPQuery(query
)
346 self
.assertRcodeEqual(res
, dns
.rcode
.NXDOMAIN
)
348 def testHookedNXD(self
):
349 expected
= dns
.rrset
.from_text('nxdomain.luahooks.example.', 3600, dns
.rdataclass
.IN
, 'A', '192.0.2.1')
350 query
= dns
.message
.make_query('nxdomain.luahooks.example.', 'A', 'IN')
351 res
= self
.sendUDPQuery(query
)
353 self
.assertRcodeEqual(res
, dns
.rcode
.NOERROR
)
354 self
.assertRRsetInAnswer(res
, expected
)
356 def testPostResolve(self
):
357 expected
= dns
.rrset
.from_text('postresolve.luahooks.example.', 1, dns
.rdataclass
.IN
, 'A', '192.0.2.42')
358 query
= dns
.message
.make_query('postresolve.luahooks.example.', 'A', 'IN')
359 res
= self
.sendUDPQuery(query
)
361 self
.assertRcodeEqual(res
, dns
.rcode
.NOERROR
)
362 self
.assertRRsetInAnswer(res
, expected
)
363 self
.assertEqual(res
.answer
[0].ttl
, 1)
365 def testIPFilterHeader(self
):
366 query
= dns
.message
.make_query('ipfiler.luahooks.example.', 'A', 'IN')
367 query
.flags |
= dns
.flags
.AD
368 res
= self
.sendUDPQuery(query
)
369 self
.assertEqual(res
, None)
371 def testPreOutInterceptedQuery(self
):
372 query
= dns
.message
.make_query('preout.luahooks.example.', 'A', 'IN')
373 res
= self
.sendUDPQuery(query
)
374 self
.assertRcodeEqual(res
, dns
.rcode
.SERVFAIL
)
376 def testPreOutNotInterceptedQuery(self
):
377 query
= dns
.message
.make_query('preout.luahooks.example.', 'AAAA', 'IN')
378 res
= self
.sendUDPQuery(query
)
379 self
.assertRcodeEqual(res
, dns
.rcode
.NOERROR
)