diff --git a/lib/async/dns/cache.rb b/lib/async/dns/cache.rb index 7f8a2be..3260ee3 100644 --- a/lib/async/dns/cache.rb +++ b/lib/async/dns/cache.rb @@ -13,7 +13,11 @@ def age(now) end def fresh?(now = Async::Clock.now) - self.age(now) <= resource.ttl + if ttl = resource.ttl + self.age(now) <= ttl + else + true + end end end diff --git a/lib/async/dns/system.rb b/lib/async/dns/system.rb index 7695a25..8d634e6 100644 --- a/lib/async/dns/system.rb +++ b/lib/async/dns/system.rb @@ -37,6 +37,8 @@ def self.ipv6? list.any? {|a| a.ipv6? && !a.ipv6_loopback? && !a.ipv6_linklocal? } end + Resource = Struct.new(:address, :ttl) + # An interface for querying the system's hosts file. class Hosts # Hosts for the local system. @@ -84,17 +86,31 @@ def add(address, names) @addresses[address] += names names.each do |name| + name = Resolv::DNS::Name.create(name).with_origin(nil) + @names[name] ||= [] @names[name] << address end end + def each(&block) + @names.each(&block) + end + # Parse a hosts file and add the entries. def parse_hosts(io) io.each do |line| line.sub!(/#.*/, '') address, hostname, *aliases = line.split(/\s+/) + if address =~ Resolv::IPv4::Regex + address = Resolv::IPv4.create(address) + elsif address =~ Resolv::IPv6::Regex + address = Resolv::IPv6.create(address) + else + next + end + add(address, [hostname] + aliases) end end @@ -169,6 +185,24 @@ def self.resolver(**options) options[:search] = [nil] end + if hosts = Hosts.local + cache = options.fetch(:cache) do + options[:cache] = Cache.new + end + + hosts.each do |name, addresses| + addresses.each do |address| + resource = Resource.new(address, nil) + case address + when Resolv::IPv4 + cache.store(name, Resolv::DNS::Resource::IN::A, resource) + when Resolv::IPv6 + cache.store(name, Resolv::DNS::Resource::IN::AAAA, resource) + end + end + end + end + timeout = options.delete(:timeout) || DEFAULT_TIMEOUT endpoint = Endpoint.for(nameservers, timeout: timeout)