summaryrefslogtreecommitdiff
path: root/lib/resolv.rb
diff options
context:
space:
mode:
Diffstat (limited to 'lib/resolv.rb')
-rw-r--r--lib/resolv.rb47
1 files changed, 27 insertions, 20 deletions
diff --git a/lib/resolv.rb b/lib/resolv.rb
index e36dbce259..2aee310feb 100644
--- a/lib/resolv.rb
+++ b/lib/resolv.rb
@@ -513,22 +513,32 @@ class Resolv
def fetch_resource(name, typeclass)
lazy_initialize
- begin
- requester = make_udp_requester
- rescue Errno::EACCES
- # fall back to TCP
- end
+ protocols = {}
+ requesters = {}
senders = {}
begin
- @config.resolv(name) {|candidate, tout, nameserver, port|
- requester ||= make_tcp_requester(nameserver, port)
+ @config.resolv(name) do |candidate, tout, nameserver, port|
msg = Message.new
msg.rd = 1
msg.add_question(candidate, typeclass)
- unless sender = senders[[candidate, nameserver, port]]
+
+ protocol = protocols[candidate] ||= :udp
+ requester = requesters[[protocol, nameserver]] ||=
+ case protocol
+ when :udp
+ begin
+ make_udp_requester
+ rescue Errno::EACCES
+ make_tcp_requester(nameserver, port)
+ end
+ when :tcp
+ make_tcp_requester(nameserver, port)
+ end
+
+ unless sender = senders[[candidate, requester, nameserver, port]]
sender = requester.sender(msg, candidate, nameserver, port)
next if !sender
- senders[[candidate, nameserver, port]] = sender
+ senders[[candidate, requester, nameserver, port]] = sender
end
reply, reply_name = requester.request(sender, tout)
case reply.rcode
@@ -536,12 +546,7 @@ class Resolv
if reply.tc == 1 and not Requester::TCP === requester
requester.close
# Retry via TCP:
- requester = make_tcp_requester(nameserver, port)
- senders = {}
- # This will use TCP for all remaining candidates (assuming the
- # current candidate does not already respond successfully via
- # TCP). This makes sense because we already know the full
- # response will not fit in an untruncated UDP packet.
+ protocols[candidate] = :tcp
redo
else
yield(reply, reply_name)
@@ -552,9 +557,9 @@ class Resolv
else
raise Config::OtherResolvError.new(reply_name.to_s)
end
- }
+ end
ensure
- requester&.close
+ requesters.each_value { |requester| requester&.close }
end
end
@@ -569,6 +574,11 @@ class Resolv
def make_tcp_requester(host, port) # :nodoc:
return Requester::TCP.new(host, port)
+ rescue Errno::ECONNREFUSED
+ # Treat a refused TCP connection attempt to a nameserver like a timeout,
+ # as Resolv::DNS::Config#resolv considers ResolvTimeout exceptions as a
+ # hint to try the next nameserver:
+ raise ResolvTimeout
end
def extract_resources(msg, name, typeclass) # :nodoc:
@@ -1800,7 +1810,6 @@ class Resolv
end
end
-
##
# Base class for SvcParam. [RFC9460]
@@ -2499,7 +2508,6 @@ class Resolv
attr_reader :altitude
-
def encode_rdata(msg) # :nodoc:
msg.put_bytes(@version)
msg.put_bytes(@ssize.scalar)
@@ -3439,4 +3447,3 @@ class Resolv
AddressRegex = /(?:#{IPv4::Regex})|(?:#{IPv6::Regex})/
end
-