]>
git.ipfire.org Git - thirdparty/pdns.git/blob - regression-tests.recursor-dnssec/recursortests.py
3 from __future__
import print_function
16 class RecursorTest ( unittest
. TestCase
):
18 Setup all recursors and auths required for the tests
23 _recursorStartupDelay
= 2.0
28 _PREFIX
= os
. environ
[ 'PREFIX' ]
30 _config_template_default
= """
34 local-address=127.0.0.1
36 packetcache-servfail-ttl=0
42 _config_template
= """
45 _lua_config_file
= None
46 _lua_dns_script_file
= None
49 ns.root. 3600 IN A %s .8
51 _root_DS
= "63149 13 1 a59da3f5c1b97fcd5fa2b3b2b0ac91d38a60d33a"
53 # The default SOA for zones in the authoritative servers
54 _SOA
= "ns1.example.net. hostmaster.example.net. 1 3600 1800 1209600 300"
56 # The definitions of the zones on the authoritative servers, the key is the
57 # zonename and the value is the zonefile content. several strings are replaced:
58 # - {soa} => value of _SOA
59 # - {prefix} value of _PREFIX
64 ns.root. 3600 IN A {prefix} .8
66 example. 3600 IN NS ns1.example.
67 example. 3600 IN NS ns2.example.
68 example. 3600 IN DS 53174 13 1 50c9e913818767c236c06c2d8272723cb78cbf26
70 ns1.example. 3600 IN A {prefix} .10
71 ns2.example. 3600 IN A {prefix} .11
74 example. 3600 IN SOA {soa}
75 example. 3600 IN NS ns1.example.
76 example. 3600 IN NS ns2.example.
77 ns1.example. 3600 IN A {prefix} .10
78 ns2.example. 3600 IN A {prefix} .11
80 secure.example. 3600 IN NS ns.secure.example.
81 secure.example. 3600 IN DS 64723 13 1 53eb985040d3a89bacf29dbddb55a65834706f33
82 ns.secure.example. 3600 IN A {prefix} .9
84 cname-secure.example. 3600 IN NS ns.cname-secure.example.
85 cname-secure.example. 3600 IN DS 49148 13 1 a10314452d5ec4d97fcc6d7e275d217261fe790f
86 ns.cname-secure.example. 3600 IN A {prefix} .15
88 dname-secure.example. 3600 IN NS ns.dname-secure.example.
89 dname-secure.example. 3600 IN DS 42043 13 2 11c67f46b7c4d5968bc5f6cc944d58377b762bda53ddb4f3a6dbe6faf7a9940f
90 ns.dname-secure.example. 3600 IN A {prefix} .13
92 bogus.example. 3600 IN NS ns.bogus.example.
93 bogus.example. 3600 IN DS 65034 13 1 6df3bb50ea538e90eacdd7ae5419730783abb0ee
94 ns.bogus.example. 3600 IN A {prefix} .12
96 insecure.example. 3600 IN NS ns.insecure.example.
97 ns.insecure.example. 3600 IN A {prefix} .13
99 optout.example. 3600 IN NS ns1.optout.example.
100 optout.example. 3600 IN DS 59332 13 1 e664f886ae1b5df03d918bc1217d22afc29925b9
101 ns1.optout.example. 3600 IN A {prefix} .14
103 insecure-formerr.example. 3600 IN NS ns1.insecure-formerr.example.
104 ns1.insecure-formerr.example. 3600 IN A {prefix} .2
106 ecs-echo.example. 3600 IN NS ns1.ecs-echo.example.
107 ns1.ecs-echo.example. 3600 IN A {prefix} .21
109 islandofsecurity.example. 3600 IN NS ns1.islandofsecurity.example.
110 ns1.islandofsecurity.example. 3600 IN A {prefix} .9
112 sortcname.example. 3600 IN CNAME sort
113 sort.example. 3600 IN A 17.38.42.80
114 sort.example. 3600 IN A 192.168.0.1
115 sort.example. 3600 IN A 17.238.240.5
116 sort.example. 3600 IN MX 25 mx
118 delay.example. 3600 IN NS ns1.delay.example.
119 ns1.delay.example. 3600 IN A {prefix} .16
121 'secure.example' : """
122 secure.example. 3600 IN SOA {soa}
123 secure.example. 3600 IN NS ns.secure.example.
124 ns.secure.example. 3600 IN A {prefix} .9
126 secure.example. 3600 IN A 192.0.2.17
128 host1.secure.example. 3600 IN A 192.0.2.2
129 cname.secure.example. 3600 IN CNAME host1.secure.example.
130 cname-to-insecure.secure.example. 3600 IN CNAME node1.insecure.example.
131 cname-to-bogus.secure.example. 3600 IN CNAME ted.bogus.example.
132 cname-to-islandofsecurity.secure.example. 3600 IN CNAME node1.islandofsecurity.example.
134 host1.sub.secure.example. 3600 IN A 192.0.2.11
137 sub2.secure.example. 3600 IN CNAME doesnotmatter.insecure.example.
138 insecure.sub2.secure.example. 3600 IN NS ns1.insecure.example.
140 *.wildcard.secure.example. 3600 IN A 192.0.2.10
142 *.cnamewildcard.secure.example. 3600 IN CNAME host1.secure.example.
144 *.cnamewildcardnxdomain.secure.example. 3600 IN CNAME doesntexist.secure.example.
146 cname-to-formerr.secure.example. 3600 IN CNAME host1.insecure-formerr.example.
148 dname-secure.secure.example. 3600 IN DNAME dname-secure.example.
149 dname-insecure.secure.example. 3600 IN DNAME insecure.example.
150 dname-bogus.secure.example. 3600 IN DNAME bogus.example.
152 'dname-secure.example' : """
153 dname-secure.example. 3600 IN SOA {soa}
154 dname-secure.example. 3600 IN NS ns.dname-secure.example.
155 ns.dname-secure.example. 3600 IN A {prefix} .13
157 host1.dname-secure.example. IN A 192.0.2.21
159 cname-to-secure.dname-secure.example. 3600 IN CNAME host1.secure.example.
160 cname-to-insecure.dname-secure.example. 3600 IN CNAME node1.insecure.example.
161 cname-to-bogus.dname-secure.example. 3600 IN CNAME ted.bogus.example.
163 'cname-secure.example' : """
164 cname-secure.example. 3600 IN SOA {soa}
165 cname-secure.example. 3600 IN NS ns.cname-secure.example.
166 ns.cname-secure.example. 3600 IN A {prefix} .15
167 cname-secure.example. 3600 IN CNAME secure.example.
170 bogus.example. 3600 IN SOA {soa}
171 bogus.example. 3600 IN NS ns1.bogus.example.
172 ns1.bogus.example. 3600 IN A {prefix} .12
173 ted.bogus.example. 3600 IN A 192.0.2.1
174 bill.bogus.example. 3600 IN AAAA 2001:db8:12::3
176 'insecure.sub2.secure.example' : """
177 insecure.sub2.secure.example. 3600 IN SOA {soa}
178 insecure.sub2.secure.example. 3600 IN NS ns1.insecure.example.
180 node1.insecure.sub2.secure.example. 3600 IN A 192.0.2.18
182 'insecure.example' : """
183 insecure.example. 3600 IN SOA {soa}
184 insecure.example. 3600 IN NS ns1.insecure.example.
185 ns1.insecure.example. 3600 IN A {prefix} .13
187 node1.insecure.example. 3600 IN A 192.0.2.6
189 cname-to-secure.insecure.example. 3600 IN CNAME host1.secure.example.
191 dname-to-secure.insecure.example. 3600 IN DNAME dname-secure.example.
193 'optout.example' : """
194 optout.example. 3600 IN SOA {soa}
195 optout.example. 3600 IN NS ns1.optout.example.
196 ns1.optout.example. 3600 IN A {prefix} .14
198 insecure.optout.example. 3600 IN NS ns1.insecure.optout.example.
199 ns1.insecure.optout.example. 3600 IN A {prefix} .15
201 secure.optout.example. 3600 IN NS ns1.secure.optout.example.
202 secure.optout.example. 3600 IN DS 64215 13 1 b88284d7a8d8605c398e8942262f97b9a5a31787
203 ns1.secure.optout.example. 3600 IN A {prefix} .15
205 'insecure.optout.example' : """
206 insecure.optout.example. 3600 IN SOA {soa}
207 insecure.optout.example. 3600 IN NS ns1.insecure.optout.example.
208 ns1.insecure.optout.example. 3600 IN A {prefix} .15
210 node1.insecure.optout.example. 3600 IN A 192.0.2.7
212 'secure.optout.example' : """
213 secure.optout.example. 3600 IN SOA {soa}
214 secure.optout.example. 3600 IN NS ns1.secure.optout.example.
215 ns1.secure.optout.example. 3600 IN A {prefix} .15
217 node1.secure.optout.example. 3600 IN A 192.0.2.8
219 'islandofsecurity.example' : """
220 islandofsecurity.example. 3600 IN SOA {soa}
221 islandofsecurity.example. 3600 IN NS ns1.islandofsecurity.example.
222 ns1.islandofsecurity.example. 3600 IN A {prefix} .9
224 node1.islandofsecurity.example. 3600 IN A 192.0.2.20
226 'undelegated.secure.example' : """
227 undelegated.secure.example. 3600 IN SOA {soa}
228 undelegated.secure.example. 3600 IN NS ns1.undelegated.secure.example.
230 node1.undelegated.secure.example. 3600 IN A 192.0.2.21
232 'undelegated.insecure.example' : """
233 undelegated.insecure.example. 3600 IN SOA {soa}
234 undelegated.insecure.example. 3600 IN NS ns1.undelegated.insecure.example.
236 node1.undelegated.insecure.example. 3600 IN A 192.0.2.22
240 delay.example. 3600 IN SOA {soa}
241 delay.example. 3600 IN NS n1.delay.example.
242 ns1.delay.example. 3600 IN A {prefix} .16
243 *.delay.example. 0 LUA TXT ";" "local socket=require('socket')" "socket.sleep(tonumber(qname:getRawLabels()[1])/10)" "return 'a'"
247 # The private keys for the zones (note that DS records should go into
248 # the zonecontent in _zones
251 Private-key-format: v1.2
252 Algorithm: 13 (ECDSAP256SHA256)
253 PrivateKey: rhWuEydDz3QaIspSVj683B8Xq5q/ozzA38XUgzD4Fbo=
257 Private-key-format: v1.2
258 Algorithm: 13 (ECDSAP256SHA256)
259 PrivateKey: Lt0v0Gol3pRUFM7fDdcy0IWN0O/MnEmVPA+VylL8Y4U=
262 'secure.example' : """
263 Private-key-format: v1.2
264 Algorithm: 13 (ECDSAP256SHA256)
265 PrivateKey: 1G4WRoOFJJXk+fotDCHVORtJmIG2OUhKi8AO2jDPGZA=
269 Private-key-format: v1.2
270 Algorithm: 13 (ECDSAP256SHA256)
271 PrivateKey: f5jV7Q8kd5hDpMWObsuQ6SQda0ftf+JrO3uZwEg6nVw=
274 'optout.example' : """
275 Private-key-format: v1.2
276 Algorithm: 13 (ECDSAP256SHA256)
277 PrivateKey: efmq9G+J4Y2iPnIBRwJiy6Z/nIHSzpsCy/7XHhlS19A=
280 'secure.optout.example' : """
281 Private-key-format: v1.2
282 Algorithm: 13 (ECDSAP256SHA256)
283 PrivateKey: xcNUxt1Knj14A00lKQFDboluiJyM2f7FxpgsQaQ3AQ4=
286 'islandofsecurity.example' : """
287 Private-key-format: v1.2
288 Algorithm: 13 (ECDSAP256SHA256)
289 PrivateKey: o9F5iix8V68tnMcuOaM2Lt8XXhIIY//SgHIHEePk6cM=
292 'cname-secure.example' : """
293 Private-key-format: v1.2
294 Algorithm: 13 (ECDSAP256SHA256)
295 PrivateKey: kvoV/g4IO/tefSro+FLJ5UC7H3BUf0IUtZQSUOfQGyA=
298 'dname-secure.example' : """
299 Private-key-format: v1.2
300 Algorithm: 13 (ECDSAP256SHA256)
301 PrivateKey: Ep9uo6+wwjb4MaOmqq7LHav2FLrjotVOeZg8JT1Qk04=
305 # This dict is keyed with the suffix of the IP address and its value
306 # is a list of zones hosted on that IP. Note that delegations should
307 # go into the _zones's zonecontent
312 'zones' : [ 'secure.example' , 'islandofsecurity.example' ]},
314 'zones' : [ 'example' ]},
316 'zones' : [ 'example' ]},
318 'zones' : [ 'bogus.example' , 'undelegated.secure.example' , 'undelegated.insecure.example' ]},
320 'zones' : [ 'insecure.example' , 'insecure.sub2.secure.example' , 'dname-secure.example' ]},
322 'zones' : [ 'optout.example' ]},
324 'zones' : [ 'insecure.optout.example' , 'secure.optout.example' , 'cname-secure.example' ]},
325 # This zone need more threads so that the lua delay code does not cause serialization
327 'zones' : [ 'delay.example' ]}
330 _auth_cmd
= [ 'authbind' ,
336 def createConfigDir ( cls
, confdir
):
338 shutil
. rmtree ( confdir
)
340 if e
. errno
!= errno
. ENOENT
:
342 os
. mkdir ( confdir
, 0o755 )
345 def generateAuthZone ( cls
, confdir
, zonename
, zonecontent
):
346 with
open ( os
. path
. join ( confdir
, ' %s .zone' % zonename
), 'w' ) as zonefile
:
347 zonefile
. write ( zonecontent
. format ( prefix
= cls
._ PREFIX
, soa
= cls
._ SOA
))
350 def generateAuthNamedConf ( cls
, confdir
, zones
):
351 with
open ( os
. path
. join ( confdir
, 'named.conf' ), 'w' ) as namedconf
:
356 for zonename
in zones
:
357 zone
= '.' if zonename
== 'ROOT' else zonename
363 };""" % ( zone
, zonename
))
366 def generateAuthConfig ( cls
, confdir
, threads
):
367 bind_dnssec_db
= os
. path
. join ( confdir
, 'bind-dnssec.sqlite3' )
369 with
open ( os
. path
. join ( confdir
, 'pdns.conf' ), 'w' ) as pdnsconf
:
371 module-dir=../regression-tests/modules
375 bind-config= {confdir} /named.conf
376 bind-dnssec-db= {bind_dnssec_db}
386 distributor-threads= {threads} """ . format ( confdir
= confdir
,
387 bind_dnssec_db
= bind_dnssec_db
,
390 pdnsutilCmd
= [ os
. environ
[ 'PDNSUTIL' ],
391 '--config-dir= %s ' % confdir
,
395 print ( ' ' . join ( pdnsutilCmd
))
397 subprocess
. check_output ( pdnsutilCmd
, stderr
= subprocess
. STDOUT
)
398 except subprocess
. CalledProcessError
as e
:
399 raise AssertionError ( ' %s failed ( %d ): %s ' % ( pdnsutilCmd
, e
. returncode
, e
. output
))
402 def secureZone ( cls
, confdir
, zonename
, key
= None ):
403 zone
= '.' if zonename
== 'ROOT' else zonename
405 pdnsutilCmd
= [ os
. environ
[ 'PDNSUTIL' ],
406 '--config-dir= %s ' % confdir
,
410 keyfile
= os
. path
. join ( confdir
, 'dnssec.key' )
411 with
open ( keyfile
, 'w' ) as fdKeyfile
:
414 pdnsutilCmd
= [ os
. environ
[ 'PDNSUTIL' ],
415 '--config-dir= %s ' % confdir
,
422 print ( ' ' . join ( pdnsutilCmd
))
424 subprocess
. check_output ( pdnsutilCmd
, stderr
= subprocess
. STDOUT
)
425 except subprocess
. CalledProcessError
as e
:
426 raise AssertionError ( ' %s failed ( %d ): %s ' % ( pdnsutilCmd
, e
. returncode
, e
. output
))
429 def generateAllAuthConfig ( cls
, confdir
):
431 for auth_suffix
, zoneinfo
in cls
._ auth
_ zones
. items ():
432 threads
= zoneinfo
[ 'threads' ]
433 zones
= zoneinfo
[ 'zones' ]
434 authconfdir
= os
. path
. join ( confdir
, 'auth- %s ' % auth_suffix
)
436 os
. mkdir ( authconfdir
)
438 cls
. generateAuthConfig ( authconfdir
, threads
)
439 cls
. generateAuthNamedConf ( authconfdir
, zones
)
442 cls
. generateAuthZone ( authconfdir
,
445 if cls
._ zone
_ keys
. get ( zone
, None ):
446 cls
. secureZone ( authconfdir
, zone
, cls
._ zone
_ keys
. get ( zone
))
449 def startAllAuth ( cls
, confdir
):
451 for auth_suffix
, _
in cls
._ auth
_ zones
. items ():
452 authconfdir
= os
. path
. join ( confdir
, 'auth- %s ' % auth_suffix
)
453 ipaddress
= cls
._ PREFIX
+ '.' + auth_suffix
454 cls
. startAuth ( authconfdir
, ipaddress
)
457 def startAuth ( cls
, confdir
, ipaddress
):
458 print ( "Launching pdns_server.." )
459 authcmd
= list ( cls
._ auth
_ cmd
)
460 authcmd
. append ( '--config-dir= %s ' % confdir
)
461 authcmd
. append ( '--local-address= %s ' % ipaddress
)
462 print ( ' ' . join ( authcmd
))
464 logFile
= os
. path
. join ( confdir
, 'pdns.log' )
465 with
open ( logFile
, 'w' ) as fdLog
:
466 cls
._ auths
[ ipaddress
] = subprocess
. Popen ( authcmd
, close_fds
= True ,
467 stdout
= fdLog
, stderr
= fdLog
,
472 if cls
._ auths
[ ipaddress
]. poll () is not None :
474 cls
._ auths
[ ipaddress
]. kill ()
476 if e
. errno
!= errno
. ESRCH
:
478 with
open ( logFile
, 'r' ) as fdLog
:
480 sys
. exit ( cls
._ auths
[ ipaddress
]. returncode
)
483 def generateRecursorConfig ( cls
, confdir
):
484 params
= tuple ([ getattr ( cls
, param
) for param
in cls
._ config
_ params
])
488 recursorconf
= os
. path
. join ( confdir
, 'recursor.conf' )
490 with
open ( recursorconf
, 'w' ) as conf
:
491 conf
. write ( "# Autogenerated by recursortests.py \n " )
492 conf
. write ( cls
._ config
_ template
_ default
)
493 conf
. write ( cls
._ config
_ template
% params
)
495 conf
. write ( "socket-dir= %s \n " % confdir
)
496 if cls
._lu a
_ config
_ file
or cls
._ root
_ DS
:
497 luaconfpath
= os
. path
. join ( confdir
, 'conffile.lua' )
498 with
open ( luaconfpath
, 'w' ) as luaconf
:
500 luaconf
. write ( "addTA('.', ' %s ') \n " % cls
._ root
_ DS
)
501 if cls
._lu a
_ config
_ file
:
502 luaconf
. write ( cls
._lu a
_ config
_ file
)
503 conf
. write ( "lua-config-file= %s \n " % luaconfpath
)
504 if cls
._lu a
_ dns
_ script
_ file
:
505 luascriptpath
= os
. path
. join ( confdir
, 'dnsscript.lua' )
506 with
open ( luascriptpath
, 'w' ) as luascript
:
507 luascript
. write ( cls
._lu a
_ dns
_ script
_ file
)
508 conf
. write ( "lua-dns-script= %s \n " % luascriptpath
)
510 roothintspath
= os
. path
. join ( confdir
, 'root.hints' )
511 with
open ( roothintspath
, 'w' ) as roothints
:
512 roothints
. write ( cls
._ roothints
)
513 conf
. write ( "hint-file= %s \n " % roothintspath
)
516 def startResponders ( cls
):
520 def startRecursor ( cls
, confdir
, port
):
521 print ( "Launching pdns_recursor.." )
522 recursorcmd
= [ os
. environ
[ 'PDNSRECURSOR' ],
523 '--config-dir= %s ' % confdir
,
524 '--local-port= %s ' % port
,
525 '--security-poll-suffix=' ]
526 print ( ' ' . join ( recursorcmd
))
528 logFile
= os
. path
. join ( confdir
, 'recursor.log' )
529 with
open ( logFile
, 'w' ) as fdLog
:
530 cls
._ recursor
= subprocess
. Popen ( recursorcmd
, close_fds
= True ,
531 stdout
= fdLog
, stderr
= fdLog
)
533 if 'PDNSRECURSOR_FAST_TESTS' in os
. environ
:
536 delay
= cls
._ recursorStartupDelay
540 if cls
._ recursor
. poll () is not None :
544 if e
. errno
!= errno
. ESRCH
:
546 with
open ( logFile
, 'r' ) as fdLog
:
548 sys
. exit ( cls
._ recursor
. returncode
)
551 def wipeRecursorCache ( cls
, confdir
):
552 rec_controlCmd
= [ os
. environ
[ 'RECCONTROL' ],
553 '--config-dir= %s ' % confdir
,
557 subprocess
. check_output ( rec_controlCmd
, stderr
= subprocess
. STDOUT
)
558 except subprocess
. CalledProcessError
as e
:
559 raise AssertionError ( ' %s failed ( %d ): %s ' % ( rec_controlCmd
, e
. returncode
, e
. output
))
562 def setUpSockets ( cls
):
563 print ( "Setting up UDP socket.." )
564 cls
._ sock
= socket
. socket ( socket
. AF_INET
, socket
. SOCK_DGRAM
)
565 cls
._ sock
. settimeout ( 2.0 )
566 cls
._ sock
. connect (( "127.0.0.1" , cls
._ recursorPort
))
572 cls
. startResponders ()
574 confdir
= os
. path
. join ( 'configs' , cls
._ confdir
)
575 cls
. createConfigDir ( confdir
)
576 cls
. generateAllAuthConfig ( confdir
)
577 cls
. startAllAuth ( confdir
)
579 cls
. generateRecursorConfig ( confdir
)
580 cls
. startRecursor ( confdir
, cls
._ recursorPort
)
582 print ( "Launching tests.." )
585 def tearDownClass ( cls
):
586 cls
. tearDownRecursor ()
588 cls
. tearDownResponders ()
591 def tearDownResponders ( cls
):
595 def tearDownAuth ( cls
):
596 if 'PDNSRECURSOR_FAST_TESTS' in os
. environ
:
601 for _
, auth
in cls
._ auths
. items ():
604 if auth
. poll () is None :
606 if auth
. poll () is None :
610 if e
. errno
!= errno
. ESRCH
:
614 def tearDownRecursor ( cls
):
615 if 'PDNSRECURSOR_FAST_TESTS' in os
. environ
:
621 cls
._ recursor
. terminate ()
622 if cls
._ recursor
. poll () is None :
624 if cls
._ recursor
. poll () is None :
628 # There is a race-condition with the poll() and
629 # kill() statements, when the process is dead on the
630 # kill(), this is fine
631 if e
. errno
!= errno
. ESRCH
:
635 def sendUDPQuery ( cls
, query
, timeout
= 2.0 , decode
= True , fwparams
= dict ()):
637 cls
._ sock
. settimeout ( timeout
)
640 cls
._ sock
. send ( query
. to_wire ())
641 data
= cls
._ sock
. recv ( 4096 )
642 except socket
. timeout
:
646 cls
._ sock
. settimeout ( None )
652 message
= dns
. message
. from_wire ( data
, ** fwparams
)
656 def sendTCPQuery ( cls
, query
, timeout
= 2.0 ):
657 sock
= socket
. socket ( socket
. AF_INET
, socket
. SOCK_STREAM
)
659 sock
. settimeout ( timeout
)
661 sock
. connect (( "127.0.0.1" , cls
._ recursorPort
))
664 wire
= query
. to_wire ()
665 sock
. send ( struct
. pack ( "!H" , len ( wire
)))
669 ( datalen
,) = struct
. unpack ( "!H" , data
)
670 data
= sock
. recv ( datalen
)
671 except socket
. timeout
as e
:
672 print ( "Timeout: %s " % ( str ( e
)))
674 except socket
. error
as e
:
675 print ( "Network error: %s " % ( str ( e
)))
682 message
= dns
. message
. from_wire ( data
)
686 def sendTCPQueries ( cls
, queries
, timeout
= 2.0 ):
687 sock
= socket
. socket ( socket
. AF_INET
, socket
. SOCK_STREAM
)
689 sock
. settimeout ( timeout
)
691 sock
. connect (( "127.0.0.1" , cls
._ recursorPort
))
694 for query
in queries
:
695 wire
= query
. to_wire ()
696 sock
. send ( struct
. pack ( "!H" , len ( wire
)))
698 for i
in range ( len ( queries
)):
700 datalen
= sock
. recv ( 2 )
702 ( datalen
,) = struct
. unpack ( "!H" , datalen
)
703 data
. append ( sock
. recv ( datalen
))
704 except socket
. timeout
as e
:
706 except socket
. error
as e
:
707 print ( "Network error: %s " % ( str ( e
)))
714 messages
. append ( dns
. message
. from_wire ( d
))
718 # This function is called before every tests
721 ## Functions for comparisons
722 def assertMessageHasFlags ( self
, msg
, flags
, ednsflags
=[]):
723 """Asserts that msg has all the flags from flags set
725 @param msg: the dns.message.Message to check
726 @param flags: a list of strings with flag mnemonics (like ['RD', 'RA'])
727 @param ednsflags: a list of strings with edns-flag mnemonics (like ['DO'])"""
729 if not isinstance ( msg
, dns
. message
. Message
):
730 raise TypeError ( "msg is not a dns.message.Message" )
732 if isinstance ( flags
, list ):
734 if not isinstance ( elem
, str ):
735 raise TypeError ( "flags is not a list of strings" )
737 raise TypeError ( "flags is not a list of strings" )
739 if isinstance ( ednsflags
, list ):
740 for elem
in ednsflags
:
741 if not isinstance ( elem
, str ):
742 raise TypeError ( "ednsflags is not a list of strings" )
744 raise TypeError ( "ednsflags is not a list of strings" )
746 msgFlags
= dns
. flags
. to_text ( msg
. flags
). split ()
747 missingFlags
= [ flag
for flag
in flags
if flag
not in msgFlags
]
749 msgEdnsFlags
= dns
. flags
. edns_to_text ( msg
. ednsflags
). split ()
750 missingEdnsFlags
= [ ednsflag
for ednsflag
in ednsflags
if ednsflag
not in msgEdnsFlags
]
752 if len ( missingFlags
) or len ( missingEdnsFlags
) or len ( msgFlags
) > len ( flags
):
753 raise AssertionError ( "Expected flags ' %s ' (EDNS: ' %s '), found ' %s ' (EDNS: ' %s ') in query %s " %
754 ( ' ' . join ( flags
), ' ' . join ( ednsflags
),
755 ' ' . join ( msgFlags
), ' ' . join ( msgEdnsFlags
),
758 def assertMessageIsAuthenticated ( self
, msg
):
759 """Asserts that the message has the AD bit set
761 @param msg: the dns.message.Message to check"""
763 if not isinstance ( msg
, dns
. message
. Message
):
764 raise TypeError ( "msg is not a dns.message.Message" )
766 msgFlags
= dns
. flags
. to_text ( msg
. flags
)
767 self
. assertTrue ( 'AD' in msgFlags
, "No AD flag found in the message for %s " % msg
. question
[ 0 ]. name
)
769 def assertRRsetInAnswer ( self
, msg
, rrset
):
770 """Asserts the rrset (without comparing TTL) exists in the
771 answer section of msg
773 @param msg: the dns.message.Message to check
774 @param rrset: a dns.rrset.RRset object"""
777 if not isinstance ( msg
, dns
. message
. Message
):
778 raise TypeError ( "msg is not a dns.message.Message" )
780 if not isinstance ( rrset
, dns
. rrset
. RRset
):
781 raise TypeError ( "rrset is not a dns.rrset.RRset" )
784 for ans
in msg
. answer
:
785 ret
+= " %s \n " % ans
. to_text ()
786 if ans
. match ( rrset
. name
, rrset
. rdclass
, rrset
. rdtype
, 0 , None ):
787 self
. assertEqual ( ans
, rrset
, "' %s ' != ' %s '" % ( ans
. to_text (), rrset
. to_text ()))
791 raise AssertionError ( "RRset not found in answer \n\n %s " % ret
)
793 def assertMatchingRRSIGInAnswer ( self
, msg
, coveredRRset
, keys
= None ):
794 """Looks for coveredRRset in the answer section and if there is an RRSIG RRset
795 that covers that RRset. If keys is not None, this function will also try to
796 validate the RRset against the RRSIG
798 @param msg: The dns.message.Message to check
799 @param coveredRRset: The RRSet to check for
800 @param keys: a dictionary keyed by dns.name.Name with node or rdataset values to use for validation"""
802 if not isinstance ( msg
, dns
. message
. Message
):
803 raise TypeError ( "msg is not a dns.message.Message" )
805 if not isinstance ( coveredRRset
, dns
. rrset
. RRset
):
806 raise TypeError ( "coveredRRset is not a dns.rrset.RRset" )
812 for ans
in msg
. answer
:
813 ret
+= ans
. to_text () + " \n "
815 if ans
. match ( coveredRRset
. name
, coveredRRset
. rdclass
, coveredRRset
. rdtype
, 0 , None ):
817 if ans
. match ( coveredRRset
. name
, dns
. rdataclass
. IN
, dns
. rdatatype
. RRSIG
, coveredRRset
. rdtype
, None ):
819 if msgRRSet
and msgRRsigRRSet
:
823 raise AssertionError ( "RRset for ' %s ' not found in answer" % msg
. question
[ 0 ]. to_text ())
825 if not msgRRsigRRSet
:
826 raise AssertionError ( "No RRSIGs found in answer for %s : \n Full answer: \n %s " % ( msg
. question
[ 0 ]. to_text (), ret
))
830 dns
. dnssec
. validate ( msgRRSet
, msgRRsigRRSet
. to_rdataset (), keys
)
831 except dns
. dnssec
. ValidationFailure
as e
:
832 raise AssertionError ( "Signature validation failed for %s : \n %s " % ( msg
. question
[ 0 ]. to_text (), e
))
834 def assertNoRRSIGsInAnswer ( self
, msg
):
835 """Checks if there are _no_ RRSIGs in the answer section of msg"""
837 if not isinstance ( msg
, dns
. message
. Message
):
838 raise TypeError ( "msg is not a dns.message.Message" )
841 for ans
in msg
. answer
:
842 if ans
. rdtype
== dns
. rdatatype
. RRSIG
:
843 ret
+= ans
. name
. to_text () + " \n "
846 raise AssertionError ( "RRSIG found in answers for: \n %s " % ret
)
848 def assertAnswerEmpty ( self
, msg
):
849 self
. assertTrue ( len ( msg
. answer
) == 0 , "Data found in the the answer section for %s : \n %s " % ( msg
. question
[ 0 ]. to_text (), ' \n ' . join ([ i
. to_text () for i
in msg
. answer
])))
851 def assertRcodeEqual ( self
, msg
, rcode
):
852 if not isinstance ( msg
, dns
. message
. Message
):
853 raise TypeError ( "msg is not a dns.message.Message but a %s " % type ( msg
))
855 if not isinstance ( rcode
, int ):
856 if isinstance ( rcode
, str ):
857 rcode
= dns
. rcode
. from_text ( rcode
)
859 raise TypeError ( "rcode is neither a str nor int" )
861 if msg
. rcode () != rcode
:
862 msgRcode
= dns
. rcode
._ by
_ value
[ msg
. rcode ()]
863 wantedRcode
= dns
. rcode
._ by
_ value
[ rcode
]
865 raise AssertionError ( "Rcode for %s is %s , expected %s ." % ( msg
. question
[ 0 ]. to_text (), msgRcode
, wantedRcode
))
867 def assertAuthorityHasSOA ( self
, msg
):
868 if not isinstance ( msg
, dns
. message
. Message
):
869 raise TypeError ( "msg is not a dns.message.Message but a %s " % type ( msg
))
872 for rrset
in msg
. authority
:
873 if rrset
. rdtype
== dns
. rdatatype
. SOA
:
878 raise AssertionError ( "No SOA record found in the authority section: \n %s " % msg
. to_text ())
880 def assertResponseMatches ( self
, query
, expectedRRs
, response
):
881 expectedResponse
= dns
. message
. make_response ( query
)
883 if query
. flags
& dns
. flags
. RD
:
884 expectedResponse
. flags |
= dns
. flags
. RA
885 if query
. flags
& dns
. flags
. CD
:
886 expectedResponse
. flags |
= dns
. flags
. CD
888 expectedResponse
. answer
= expectedRRs
889 print ( expectedResponse
)
891 self
. assertEquals ( response
, expectedResponse
)
894 def sendQuery ( cls
, name
, rdtype
, useTCP
= False ):
895 """Helper function that creates the query"""
896 msg
= dns
. message
. make_query ( name
, rdtype
, want_dnssec
= True )
897 msg
. flags |
= dns
. flags
. AD
900 return cls
. sendTCPQuery ( msg
)
901 return cls
. sendUDPQuery ( msg
)
903 def createQuery ( self
, name
, rdtype
, flags
, ednsflags
):
904 """Helper function that creates the query with the specified flags.
905 The flags need to be strings (no checking is performed atm)"""
906 msg
= dns
. message
. make_query ( name
, rdtype
)
907 msg
. flags
= dns
. flags
. from_text ( flags
)
908 msg
. flags
+= dns
. flags
. from_text ( 'RD' )
909 msg
. use_edns ( edns
= 0 , ednsflags
= dns
. flags
. edns_from_text ( ednsflags
))