ANN: net-mdns, multicast DNS and service discovery (aka "Rendezvous")

S

Sam Roberts

Hi,

net-mdns is an extension to the standard 'resolv' resolver library that
adds support for multicast DNS. mDNS is an extension of hierarchical,
unicast DNS to link-local unicast. It is most widely known because it is
part of Apple's OS X "Rendezvous" system, where it is used to do service
discovery over local networks.

I've been planning to do this awhile, but a post by Ben Giddings made me
think that I should do it sooner rather than later. Thanks!

It's beta, but it works (for me and my Alpha tester, Ben, anyhow).

RAA - http://raa.ruby-lang.org/project/net-mdns/

The rdoc overview is below, to get an idea what its about.

Cheers,
Sam

main:Resolv::MDNS
title:mDNS - multicast DNS and service discovery (aka "Rendezvous")

Author:: Sam Roberts <[email protected]>
Copyright:: Copyright (C) 2005 Sam Roberts
License:: May be distributed under the same terms as Ruby
Version:: 0.0
Homepage:: http://vpim.rubyforge.org/mdns
Download:: http://vpim.rubyforge.org/mdns/mdns.tgz

== Summary
An extension to the standard 'resolv' resolver library that adds support
for multicast DNS. mDNS is an extension of hierarchical, unicast DNS to
link-local multicast. It is most widely known because it is part of Apple's
OS X "Rendezvous" system, where it is used to do service discovery over
local networks.

MDNS can be used for:
- name to address lookups on local networks
- address to name lookups on local networks (only for link-local addresses)
- discovery of services on local networks

= Example
require 'net/http'
require 'net/dns/mdns-resolv'
require 'resolv-replace'

# Address lookup

begin
puts Resolv.getaddress('example.local')
rescue Resolv::ResolvError
puts "no such address!"
end

# Service discovery

mdns = Resolv::MDNS.new

mdns.each_resource('_http._tcp.local', Resolv::DNS::Resource::IN::pTR) do |rrhttp|
service = rrhttp.name
host = nil
port = nil
path = '/'

rrsrv = mdns.getresource(rrhttp.name, Resolv::DNS::Resource::IN::SRV)
host, port = rrsrv.target.to_s, rrsrv.port
rrtxt = mdns.getresource(rrhttp.name, Resolv::DNS::Resource::IN::TXT)
if rrtxt.data =~ /path=(.*)/
path = $1
end

http = Net::HTTP.new(host, port)

headers = http.head(path)

puts "#{service[0]} on #{host}:#{port}#{path} was last-modified #{headers['last-modified']}"
end

== Address Lookups
When used for name lookups, it is most useful to add MDNS to the default
set of resolvers queried when using the 'resolv' module methods. This is
done by doing:
require 'net/dns/mdns-resolv'
Resolv.getaddress('localhost') # resolved using Resolv::Hosts("/etc/hosts")
Resolv.getaddress('www.example.com') # resolved using Resolv::DNS
Resolv.getaddress('example.local') # resolved using Resolv::MDNS
Using this approach means that both global DNS names and local names can be
resolved. When doing this, you may also consider doing:
require 'resolv-replace'
This has the effect of replacing the default ruby implementation of address
lookup in IPSocket, TCPSocket, UDPSocket, and SOCKSocket with
Resolv.getaddress, so (if 'net/dns/mdns-resolv' has been required) the
standard libraries TCP/IP classes will use mDNS for name lookups in the .local domain.

== Service Discovery

Service discovery consists of 2 stages:
- enumerating the names of the instances of the service
- resolving the instance names

= Service Enumeration

To do this query the pointer records (Resolv::DNS::Resource::IN::pTR) for
names of the form _svc._prot.local. The values of svc and prot for common
services can be found at http://www.dns-sd.org/ServiceTypes.html.
The first label of the name returned is suitable for display to peoplem, and
should be unique in the network.

= Service Resolution

In order to resolve a service name query the service record
(Resolv::DNS::Resource::IN::SRV) for the name. The service record contains
a host and port to connect to. The host name will have to be resolved to
an address. This can be done explicitly using mDNS or, if resolv-replace
and mdns-default have been required, it will be done by the standard library.
In addition, some services put "extra" information about the service in a
text (Resolv::DNS::Resource::IN::TXT) record associated with the service name.
The format of the text record is service-specific.

== For More Information

See the following:
- draft-cheshire-dnsext-multicastdns-04.txt for a description of mDNS
- RFC 2782 for a description of DNS SRV records
- draft-cheshire-dnsext-dns-sd-02.txt for a description of how to
use SRV, PTR, and TXT records for service discovery
- http://www.dns-sd.org

== Comparison to the DNS-SD Extension

The DNS-SD project at http://dnssd.rubyforge.org/wiki/wiki.pl is another
approach to mDNS and service discovery.

