Skip to content

Commit 0074767

Browse files
committed
Handle invalid nameservers in Resolver setup
1 parent 1b37701 commit 0074767

5 files changed

Lines changed: 93 additions & 7 deletions

File tree

lib/dnsruby/cache.rb

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,14 +68,12 @@ def add(message)
6868
# This method "fixes up" the response, so that the header and ttls are OK
6969
# The resolver will still need to copy the flags and ID across from the query
7070
def find(qname, qtype, qclass = Classes.IN)
71-
# print "CACHE find : #{qname}, #{qtype}\n"
7271
qn = Name.create(qname)
7372
qn.absolute = true
7473
key = CacheKey.new(qn, qtype, qclass).to_s
7574
@mutex.synchronize {
7675
data = @cache[key]
7776
if (!data)
78-
# print "CACHE lookup failed\n"
7977
return nil
8078
end
8179
if (data.expiration <= Time.now.to_i)

lib/dnsruby/packet_sender.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,7 @@ def initialize(*args)
221221
else
222222
send(attr.to_s + "=", arg[attr])
223223
end
224-
end
224+
end
225225
rescue Exception => e
226226
Dnsruby.log.error { "PacketSender : Argument #{attr}, #{arg[attr]} not valid : #{e}\n" }
227227
end
@@ -236,7 +236,7 @@ def initialize(*args)
236236
rescue ArgumentError
237237
return
238238
end
239-
else
239+
else
240240
@server=Config.resolve_server(@server)
241241
end
242242

lib/dnsruby/resolver.rb

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -401,7 +401,7 @@ def send_async(msg, client_queue, client_query_id = nil)
401401
if @single_resolvers.length == 0
402402
Thread.start {
403403
sleep(@query_timeout == 0 ? 1 : @query_timeout)
404-
client_queue.push([client_query_id, nil, ResolvTimeout.new('Query timed out - no nameservers configured')])
404+
client_queue.push([client_query_id, nil, ResolvTimeout.new('Query timed out - no valid nameservers configured')])
405405
}
406406
end
407407
client_query_id
@@ -436,7 +436,7 @@ def close
436436
# * :tcp_pipelining
437437
# * :tcp_pipelining_max_queries - can be a number or :infinite symbol
438438
def initialize(*args)
439-
# @TODO@ Should we allow :namesver to be an RRSet of NS records? Would then need to randomly order them?
439+
# @TODO@ Should we allow :nameserver to be an RRSet of NS records? Would then need to randomly order them?
440440
@resolver_ruby = nil
441441
@src_address = nil
442442
@src_address6 = nil
@@ -506,10 +506,16 @@ def add_config_nameservers # :nodoc: all
506506
end
507507

508508
new_resolvers = threads.map(&:value).compact
509+
new_resolvers = new_resolvers.select do |resolver|
510+
!resolver.nil? && !resolver.server.nil?
511+
end
509512
if new_resolvers.empty?
510-
throw new ArgumentError, "No valid nameservers found in config"
513+
raise ArgumentError.new("No valid nameservers found in config")
511514
end
512515
@single_res_mutex.synchronize { @single_resolvers.concat(new_resolvers) }
516+
if @single_resolvers.nil? || @single_resolvers.empty?
517+
raise ArgumentError.new("No valid nameservers found")
518+
end
513519
end
514520

515521
def set_config_nameserver(n)

lib/dnsruby/timetest.rb

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
class TestDomain
2+
ROOT_NAMESERVERS = %w[
3+
a.root-servers.net
4+
b.root-servers.net
5+
c.root-servers.net
6+
d.root-servers.net
7+
e.root-servers.net
8+
f.root-servers.net
9+
g.root-servers.net
10+
h.root-servers.net
11+
i.root-servers.net
12+
j.root-servers.net
13+
k.root-servers.net
14+
l.root-servers.net
15+
m.root-servers.net
16+
].freeze
17+
18+
def name
19+
"example.com"
20+
end
21+
22+
def recursive_query(type, ns: ROOT_NAMESERVERS)
23+
return [] unless ns
24+
25+
msg = nil
26+
puts "Time: #{Benchmark.realtime { msg = resolve_query(type, ns: ns, recurse: false, cache: ROOT_NAMESERVERS.intersect?(ns)) }}"
27+
return [] unless msg
28+
29+
# The answer is received.
30+
return msg.answer.map { |rr| rr.rdata_to_string } if msg.answer
31+
32+
# Another layer of intermediaries.
33+
authority = msg.authority.
34+
find_all { |rr| rr.type == Dnsruby::Types.NS }.
35+
map(&:rdata).map(&:to_s).reject(&:blank?)
36+
return [] unless authority
37+
38+
recursive_query(type, ns: authority)
39+
end
40+
41+
private
42+
43+
def resolve_query(type, ns: nil, recurse: true, cache: true)
44+
puts "Caching: #{cache} | NS: #{ns.first}"
45+
46+
resolver = Dnsruby::Resolver.
47+
new(recurse: recurse, do_caching: cache, retry_times: 2)
48+
49+
resolver.nameserver = [ns].flatten.shift
50+
51+
resolver.query(name, type)
52+
end
53+
end

test/tc_res_config.rb

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,4 +92,33 @@ def test_dns
9292
end;
9393
end
9494

95+
def test_bad_ns
96+
begin
97+
res = Dnsruby::Resolver.new(:nameserver => ["ns32.domiancontrol.com."])
98+
res.query("example.com")
99+
assert(false, "Should not query with bad nameserver")
100+
rescue Exception => e
101+
# OK
102+
end
103+
end
104+
105+
def test_bad_ns_post_init
106+
begin
107+
resolver = Dnsruby::Resolver.new(recurse: false, do_caching: false, retry_times: 2)
108+
resolver.nameserver = ["ns32.domiancontrol.com."]
109+
assert(false, "Should not allow bad nameserver")
110+
resolver.query("example.com")
111+
rescue ArgumentError
112+
end
113+
end
114+
115+
def test_one_good_ns_rest_bad
116+
begin
117+
resolver = Dnsruby::Resolver.new(recurse: false, do_caching: false, retry_times: 2)
118+
resolver.nameserver = ["ns32.domiancontrol.com.", "1.1.1.1"]
119+
resolver.query("example.com")
120+
rescue ArgumentError
121+
assert(false, "Should allow one good nameserver")
122+
end
123+
end
95124
end

0 commit comments

Comments
 (0)