Skip to content

Commit 9d4dac0

Browse files
committed
Add support for search and ndots.
1 parent 725ca62 commit 9d4dac0

File tree

4 files changed

+56
-44
lines changed

4 files changed

+56
-44
lines changed

lib/async/dns/extensions/resolv.rb

-9
Original file line numberDiff line numberDiff line change
@@ -40,15 +40,6 @@ class OriginError < ArgumentError
4040

4141
# Extensions to the `Resolv::DNS::Name` class.
4242
class Name
43-
# Generate a strinng representation of the name.
44-
#
45-
# If the name is absolute, a trailing dot is added.
46-
#
47-
# @returns [String] The string representation of the name.
48-
def to_s
49-
"#{@labels.join('.')}#{@absolute ? '.' : ''}"
50-
end
51-
5243
# Computes the name, typically absolute, with the specified origin as a suffix. If the origin is nil, don't change the name, but change it to absolute (as specified).
5344
#
5445
# @parameter origin [Array | String] The origin to append to the name.

lib/async/dns/resolver.rb

+47-28
Original file line numberDiff line numberDiff line change
@@ -26,18 +26,16 @@ class ResolutionFailure < StandardError
2626

2727
# Resolve names to addresses using the DNS protocol.
2828
class Resolver
29-
# 10ms wait between making requests. Override with `options[:delay]`
30-
DEFAULT_DELAY = 0.01
31-
32-
# Try a given request 10 times before failing. Override with `options[:retries]`.
33-
DEFAULT_RETRIES = 10
34-
3529
# Servers are specified in the same manor as options[:listen], e.g.
3630
# [:tcp/:udp, address, port]
3731
# In the case of multiple servers, they will be checked in sequence.
38-
def initialize(endpoint = nil, origin: nil, cache: Cache.new)
32+
def initialize(endpoint = nil, origin: nil, cache: Cache.new, timeout: nil, ndots: 1, search: [nil])
3933
@endpoint = endpoint || System.default_nameservers
4034

35+
if timeout
36+
@endpoint = @endpoint.with(timeout: timeout)
37+
end
38+
4139
# Legacy support for multiple endpoints:
4240
if @endpoint.is_a?(Array)
4341
endpoints = @endpoint.map do |specification|
@@ -47,7 +45,14 @@ def initialize(endpoint = nil, origin: nil, cache: Cache.new)
4745
@endpoint = ::IO::Endpoint.composite(*endpoints)
4846
end
4947

50-
@origin = origin
48+
@ndots = ndots
49+
50+
@search = search
51+
52+
if origin
53+
@search = [origin] + @search
54+
end
55+
5156
@cache = cache
5257
@count = 0
5358
end
@@ -57,21 +62,21 @@ def initialize(endpoint = nil, origin: nil, cache: Cache.new)
5762
# Generates a fully qualified name from a given name.
5863
#
5964
# @parameter name [String | Resolv::DNS::Name] The name to fully qualify.
60-
def fully_qualified_name(name)
61-
# If we are passed an existing deconstructed name:
62-
if Resolv::DNS::Name === name
63-
if name.absolute?
64-
return name
65-
else
66-
return name.with_origin(@origin)
67-
end
68-
end
65+
def fully_qualified_names(name)
66+
return to_enum(:fully_qualified_names, name) unless block_given?
6967

70-
# ..else if we have a string, we need to do some basic processing:
71-
if name.end_with? '.'
72-
return Resolv::DNS::Name.create(name)
68+
name = Resolv::DNS::Name.create(name)
69+
70+
if name.absolute?
71+
yield name
7372
else
74-
return Resolv::DNS::Name.create(name).with_origin(@origin)
73+
if @ndots <= name.length - 1
74+
yield name
75+
end
76+
77+
@search.each do |domain|
78+
yield name.with_origin(domain)
79+
end
7580
end
7681
end
7782