DNS-SD is a compiled ruby extension implemented on top of the dns_sd.h APIs
published by Apple. These APIs work by contacting a local mDNS daemon
(through unix domain sockets) and should be more efficient (they can
take advantage of the daemon's cache) and likely a better way of doing
mDNS queries than using pure ruby. Also, the mDNS daemon is capable of
advertising services over the network, and Resolv::MDNS can't do that,
though I'm working on it. There's some technical obstacles.

Currently, the only thing I'm aware of Resolv::MDNS doing that DNS-SD
doesn't is integrate into the standard library so that link-local domain
names can be used throughout the standard networking classes. There is no
reason DNS-SD can't do this, and I'll try and add that capability as soon as I
find a way to install and use DNS-SD, which leads to why you might be
interested in Resolv::MDNS.

The DNS-SD extension requires the dns_sd.h C language APIs for the Apple
mDNS daemon. Installing the Apple responder can be quite difficult, and
requires a running daemon. It also requires compiling the extension. If
you need a pure ruby implementation, or if building DNS-SD turns out to be
difficult for you, Resolv::MDNS may be useful to you.

== Samples

There are a few samples in the samples/ directory:
- mdns.rb is useful for finding out as much as possible about services on .local
- mdns_demo.rb is a sample provided by Ben Giddings, with better docs, showing
the call sequence he uses when resolving services. Thanks, Ben!

== TODO

- Implement a Resolv:: object that uses the DNS-SD project, so the standard
library will use it for .local name lookups.
- Implement response cacheing and service advertising in Resolv::MDNS.
- Implement a higher level service discovery API that will work with either
DNS-SD or Resolv::MDNS, so either can be used (as available) without code
changes.
- Various API improvements, testing, ...

== Author

Any feedback, questions, problems, etc., please contact me, Sam Roberts,
via (e-mail address removed), or directly.
 
B

Ben Giddings

Hi Sam,

Thanks for putting this up!

Just to let you folks know, this may be alpha software, and may still
have bugs, but it works for what I need, and works well. You may be
interested to know that it is in much better shape than Python's
zeroconf implementation.

Ben
 
L

Lyndon Samson

Rendezvous is a ( good ) Tibco messaging product, don't get their
lawyers fired up again ;-)



Hi,

net-mdns is an extension to the standard 'resolv' resolver library that
adds support for multicast DNS. mDNS is an extension of hierarchical,
unicast DNS to link-local unicast. It is most widely known because it is
part of Apple's OS X "Rendezvous" system, where it is used to do service
discovery over local networks.

I've been planning to do this awhile, but a post by Ben Giddings made me
think that I should do it sooner rather than later. Thanks!

It's beta, but it works (for me and my Alpha tester, Ben, anyhow).

RAA - http://raa.ruby-lang.org/project/net-mdns/

The rdoc overview is below, to get an idea what its about.

Cheers,
Sam

main:Resolv::MDNS
title:mDNS - multicast DNS and service discovery (aka "Rendezvous")

Author:: Sam Roberts <[email protected]>
Copyright:: Copyright (C) 2005 Sam Roberts
License:: May be distributed under the same terms as Ruby
Version:: 0.0
Homepage:: http://vpim.rubyforge.org/mdns
Download:: http://vpim.rubyforge.org/mdns/mdns.tgz

== Summary
An extension to the standard 'resolv' resolver library that adds support
for multicast DNS. mDNS is an extension of hierarchical, unicast DNS to
link-local multicast. It is most widely known because it is part of Apple's
OS X "Rendezvous" system, where it is used to do service discovery over
local networks.

MDNS can be used for:
- name to address lookups on local networks
- address to name lookups on local networks (only for link-local addresses)
- discovery of services on local networks

= Example
require 'net/http'
require 'net/dns/mdns-resolv'
require 'resolv-replace'

# Address lookup

begin
puts Resolv.getaddress('example.local')
rescue Resolv::ResolvError
puts "no such address!"
end

# Service discovery

mdns = Resolv::MDNS.new

mdns.each_resource('_http._tcp.local', Resolv::DNS::Resource::IN::pTR) do |rrhttp|
service = rrhttp.name
host = nil
port = nil
path = '/'

rrsrv = mdns.getresource(rrhttp.name, Resolv::DNS::Resource::IN::SRV)
host, port = rrsrv.target.to_s, rrsrv.port
rrtxt = mdns.getresource(rrhttp.name, Resolv::DNS::Resource::IN::TXT)
if rrtxt.data =~ /path=(.*)/
path = $1
end

http = Net::HTTP.new(host, port)

headers = http.head(path)

puts "#{service[0]} on #{host}:#{port}#{path} was last-modified #{headers['last-modified']}"
end

== Address Lookups
When used for name lookups, it is most useful to add MDNS to the default
set of resolvers queried when using the 'resolv' module methods. This is
done by doing:
require 'net/dns/mdns-resolv'
Resolv.getaddress('localhost') # resolved using Resolv::Hosts("/etc/hosts")
Resolv.getaddress('www.example.com') # resolved using Resolv::DNS
Resolv.getaddress('example.local') # resolved using Resolv::MDNS
Using this approach means that both global DNS names and local names can be
resolved. When doing this, you may also consider doing:
require 'resolv-replace'
This has the effect of replacing the default ruby implementation of address
lookup in IPSocket, TCPSocket, UDPSocket, and SOCKSocket with
Resolv.getaddress, so (if 'net/dns/mdns-resolv' has been required) the
standard libraries TCP/IP classes will use mDNS for name lookups in the .local domain.

