rubysl-resolv 1.0.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 0c986938060ce85ff5f500d024c015bb3fb76aac
4
- data.tar.gz: 3adf0ca646fbbc18fff5f059f46fb27e6497de96
3
+ metadata.gz: 1f910ca03a2f2e7fc5ba345a15f7e35786dd07b5
4
+ data.tar.gz: 95ab27ed98857c6cc1055b92a6c47d008a9d3ec0
5
5
  SHA512:
6
- metadata.gz: 2f96573ce73b14781b85f0a058ec9a0343b3f16edc9a6216821bd5d7a9a25a6be63815c2b05d589734c2b05cd24e1896114bd26ca84810752a6221d69eba9091
7
- data.tar.gz: ad2990b751425197cc1be5f2cacd81f0940ec9ca397ac52c303796341e427e9f91cac3316f7c3bc6788a51763e8e62799200b071e182c0b748be490e2e5ed07f
6
+ metadata.gz: 8be3e9e9377c375c5bd7a88f3d6c48a7536af1fe6133e939b738f946af57525b6f70fc48993a015c1a5db04e440890bfbe78ce5dc22c9061c058b628ae18a24a
7
+ data.tar.gz: ec78bb44fc70c12de9caee8c9cfa7c9d8542f83b7eda0e43f7bd9dfa86ac38adafd6a7fba69c281993ce82673669534827584f3df96d0763ba28b69678ab387b
data/.travis.yml CHANGED
@@ -3,5 +3,5 @@ env:
3
3
  - RUBYLIB=lib
4
4
  script: bundle exec mspec
5
5
  rvm:
6
- - 1.8.7
7
- - rbx-nightly-18mode
6
+ - 1.9.3
7
+ - rbx-nightly-19mode
@@ -9,28 +9,28 @@ rescue LoadError
9
9
  end
10
10
 
11
11
  # Resolv is a thread-aware DNS resolver library written in Ruby. Resolv can
12
- # handle multiple DNS requests concurrently without blocking. The ruby
12
+ # handle multiple DNS requests concurrently without blocking the entire ruby
13
13
  # interpreter.
14
14
  #
15
- # See also resolv-replace.rb to replace the libc resolver with # Resolv.
16
- #
15
+ # See also resolv-replace.rb to replace the libc resolver with Resolv.
16
+ #
17
17
  # Resolv can look up various DNS resources using the DNS module directly.
18
- #
18
+ #
19
19
  # Examples:
20
- #
20
+ #
21
21
  # p Resolv.getaddress "www.ruby-lang.org"
22
22
  # p Resolv.getname "210.251.121.214"
23
- #
23
+ #
24
24
  # Resolv::DNS.open do |dns|
25
25
  # ress = dns.getresources "www.ruby-lang.org", Resolv::DNS::Resource::IN::A
26
26
  # p ress.map { |r| r.address }
27
27
  # ress = dns.getresources "ruby-lang.org", Resolv::DNS::Resource::IN::MX
28
28
  # p ress.map { |r| [r.exchange.to_s, r.preference] }
29
29
  # end
30
- #
31
- #
30
+ #
31
+ #
32
32
  # == Bugs
33
- #
33
+ #
34
34
  # * NIS is not supported.
35
35
  # * /etc/nsswitch.conf is not supported.
36
36
 
@@ -38,14 +38,14 @@ class Resolv
38
38
 
39
39
  ##
40
40
  # Looks up the first IP address for +name+.
41
-
41
+
42
42
  def self.getaddress(name)
43
43
  DefaultResolver.getaddress(name)
44
44
  end
45
45
 
46
46
  ##
47
47
  # Looks up all IP address for +name+.
48
-
48
+
49
49
  def self.getaddresses(name)
50
50
  DefaultResolver.getaddresses(name)
51
51
  end
@@ -87,7 +87,7 @@ class Resolv
87
87
 
88
88
  ##
89
89
  # Looks up the first IP address for +name+.
90
-
90
+
91
91
  def getaddress(name)
92
92
  each_address(name) {|address| return address}
93
93
  raise ResolvError.new("no address for #{name}")
