lib/ftw/dns.rb in ftw-0.0.8 vs lib/ftw/dns.rb in ftw-0.0.9

- old
+ new

@@ -1,40 +1,44 @@ require "ftw/namespace" require "socket" # for Socket.gethostbyname require "ftw/singleton" +require "ftw/dns/dns" # I wrap whatever Ruby provides because it is historically very # inconsistent in implementation behavior across ruby platforms and versions. # In the future, this will probably implement the DNS protocol, but for now # chill in the awkward, but already-written, ruby stdlib. # # I didn't really want to write a DNS library, but a consistent API and # behavior is necessary for my continued sanity :) class FTW::DNS extend FTW::Singleton - # TODO(sissel): Switch to using Resolv::DNS since it lets you (the programmer) - # choose dns configuration (servers, etc) + # The ipv4-in-ipv6 address space prefix. V4_IN_V6_PREFIX = "0:" * 12 + # An array of resolvers. By default this includes a FTW::DNS::DNS instance. + attr_reader :resolvers + private + # A new resolver. + # + # The default set of resolvers is only {FTW::DNS::DNS} which does DNS + # resolution. + def initialize + @resolvers = [FTW::DNS::DNS.new] + end # def initialize + # Resolve a hostname. # - # It will return an array of all known addresses for the host. + # Returns an array of all addresses for this host. Empty array resolution + # failure. def resolve(hostname) - official, aliases, family, *addresses = Socket.gethostbyname(hostname) - # We ignore family, here. Ruby will return v6 *and* v4 addresses in - # the same gethostbyname() call. It is confusing. - # - # Let's just rely entirely on the length of the address string. - return addresses.collect do |address| - if address.length == 16 - unpack_v6(address) - else - unpack_v4(address) - end + return @resolvers.reduce([]) do |memo, resolver| + result = resolver.resolve(hostname) + memo += result unless result.nil? end end # def resolve # Resolve hostname and choose one of the results at random. # @@ -42,28 +46,8 @@ # multiple addresses. def resolve_random(hostname) addresses = resolve(hostname) return addresses[rand(addresses.size)] end # def resolve_random - - # Unserialize a 4-byte ipv4 address into a human-readable a.b.c.d string - def unpack_v4(address) - return address.unpack("C4").join(".") - end # def unpack_v4 - - # Unserialize a 16-byte ipv6 address into a human-readable a:b:c:...:d string - def unpack_v6(address) - if address.length == 16 - # Unpack 16 bit chunks, convert to hex, join with ":" - address.unpack("n8").collect { |p| p.to_s(16) } \ - .join(":").sub(/(?:0:(?:0:)+)/, "::") - else - # assume ipv4 - # Per the following sites, "::127.0.0.1" is valid and correct - # http://en.wikipedia.org/wiki/IPv6#IPv4-mapped_IPv6_addresses - # http://www.tcpipguide.com/free/t_IPv6IPv4AddressEmbedding.htm - "::" + unpack_v4(address) - end - end # def unpack_v6 public(:resolve, :resolve_random) end # class FTW::DNS