Manually Adding DNS-SD Service Discovery Records to an Existing Name Server

Overview

Zero Configuration Networking, or Bonjour as Apple calls it, is a networking technology that allows devices to automatically discover each other without any configuration. In the first release, Apple’s Bonjour used link-local Multicast DNS to discover services being advertised on the local network, because small ad hoc networks were the area of TCP/IP networking most urgently in need of improvement, but from the start the DNS-SD road-map included wide-area discovery too. Starting in Mac OS X v10.4 Tiger and Bonjour for Windows, clients also use conventional Unicast DNS to discover services being advertised in any accessible domain anywhere in the world.

There are several ways you can use Wide-Area DNS Service Discovery. One is to set up a Dynamic DNS Server to allow machines to automatically advertise their services. Another way, described here, is manually to add DNS records describing the services you want to advertise for clients to discover. If you want to try this out in isolation first, not on your existing name server, then the instructions in Setting up a Test Server to experiment with Wide-Area DNS-SD describe how to do that.

Conceptually you can think of this “read-only” DNS-SD. You don’t allow individual machines to dynamically register to advertise services, but you do allow client machines to query your DNS server to discover a carefully selected set of services you’ve chosen to advertise. One obvious service type to advertise is web pages. Many companies have internal web pages of useful information for employees, including a page of information for new employees. The catch is that new employees, being new employees, probably don’t know the URL for the information page. Long-time employees, having not consulted the “new employee information page” for years, probably don’t remember the URL. This problem of “not knowing the URL” recurs in many situations. You might be waiting in an airport, using the WiFi network, and the airport might have a web page showing flight departure times, but you don’t know the URL to type. Indeed, you might not even know that the airport has a web page showing flight departure times, because the WiFi network operator has no good way to communicate that information to you. Similarly you could be using the network in a hotel room and not know about useful information pages the hotel has to offer. Adding static service records to an organization’s DNS server offers a solution to this problem.

How to Set It Up

You can advertise a single web page to local clients by adding just five records to your DNS server’s zone file, as shown below. Advertising additional pages requires just three more records each. While you’re experimenting you may want to set a short DNS TTL (time-to-live) so you can make changes without having to wait a long time for the updates to propagate.

You don’t need to run your own local DNS server to do this — services like DynDNS can host domains for you, and through their web interfaces you can add the necessary PTR, SRV and TXT records. The DNS server holding the service records doesn’t have to be on-site — it can be anywhere in the world. The way your clients discover which domain to query is from the domain they learn from your DHCP server. For this reason, in the administration screen for your home gateway’s DHCP server, you should set the “domain” or “domain name” setting to be the name of your domain that you control, not your ISP’s domain name.

; 1. Domain Enumeration
;
; These records invite clients to browse this domain.
; (The '@' sign means "the current domain" --
; i.e. the domain being described by this zone file.)