@@ -95,7 +95,7 @@ class Resolv
95
95
 
96
96
  ##
97
97
  # Looks up all IP address for +name+.
98
-
98
+
99
99
  def getaddresses(name)
100
100
  ret = []
101
101
  each_address(name) {|address| ret << address}
@@ -162,10 +162,10 @@ class Resolv
162
162
  class ResolvTimeout < TimeoutError; end
163
163
 
164
164
  ##
165
- # DNS::Hosts is a hostname resolver that uses the system hosts file.
165
+ # Resolv::Hosts is a hostname resolver that uses the system hosts file.
166
166
 
167
167
  class Hosts
168
- if /mswin32|mingw|bccwin/ =~ RUBY_PLATFORM
168
+ if /mswin|mingw|bccwin/ =~ RUBY_PLATFORM
169
169
  require 'win32/resolv'
170
170
  DefaultFileName = Win32::Resolv.get_hosts_path
171
171
  else
@@ -173,7 +173,7 @@ class Resolv
173
173
  end
174
174
 
175
175
  ##
176
- # Creates a new DNS::Hosts, using +filename+ for its data source.
176
+ # Creates a new Resolv::Hosts, using +filename+ for its data source.
177
177
 
178
178
  def initialize(filename = DefaultFileName)
179
179
  @filename = filename
@@ -289,11 +289,6 @@ class Resolv
289
289
 
290
290
  UDPSize = 512
291
291
 
292
- ##
293
- # Group of DNS resolver threads (obsolete)
294
-
295
- DNSThreadGroup = ThreadGroup.new
296
-
297
292
  ##
298
293
  # Creates a new DNS resolver. See Resolv::DNS.new for argument details.
299
294
  #
@@ -314,10 +309,20 @@ class Resolv
314
309
  # Creates a new DNS resolver.
315
310
  #
316
311
  # +config_info+ can be:
317
- #
312
+ #
318
313
  # nil:: Uses /etc/resolv.conf.
319
314
  # String:: Path to a file using /etc/resolv.conf's format.
320
315
  # Hash:: Must contain :nameserver, :search and :ndots keys.
316
+ # :nameserver_port can be used to specify port number of nameserver address.
317
+ #
318
+ # The value of :nameserver should be an address string or
319
+ # an array of address strings.
320
+ # - :nameserver => '8.8.8.8'
321
+ # - :nameserver => ['8.8.8.8', '8.8.4.4']
322
+ #
323
+ # The value of :nameserver_port should be an array of
324
+ # pair of nameserver address and port number.
325
+ # - :nameserver_port => [['8.8.8.8', 53], ['8.8.4.4', 53]]
321
326
  #
322
327
  # Example:
323
328
  #
@@ -331,6 +336,21 @@ class Resolv
331
336
  @initialized = nil
332
337
  end
333
338
 
339
+ # Sets the resolver timeouts. This may be a single positive number
340
+ # or an array of positive numbers representing timeouts in seconds.
341
+ # If an array is specified, a DNS request will retry and wait for
342
+ # each successive interval in the array until a successful response
343
+ # is received. Specifying +nil+ reverts to the default timeouts:
344
+ # [ 5, second = 5 * 2 / nameserver_count, 2 * second, 4 * second ]
345
+ #
346
+ # Example:
347
+ #
348
+ # dns.timeouts = 3
349
+ #
350
+ def timeouts=(values)
351
+ @config.timeouts = values
352
+ end
353
+
334
354
  def lazy_initialize # :nodoc:
