Class: Celluloid::IO::DNSResolver
- Inherits:
-
Object
- Object
- Celluloid::IO::DNSResolver
- Defined in:
- lib/celluloid/io/dns_resolver.rb
Overview
Asynchronous DNS resolver using Celluloid::IO::UDPSocket
Constant Summary collapse
- RESOLV_CONF =
'/etc/resolv.conf'
- HOSTS =
'/etc/hosts'
- DNS_PORT =
53
Class Method Summary collapse
- .generate_id ⇒ Object
-
.hosts(hostfile = HOSTS) ⇒ Object
FIXME: Y U NO Resolv::Hosts?.
- .nameservers(config = RESOLV_CONF) ⇒ Object
Instance Method Summary collapse
-
#initialize ⇒ DNSResolver
constructor
A new instance of DNSResolver.
- #resolve(hostname) ⇒ Object
Constructor Details
#initialize ⇒ DNSResolver
Returns a new instance of DNSResolver.
35 36 37 38 39 40 41 42 43 44 |
# File 'lib/celluloid/io/dns_resolver.rb', line 35 def initialize @nameservers, @hosts = self.class.nameservers, self.class.hosts # TODO: fall back on other nameservers if the first one is unavailable @server = @nameservers.first # The non-blocking secret sauce is here, as this is actually a # Celluloid::IO::UDPSocket @socket = UDPSocket.new end |
Class Method Details
.generate_id ⇒ Object
14 15 16 |
# File 'lib/celluloid/io/dns_resolver.rb', line 14 def self.generate_id @mutex.synchronize { @identifier = (@identifier + 1) & 0xFFFF } end |
.hosts(hostfile = HOSTS) ⇒ Object
FIXME: Y U NO Resolv::Hosts?
23 24 25 26 27 28 29 30 31 32 33 |
# File 'lib/celluloid/io/dns_resolver.rb', line 23 def self.hosts(hostfile = HOSTS) hosts = {} File.open(hostfile) do |f| f.each_line do |host_entry| entries = host_entry.gsub(/#.*$/, '').gsub(/\s+/, ' ').split(' ') addr = entries.shift entries.each { |e| hosts[e] ||= addr } end end hosts end |
.nameservers(config = RESOLV_CONF) ⇒ Object
18 19 20 |
# File 'lib/celluloid/io/dns_resolver.rb', line 18 def self.nameservers(config = RESOLV_CONF) File.read(config).scan(/^\s*nameserver\s+([0-9.:]+)/).flatten end |
Instance Method Details
#resolve(hostname) ⇒ Object
46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 |
# File 'lib/celluloid/io/dns_resolver.rb', line 46 def resolve(hostname) host = @hosts[hostname] if host begin return Resolv::IPv4.create(host) rescue ArgumentError end begin return Resolv::IPv6.create(host) rescue ArgumentError end raise Resolv::ResolvError, "invalid entry in hosts file: #{host}" end query = Resolv::DNS::Message.new query.id = self.class.generate_id query.rd = 1 query.add_question hostname, Resolv::DNS::Resource::IN::A @socket.send query.encode, 0, @server, DNS_PORT data, _ = @socket.recvfrom(512) response = Resolv::DNS::Message.decode(data) addrs = [] # The answer might include IN::CNAME entries so filters them out # to include IN::A & IN::AAAA entries only. response.each_answer { |name, ttl, value| addrs << (value.respond_to?(:address) ? value.address : nil) } addrs.compact! return if addrs.empty? return addrs.first if addrs.size == 1 addrs end |