[rubygems/rubygems] Use a constant empty tar header to avoid extra allocations
[ruby.git] / test / resolv / test_dns.rb
blob40c5406db8352599ef5bf0f6ba6c4ee743bf658e
1 # frozen_string_literal: false
2 require 'test/unit'
3 require 'resolv'
4 require 'socket'
5 require 'tempfile'
7 class Object # :nodoc:
8   def stub name, val_or_callable, &block
9     new_name = "__minitest_stub__#{name}"
11     metaclass = class << self; self; end
13     if respond_to? name and not methods.map(&:to_s).include? name.to_s then
14       metaclass.send :define_method, name do |*args|
15         super(*args)
16       end
17     end
19     metaclass.send :alias_method, new_name, name
21     metaclass.send :define_method, name do |*args|
22       if val_or_callable.respond_to? :call then
23         val_or_callable.call(*args)
24       else
25         val_or_callable
26       end
27     end
29     yield self
30   ensure
31     metaclass.send :undef_method, name
32     metaclass.send :alias_method, name, new_name
33     metaclass.send :undef_method, new_name
34   end unless method_defined?(:stub) # lib/rubygems/test_case.rb also has the same method definition
35 end
37 class TestResolvDNS < Test::Unit::TestCase
38   def setup
39     @save_do_not_reverse_lookup = BasicSocket.do_not_reverse_lookup
40     BasicSocket.do_not_reverse_lookup = true
41   end
43   def teardown
44     BasicSocket.do_not_reverse_lookup = @save_do_not_reverse_lookup
45   end
47   def with_tcp(host, port)
48     t = TCPServer.new(host, port)
49     begin
50       t.listen(1)
51       yield t
52     ensure
53       t.close
54     end
55   end
57   def with_udp(host, port)
58     u = UDPSocket.new
59     begin
60       u.bind(host, port)
61       yield u
62     ensure
63       u.close
64     end
65   end
67   def with_udp_and_tcp(host, port)
68     if port == 0
69       # Automatic port; we might need to retry until we find a port which is free on both UDP _and_ TCP.
70       retries_remaining = 5
71       t = nil
72       u = nil
73       begin
74         begin
75           u = UDPSocket.new
76           u.bind(host, 0)
77           _, udp_port, _, _ = u.addr
78           t = TCPServer.new(host, udp_port)
79           t.listen(1)
80         rescue Errno::EADDRINUSE, Errno::EACCES
81           # ADDRINUSE is what should get thrown if we try and bind a port which is already bound on UNIXen,
82           # but windows can sometimes throw EACCESS.
83           # See: https://stackoverflow.com/questions/48478869/cannot-bind-to-some-ports-due-to-permission-denied
84           retries_remaining -= 1
85           if retries_remaining > 0
86             t&.close
87             t = nil
88             u&.close
89             u = nil
90             retry
91           end
92           raise
93         end
95         # If we get to this point, we have a valid t & u socket
96         yield u, t
97       ensure
98         t&.close
99         u&.close
100       end
101     else
102       # Explicitly specified port, don't retry the bind.
103       with_udp(host, port) do |u|
104         with_tcp(host, port) do |t|
105           yield u, t
106         end
107       end
108     end
109   end
111   # [ruby-core:65836]
112   def test_resolve_with_2_ndots
113     conf = Resolv::DNS::Config.new :nameserver => ['127.0.0.1'], :ndots => 2
114     assert conf.single?
116     candidates = []
117     conf.resolv('example.com') { |candidate, *args|
118       candidates << candidate
119       raise Resolv::DNS::Config::NXDomain
120     }
121     n = Resolv::DNS::Name.create 'example.com.'
122     assert_equal n, candidates.last
123   end
125   def test_query_ipv4_address
126     begin
127       OpenSSL
128     rescue LoadError
129       omit 'autoload problem. see [ruby-dev:45021][Bug #5786]'
130     end if defined?(OpenSSL)
132     with_udp('127.0.0.1', 0) {|u|
133       _, server_port, _, server_address = u.addr
134       begin
135         client_thread = Thread.new {
136           Resolv::DNS.open(:nameserver_port => [[server_address, server_port]]) {|dns|
137             dns.getresources("foo.example.org", Resolv::DNS::Resource::IN::A)
138           }
139         }
140         server_thread = Thread.new {
141           msg, (_, client_port, _, client_address) = Timeout.timeout(5) {u.recvfrom(4096)}
142           id, word2, qdcount, ancount, nscount, arcount = msg.unpack("nnnnnn")
143           qr =     (word2 & 0x8000) >> 15
144           opcode = (word2 & 0x7800) >> 11
145           aa =     (word2 & 0x0400) >> 10
146           tc =     (word2 & 0x0200) >> 9
147           rd =     (word2 & 0x0100) >> 8
148           ra =     (word2 & 0x0080) >> 7
149           z =      (word2 & 0x0070) >> 4
150           rcode =   word2 & 0x000f
151           rest = msg[12..-1]
152           assert_equal(0, qr) # 0:query 1:response
153           assert_equal(0, opcode) # 0:QUERY 1:IQUERY 2:STATUS
154           assert_equal(0, aa) # Authoritative Answer
155           assert_equal(0, tc) # TrunCation
156           assert_equal(1, rd) # Recursion Desired
157           assert_equal(0, ra) # Recursion Available
158           assert_equal(0, z) # Reserved for future use
159           assert_equal(0, rcode) # 0:No-error 1:Format-error 2:Server-failure 3:Name-Error 4:Not-Implemented 5:Refused
160           assert_equal(1, qdcount) # number of entries in the question section.
161           assert_equal(0, ancount) # number of entries in the answer section.
162           assert_equal(0, nscount) # number of entries in the authority records section.
163           assert_equal(0, arcount) # number of entries in the additional records section.
164           name = [3, "foo", 7, "example", 3, "org", 0].pack("Ca*Ca*Ca*C")
165           assert_operator(rest, :start_with?, name)
166           rest = rest[name.length..-1]
167           assert_equal(4, rest.length)
168           qtype, _ = rest.unpack("nn")
169           assert_equal(1, qtype) # A
170           assert_equal(1, qtype) # IN
171           id = id
172           qr = 1
173           opcode = opcode
174           aa = 0
175           tc = 0
176           rd = rd
177           ra = 1
178           z = 0
179           rcode = 0
180           qdcount = 0
181           ancount = 1
182           nscount = 0
183           arcount = 0
184           word2 = (qr << 15) |
185                   (opcode << 11) |
186                   (aa << 10) |
187                   (tc << 9) |
188                   (rd << 8) |
189                   (ra << 7) |
190                   (z << 4) |
191                   rcode
192           msg = [id, word2, qdcount, ancount, nscount, arcount].pack("nnnnnn")
193           type = 1
194           klass = 1
195           ttl = 3600
196           rdlength = 4
197           rdata = [192,0,2,1].pack("CCCC") # 192.0.2.1 (TEST-NET address) RFC 3330
198           rr = [name, type, klass, ttl, rdlength, rdata].pack("a*nnNna*")
199           msg << rr
200           u.send(msg, 0, client_address, client_port)
201         }
202         result, _ = assert_join_threads([client_thread, server_thread])
203         assert_instance_of(Array, result)
204         assert_equal(1, result.length)
205         rr = result[0]
206         assert_instance_of(Resolv::DNS::Resource::IN::A, rr)
207         assert_instance_of(Resolv::IPv4, rr.address)
208         assert_equal("192.0.2.1", rr.address.to_s)
209         assert_equal(3600, rr.ttl)
210       end
211     }
212   end
214   def test_query_ipv4_address_truncated_tcp_fallback
215     begin
216       OpenSSL
217     rescue LoadError
218       skip 'autoload problem. see [ruby-dev:45021][Bug #5786]'
219     end if defined?(OpenSSL)
221     num_records = 50
223     with_udp_and_tcp('127.0.0.1', 0) {|u, t|
224       _, server_port, _, server_address = u.addr
225       client_thread = Thread.new {
226         Resolv::DNS.open(:nameserver_port => [[server_address, server_port]]) {|dns|
227           dns.getresources("foo.example.org", Resolv::DNS::Resource::IN::A)
228         }
229       }
230       udp_server_thread = Thread.new {
231         msg, (_, client_port, _, client_address) = Timeout.timeout(5) {u.recvfrom(4096)}
232         id, word2, qdcount, ancount, nscount, arcount = msg.unpack("nnnnnn")
233         qr =     (word2 & 0x8000) >> 15
234         opcode = (word2 & 0x7800) >> 11
235         aa =     (word2 & 0x0400) >> 10
236         tc =     (word2 & 0x0200) >> 9
237         rd =     (word2 & 0x0100) >> 8
238         ra =     (word2 & 0x0080) >> 7
239         z =      (word2 & 0x0070) >> 4
240         rcode =   word2 & 0x000f
241         rest = msg[12..-1]
242         assert_equal(0, qr) # 0:query 1:response
243         assert_equal(0, opcode) # 0:QUERY 1:IQUERY 2:STATUS
244         assert_equal(0, aa) # Authoritative Answer
245         assert_equal(0, tc) # TrunCation
246         assert_equal(1, rd) # Recursion Desired
247         assert_equal(0, ra) # Recursion Available
248         assert_equal(0, z) # Reserved for future use
249         assert_equal(0, rcode) # 0:No-error 1:Format-error 2:Server-failure 3:Name-Error 4:Not-Implemented 5:Refused
250         assert_equal(1, qdcount) # number of entries in the question section.
251         assert_equal(0, ancount) # number of entries in the answer section.
252         assert_equal(0, nscount) # number of entries in the authority records section.
253         assert_equal(0, arcount) # number of entries in the additional records section.
254         name = [3, "foo", 7, "example", 3, "org", 0].pack("Ca*Ca*Ca*C")
255         assert_operator(rest, :start_with?, name)
256         rest = rest[name.length..-1]
257         assert_equal(4, rest.length)
258         qtype, _ = rest.unpack("nn")
259         assert_equal(1, qtype) # A
260         assert_equal(1, qtype) # IN
261         id = id
262         qr = 1
263         opcode = opcode
264         aa = 0
265         tc = 1
266         rd = rd
267         ra = 1
268         z = 0
269         rcode = 0
270         qdcount = 0
271         ancount = num_records
272         nscount = 0
273         arcount = 0
274         word2 = (qr << 15) |
275                 (opcode << 11) |
276                 (aa << 10) |
277                 (tc << 9) |
278                 (rd << 8) |
279                 (ra << 7) |
280                 (z << 4) |
281                 rcode
282         msg = [id, word2, qdcount, ancount, nscount, arcount].pack("nnnnnn")
283         type = 1
284         klass = 1
285         ttl = 3600
286         rdlength = 4
287         num_records.times do |i|
288           rdata = [192,0,2,i].pack("CCCC") # 192.0.2.x (TEST-NET address) RFC 3330
289           rr = [name, type, klass, ttl, rdlength, rdata].pack("a*nnNna*")
290           msg << rr
291         end
292         u.send(msg[0...512], 0, client_address, client_port)
293       }
294       tcp_server_thread = Thread.new {
295         ct = t.accept
296         msg = ct.recv(512)
297         msg.slice!(0..1) # Size (only for TCP)
298         id, word2, qdcount, ancount, nscount, arcount = msg.unpack("nnnnnn")
299         qr =     (word2 & 0x8000) >> 15
300         opcode = (word2 & 0x7800) >> 11
301         aa =     (word2 & 0x0400) >> 10
302         tc =     (word2 & 0x0200) >> 9
303         rd =     (word2 & 0x0100) >> 8
304         ra =     (word2 & 0x0080) >> 7
305         z =      (word2 & 0x0070) >> 4
306         rcode =   word2 & 0x000f
307         rest = msg[12..-1]
308         assert_equal(0, qr) # 0:query 1:response
309         assert_equal(0, opcode) # 0:QUERY 1:IQUERY 2:STATUS
310         assert_equal(0, aa) # Authoritative Answer
311         assert_equal(0, tc) # TrunCation
312         assert_equal(1, rd) # Recursion Desired
313         assert_equal(0, ra) # Recursion Available
314         assert_equal(0, z) # Reserved for future use
315         assert_equal(0, rcode) # 0:No-error 1:Format-error 2:Server-failure 3:Name-Error 4:Not-Implemented 5:Refused
316         assert_equal(1, qdcount) # number of entries in the question section.
317         assert_equal(0, ancount) # number of entries in the answer section.
318         assert_equal(0, nscount) # number of entries in the authority records section.
319         assert_equal(0, arcount) # number of entries in the additional records section.
320         name = [3, "foo", 7, "example", 3, "org", 0].pack("Ca*Ca*Ca*C")
321         assert_operator(rest, :start_with?, name)
322         rest = rest[name.length..-1]
323         assert_equal(4, rest.length)
324         qtype, _ = rest.unpack("nn")
325         assert_equal(1, qtype) # A
326         assert_equal(1, qtype) # IN
327         id = id
328         qr = 1
329         opcode = opcode
330         aa = 0
331         tc = 0
332         rd = rd
333         ra = 1
334         z = 0
335         rcode = 0
336         qdcount = 0
337         ancount = num_records
338         nscount = 0
339         arcount = 0
340         word2 = (qr << 15) |
341                 (opcode << 11) |
342                 (aa << 10) |
343                 (tc << 9) |
344                 (rd << 8) |
345                 (ra << 7) |
346                 (z << 4) |
347                 rcode
348         msg = [id, word2, qdcount, ancount, nscount, arcount].pack("nnnnnn")
349         type = 1
350         klass = 1
351         ttl = 3600
352         rdlength = 4
353         num_records.times do |i|
354           rdata = [192,0,2,i].pack("CCCC") # 192.0.2.x (TEST-NET address) RFC 3330
355           rr = [name, type, klass, ttl, rdlength, rdata].pack("a*nnNna*")
356           msg << rr
357         end
358         msg = "#{[msg.bytesize].pack("n")}#{msg}" # Prefix with size
359         ct.send(msg, 0)
360         ct.close
361       }
362       result, _ = assert_join_threads([client_thread, udp_server_thread, tcp_server_thread])
363       assert_instance_of(Array, result)
364       assert_equal(50, result.length)
365       result.each_with_index do |rr, i|
366         assert_instance_of(Resolv::DNS::Resource::IN::A, rr)
367         assert_instance_of(Resolv::IPv4, rr.address)
368         assert_equal("192.0.2.#{i}", rr.address.to_s)
369         assert_equal(3600, rr.ttl)
370       end
371     }
372   end
374   def test_query_ipv4_duplicate_responses
375     begin
376       OpenSSL
377     rescue LoadError
378       omit 'autoload problem. see [ruby-dev:45021][Bug #5786]'
379     end if defined?(OpenSSL)
381     with_udp('127.0.0.1', 0) {|u|
382       _, server_port, _, server_address = u.addr
383       begin
384         client_thread = Thread.new {
385           Resolv::DNS.open(:nameserver_port => [[server_address, server_port]], :search => ['bad1.com', 'bad2.com', 'good.com'], ndots: 5) {|dns|
386             dns.getaddress("example")
387           }
388         }
389         server_thread = Thread.new {
390           3.times do
391             msg, (_, client_port, _, client_address) = Timeout.timeout(5) {u.recvfrom(4096)}
392             id, flags, qdcount, ancount, nscount, arcount = msg.unpack("nnnnnn")
394             qr =     (flags & 0x8000) >> 15
395             opcode = (flags & 0x7800) >> 11
396             aa =     (flags & 0x0400) >> 10
397             tc =     (flags & 0x0200) >> 9
398             rd =     (flags & 0x0100) >> 8
399             ra =     (flags & 0x0080) >> 7
400             z =      (flags & 0x0070) >> 4
401             rcode =   flags & 0x000f
402             _rest = msg[12..-1]
404             questions = msg.bytes[12..-1]
405             labels = []
406             idx = 0
407             while idx < questions.length-5
408               size = questions[idx]
409               labels << questions[idx+1..idx+size].pack('c*')
410               idx += size+1
411             end
412             hostname = labels.join('.')
414             if hostname == "example.good.com"
415               id = id
416               qr = 1
417               opcode = opcode
418               aa = 0
419               tc = 0
420               rd = rd
421               ra = 1
422               z = 0
423               rcode = 0
424               qdcount = 1
425               ancount = 1
426               nscount = 0
427               arcount = 0
428               word2 = (qr << 15) |
429                       (opcode << 11) |
430                       (aa << 10) |
431                       (tc << 9) |
432                       (rd << 8) |
433                       (ra << 7) |
434                       (z << 4) |
435                       rcode
436               msg = [id, word2, qdcount, ancount, nscount, arcount].pack("nnnnnn")
437               msg << questions.pack('c*')
438               type = 1
439               klass = 1
440               ttl = 3600
441               rdlength = 4
442               rdata = [52,0,2,1].pack("CCCC")
443               rr = [0xc00c, type, klass, ttl, rdlength, rdata].pack("nnnNna*")
444               msg << rr
445               rdata = [52,0,2,2].pack("CCCC")
446               rr = [0xc00c, type, klass, ttl, rdlength, rdata].pack("nnnNna*")
447               msg << rr
449               u.send(msg, 0, client_address, client_port)
450             else
451               id = id
452               qr = 1
453               opcode = opcode
454               aa = 0
455               tc = 0
456               rd = rd
457               ra = 1
458               z = 0
459               rcode = 3
460               qdcount = 1
461               ancount = 0
462               nscount = 0
463               arcount = 0
464               word2 = (qr << 15) |
465                       (opcode << 11) |
466                       (aa << 10) |
467                       (tc << 9) |
468                       (rd << 8) |
469                       (ra << 7) |
470                       (z << 4) |
471                       rcode
472               msg = [id, word2, qdcount, ancount, nscount, arcount].pack("nnnnnn")
473               msg << questions.pack('c*')
475               u.send(msg, 0, client_address, client_port)
476               u.send(msg, 0, client_address, client_port)
477             end
478           end
479         }
480         result, _ = assert_join_threads([client_thread, server_thread])
481         assert_instance_of(Resolv::IPv4, result)
482         assert_equal("52.0.2.1", result.to_s)
483       end
484     }
485   end
487   def test_query_ipv4_address_timeout
488     with_udp('127.0.0.1', 0) {|u|
489       _, port , _, host = u.addr
490       start = nil
491       rv = Resolv::DNS.open(:nameserver_port => [[host, port]]) {|dns|
492         dns.timeouts = 0.1
493         start = Time.now
494         dns.getresources("foo.example.org", Resolv::DNS::Resource::IN::A)
495       }
496       t2 = Time.now
497       diff = t2 - start
498       assert rv.empty?, "unexpected: #{rv.inspect} (expected empty)"
499       assert_operator 0.1, :<=, diff
501       rv = Resolv::DNS.open(:nameserver_port => [[host, port]]) {|dns|
502         dns.timeouts = [ 0.1, 0.2 ]
503         start = Time.now
504         dns.getresources("foo.example.org", Resolv::DNS::Resource::IN::A)
505       }
506       t2 = Time.now
507       diff = t2 - start
508       assert rv.empty?, "unexpected: #{rv.inspect} (expected empty)"
509       assert_operator 0.3, :<=, diff
510     }
511   end
513   def test_no_server
514     omit if /mswin/ =~ RUBY_PLATFORM && ENV.key?('GITHUB_ACTIONS') # not working from the beginning
515     u = UDPSocket.new
516     u.bind("127.0.0.1", 0)
517     _, port, _, host = u.addr
518     u.close
519     # A race condition here.
520     # Another program may use the port.
521     # But no way to prevent it.
522     begin
523       Timeout.timeout(5) do
524         Resolv::DNS.open(:nameserver_port => [[host, port]]) {|dns|
525           assert_equal([], dns.getresources("test-no-server.example.org", Resolv::DNS::Resource::IN::A))
526         }
527       end
528     rescue Timeout::Error
529       if RUBY_PLATFORM.match?(/mingw/)
530         # cannot repo locally
531         omit 'Timeout Error on MinGW CI'
532       else
533         raise Timeout::Error
534       end
535     end
536   end
538   def test_invalid_byte_comment
539     bug9273 = '[ruby-core:59239] [Bug #9273]'
540     Tempfile.create('resolv_test_dns_') do |tmpfile|
541       tmpfile.print("\xff\x00\x40")
542       tmpfile.close
543       assert_nothing_raised(ArgumentError, bug9273) do
544         Resolv::DNS::Config.parse_resolv_conf(tmpfile.path)
545       end
546     end
547   end
549   def test_resolv_conf_by_command
550     Dir.mktmpdir do |dir|
551       Dir.chdir(dir) do
552         assert_raise(Errno::ENOENT, Errno::EINVAL) do
553           Resolv::DNS::Config.parse_resolv_conf("|echo foo")
554         end
555       end
556     end
557   end
559   def test_dots_diffences
560     name1 = Resolv::DNS::Name.create("example.org")
561     name2 = Resolv::DNS::Name.create("ex.ampl.eo.rg")
562     assert_not_equal(name1, name2, "different dots")
563   end
565   def test_case_insensitive_name
566     bug10550 = '[ruby-core:66498] [Bug #10550]'
567     lower = Resolv::DNS::Name.create("ruby-lang.org")
568     upper = Resolv::DNS::Name.create("Ruby-Lang.org")
569     assert_equal(lower, upper, bug10550)
570   end
572   def test_ipv6_name
573     addr = Resolv::IPv6.new("\0"*16)
574     labels = addr.to_name.to_a
575     expected = (['0'] * 32 + ['ip6', 'arpa']).map {|label| Resolv::DNS::Label::Str.new(label) }
576     assert_equal(expected, labels)
577   end
579   def test_ipv6_create
580     ref = '[Bug #11910] [ruby-core:72559]'
581     assert_instance_of Resolv::IPv6, Resolv::IPv6.create('::1'), ref
582     assert_instance_of Resolv::IPv6, Resolv::IPv6.create('::1:127.0.0.1'), ref
583   end
585   def test_ipv6_to_s
586     test_cases = [
587       ["2001::abcd:abcd:abcd", "2001::ABcd:abcd:ABCD"],
588       ["2001:db8::1", "2001:db8::0:1"],
589       ["::", "0:0:0:0:0:0:0:0"],
590       ["2001::", "2001::0"],
591       ["2001:db8:0:1:1:1:1:1", "2001:db8:0:1:1:1:1:1"], # RFC 5952 Section 4.2.2.
592       ["2001:db8::1:1:1:1", "2001:db8:0:0:1:1:1:1"],
593       ["1::1:0:0:0:1", "1:0:0:1:0:0:0:1"],
594       ["1::1:0:0:1", "1:0:0:0:1:0:0:1"],
595     ]
597     test_cases.each do |expected, ipv6|
598       assert_equal expected, Resolv::IPv6.create(ipv6).to_s
599     end
600   end
602   def test_ipv6_should_be_16
603     ref = '[rubygems:1626]'
605     broken_message =
606       "\0\0\0\0\0\0\0\0\0\0\0\1" \
607       "\x03ns2\bdnsimple\x03com\x00" \
608       "\x00\x1C\x00\x01\x00\x02OD" \
609       "\x00\x10$\x00\xCB\x00 I\x00\x01\x00\x00\x00\x00"
611     e = assert_raise_with_message(Resolv::DNS::DecodeError, /IPv6 address must be 16 bytes/, ref) do
612       Resolv::DNS::Message.decode broken_message
613     end
614     assert_kind_of(ArgumentError, e.cause)
615   end
617   def test_too_big_label_address
618     n = 2000
619     m = Resolv::DNS::Message::MessageEncoder.new {|msg|
620       2.times {
621         n.times {|i| msg.put_labels(["foo#{i}"]) }
622       }
623     }
624     Resolv::DNS::Message::MessageDecoder.new(m.to_s) {|msg|
625       2.times {
626         n.times {|i|
627           assert_equal(["foo#{i}"], msg.get_labels.map {|label| label.to_s })
628         }
629       }
630     }
631     assert_operator(2**14, :<, m.to_s.length)
632   end
634   def assert_no_fd_leak
635     socket = assert_throw(self) do |tag|
636       Resolv::DNS.stub(:bind_random_port, ->(s, *) {throw(tag, s)}) do
637         yield.getname("8.8.8.8")
638       end
639     end
641     assert_predicate(socket, :closed?, "file descriptor leaked")
642   end
644   def test_no_fd_leak_connected
645     assert_no_fd_leak {Resolv::DNS.new(nameserver_port: [['127.0.0.1', 53]])}
646   end
648   def test_no_fd_leak_unconnected
649     assert_no_fd_leak {Resolv::DNS.new}
650   end
652   def test_each_name
653     dns = Resolv::DNS.new
654     def dns.each_resource(name, typeclass)
655       yield typeclass.new(name)
656     end
658     dns.each_name('127.0.0.1') do |ptr|
659       assert_equal('1.0.0.127.in-addr.arpa', ptr.to_s)
660     end
661     dns.each_name(Resolv::IPv4.create('127.0.0.1')) do |ptr|
662       assert_equal('1.0.0.127.in-addr.arpa', ptr.to_s)
663     end
664     dns.each_name('::1') do |ptr|
665       assert_equal('1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa', ptr.to_s)
666     end
667     dns.each_name(Resolv::IPv6.create('::1')) do |ptr|
668       assert_equal('1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa', ptr.to_s)
669     end
670     dns.each_name(Resolv::DNS::Name.create('1.0.0.127.in-addr.arpa.')) do |ptr|
671       assert_equal('1.0.0.127.in-addr.arpa', ptr.to_s)
672     end
673     assert_raise(Resolv::ResolvError) { dns.each_name('example.com') }
674   end
676   def test_unreachable_server
677     unreachable_ip = '127.0.0.1'
678     sock = UDPSocket.new
679     sock.connect(unreachable_ip, 53)
680     begin
681       sock.send('1', 0)
682     rescue Errno::ENETUNREACH, Errno::EHOSTUNREACH
683     else
684       omit('cannot test unreachable server, as IP used is reachable')
685     end
687     config = {
688       :nameserver => [unreachable_ip],
689       :search => ['lan'],
690       :ndots => 1
691     }
692     r = Resolv.new([Resolv::DNS.new(config)])
693     assert_equal([], r.getaddresses('www.google.com'))
695     config[:raise_timeout_errors] = true
696     r = Resolv.new([Resolv::DNS.new(config)])
697     assert_raise(Resolv::ResolvError) { r.getaddresses('www.google.com') }
698   ensure
699     sock&.close
700   end