@@ -457,4 +457,118 @@ def dns.each_resource(name, typeclass)
457457 end
458458 assert_raise ( Resolv ::ResolvError ) { dns . each_name ( 'example.com' ) }
459459 end
460- end
460+
461+ def test_query_ipv4_try_next_dns_if_first_answers_with_servfail
462+ begin
463+ OpenSSL
464+ rescue LoadError
465+ omit 'autoload problem. see [ruby-dev:45021][Bug #5786]'
466+ end if defined? ( OpenSSL )
467+
468+ with_udp ( '127.0.0.1' , 0 ) { |first |
469+ with_udp ( '127.0.0.1' , 0 ) { |second |
470+ _ , server_one_port , _ , server_one_address = first . addr
471+ _ , server_two_port , _ , server_two_address = second . addr
472+ begin
473+ client_thread = Thread . new {
474+ Resolv ::DNS . open ( :nameserver_port => [ [ server_one_address , server_one_port ] , [ server_two_address , server_two_port ] ] ) . getaddress ( "example.org" )
475+ }
476+ server_one_thread = Thread . new {
477+ msg , ( _ , client_port , _ , client_address ) = Timeout . timeout ( 5 ) { first . recvfrom ( 4096 ) }
478+ id , flags , qdcount , ancount , nscount , arcount = msg . unpack ( "nnnnnn" )
479+
480+ qr = ( flags & 0x8000 ) >> 15
481+ opcode = ( flags & 0x7800 ) >> 11
482+ aa = ( flags & 0x0400 ) >> 10
483+ tc = ( flags & 0x0200 ) >> 9
484+ rd = ( flags & 0x0100 ) >> 8
485+ ra = ( flags & 0x0080 ) >> 7
486+ z = ( flags & 0x0070 ) >> 4
487+ rcode = flags & 0x000f
488+ _rest = msg [ 12 ..-1 ]
489+ questions = msg . bytes [ 12 ..-1 ]
490+
491+ id = id
492+ qr = 1
493+ opcode = opcode
494+ aa = 0
495+ tc = 0
496+ rd = rd
497+ ra = 1
498+ z = 0
499+ rcode = 2 # ServFail
500+ qdcount = 1
501+ ancount = 0
502+ nscount = 0
503+ arcount = 0
504+ word2 = ( qr << 15 ) |
505+ ( opcode << 11 ) |
506+ ( aa << 10 ) |
507+ ( tc << 9 ) |
508+ ( rd << 8 ) |
509+ ( ra << 7 ) |
510+ ( z << 4 ) |
511+ rcode
512+ msg = [ id , word2 , qdcount , ancount , nscount , arcount ] . pack ( "nnnnnn" )
513+ msg << questions . pack ( 'c*' )
514+
515+ first . send ( msg , 0 , client_address , client_port )
516+ }
517+ server_two_thread = Thread . new {
518+ msg , ( _ , client_port , _ , client_address ) = Timeout . timeout ( 5 ) { second . recvfrom ( 4096 ) }
519+ id , flags , qdcount , ancount , nscount , arcount = msg . unpack ( "nnnnnn" )
520+
521+ qr = ( flags & 0x8000 ) >> 15
522+ opcode = ( flags & 0x7800 ) >> 11
523+ aa = ( flags & 0x0400 ) >> 10
524+ tc = ( flags & 0x0200 ) >> 9
525+ rd = ( flags & 0x0100 ) >> 8
526+ ra = ( flags & 0x0080 ) >> 7
527+ z = ( flags & 0x0070 ) >> 4
528+ rcode = flags & 0x000f
529+ _rest = msg [ 12 ..-1 ]
530+
531+ questions = msg . bytes [ 12 ..-1 ]
532+
533+ id = id
534+ qr = 1
535+ opcode = opcode
536+ aa = 0
537+ tc = 0
538+ rd = rd
539+ ra = 1
540+ z = 0
541+ rcode = 0 # NoError
542+ qdcount = 1
543+ ancount = 1
544+ nscount = 0
545+ arcount = 0
546+ word2 = ( qr << 15 ) |
547+ ( opcode << 11 ) |
548+ ( aa << 10 ) |
549+ ( tc << 9 ) |
550+ ( rd << 8 ) |
551+ ( ra << 7 ) |
552+ ( z << 4 ) |
553+ rcode
554+ msg = [ id , word2 , qdcount , ancount , nscount , arcount ] . pack ( "nnnnnn" )
555+ msg << questions . pack ( 'c*' )
556+ type = 1
557+ klass = 1
558+ ttl = 3600
559+ rdlength = 4
560+ rdata = [ 52 , 0 , 2 , 1 ] . pack ( "CCCC" )
561+ rr = [ 0xc00c , type , klass , ttl , rdlength , rdata ] . pack ( "nnnNna*" )
562+ msg << rr
563+
564+ second . send ( msg , 0 , client_address , client_port )
565+ }
566+ result , _ , _ = assert_join_threads ( [ client_thread , server_one_thread , server_two_thread ] )
567+
568+ assert_instance_of ( Resolv ::IPv4 , result )
569+ assert_equal ( "52.0.2.1" , result . to_s )
570+ end
571+ }
572+ }
573+ end
574+ end
0 commit comments