Let Resolver#send_tcp take a block

This solves the looping problem. Since the TCP connection wouldn't
necessarily close, we couldn't count on a 0-length recv, and the
connection was timing out. Changed it so send_tcp can take a block, in
which we do parsing. AXFR responses are sandwiched between SOA answers,
so when the second one is reached, the transfer is done.

This is also cleaner for existing code that uses send_tcp, since if no
block is passed, it just returns the first response and tears down the
connection, just like it used to.
unstable
Daniel Miller 2012-08-20 20:51:18 -05:00
parent c015121dc0
commit 1aa83b830f
1 changed files with 33 additions and 26 deletions

View File

@ -1019,27 +1019,29 @@ module Net # :nodoc:
method = :send_tcp
end
ans = self.old_send(method, packet, packet_data)
answers = []
soa = 0
self.old_send(method, packet, packet_data) do |ans|
@logger.info "Received #{ans[0].size} bytes from #{ans[1][2]+":"+ans[1][1].to_s}"
unless ans
begin
response = Net::DNS::Packet.parse(ans[0],ans[1])
if response.answer[0].type == "SOA"
soa += 1
if soa >= 2
break
end
end
answers << response
rescue NameError => e
@logger.warn "Error parsing axfr response: #{e.message}"
end
end
if answers.empty?
@logger.fatal "No response from nameservers list: aborting"
raise NoResponseError
end
@logger.info "Received #{ans[0].size} bytes from #{ans[1][2]+":"+ans[1][1].to_s}"
pos = 0
begin
while pos < buffer.size
len = buffer.unpack("n")[0]
response = Net::DNS::Packet.parse(ans[0][pos,len],ans[1])
pos += len
answers << response
end
rescue NameError => e
@logger.warn "Error parsing axfr response: #{e.message}"
end
return answers
end
@ -1166,21 +1168,22 @@ module Net # :nodoc:
@config[:tcp_timeout].timeout do
catch "next nameserver" do
buffer = ""
socket.connect(sockaddr)
@logger.info "Contacting nameserver #{ns} port #{@config[:port]}"
socket.write(length+packet_data)
got_something = false
loop do
ansbuf = ""
buffer = ""
ans = socket.recv(Net::DNS::INT16SZ)
if ans.size == 0
if buffer.size > 0
if got_something
break #Proper exit from loop
else
@logger.warn "Connection reset to namserver #{ns}, trying next."
@logger.warn "Connection reset to nameserver #{ns}, trying next."
throw "next nameserver"
end
end
got_something = true
len = ans.unpack("n")[0]
@logger.info "Receiving #{len} bytes..."
@ -1190,20 +1193,23 @@ module Net # :nodoc:
throw "next nameserver"
end
while (ansbuf.size < len)
left = len - ansbuf.size
while (buffer.size < len)
left = len - buffer.size
temp,from = socket.recvfrom(left)
ansbuf += temp
buffer += temp
end
unless ansbuf.size == len
unless buffer.size == len
@logger.warn "Malformed packet from nameserver #{ns}, trying next."
throw "next nameserver"
end
buffer += ansbuf
if block_given?
yield [buffer,["",@config[:port],ns.to_s,ns.to_s]]
else
return [buffer,["",@config[:port],ns.to_s,ns.to_s]]
end
end
end
return [buffer,["",@config[:port],ns.to_s,ns.to_s]]
end
rescue Timeout::Error
@logger.warn "Nameserver #{ns} not responding within TCP timeout, trying next one"
@ -1212,6 +1218,7 @@ module Net # :nodoc:
socket.close
end
end
return nil
end
def send_udp(packet,packet_data)