b._dns-sd._udp  IN PTR @   ;  b = browse domain
lb._dns-sd._udp IN PTR @   ; lb = legacy browse domain
; (domain that will be used for clients that don't specify a domain to browse)

; 2. List of named service entities
;
; These records list the named 'http' service entities we want clients
; to be able to discover. You can use upper-case, punctuation,
; UTF-8 rich text, etc., in service names, but certain punctuation
; like spaces and dots needs to be escaped with a backslash in the
; name server zone file (on the wire it's sent as raw data, not escaped).

_http._tcp  PTR New\ Employee\ Information\ Page._http._tcp

; 3. SRV & TXT records describing each service entity named above
;
; These records tell clients how to access the named 'http' service entities
; listed above. In the example below, fill in the correct host name.
; If it's a fully qualified host name, it needs to end with a dot, as shown.
; If it's a partial host name relative to the current zone (e.g. just "neinfo",
; with the remainder of the name being implicit) then don't end it with a dot.
; The "path=/xxx" in the TXT record tells the web browser the specific
; page on the server it should request in its "HTTP GET" command.
; Often, but not always, the path will be just "/".

New\ Employee\ Information\ Page._http._tcp     SRV 0 0 80 neinfo.example.com.
                                                TXT path=/

How it Works

Now that you’ve created your DNS records, the process works like this:

  1. When a client gets an address from your DHCP server, your DHCP server also includes information specifying a default DNS domain. In this example, we’ll assume that’s “example.com.”
  2. The client needs to determine whether you’d like it to use Wide-Area DNS-SD to browse for services. It does this by prepending the text “lb._dns-sd._udp” to the default DNS domain, and then doing a query for PTR records with that name (in this case “lb._dns-sd._udp.example.com.”).
  3. In our example the client’s query gets an answer: “example.com.” In principle the PTR record could indicate some other domain to browse instead, but in the common case a self-referential PTR referring back to the same domain is usually easiest.
  4. The client now knows it’s supposed to browse for services in “example.com.” Any time an application like the Safari web browser calls one of the DNS-SD browsing APIs to browse for services, without explicitly specifying a particular DNS domain to browse, the mdnsd daemon will automatically browse the default browse domain it learned from the network.

You can advertise other service types too, not just HTTP (web) servers. You can advertise printers that magically show up in the Mac’s print dialog, and in the Printer Setup Wizard in Bonjour for Windows. You can advertise FTP servers and SSH servers that magically show up in Terminal’s “Connect to Server” window. You could even advertise a shared iPhoto album of pictures from the company party that would magically show up in iPhoto’s side-bar. For the current list of service types, see DNS SRV (RFC 2782) Service Types.

Microsoft DNS

Microsoft’s Active Directory DNS server software can’t handle names with spaces in them. While you could make a rule that you have to name all your services without using any spaces, that’s a pretty ugly limitation. (Kind-of reminds you of the days of DOS 8.3 filenames, doesn’t it?) Fortunately, DNS-SD’s domain enumeration pointers give you just the amount of indirection you need to work around this problem. Instead of making the domain enumeration pointers be self-referential loops pointing back at the same domain, you can point them at a different domain, like this:

b._dns-sd._udp  IN PTR dns-sd-services
lb._dns-sd._udp IN PTR dns-sd-services

dns-sd-services IN NS  our-linux-machine-running-BIND-9

This zone file snippet (let’s say we’ve added it to the zone file for example.com) does two things. Firstly, it tells clients that they should browse in subdomain dns-sd-services.example.com. Secondly, it delegates the dns-sd-services.example.com subdomain to some other machine running some other name server software that doesn’t suffer Microsoft’s character set limitations, such as BIND 9.

Another similar scenario is where the parent domain is run on a perfectly capable Linux machine, but the _tcp and _udp subdomains have been delegated to a Microsoft Active Directory DNS server. In this case the solution is similar. The following two records on the Microsoft Active Directory DNS server for the “_udp.example.com.” domain direct clients back to the parent server for their DNS-SD browsing needs:

b._dns-sd       IN PTR dns-sd-services.example.com.
lb._dns-sd      IN PTR dns-sd-services.example.com.

As in the previous example, clients are directed to browse dns-sd-services.example.com. However, unlike the last example, it’s not necessary in this case to delegate “dns-sd-services.example.com” to a different server, since the “example.com” server is already capable of handling these queries. Delegating subdomains to a different machine is an option in DNS, not a requrement. You can choose to let the example.com server answer dns-sd-services.example.com queries too, or you can choose to delegate those to a different machine, as you wish. If you choose to take the simple route of just adding them to the existing example.com zone file, just remember to add the “dns-sd-services” part after each name, as shown below:

_http._tcp.dns-sd-services                         PTR New\ Employee\ Page._http._tcp.dns-sd-services
New\ Employee\ Page._http._tcp.dns-sd-services     SRV 0 0 80 neinfo.example.com.
                                                   TXT path=/

Using $INCLUDE files

If you plan to create a long list of services and all the repetition is looking a little tedious, you can use BIND’s $INCLUDE directive to make things a bit neater. For example, you could put the following lines in a file called “web-pages”:

@                       PTR New\ Employee\ Page
New\ Employee\ Page     SRV 0 0 80 neinfo.example.com.
                        TXT path=/

Now, in your main zone file for “example.com” you would reference this file using the $INCLUDE directive:

$INCLUDE web-pages _http._tcp.dns-sd-services

This tells the name server to read the web-pages file, but using the automatic suffix “_http._tcp.dns-sd-services.example.com” for relative names in that file instead of just “example.com”.

Learing the TXT record keys to use

Some services, like AirPrint printers, have many keys in the TXT record, which the client uses to identify the type of printer and its capabilities. Working out the correct TXT record keys to use by hand can be tedious. Fortunately, the dns-sd command-line tool can help.

Using the dns-sd -Z _ipp._tcp,_universal command will browse the local network for AirPrint-capable IPP printers, and output the results in BIND-compatible zone file format. You can then just copy-and-paste the PTR/SRV/TXT records for the AirPrint printers you want to make available into your DNS server’s zone file. You can put the entries into your main zone file, or into a sub-file called “AirPrint” which you include using the $INCLUDE directive as shown above.

To make your printers discoverable by AirPrint clients, you need to add one more PTR record by hand for each printer. AirPrint clients do not browse for all IPP printers; they browse for only the subset of IPP printers that support Universal Raster Format (URF). To tell the clients that the printer supports URF, you need to add one additional PTR record. This is identical to the PTR record that is output by the dns-sd -Z command, except that the name has “_universal._sub” prepended onto it.

Below is an example. In the DNS server’s zone file, $INCLUDE the AirPrint list, like this:

b._dns-sd._udp  IN PTR @
lb._dns-sd._udp IN PTR @
$INCLUDE AirPrint _ipp._tcp

The AirPrint file looks like this. Note the _universal._sub line added by hand.

@               PTR     Stuart\032Cheshire\226\128\153s\032Wide\032Area\032Bonjour\032AirPrint\032Printer
_universal._sub PTR     Stuart\032Cheshire\226\128\153s\032Wide\032Area\032Bonjour\032AirPrint\032Printer

Stuart\032Cheshire\226\128\153s\032Wide\032Area\032Bonjour\032AirPrint\032Printer       SRV     0 0 631 fqdn-of-printer.example.com.
Stuart\032Cheshire\226\128\153s\032Wide\032Area\032Bonjour\032AirPrint\032Printer       TXT     "txtvers=1" "qtotal=1" "rp=printers/HP_Color_LaserJet_9500" "ty=HP Color LaserJet
 9500 MFP" "adminurl=http://msweet.apple.com.:631/printers/HP_Color_LaserJet_9500" "note=Shared HP CLJ 9500; In DA7/4 Near Howard" "priority=0" "product=(HP color LaserJet 9500 
MFP)" "printer-state=3" "printer-type=0xC0B0DE" "Transparent=T" "Binary=T" "Fax=F" "Color=T" "Duplex=T" "Staple=F" "Copies=T" "Collate=T" "Punch=F" "Bind=F" "Sort=F" "Scan=F" "p
dl=application/octet-stream,application/pdf,application/postscript,image/jpeg,image/png,image/urf" "air=username,password" "URF=W8,SRGB24,CP255,RS600,DM1"


http://www.dns-sd.org