335
355
  @mutex.synchronize {
336
356
  unless @initialized
@@ -384,9 +404,21 @@ class Resolv
384
404
 
385
405
  def each_address(name)
386
406
  each_resource(name, Resource::IN::A) {|resource| yield resource.address}
387
- each_resource(name, Resource::IN::AAAA) {|resource| yield resource.address}
407
+ if use_ipv6?
408
+ each_resource(name, Resource::IN::AAAA) {|resource| yield resource.address}
409
+ end
388
410
  end
389
411
 
412
+ def use_ipv6? # :nodoc:
413
+ begin
414
+ list = Socket.ip_address_list
415
+ rescue NotImplementedError
416
+ return true
417
+ end
418
+ list.any? {|a| a.ipv6? && !a.ipv6_loopback? && !a.ipv6_linklocal? }
419
+ end
420
+ private :use_ipv6?
421
+
390
422
  ##
391
423
  # Gets the hostname for +address+ from the DNS resolver.
392
424
  #
@@ -462,7 +494,7 @@ class Resolv
462
494
  ##
463
495
  # Looks up all +typeclass+ DNS resources for +name+. See #getresource for
464
496
  # argument details.
465
-
497
+
466
498
  def getresources(name, typeclass)
467
499
  ret = []
468
500
  each_resource(name, typeclass) {|resource| ret << resource}
@@ -472,24 +504,36 @@ class Resolv
472
504
  ##
473
505
  # Iterates over all +typeclass+ DNS resources for +name+. See
474
506
  # #getresource for argument details.
475
-
507
+
476
508
  def each_resource(name, typeclass, &proc)
477
509
  lazy_initialize
478
- requester = make_requester
510
+ requester = make_udp_requester
479
511
  senders = {}
480
512
  begin
481
- @config.resolv(name) {|candidate, tout, nameserver|
513
+ @config.resolv(name) {|candidate, tout, nameserver, port|
482
514
  msg = Message.new
483
515
  msg.rd = 1
484
516
  msg.add_question(candidate, typeclass)
485
- unless sender = senders[[candidate, nameserver]]
486
- sender = senders[[candidate, nameserver]] =
487
- requester.sender(msg, candidate, nameserver)
517
+ unless sender = senders[[candidate, nameserver, port]]
518
+ sender = senders[[candidate, nameserver, port]] =
519
+ requester.sender(msg, candidate, nameserver, port)
488
520
  end
489
521
  reply, reply_name = requester.request(sender, tout)
490
522
  case reply.rcode
491
523
  when RCode::NoError
492
- extract_resources(reply, reply_name, typeclass, &proc)
524
+ if reply.tc == 1 and not Requester::TCP === requester
525
+ requester.close
526
+ # Retry via TCP:
527
+ requester = make_tcp_requester(nameserver, port)
528
+ senders = {}
529
+ # This will use TCP for all remaining candidates (assuming the
530
+ # current candidate does not already respond successfully via
531
+ # TCP). This makes sense because we already know the full
532
+ # response will not fit in an untruncated UDP packet.
533
+ redo
534
+ else
535
+ extract_resources(reply, reply_name, typeclass, &proc)
536
+ end
493
537
  return
494
538
  when RCode::NXDomain
495
539
  raise Config::NXDomain.new(reply_name.to_s)
@@ -502,14 +546,19 @@ class Resolv
502
546
  end
503
547
  end
504
548
 
505
- def make_requester # :nodoc:
506
- if nameserver = @config.single?
507
- Requester::ConnectedUDP.new(nameserver)
549
+ def make_udp_requester # :nodoc:
550
+ nameserver_port = @config.nameserver_port
551
+ if nameserver_port.length == 1
552
+ Requester::ConnectedUDP.new(*nameserver_port[0])
508
553
  else
509
- Requester::UnconnectedUDP.new
554
+ Requester::UnconnectedUDP.new(*nameserver_port)
510
555
  end
511
556
  end
512
557
 
558
+ def make_tcp_requester(host, port) # :nodoc:
559
+ return Requester::TCP.new(host, port)
560
+ end
561
+
513
562
  def extract_resources(msg, name, typeclass) # :nodoc:
514
563
  if typeclass < Resource::ANY
515
564
  n0 = Name.create(name)
@@ -565,8 +614,8 @@ class Resolv
565
614
  base + random(len)
566
615
  end
567
616
 
568
- RequestID = {}
569
- RequestIDMutex = Mutex.new
617
+ RequestID = {} # :nodoc:
618
+ RequestIDMutex = Mutex.new # :nodoc:
570
619
 
571
620
  def self.allocate_request_id(host, port) # :nodoc:
572
621
  id = nil
@@ -574,7 +623,7 @@ class Resolv
574
623
  h = (RequestID[[host, port]] ||= {})
575
624
  begin
576
625
  id = rangerand(0x0000..0xffff)
577
- end while h[id]
626
+ end while h[id]
578
627
  h[id] = true
579
628
  }
580
629
  id
@@ -592,10 +641,10 @@ class Resolv
592
641
  }
593
642
  end
594
643
 
595
- def self.bind_random_port(udpsock) # :nodoc:
644
+ def self.bind_random_port(udpsock, bind_host="0.0.0.0") # :nodoc:
596
645
  begin
597
646
  port = rangerand(1024..65535)
598
- udpsock.bind("", port)
647
+ udpsock.bind(bind_host, port)
599
648
  rescue Errno::EADDRINUSE
600
649
  retry
601
650
  end
@@ -604,18 +653,33 @@ class Resolv
604
653
  class Requester # :nodoc:
605
654
  def initialize
606
655
  @senders = {}
607
- @sock = nil
656
+ @socks = nil
608
657
  end
609
658
 
610
659
  def request(sender, tout)
611
- timelimit = Time.now + tout
660
+ start = Time.now
661
+ timelimit = start + tout
612
662
  sender.send
613
- while (now = Time.now) < timelimit
614
- timeout = timelimit - now
615
- if !IO.select([@sock], nil, nil, timeout)
663
+ while true
664
+ before_select = Time.now
665
+ timeout = timelimit - before_select
666
+ if timeout <= 0
667
+ raise ResolvTimeout
668
+ end
669
+ select_result = IO.select(@socks, nil, nil, timeout)
670
+ if !select_result
671
+ after_select = Time.now
672
+ next if after_select < timelimit
673
+ raise ResolvTimeout
674
+ end
675
+ begin
676
+ reply, from = recv_reply(select_result[0])
677
+ rescue Errno::ECONNREFUSED, # GNU/Linux, FreeBSD
678
+ Errno::ECONNRESET # Windows
679
+ # No name server running on the server?
680
+ # Don't wait anymore.
616
681
  raise ResolvTimeout
617
682
  end
618
- reply, from = recv_reply
619
683
  begin
620
684
  msg = Message.decode(reply)
621
685
  rescue DecodeError
@@ -631,9 +695,11 @@ class Resolv
631
695
  end
632
696
 
633
697
  def close
634
- sock = @sock
635
- @sock = nil
636
- sock.close if sock
698
+ socks = @socks
699
+ @socks = nil
700
+ if socks
701
+ socks.each {|sock| sock.close }
702
+ end
637
703
  end
638
704
 
639
705
  class Sender # :nodoc:
@@ -645,15 +711,31 @@ class Resolv
645
711
  end
646
712
 
647
713
  class UnconnectedUDP < Requester # :nodoc:
648
- def initialize
714
+ def initialize(*nameserver_port)
649
715
  super()
650
- @sock = UDPSocket.new
651
- @sock.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC) if defined? Fcntl::F_SETFD
652
- DNS.bind_random_port(@sock)
716
+ @nameserver_port = nameserver_port
717
+ @socks_hash = {}
718
+ @socks = []
719
+ nameserver_port.each {|host, port|
720
+ if host.index(':')
721
+ bind_host = "::"
722
+ af = Socket::AF_INET6
723
+ else
724
+ bind_host = "0.0.0.0"
725
+ af = Socket::AF_INET
726
+ end
727
+ next if @socks_hash[bind_host]
728
+ sock = UDPSocket.new(af)
729
+ sock.do_not_reverse_lookup = true
730
+ sock.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC) if defined? Fcntl::F_SETFD
731
+ DNS.bind_random_port(sock, bind_host)
732
+ @socks << sock
733
+ @socks_hash[bind_host] = sock
734
+ }
653
735
  end
