1require 'test/unit' 2require 'resolv' 3require 'socket' 4require 'tempfile' 5 6class TestResolvDNS < Test::Unit::TestCase 7 def setup 8 @save_do_not_reverse_lookup = BasicSocket.do_not_reverse_lookup 9 BasicSocket.do_not_reverse_lookup = true 10 end 11 12 def teardown 13 BasicSocket.do_not_reverse_lookup = @save_do_not_reverse_lookup 14 end 15 16 def with_udp(host, port) 17 u = UDPSocket.new 18 begin 19 u.bind(host, port) 20 yield u 21 ensure 22 u.close 23 end 24 end 25 26 def test_query_ipv4_address 27 begin 28 OpenSSL 29 rescue LoadError 30 skip 'autoload problem. see [ruby-dev:45021][Bug #5786]' 31 end if defined?(OpenSSL) 32 33 with_udp('127.0.0.1', 0) {|u| 34 _, server_port, _, server_address = u.addr 35 begin 36 th = Thread.new { 37 Resolv::DNS.open(:nameserver_port => [[server_address, server_port]]) {|dns| 38 dns.getresources("foo.example.org", Resolv::DNS::Resource::IN::A) 39 } 40 } 41 msg, (af, client_port, _, client_address) = u.recvfrom(4096) 42 id, word2, qdcount, ancount, nscount, arcount = msg.unpack("nnnnnn") 43 qr = (word2 & 0x8000) >> 15 44 opcode = (word2 & 0x7800) >> 11 45 aa = (word2 & 0x0400) >> 10 46 tc = (word2 & 0x0200) >> 9 47 rd = (word2 & 0x0100) >> 8 48 ra = (word2 & 0x0080) >> 7 49 z = (word2 & 0x0070) >> 4 50 rcode = word2 & 0x000f 51 rest = msg[12..-1] 52 assert_equal(0, qr) # 0:query 1:response 53 assert_equal(0, opcode) # 0:QUERY 1:IQUERY 2:STATUS 54 assert_equal(0, aa) # Authoritative Answer 55 assert_equal(0, tc) # TrunCation 56 assert_equal(1, rd) # Recursion Desired 57 assert_equal(0, ra) # Recursion Available 58 assert_equal(0, z) # Reserved for future use 59 assert_equal(0, rcode) # 0:No-error 1:Format-error 2:Server-failure 3:Name-Error 4:Not-Implemented 5:Refused 60 assert_equal(1, qdcount) # number of entries in the question section. 61 assert_equal(0, ancount) # number of entries in the answer section. 62 assert_equal(0, nscount) # number of entries in the authority records section. 63 assert_equal(0, arcount) # number of entries in the additional records section. 64 name = [3, "foo", 7, "example", 3, "org", 0].pack("Ca*Ca*Ca*C") 65 assert_operator(rest, :start_with?, name) 66 rest = rest[name.length..-1] 67 assert_equal(4, rest.length) 68 qtype, qclass = rest.unpack("nn") 69 assert_equal(1, qtype) # A 70 assert_equal(1, qtype) # IN 71 id = id 72 qr = 1 73 opcode = opcode 74 aa = 0 75 tc = 0 76 rd = rd 77 ra = 1 78 z = 0 79 rcode = 0 80 qdcount = 0 81 ancount = 1 82 nscount = 0 83 arcount = 0 84 word2 = (qr << 15) | 85 (opcode << 11) | 86 (aa << 10) | 87 (tc << 9) | 88 (rd << 8) | 89 (ra << 7) | 90 (z << 4) | 91 rcode 92 msg = [id, word2, qdcount, ancount, nscount, arcount].pack("nnnnnn") 93 type = 1 94 klass = 1 95 ttl = 3600 96 rdlength = 4 97 rdata = [192,0,2,1].pack("CCCC") # 192.0.2.1 (TEST-NET address) RFC 3330 98 rr = [name, type, klass, ttl, rdlength, rdata].pack("a*nnNna*") 99 msg << rr 100 u.send(msg, 0, client_address, client_port) 101 result = th.value 102 assert_instance_of(Array, result) 103 assert_equal(1, result.length) 104 rr = result[0] 105 assert_instance_of(Resolv::DNS::Resource::IN::A, rr) 106 assert_instance_of(Resolv::IPv4, rr.address) 107 assert_equal("192.0.2.1", rr.address.to_s) 108 assert_equal(3600, rr.ttl) 109 ensure 110 th.join 111 end 112 } 113 end 114 115 def test_query_ipv4_address_timeout 116 with_udp('127.0.0.1', 0) {|u| 117 _, port , _, host = u.addr 118 start = nil 119 rv = Resolv::DNS.open(:nameserver_port => [[host, port]]) {|dns| 120 dns.timeouts = 0.1 121 start = Time.now 122 dns.getresources("foo.example.org", Resolv::DNS::Resource::IN::A) 123 } 124 t2 = Time.now 125 diff = t2 - start 126 assert rv.empty?, "unexpected: #{rv.inspect} (expected empty)" 127 assert_operator 0.1, :<=, diff 128 129 rv = Resolv::DNS.open(:nameserver_port => [[host, port]]) {|dns| 130 dns.timeouts = [ 0.1, 0.2 ] 131 start = Time.now 132 dns.getresources("foo.example.org", Resolv::DNS::Resource::IN::A) 133 } 134 t2 = Time.now 135 diff = t2 - start 136 assert rv.empty?, "unexpected: #{rv.inspect} (expected empty)" 137 assert_operator 0.3, :<=, diff 138 } 139 end 140 141 def test_no_server 142 u = UDPSocket.new 143 u.bind("127.0.0.1", 0) 144 _, port, _, host = u.addr 145 u.close 146 # A rase condition here. 147 # Another program may use the port. 148 # But no way to prevent it. 149 Resolv::DNS.open(:nameserver_port => [[host, port]]) {|dns| 150 assert_equal([], dns.getresources("test-no-server.example.org", Resolv::DNS::Resource::IN::A)) 151 } 152 end 153 154 def test_invalid_byte_comment 155 bug9273 = '[ruby-core:59239] [Bug #9273]' 156 Tempfile.open('resolv_test_dns_') do |tmpfile| 157 tmpfile.print("\xff\x00\x40") 158 tmpfile.close 159 assert_nothing_raised(ArgumentError, bug9273) do 160 Resolv::DNS::Config.parse_resolv_conf(tmpfile.path) 161 end 162 end 163 end 164end 165