@@ -457,4 +457,118 @@ def dns.each_resource(name, typeclass)
457
457
end
458
458
assert_raise ( Resolv ::ResolvError ) { dns . each_name ( 'example.com' ) }
459
459
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