654
736
 
655
- def recv_reply
656
- reply, from = @sock.recvfrom(UDPSize)
737
+ def recv_reply(readable_socks)
738
+ reply, from = readable_socks[0].recvfrom(UDPSize)
657
739
  return reply, [from[3],from[1]]
658
740
  end
659
741
 
@@ -662,8 +744,9 @@ class Resolv
662
744
  id = DNS.allocate_request_id(host, port)
663
745
  request = msg.encode
664
746
  request[0,2] = [id].pack('n')
747
+ sock = @socks_hash[host.index(':') ? "::" : "0.0.0.0"]
665
748
  return @senders[[service, id]] =
666
- Sender.new(request, data, @sock, host, port)
749
+ Sender.new(request, data, sock, host, port)
667
750
  end
668
751
 
669
752
  def close
@@ -692,14 +775,17 @@ class Resolv
692
775
  super()
693
776
  @host = host
694
777
  @port = port
695
- @sock = UDPSocket.new(host.index(':') ? Socket::AF_INET6 : Socket::AF_INET)
696
- DNS.bind_random_port(@sock)
697
- @sock.connect(host, port)
698
- @sock.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC) if defined? Fcntl::F_SETFD
778
+ is_ipv6 = host.index(':')
779
+ sock = UDPSocket.new(is_ipv6 ? Socket::AF_INET6 : Socket::AF_INET)
780
+ @socks = [sock]
781
+ sock.do_not_reverse_lookup = true
782
+ sock.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC) if defined? Fcntl::F_SETFD
783
+ DNS.bind_random_port(sock, is_ipv6 ? "::" : "0.0.0.0")
784
+ sock.connect(host, port)
699
785
  end
