Manually Adding DNS-SD Service Discovery Records to an Existing Authoritative 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 authoritative 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 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 authoritative DNS server offers a solution to this problem.

Terminology Background: Authoritative Name Server vs. Recursive Resolver

A common misperception is that the service discovery records need to be created on a DNS server that the service discovery client is configured to use. Or, conversely, that the client needs to be configured to use the DNS server where the service discovery records exist. This is not correct. To look up the address of “www.amazon.com” you don’t need first to configure your client to use Amazon’s DNS servers. To look up the address of “www.google.com” you don’t need first to configure your client to use Google’s DNS servers. Just like looking up addresses, to discover services advertised in a given domain you don’t need first to configure your client to use that domain’s DNS servers. This is the beauty of DNS. The answer to a DNS question depends (generally speaking) only on what the question is, not which server you ask. You can send your DNS question to any DNS server in the world, and (generally speaking) always get the same answer for your question.

This common misperception about DNS-SD stems from the fact that the term “DNS server” is used to refer to two very different things. One is an authoritative name server. The other is a recursive resolver. Historically this use of the generic term “DNS server” to refer to both functions is because name server software like “named” (the name dæmon) could perform either or both functions, and when experienced DNS operators used the term “DNS server” they instinctively knew by context which function they were talking about (and they assumed the person they were talking to instinctively knew as well). The distinction has been less clear to people who are not experienced DNS operators (and sometimes even the experienced DNS operators get the functions muddled in their mind and forget which one they’re talking about).

  1. The first function of the “named” software is to be an authoritative name server for a domain. This is the ultimate repository where the authoritative DNS information about a domain resides. The authoritative name server function may be replicated for reliability — i.e., there may be several authoritative name servers for a given domain, all with the same DNS record data. Typical clients never communicate directly with authoritative name servers.

  2. The second function of the “named” software is to be a recursive resolver. Typical clients send their queries to their configured recursive resolver. Many clients get their recursive resolver configured via DHCP. Some users manually configure their clients to use another recursive resolver, such as one of the public resolvers operated by Google. That recursive resolver may return answers it had previously cached (hence its other common name, “caching resolver”) or may communicate with one or more authoritative name servers on the client’s behalf. This may require multiple round-trips to multiple authoritative name servers to determine which authoritative name server, somewhere on the planet, holds the answers the client seeks. Once the recursive resolver has retrieved the requested answers, it sends them to the client.

Unlike many other service discovery mechanisms where the clients do need to be configured somehow with the address of the correct service discovery server to use (and are limited to using only one service discovery server at a time), a big benefit of DNS-Based Service Discovery is that the clients continue to use their existing recursive resolver, unchanged, and that recursive resolver continues to talk to many authoritative servers on the client’s behalf. All of this is not a new invention; it is simply making use of the DNS protocol and machinery already in place.

So, in summary, to deploy DNS-SD, clients do not need to be configured to use a different recursive resolver, and no changes are required on the recursive resolver the clients are using. The configuration the clients need is not whom to ask, but what to ask. From what the client is asking, the recursive resolver works out whom to ask by itself — just as the recursive resolver does already when you ask it to look up host names, which may reside on authoritative servers anywhere on the planet. The clients need to know in which domain to look for services, not which recursive resolver to ask. Fortunately, in most cases, the necessary configuration is already present. When clients get a response packet from the local network’s DHCP server, there’s a “domain” parameter in that packet, and it’s typically used as the client’s default DNS search domain. DNS-SD clients also use it to discover their default DNS service discovery domain. So, in most cases, all the required client configuration is already in place. What remains is simply to add a few service discovery records to the authoritative name server(s) for the domain given in the client’s DHCP configuration, and that’s what the remainder of this page talks about.

How to Set It Up

You can advertise a single web page to local clients by adding just five records to your authoritative 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 authoritative 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 authoritative 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.

In the example here, assuming that the DHCP “domain” option is set to “example.com”, the text below shows the content of the zone file for “example.com”. In other words, if the “/etc/named.conf” configuration file contains a line saying
zone "example.com" { type master; file "example-zone"; };
then the text shown below goes in the “example-zone” file.

Note that all names in the zone file that are not fully qualified (i.e., do not end with a dot) are relative to the zone file origin (e.g., the unqualified host name “ne-info” is equivalent to the fully qualified host name “ne-info.example.com.”).

One of the goals of DNS-Based Service Discovery is to provide a user-friendly experience, so it is fortunate that the DNS protocol on the wire (or over the air) fully supports arbitrary 8-bit values in names, allowing the use of rich-text names, including spaces. When used in a text-based configuration file, where spaces have significance as separators between fields, literal spaces in names are prefixed with a backslash and written as “\ ”. More generally speaking, any desired 8-bit value can be represented in the text-based zone file using a backslash followed by a three-digit decimal number. In the example here, the name written in the text-based zone file as “New\ Employee\ Information\ Page” appears to the user as “New Employee Information Page”.

; 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 "ne-info",
; 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 ne-info
                                                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 authoritative 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 authoritative server, since the “example.com” authoritative server is already capable of handling these queries. Delegating subdomains to a different machine is an option in DNS, not a requirement. You can choose to let the example.com authoritative 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 ne-info.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 ne-info.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 authoritative 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”.

Learning the TXT record keys to use
(or: “How to set up Wide-Area AirPrint”)

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 link for AirPrint-capable IPP printers, and output the results in BIND-compatible zone file format. For each AirPrint printer that you want to make available, copy-and-paste the appropriate PTR/SRV/TXT records into your authoritative 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 below.

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 authoritative server’s zone file, $INCLUDE the AirPrint list, like this:

b._dns-sd._udp  IN PTR @    ; Standard records to signal clients to enable Wide-Area discovery for this domain
lb._dns-sd._udp IN PTR @
$INCLUDE AirPrint _ipp._tcp ; Include our list of AirPrint printers to advertise

The content of the AirPrint file is as illustrated in the example below.

Note the _universal._sub line added by hand.

Also note the liberal use of backslash escaping in this example to illustrate the creation of a user-friendly rich-text name. The sequence “\032” represents a literal space character and the sequence “\226\128\153” is the UTF-8 byte sequence for an apostrophe character. Thus the printer name “Stuart Cheshire’s Wide Area Bonjour AirPrint Printer” (with spaces and an apostrophe) appears in the text-based configuration file as “Stuart\032Cheshire\226\128\153s\032Wide\032Area\032Bonjour\032AirPrint\032Printer”.

Providing user-friendly rich-text names is optional, not mandatory. It is possible to name services using only lowercase letters and no spaces, and this will also work fine. This may be preferable in some environments, where users familiar with names containing only lowercase letters and no spaces might find capital letters and spaces disconcerting. In some situations it may be convenient to make the user-visible service instance name be the same as the fully-qualified host name of the device providing the service. To include literal dot characters in a service instance name in a zone file, prefix them with a backslash character to differentiate them from the dots that signify DNS label boundaries. Thus, to advertise a printer with service instance name “printer.example.com”, the name of its SRV record would be “printer\.example\.com._ipp._tcp.example.com.

The TXT records for AirPrint printers are sometimes quite long. The entire TXT record content can be pasted into the zone file as a single line. Alternatively, if you wish to split the TXT record content over multiple lines, enclose the multiple lines in parentheses as shown in the example below.

@               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"
    "pdl=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