Skip to content

Commit 2edf4a6

Browse files
committed
Merge remote branch 'bonsaiviking/axfr' into bonsai-afxr
2 parents b8132ca + 1aa83b8 commit 2edf4a6

2 files changed

Lines changed: 191 additions & 116 deletions

File tree

lib/net/dns/resolver.rb

Lines changed: 88 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -995,12 +995,54 @@ def send(argument,type=Net::DNS::A,cls=Net::DNS::IN)
995995
#
996996
# Performs a zone transfer for the zone passed as a parameter.
997997
#
998-
# It is actually only a wrapper to a send with type set as Net::DNS::AXFR,
999-
# since it is using the same infrastucture.
998+
# Returns a list of Net::DNS::Packet (not answers!)
1000999
#
10011000
def axfr(name,cls=Net::DNS::IN)
10021001
@logger.info "Requested AXFR transfer, zone #{name} class #{cls}"
1003-
send(name,Net::DNS::AXFR,cls)
1002+
if @config[:nameservers].size == 0
1003+
raise Resolver::Error, "No nameservers specified!"
1004+
end
1005+
1006+
method = :send_tcp
1007+
packet = make_query_packet(name, Net::DNS::AXFR, cls)
1008+
1009+
# Store packet_data for performance improvements,
1010+
# so methods don't keep on calling Packet#data
1011+
packet_data = packet.data
1012+
packet_size = packet_data.size
1013+
1014+
if @raw
1015+
@logger.warn "AXFR query, switching to TCP over RAW socket"
1016+
method = :send_raw_tcp
1017+
else
1018+
@logger.warn "AXFR query, switching to TCP"
1019+
method = :send_tcp
1020+
end
1021+
1022+
answers = []
1023+
soa = 0
1024+
self.old_send(method, packet, packet_data) do |ans|
1025+
@logger.info "Received #{ans[0].size} bytes from #{ans[1][2]+":"+ans[1][1].to_s}"
1026+
1027+
begin
1028+
response = Net::DNS::Packet.parse(ans[0],ans[1])
1029+
if response.answer[0].type == "SOA"
1030+
soa += 1
1031+
if soa >= 2
1032+
break
1033+
end
1034+
end
1035+
answers << response
1036+
rescue NameError => e
1037+
@logger.warn "Error parsing axfr response: #{e.message}"
1038+
end
1039+
end
1040+
if answers.empty?
1041+
@logger.fatal "No response from nameservers list: aborting"
1042+
raise NoResponseError
1043+
end
1044+
1045+
return answers
10041046
end
10051047

10061048
#
@@ -1119,45 +1161,64 @@ def send_tcp(packet,packet_data)
11191161

11201162
@config[:nameservers].each do |ns|
11211163
begin
1122-
buffer = ""
11231164
socket = Socket.new(Socket::AF_INET,Socket::SOCK_STREAM,0)
11241165
socket.bind(Socket.pack_sockaddr_in(@config[:source_port],@config[:source_address].to_s))
11251166

11261167
sockaddr = Socket.pack_sockaddr_in(@config[:port],ns.to_s)
11271168

11281169
@config[:tcp_timeout].timeout do
1129-
socket.connect(sockaddr)
1130-
@logger.info "Contacting nameserver #{ns} port #{@config[:port]}"
1131-
socket.write(length+packet_data)
1132-
ans = socket.recv(Net::DNS::INT16SZ)
1133-
len = ans.unpack("n")[0]
1134-
1135-
@logger.info "Receiving #{len} bytes..."
1136-
1137-
if len == 0
1138-
@logger.warn "Receiving 0 lenght packet from nameserver #{ns}, trying next."
1139-
next
1140-
end
1141-
1142-
while (buffer.size < len)
1143-
left = len - buffer.size
1144-
temp,from = socket.recvfrom(left)
1145-
buffer += temp
1146-
end
1147-
1148-
unless buffer.size == len
1149-
@logger.warn "Malformed packet from nameserver #{ns}, trying next."
1150-
next
1170+
catch "next nameserver" do
1171+
socket.connect(sockaddr)
1172+
@logger.info "Contacting nameserver #{ns} port #{@config[:port]}"
1173+
socket.write(length+packet_data)
1174+
got_something = false
1175+
loop do
1176+
buffer = ""
1177+
ans = socket.recv(Net::DNS::INT16SZ)
1178+
if ans.size == 0
1179+
if got_something
1180+
break #Proper exit from loop
1181+
else
1182+
@logger.warn "Connection reset to nameserver #{ns}, trying next."
1183+
throw "next nameserver"
1184+
end
1185+
end
1186+
got_something = true
1187+
len = ans.unpack("n")[0]
1188+
1189+
@logger.info "Receiving #{len} bytes..."
1190+
1191+
if len == 0
1192+
@logger.warn "Receiving 0 length packet from nameserver #{ns}, trying next."
1193+
throw "next nameserver"
1194+
end
1195+
1196+
while (buffer.size < len)
1197+
left = len - buffer.size
1198+
temp,from = socket.recvfrom(left)
1199+
buffer += temp
1200+
end
1201+
1202+
unless buffer.size == len
1203+
@logger.warn "Malformed packet from nameserver #{ns}, trying next."
1204+
throw "next nameserver"
1205+
end
1206+
if block_given?
1207+
yield [buffer,["",@config[:port],ns.to_s,ns.to_s]]
1208+
else
1209+
return [buffer,["",@config[:port],ns.to_s,ns.to_s]]
1210+
end
1211+
end
11511212
end
11521213
end
1153-
return [buffer,["",@config[:port],ns.to_s,ns.to_s]]
11541214
rescue Timeout::Error
11551215
@logger.warn "Nameserver #{ns} not responding within TCP timeout, trying next one"
11561216
next
11571217
ensure
11581218
socket.close
11591219
end
11601220
end
1221+
return nil
11611222
end
11621223

11631224
def send_udp(packet,packet_data)

0 commit comments

Comments
 (0)