700
786
 
701
- def recv_reply
702
- reply = @sock.recv(UDPSize)
787
+ def recv_reply(readable_socks)
788
+ reply = readable_socks[0].recv(UDPSize)
703
789
  return reply, nil
704
790
  end
705
791
 
@@ -710,7 +796,7 @@ class Resolv
710
796
  id = DNS.allocate_request_id(@host, @port)
711
797
  request = msg.encode
712
798
  request[0,2] = [id].pack('n')
713
- return @senders[[nil,id]] = Sender.new(request, data, @sock)
799
+ return @senders[[nil,id]] = Sender.new(request, data, @socks[0])
714
800
  end
715
801
 
716
802
  def close
@@ -733,14 +819,15 @@ class Resolv
733
819
  super()
734
820
  @host = host
735
821
  @port = port
736
- @sock = TCPSocket.new(@host, @port)
737
- @sock.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC) if defined? Fcntl::F_SETFD
822
+ sock = TCPSocket.new(@host, @port)
823
+ @socks = [sock]
824
+ sock.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC) if defined? Fcntl::F_SETFD
738
825
  @senders = {}
739
826
  end
740
827
 
741
- def recv_reply
742
- len = @sock.read(2).unpack('n')[0]
743
- reply = @sock.read(len)
828
+ def recv_reply(readable_socks)
829
+ len = readable_socks[0].read(2).unpack('n')[0]
830
+ reply = @socks[0].read(len)
744
831
  return reply, nil
745
832
  end
746
833
 
@@ -751,7 +838,7 @@ class Resolv
751
838
  id = DNS.allocate_request_id(@host, @port)
752
839
  request = msg.encode
753
840
  request[0,2] = [request.length, id].pack('nn')
754
- return @senders[[nil,id]] = Sender.new(request, data, @sock)
841
+ return @senders[[nil,id]] = Sender.new(request, data, @socks[0])
755
842
  end
756
843
 
757
844
  class Sender < Requester::Sender # :nodoc:
@@ -782,6 +869,20 @@ class Resolv
782
869
  @mutex = Mutex.new
783
870
  @config_info = config_info
784
871
  @initialized = nil
872
+ @timeouts = nil
873
+ end
874
+
875
+ def timeouts=(values)
876
+ if values
877
+ values = Array(values)
878
+ values.each do |t|
879
+ Numeric === t or raise ArgumentError, "#{t.inspect} is not numeric"
880
+ t > 0.0 or raise ArgumentError, "timeout=#{t} must be postive"
881
+ end
882
+ @timeouts = values
883
+ else
884
+ @timeouts = nil
885
+ end
785
886
  end
786
887
 
787
888
  def Config.parse_resolv_conf(filename)