@@ -87,23 +92,37 @@ def next_id!
8792
#
8893
# @returns [Resolv::DNS::Message] The response from the server.
8994
def query(name, resource_class = Resolv::DNS::Resource::IN::A)
90-
self.dispatch_query(self.fully_qualified_name(name), resource_class)
95+
response = nil
96+
97+
self.fully_qualified_names(name) do |fully_qualified_name|
98+
response = self.dispatch_query(fully_qualified_name, resource_class)
99+
100+
break if response.rcode == Resolv::DNS::RCode::NoError
101+
end
102+
103+
return response
91104
end
92105

93106
# Look up a named resource of the given resource_class.
94107
def records_for(name, resource_classes)
95108
Console.debug(self) {"Looking up records for #{name.inspect} with #{resource_classes.inspect}."}
96-
name = self.fully_qualified_name(name)
97109
resource_classes = Array(resource_classes)
110+
resources = nil
98111

99-
@cache.fetch(name, resource_classes) do |name, resource_class|
100-
if response = self.dispatch_query(name, resource_class)
101-
response.answer.each do |name, ttl, record|
102-
Console.debug(self) {"Caching record for #{name.inspect} with #{record.class} and TTL #{ttl}."}
103-
@cache.store(name, resource_class, record)
112+
self.fully_qualified_names(name) do |fully_qualified_name|
113+
resources = @cache.fetch(fully_qualified_name, resource_classes) do |name, resource_class|
114+
if response = self.dispatch_query(name, resource_class)
115+
response.answer.each do |name, ttl, record|
116+
Console.debug(self) {"Caching record for #{name.inspect} with #{record.class} and TTL #{ttl}."}
117+
@cache.store(name, resource_class, record)
118+
end
104119
end
105120
end
121+
122+
break if resources.any?
106123
end
124+
125+
return resources
107126
end
108127

109128
if System.ipv6?

test/async/dns/resolver.rb

+5-3
Original file line numberDiff line numberDiff line change
@@ -67,10 +67,12 @@
6767
let(:resolver) {Async::DNS::Resolver.new(origin: "foo.bar.")}
6868

6969
it "should generate fully qualified domain name with specified origin" do
70-
fully_qualified_name = resolver.fully_qualified_name("baz")
70+
fully_qualified_names = resolver.fully_qualified_names("baz").to_a
7171

72-
expect(fully_qualified_name).to be(:absolute?)
73-
expect(fully_qualified_name.to_s).to be == "baz.foo.bar."
72+
expect(fully_qualified_names).to be == [
73+
Resolv::DNS::Name.create("baz.foo.bar."),
74+
Resolv::DNS::Name.create("baz."),
75+
]
7476
end
7577
end
7678
end

test/resolv/dns/name.rb

+4-4
Original file line numberDiff line numberDiff line change
@@ -19,23 +19,23 @@
1919

2020
expect(fully_qualified_name.to_a.size).to be == 3
2121
expect(fully_qualified_name).to be(:absolute?)
22-
expect(fully_qualified_name.to_s).to be == "foo.bar.org."
22+
expect(fully_qualified_name.to_s).to be == "foo.bar.org"
2323
end
2424

2525
it "should handle nil origin as absolute" do
2626
fully_qualified_name = name.with_origin(nil)
2727

2828
expect(fully_qualified_name.to_a.size).to be == 2
2929
expect(fully_qualified_name).to be(:absolute?)
30-
expect(fully_qualified_name.to_s).to be == "foo.bar."
30+
expect(fully_qualified_name.to_s).to be == "foo.bar"
3131
end
3232

3333
it "should handle empty origin as absolute" do
3434
fully_qualified_name = name.with_origin('')
3535

3636
expect(fully_qualified_name.to_a.size).to be == 2
3737
expect(fully_qualified_name).to be(:absolute?)
38-
expect(fully_qualified_name.to_s).to be == "foo.bar."
38+
expect(fully_qualified_name.to_s).to be == "foo.bar"
3939
end
4040
end
4141

@@ -44,7 +44,7 @@
4444

4545
it "should be absolute" do
4646
expect(name).to be(:absolute?)
47-
expect(name.to_s).to be == "foo.bar."
47+
expect(name.to_s).to be == "foo.bar"
4848
end
4949

5050
it "should remove the specified origin" do

0 commit comments

Comments
 (0)