Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Handle RCode::ServFail from nameserver response #26

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions lib/resolv.rb
Original file line number Diff line number Diff line change
Expand Up @@ -116,8 +116,10 @@ def each_address(name)
yielded = false
@resolvers.each {|r|
r.each_address(name) {|address|
yield address.to_s
yielded = true
if block_given?
yield address.to_s
yielded = true
end
BobSilent marked this conversation as resolved.
Show resolved Hide resolved
}
return if yielded
}
Expand Down Expand Up @@ -554,6 +556,8 @@ def fetch_resource(name, typeclass)
yield(reply, reply_name)
end
return
when RCode::ServFail
next
when RCode::NXDomain
raise Config::NXDomain.new(reply_name.to_s)
else
Expand Down
116 changes: 115 additions & 1 deletion test/resolv/test_dns.rb
Original file line number Diff line number Diff line change
Expand Up @@ -630,7 +630,7 @@ def dns.each_resource(name, typeclass)
end
assert_raise(Resolv::ResolvError) { dns.each_name('example.com') }
end

def test_unreachable_server
unreachable_ip = '127.0.0.1'
sock = UDPSocket.new
Expand All @@ -656,4 +656,118 @@ def test_unreachable_server
ensure
sock&.close
end

def test_query_ipv4_try_next_dns_if_first_answers_with_servfail
begin
OpenSSL
rescue LoadError
omit 'autoload problem. see [ruby-dev:45021][Bug #5786]'
end if defined?(OpenSSL)

with_udp('127.0.0.1', 0) {|first|
with_udp('127.0.0.1', 0) {|second|
_, server_one_port, _, server_one_address = first.addr
_, server_two_port, _, server_two_address = second.addr
begin
client_thread = Thread.new {
Resolv::DNS.open(:nameserver_port => [[server_one_address, server_one_port], [server_two_address, server_two_port]]).getaddress("example.org")
}
server_one_thread = Thread.new {
msg, (_, client_port, _, client_address) = Timeout.timeout(5) {first.recvfrom(4096)}
id, flags, qdcount, ancount, nscount, arcount = msg.unpack("nnnnnn")

qr = (flags & 0x8000) >> 15
opcode = (flags & 0x7800) >> 11
aa = (flags & 0x0400) >> 10
tc = (flags & 0x0200) >> 9
rd = (flags & 0x0100) >> 8
ra = (flags & 0x0080) >> 7
z = (flags & 0x0070) >> 4
rcode = flags & 0x000f
_rest = msg[12..-1]
questions = msg.bytes[12..-1]

id = id
qr = 1
opcode = opcode
aa = 0
tc = 0
rd = rd
ra = 1
z = 0
rcode = 2 # ServFail
qdcount = 1
ancount = 0
nscount = 0
arcount = 0
word2 = (qr << 15) |
(opcode << 11) |
(aa << 10) |
(tc << 9) |
(rd << 8) |
(ra << 7) |
(z << 4) |
rcode
msg = [id, word2, qdcount, ancount, nscount, arcount].pack("nnnnnn")
msg << questions.pack('c*')

first.send(msg, 0, client_address, client_port)
}
server_two_thread = Thread.new {
msg, (_, client_port, _, client_address) = Timeout.timeout(5) {second.recvfrom(4096)}
id, flags, qdcount, ancount, nscount, arcount = msg.unpack("nnnnnn")

qr = (flags & 0x8000) >> 15
opcode = (flags & 0x7800) >> 11
aa = (flags & 0x0400) >> 10
tc = (flags & 0x0200) >> 9
rd = (flags & 0x0100) >> 8
ra = (flags & 0x0080) >> 7
z = (flags & 0x0070) >> 4
rcode = flags & 0x000f
_rest = msg[12..-1]

questions = msg.bytes[12..-1]

id = id
qr = 1
opcode = opcode
aa = 0
tc = 0
rd = rd
ra = 1
z = 0
rcode = 0 # NoError
qdcount = 1
ancount = 1
nscount = 0
arcount = 0
word2 = (qr << 15) |
(opcode << 11) |
(aa << 10) |
(tc << 9) |
(rd << 8) |
(ra << 7) |
(z << 4) |
rcode
msg = [id, word2, qdcount, ancount, nscount, arcount].pack("nnnnnn")
msg << questions.pack('c*')
type = 1
klass = 1
ttl = 3600
rdlength = 4
rdata = [52,0,2,1].pack("CCCC")
rr = [0xc00c, type, klass, ttl, rdlength, rdata].pack("nnnNna*")
msg << rr

second.send(msg, 0, client_address, client_port)
}
result, _, _ = assert_join_threads([client_thread, server_one_thread, server_two_thread])

assert_instance_of(Resolv::IPv4, result)
assert_equal("52.0.2.1", result.to_s)
end
}
}
end
end