Bug #8285 ยป ruby-trunk-8285-resolv-tcp-fallback-fix.diff
lib/resolv.rb (working copy) | ||
---|---|---|
def fetch_resource(name, typeclass)
|
||
lazy_initialize
|
||
requester = make_udp_requester
|
||
protocols = {}
|
||
requesters = {}
|
||
senders = {}
|
||
begin
|
||
@config.resolv(name) {|candidate, tout, nameserver, port|
|
||
msg = Message.new
|
||
msg.rd = 1
|
||
msg.add_question(candidate, typeclass)
|
||
unless sender = senders[[candidate, nameserver, port]]
|
||
sender = senders[[candidate, nameserver, port]] =
|
||
protocol = protocols[candidate| ||= :udp
|
||
requester = requesters[[protocol, nameserver]] ||= case protocol
|
||
when :udp then make_udp_requester
|
||
when :tcp then make_tcp_requester(nameserver, port)
|
||
end
|
||
sender = senders[[candidate, requester, nameserver, port]] ||=
|
||
requester.sender(msg, candidate, nameserver, port)
|
||
end
|
||
reply, reply_name = requester.request(sender, tout)
|
||
case reply.rcode
|
||
when RCode::NoError
|
||
if reply.tc == 1 and not Requester::TCP === requester
|
||
requester.close
|
||
if protocol == :udp and reply.tc == 1
|
||
# 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)
|
||
... | ... | |
end
|
||
}
|
||
ensure
|
||
requester.close
|
||
requesters.each_value { |requester| requester.close }
|
||
end
|
||
end
|
||
def make_udp_requester # :nodoc:
|
||
nameserver_port = @config.nameserver_port
|
||
... | ... | |
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:
|