@@ -822,7 +923,7 @@ class Resolv
822
923
  if File.exist? filename
823
924
  config_hash = Config.parse_resolv_conf(filename)
824
925
  else
825
- if /mswin32|cygwin|mingw|bccwin/ =~ RUBY_PLATFORM
926
+ if /mswin|cygwin|mingw|bccwin/ =~ RUBY_PLATFORM
826
927
  require 'win32/resolv'
827
928
  search, nameserver = Win32::Resolv.get_resolv_info
828
929
  config_hash = {}
@@ -830,13 +931,13 @@ class Resolv
830
931
  config_hash[:search] = [search].flatten if search
831
932
  end
832
933
  end
833
- config_hash
934
+ config_hash || {}
834
935
  end
835
936
 
836
937
  def lazy_initialize
837
938
  @mutex.synchronize {
838
939
  unless @initialized
839
- @nameserver = []
940
+ @nameserver_port = []
840
941
  @search = nil
841
942
  @ndots = 1
842
943
  case @config_info
@@ -855,11 +956,18 @@ class Resolv
855
956
  else
856
957
  raise ArgumentError.new("invalid resolv configuration: #{@config_info.inspect}")
857
958
  end
858
- @nameserver = config_hash[:nameserver] if config_hash.include? :nameserver
959
+ if config_hash.include? :nameserver
960
+ @nameserver_port = config_hash[:nameserver].map {|ns| [ns, Port] }
961
+ end
962
+ if config_hash.include? :nameserver_port
963
+ @nameserver_port = config_hash[:nameserver_port].map {|ns, port| [ns, (port || Port)] }
964
+ end
859
965
  @search = config_hash[:search] if config_hash.include? :search
860
966
  @ndots = config_hash[:ndots] if config_hash.include? :ndots
861
967
 
862
- @nameserver = ['0.0.0.0'] if @nameserver.empty?
968
+ if @nameserver_port.empty?
969
+ @nameserver_port << ['0.0.0.0', Port]
970
+ end
863
971
  if @search
864
972
  @search = @search.map {|arg| Label.split(arg) }
865
973
  else
@@ -871,9 +979,14 @@ class Resolv
871
979
  end
872
980
  end
873
981
 
874
- if !@nameserver.kind_of?(Array) ||
875
- !@nameserver.all? {|ns| String === ns }
876
- raise ArgumentError.new("invalid nameserver config: #{@nameserver.inspect}")
982
+ if !@nameserver_port.kind_of?(Array) ||
983
+ @nameserver_port.any? {|ns_port|
984
+ !(Array === ns_port) ||
985
+ ns_port.length != 2
986
+ !(String === ns_port[0]) ||
987
+ !(Integer === ns_port[1])
988
+ }
989
+ raise ArgumentError.new("invalid nameserver config: #{@nameserver_port.inspect}")
877
990
  end
878
991
 
879
992
  if !@search.kind_of?(Array) ||
@@ -893,13 +1006,17 @@ class Resolv
893
1006
 
894
1007
  def single?
895
1008
  lazy_initialize
896
- if @nameserver.length == 1
897
- return @nameserver[0]
1009
+ if @nameserver_port.length == 1
1010
+ return @nameserver_port[0]
898
1011
  else
899
1012
  return nil
900
1013
  end
901
1014
  end
902
1015
 
1016
+ def nameserver_port
1017
+ @nameserver_port
1018
+ end
1019
+
903
1020
  def generate_candidates(name)
904
1021
  candidates = nil
905
1022
  name = Name.create(name)
@@ -920,7 +1037,7 @@ class Resolv
920
1037
 
921
1038
  def generate_timeouts
922
1039
  ts = [InitialTimeout]
923
- ts << ts[-1] * 2 / @nameserver.length
1040
+ ts << ts[-1] * 2 / @nameserver_port.length
924
1041
  ts << ts[-1] * 2
925
1042
  ts << ts[-1] * 2
926
1043
  return ts
@@ -928,14 +1045,14 @@ class Resolv
928
1045
 
929
1046
  def resolv(name)
930
1047
  candidates = generate_candidates(name)
931
- timeouts = generate_timeouts
1048
+ timeouts = @timeouts || generate_timeouts
932
1049
  begin
933
1050
  candidates.each {|candidate|
934
1051
  begin
935
1052
  timeouts.each {|tout|
936
- @nameserver.each {|nameserver|
1053
+ @nameserver_port.each {|nameserver, port|
937
1054
  begin
938
- yield candidate, tout, nameserver
1055
+ yield candidate, tout, nameserver, port
939
1056
  rescue ResolvTimeout
940
1057
  end
941
1058
  }
@@ -1042,7 +1159,7 @@ class Resolv
1042
1159
  # A representation of a DNS name.
1043
1160
 
1044
1161
  class Name
1045
-
1162
+
1046
1163
  ##
1047
1164
  # Creates a new DNS name from +arg+. +arg+ can be:
1048
1165
  #
@@ -1353,6 +1470,10 @@ class Resolv
1353
1470
  yield self
1354
1471
  end
1355
1472
 
1473
+ def inspect
1474
+ "\#<#{self.class}: #{@data[0, @index].inspect} #{@data[@index..-1].inspect}>"
1475
+ end
1476
+
1356
1477
  def get_length16
1357
1478
  len, = self.get_unpack('n')
1358
1479
  save_limit = @limit
@@ -1376,6 +1497,7 @@ class Resolv
1376
1497
  def get_unpack(template)
1377
1498
  len = 0
1378
1499
  template.each_byte {|byte|
1500
+ byte = "%c" % byte
1379
1501
  case byte
1380
1502
  when ?c, ?C
1381
1503
  len += 1
@@ -1394,7 +1516,7 @@ class Resolv
1394
1516
  end
1395
1517
 
1396
1518
  def get_string
1397
- len = @data[@index]
1519
+ len = @data[@index].ord
1398
1520
  raise DecodeError.new("limit exceeded") if @limit < @index + 1 + len
1399
1521
  d = @data[@index + 1, len]
1400
1522
  @index += 1 + len
@@ -1417,7 +1539,7 @@ class Resolv
1417
1539
  limit = @index if !limit || @index < limit
1418
1540
  d = []
1419
1541
  while true
1420
- case @data[@index]
1542
+ case @data[@index].ord
1421
1543
  when 0
1422
1544
  @index += 1
1423
1545
  return d
@@ -1452,7 +1574,9 @@ class Resolv
1452
1574
  name = self.get_name
1453
1575
  type, klass, ttl = self.get_unpack('nnN')
1454
1576
  typeclass = Resource.get_class(type, klass)
1455
- return name, ttl, self.get_length16 {typeclass.decode_rdata(self)}
1577
+ res = self.get_length16 { typeclass.decode_rdata self }
1578
+ res.instance_variable_set :@ttl, ttl
1579
+ return name, ttl, res
1456
1580
  end
1457
1581
  end
1458
1582
  end
@@ -1462,11 +1586,11 @@ class Resolv
1462
1586
 
1463
1587
  class Query
1464
1588
  def encode_rdata(msg) # :nodoc:
1465
- raise EncodeError.new("#{self.class} is query.")
1589
+ raise EncodeError.new("#{self.class} is query.")
1466
1590
  end
1467
1591
 
1468
1592
  def self.decode_rdata(msg) # :nodoc:
1469
- raise DecodeError.new("#{self.class} is query.")
1593
+ raise DecodeError.new("#{self.class} is query.")
1470
1594
  end
1471
1595
  end
1472
1596
 
@@ -1491,10 +1615,16 @@ class Resolv
1491
1615
  end
1492
1616
 
1493
1617
  def ==(other) # :nodoc:
1494
- return self.class == other.class &&
1495
- self.instance_variables == other.instance_variables &&
1496
- self.instance_variables.collect {|name| self.instance_eval name} ==
1497
- other.instance_variables.collect {|name| other.instance_eval name}
1618
+ return false unless self.class == other.class
1619
+ s_ivars = self.instance_variables
1620
+ s_ivars.sort!
1621
+ s_ivars.delete "@ttl"
1622
+ o_ivars = other.instance_variables
1623
+ o_ivars.sort!
1624
+ o_ivars.delete "@ttl"
1625
+ return s_ivars == o_ivars &&
1626
+ s_ivars.collect {|name| self.instance_variable_get name} ==
1627
+ o_ivars.collect {|name| other.instance_variable_get name}
1498
1628
  end
1499
1629
 
1500
1630
  def eql?(other) # :nodoc:
@@ -1503,8 +1633,10 @@ class Resolv
1503
1633
 
1504
1634
  def hash # :nodoc:
1505
1635
  h = 0
1506
- self.instance_variables.each {|name|
1507
- h ^= self.instance_eval("#{name}.hash")
1636
+ vars = self.instance_variables
1637
+ vars.delete "@ttl"
1638
+ vars.each {|name|
1639
+ h ^= self.instance_variable_get(name).hash
1508
1640
  }
1509
1641
  return h
1510
1642
  end
@@ -1933,7 +2065,7 @@ class Resolv
1933
2065
  def initialize(address)
1934
2066
  @address = IPv6.create(address)
1935
2067
  end
1936
-
2068
+
1937
2069
  ##
1938
2070
  # The Resolv::IPv6 address for this AAAA.
1939
2071
 
@@ -1950,7 +2082,7 @@ class Resolv
1950
2082
 
1951
2083
  ##
1952
2084
  # SRV resource record defined in RFC 2782
1953
- #
2085
+ #
1954
2086
  # These records identify the hostname and port that a service is
1955
2087
  # available at.
1956
2088
 
@@ -2033,7 +2165,11 @@ class Resolv
2033
2165
  ##
2034
2166
  # Regular expression IPv4 addresses must match.
2035
2167
 
2036
- Regex = /\A(\d+)\.(\d+)\.(\d+)\.(\d+)\z/
2168
+ Regex256 = /0
2169
+ |1(?:[0-9][0-9]?)?
2170
+ |2(?:[0-4][0-9]?|5[0-5]?|[6-9])?
2171
+ |[3-9][0-9]?/x
2172
+ Regex = /\A(#{Regex256})\.(#{Regex256})\.(#{Regex256})\.(#{Regex256})\z/
2037
2173
 
2038
2174
  def self.create(arg)
2039
2175
  case arg
@@ -2054,8 +2190,11 @@ class Resolv
2054
2190
  end
2055
2191
 
2056
2192
  def initialize(address) # :nodoc:
2057
- unless address.kind_of?(String) && address.length == 4
2058
- raise ArgumentError.new('IPv4 address must be 4 bytes')
2193
+ unless address.kind_of?(String)
2194
+ raise ArgumentError, 'IPv4 address must be a string'
2195
+ end
2196
+ unless address.length == 4
2197
+ raise ArgumentError, "IPv4 address expects 4 bytes but #{address.length} bytes"
2059
2198
  end
2060
2199
  @address = address
2061
2200
  end
@@ -1,5 +1,5 @@
1
1
  module RubySL
2
2
  module Resolv
3
- VERSION = "1.0.0"
3
+ VERSION = "2.0.0"
4
4
  end
5
5
  end
@@ -16,6 +16,8 @@ Gem::Specification.new do |spec|
16
16
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
17
17
  spec.require_paths = ["lib"]
18
18
 
19
+ spec.required_ruby_version = "~> 2.0"
20
+
19
21
  spec.add_development_dependency "bundler", "~> 1.3"
20
22
  spec.add_development_dependency "rake", "~> 10.0"
21
23
  spec.add_development_dependency "mspec", "~> 1.5"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rubysl-resolv
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brian Shirai
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-08-27 00:00:00.000000000 Z
11
+ date: 2013-08-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -84,9 +84,9 @@ require_paths:
84
84
  - lib
85
85
  required_ruby_version: !ruby/object:Gem::Requirement
86
86
  requirements:
87
- - - '>='
87
+ - - ~>
88
88
  - !ruby/object:Gem::Version
89
- version: '0'
89
+ version: '2.0'
90
90
  required_rubygems_version: !ruby/object:Gem::Requirement
91
91
  requirements:
92
92
  - - '>='