summaryrefslogtreecommitdiff
path: root/lib/resolv.rb
diff options
context:
space:
mode:
authorakr <akr@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2013-04-06 14:32:34 +0000
committerakr <akr@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2013-04-06 14:32:34 +0000
commit9791353555d0cc691c1197699e5332d2da014740 (patch)
treedff249913314aa1e2f4a5752a3c76aa157b0edec /lib/resolv.rb
parent4c1e97226fee947895c476344afffac391c4ea41 (diff)
* lib/resolv.rb: Add one-shot multicast DNS support.
[ruby-core:53387] [Feature #8089] by Eric Hodel. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@40160 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'lib/resolv.rb')
-rw-r--r--lib/resolv.rb114
1 files changed, 112 insertions, 2 deletions
diff --git a/lib/resolv.rb b/lib/resolv.rb
index 7ad74e1517..a62b5bcb12 100644
--- a/lib/resolv.rb
+++ b/lib/resolv.rb
@@ -665,7 +665,12 @@ class Resolv
def request(sender, tout)
start = Time.now
timelimit = start + tout
- sender.send
+ begin
+ sender.send
+ rescue Errno::EHOSTUNREACH
+ # multi-homed IPv6 may generate this
+ raise ResolvTimeout
+ end
while true
before_select = Time.now
timeout = timelimit - before_select
@@ -691,7 +696,7 @@ class Resolv
rescue DecodeError
next # broken DNS message ignored
end
- if s = @senders[[from,msg.id]]
+ if s = sender_for(from, msg)
break
else
# unexpected DNS message ignored
@@ -700,6 +705,10 @@ class Resolv
return msg, s.data
end
+ def sender_for(addr, msg)
+ @senders[[addr,msg.id]]
+ end
+
def close
socks = @socks
@socks = nil
@@ -820,6 +829,22 @@ class Resolv
end
end
+ class MDNSOneShot < UnconnectedUDP # :nodoc:
+ def sender(msg, data, host, port=Port)
+ service = [host, port]
+ id = DNS.allocate_request_id(host, port)
+ request = msg.encode
+ request[0,2] = [id].pack('n')
+ sock = @socks_hash[host.index(':') ? "::" : "0.0.0.0"]
+ return @senders[id] =
+ UnconnectedUDP::Sender.new(request, data, sock, host, port)
+ end
+
+ def sender_for(addr, msg)
+ @senders[msg.id]
+ end
+ end
+
class TCP < Requester # :nodoc:
def initialize(host, port=Port)
super()
@@ -2388,11 +2413,96 @@ class Resolv
end
##
+ # Resolv::MDNS is a one-shot Multicast DNS (mDNS) resolver. It blindly
+ # makes queries to the mDNS addresses without understanding anything about
+ # multicast ports.
+ #
+ # Information taken form the following places:
+ #
+ # * RFC 6762
+
+ class MDNS < DNS
+
+ ##
+ # Default mDNS Port
+
+ Port = 5353
+
+ ##
+ # Default IPv4 mDNS address
+
+ AddressV4 = '224.0.0.251'
+
+ ##
+ # Default IPv6 mDNS address
+
+ AddressV6 = 'ff02::fb'
+
+ ##
+ # Default mDNS addresses
+
+ Addresses = [
+ [AddressV4, Port],
+ [AddressV6, Port],
+ ]
+
+ ##
+ # Creates a new one-shot Multicast DNS (mDNS) resolver.
+ #
+ # +config_info+ can be:
+ #
+ # nil::
+ # Uses the default mDNS addresses
+ #
+ # Hash::
+ # Must contain :nameserver or :nameserver_port like
+ # Resolv::DNS#initialize.
+
+ def initialize(config_info=nil)
+ if config_info then
+ super({ nameserver_port: Addresses }.merge(config_info))
+ else
+ super(nameserver_port: Addresses)
+ end
+ end
+
+ ##
+ # Iterates over all IP addresses for +name+ retrieved from the mDNS
+ # resolver, provided name ends with "local". If the name does not end in
+ # "local" no records will be returned.
+ #
+ # +name+ can be a Resolv::DNS::Name or a String. Retrieved addresses will
+ # be a Resolv::IPv4 or Resolv::IPv6
+
+ def each_address(name)
+ name = Resolv::DNS::Name.create(name)
+
+ return unless name.to_a.last == 'local'
+
+ super(name)
+ end
+
+ def make_udp_requester # :nodoc:
+ nameserver_port = @config.nameserver_port
+ Requester::MDNSOneShot.new(*nameserver_port)
+ end
+
+ end
+
+ ##
# Default resolver to use for Resolv class methods.
DefaultResolver = self.new
##
+ # Replaces the resolvers in the default resolver with +new_resolvers+. This
+ # allows resolvers to be changed for resolv-replace.
+
+ def DefaultResolver.replace_resolvers new_resolvers
+ @resolvers = new_resolvers
+ end
+
+ ##
# Address Regexp to use for matching IP addresses.
AddressRegex = /(?:#{IPv4::Regex})|(?:#{IPv6::Regex})/