== Service Discovery

Service discovery consists of 2 stages:
- enumerating the names of the instances of the service
- resolving the instance names

= Service Enumeration

To do this query the pointer records (Resolv::DNS::Resource::IN::pTR) for
names of the form _svc._prot.local. The values of svc and prot for common
services can be found at http://www.dns-sd.org/ServiceTypes.html.
The first label of the name returned is suitable for display to peoplem, and
should be unique in the network.

= Service Resolution

In order to resolve a service name query the service record
(Resolv::DNS::Resource::IN::SRV) for the name. The service record contains
a host and port to connect to. The host name will have to be resolved to
an address. This can be done explicitly using mDNS or, if resolv-replace
and mdns-default have been required, it will be done by the standard library.
In addition, some services put "extra" information about the service in a
text (Resolv::DNS::Resource::IN::TXT) record associated with the service name.
The format of the text record is service-specific.

== For More Information

See the following:
- draft-cheshire-dnsext-multicastdns-04.txt for a description of mDNS
- RFC 2782 for a description of DNS SRV records
- draft-cheshire-dnsext-dns-sd-02.txt for a description of how to
use SRV, PTR, and TXT records for service discovery
- http://www.dns-sd.org

== Comparison to the DNS-SD Extension

The DNS-SD project at http://dnssd.rubyforge.org/wiki/wiki.pl is another
approach to mDNS and service discovery.

DNS-SD is a compiled ruby extension implemented on top of the dns_sd.h APIs
published by Apple. These APIs work by contacting a local mDNS daemon
(through unix domain sockets) and should be more efficient (they can
take advantage of the daemon's cache) and likely a better way of doing
mDNS queries than using pure ruby. Also, the mDNS daemon is capable of
advertising services over the network, and Resolv::MDNS can't do that,
though I'm working on it. There's some technical obstacles.

Currently, the only thing I'm aware of Resolv::MDNS doing that DNS-SD
doesn't is integrate into the standard library so that link-local domain
names can be used throughout the standard networking classes. There is no
reason DNS-SD can't do this, and I'll try and add that capability as soon as I
find a way to install and use DNS-SD, which leads to why you might be
interested in Resolv::MDNS.

The DNS-SD extension requires the dns_sd.h C language APIs for the Apple
mDNS daemon. Installing the Apple responder can be quite difficult, and
requires a running daemon. It also requires compiling the extension. If
you need a pure ruby implementation, or if building DNS-SD turns out to be
difficult for you, Resolv::MDNS may be useful to you.

== Samples

There are a few samples in the samples/ directory:
- mdns.rb is useful for finding out as much as possible about services on .local
- mdns_demo.rb is a sample provided by Ben Giddings, with better docs, showing
the call sequence he uses when resolving services. Thanks, Ben!

== TODO

- Implement a Resolv:: object that uses the DNS-SD project, so the standard
library will use it for .local name lookups.
- Implement response cacheing and service advertising in Resolv::MDNS.
- Implement a higher level service discovery API that will work with either
DNS-SD or Resolv::MDNS, so either can be used (as available) without code
changes.
- Various API improvements, testing, ...

== Author

Any feedback, questions, problems, etc., please contact me, Sam Roberts,
via (e-mail address removed), or directly.
 
B

Ben Giddings

Rendezvous is a ( good ) Tibco messaging product, don't get their
lawyers fired up again ;-)

Um, google sez Apple wins. Apple has called their implementation of
zeroconf Rendezvous forever. If there's anybody's lawyers we have to
worry about it's, Apple's. I think they trademarked "Rendezvous", the
IETF name is "zeroconf". Meh, whatever. It's great software, we can
figure out the names later. :)

Ben
 
G

Garrett Rooney

Ben said:
Um, google sez Apple wins. Apple has called their implementation of
zeroconf Rendezvous forever. If there's anybody's lawyers we have to
worry about it's, Apple's. I think they trademarked "Rendezvous", the
IETF name is "zeroconf". Meh, whatever. It's great software, we can
figure out the names later. :)

Actually, Apple is phasing out the name "Rendezvous" because of the
Tibco lawsuit. Regardless, just call it MDNS (multicast DNS) or DNSSD
(DNS service discovery), depending on what you're actually talking about
and you're fine.

-garrett
 
S

Sam Roberts

Actually, Apple is phasing out the name "Rendezvous" because of the
Tibco lawsuit. Regardless, just call it MDNS (multicast DNS) or DNSSD
(DNS service discovery), depending on what you're actually talking about
and you're fine.

Note that the lib is called net-mdns, and the only mention of
"Rendezous" is one note that Apple calls it that. Which they still do,
its smeared across their web site, and the minds of their users.

Cheers,
Sam
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,013
Latest member
KatriceSwa

Latest Threads

Top