Module: Net::DNS::MDNS

Defined in:
lib/net/dns/mdns.rb

Overview

:main:Net::DNS::MDNS :title:net-mdns - multicast DNS and DNS service discovery

Author

Sam Roberts <[email protected]>

Copyright

Copyright © 2005 Sam Roberts

License

May be distributed under the same terms as Ruby

Version

0.4

Homepage

dnssd.rubyforge.org/net-mdns

Download

rubyforge.org/frs/?group_id=316

Summary

An implementation of a multicast DNS (mDNS) responder. mDNS is an extension of hierarchical, unicast DNS to link-local multicast, used to do service discovery and address lookups over local networks. It is most widely known because it is part of Apple’s OS X.

net-mdns consists of:

  • Net::DNS::MDNSSD: a high-level API for browsing, resolving, and advertising services using DNS-SD over mDNS that aims to be compatible with DNSSD, see below for more information.

  • Resolv::MDNS: an extension to the ‘resolv’ resolver library that adds support for multicast DNS.

  • Net::DNS::MDNS: the low-level APIs and mDNS responder at the core of Resolv::MDNS and Net::DNS::MDNSSD.

net-mdns can be used for:

  • name to address lookups on local networks

  • address to name lookups on local networks

  • discovery of services on local networks

  • advertisement of services on local networks

Client Example

This is an example of finding all _http._tcp services, connecting to them, and printing the ‘Server’ field of the HTTP headers using Net::HTTP (from exhttp.txt):

require 'net/http'
require 'thread'
require 'pp'

# For MDNSSD
require 'net/dns/mdns-sd'

# To make Resolv aware of mDNS
require 'net/dns/resolv-mdns'

# To make TCPSocket use Resolv, not the C library resolver.
require 'net/dns/resolv-replace'

# Use a short name.
DNSSD = Net::DNS::MDNSSD

# Sync stdout, and don't write to console from multiple threads.
$stdout.sync
$lock = Mutex.new

# Be quiet.
debug = false

DNSSD.browse('_http._tcp') do |b|
  $lock.synchronize { pp b } if debug
  DNSSD.resolve(b.name, b.type) do |r|
    $lock.synchronize { pp r } if debug
    begin
      http = Net::HTTP.new(r.target, r.port)

      path = r.text_record['path'] || '/'

      headers = http.head(path)

      $lock.synchronize do
        puts "#{r.name.inspect} on #{r.target}:#{r.port}#{path} was last-modified #{headers['server']}"
      end
    rescue
      $lock.synchronize { puts $!; puts $!.backtrace }
    end
  end
end

# Hit enter when you think that's all.
STDIN.gets

Server Example

This is an example of advertising a webrick server using DNS-SD (from exwebrick.txt).

require 'webrick'
require 'net/dns/mdns-sd'

DNSSD = Net::DNS::MDNSSD

class HelloServlet < WEBrick::HTTPServlet::AbstractServlet
  def do_GET(req, resp)   
    resp.body = "hello, world\n"
    resp['content-type'] = 'text/plain'
    raise WEBrick::HTTPStatus::OK
  end
end

server = WEBrick::HTTPServer.new( :Port => 8080 )

server.mount( '/hello/', HelloServlet )

handle = DNSSD.register("hello", '_http._tcp', 'local', 8080, 'path' => '/hello/')

['INT', 'TERM'].each { |signal| 
  trap(signal) { server.shutdown; handle.stop; }
}

server.start

Samples

There are a few command line utilities in the samples/ directory:

  • mdns.txt, mdns.rb is a command line interface for to Net::DNS::MDNSSD (or to DNSSD)

  • v1demo.txt, v1demo.rb is a sample provided by Ben Giddings showing the call sequences to use with Resolv::MDNS for service resolution. This predates Net::DNS::MDNSSD, so while its a great sample, you might want to look at mdns.rb instead.

  • v1mdns.txt, v1mdns.rb is a low-level utility for exercising Resolv::MDNS.

  • mdns-watch.txt, mdns-watch.rb is a utility that dumps all mDNS traffic, useful for debugging.

Comparison to the DNS-SD Extension

The DNS-SD project at dnssd.rubyforge.org 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 since they use a daemon written in C by a dedicated team at Apple.

Currently, the only thing I’m aware of net-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, and allow querying of arbitrary DNS record types. There is no reason DNS-SD can’t do this, it just needs to wrap DNSServiceQueryRecord() and expose it, and that will happen sometime soon.

Since net-mdns doesn’t do significantly more than DNSSD, why would you be interested in it?

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, net-mdns may be useful to you.

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

  • www.dns-sd.org (a list of services is at www.dns-sd.org/ServiceTypes.html).

  • dnssd.rubyforge.org - for DNSSD, a C extension for communicating with Apple’s mDNSResponder daemon.

TODO

See TODO.

Thanks

  • to Tanaka Akira for resolv.rb, I learned a lot about meta-programming and ruby idioms from it, as well as getting an almost-complete implementation of the DNS message format and a resolver framework I could plug mDNS support into.

  • to Charles Mills for letting me add net-mdns to DNS-SD’s Rubyforge project when he hardly knew me, and hadn’t even seen any code yet.

  • to Ben Giddings for promising to use this if I wrote it, which was the catalyst for resuming a year-old prototype.

Author

Any feedback, questions, problems, etc., please contact me, Sam Roberts, via [email protected], or directly.

Defined Under Namespace

Modules: QueryImp Classes: Answer, BackgroundQuery, Cache, Query, Question, Responder, Service