RFC 6763

DNS-Based Service Discovery

๐Ÿ“… published February 2013, from ietf

DNS-Based Service Discovery ๐ŸŽ€

RFC 6763, published February 2013 (ISSN 2070-1721) ๐Ÿ—“๏ธ

This one was written by S. Cheshire and M. Krochmal from Apple Inc. โœจ It's on the Standards Track, so it's an official Internet Standard, not just a suggestion. The title block doesn't list any "obsoletes" or "updates" entries, so it's not replacing or changing another RFC. ๐Ÿ’…

Abstract โœจ

okay so this doc is all about how DNS records get named and structured so that service discovery works ๐Ÿฆ‹ You tell your client what kind of service you want and which domain to look in, and it can find a list of named instances of that service using totally normal DNS queries. The whole mechanism is called DNS-based Service Discovery, or DNS-SD for short. iconic ๐Ÿ”ฅ

Status of This Memo ๐Ÿ“

This is an Internet Standards Track document. ๐Ÿ‘‘

It's a product of the Internet Engineering Task Force (IETF), and it represents the consensus of the IETF community. It went through public review and got approved for publication by the Internet Engineering Steering Group (IESG). If you want more info on Internet Standards, check out Section 2 of RFC 5741 ๐ŸŒธ

For the current status of this document, any errata, and how to give feedback, go to http://www.rfc-editor.org/info/rfc6763 ๐Ÿ’–

Copyright (c) 2013 IETF Trust and the persons identified as the document authors. All rights reserved. ๐Ÿซถ

This document is subject to BCP 78 and the IETF Trust's Legal Provisions Relating to IETF Documents (http://trustee.ietf.org/license-info) as they were in effect on the date of publication. Please read these carefully, because they spell out your rights and restrictions with respect to this document. ๐Ÿ™ˆ Code Components pulled out of this document must include Simplified BSD License text, as described in Section 4.e of the Trust Legal Provisions, and they come without warranty, as described in the Simplified BSD License. โš–๏ธ

Table of Contents ๐Ÿงš

1. Introduction ....................................................3
2. Conventions and Terminology Used in This Document ...............5
3. Design Goals ....................................................5
4. Service Instance Enumeration (Browsing) .........................6
   4.1. Structured Service Instance Names ..........................6
   4.2. User Interface Presentation ................................9
   4.3. Internal Handling of Names .................................9
5. Service Instance Resolution ....................................10
6. Data Syntax for DNS-SD TXT Records .............................11
   6.1. General Format Rules for DNS TXT Records ..................11
   6.2. DNS-SD TXT Record Size ....................................12
   6.3. DNS TXT Record Format Rules for Use in DNS-SD .............13
   6.4. Rules for Keys in DNS-SD Key/Value Pairs ..................14
   6.5. Rules for Values in DNS-SD Key/Value Pairs ................16
   6.6. Example TXT Record ........................................17
   6.7. Version Tag ...............................................17
   6.8. Service Instances with Multiple TXT Records ...............18
7. Service Names ..................................................19
   7.1. Selective Instance Enumeration (Subtypes) .................21
   7.2. Service Name Length Limits ................................23
8. Flagship Naming ................................................25
9. Service Type Enumeration .......................................27
10. Populating the DNS with Information ...........................27
11. Discovery of Browsing and Registration Domains (Domain
    Enumeration) ..................................................28
12. DNS Additional Record Generation ..............................30
   12.1. PTR Records ..............................................30
   12.2. SRV Records ..............................................30
   12.3. TXT Records ..............................................31
   12.4. Other Record Types .......................................31
13. Working Examples ..............................................31
   13.1. What web pages are being advertised from dns-sd.org? .....31
   13.2. What printer-configuration web pages are there? ..........31
   13.3. How do I access the web page called "Service
         Discovery"? ..............................................32
14. IPv6 Considerations ...........................................32
15. Security Considerations .......................................32
16. IANA Considerations ...........................................32
17. Acknowledgments ...............................................33
18. References ....................................................33
   18.1. Normative References .....................................33
   18.2. Informative References ...................................34
Appendix A. Rationale for Using DNS as a Basis for Service
            Discovery .............................................37

Appendix B. Ordering of Service Instance Name Components ..........38
   B.1. Semantic Structure ........................................38
   B.2. Network Efficiency ........................................39
   B.3. Operational Flexibility ...................................39
Appendix C. What You See Is What You Get ..........................40
Appendix D. Choice of Factory-Default Names .......................42
Appendix E. Name Encodings in the Domain Name System ..............44
Appendix F. "Continuous Live Update" Browsing Model ...............45
Appendix G. Deployment History ....................................47

1. Introduction ๐Ÿฆ‹

okay so this doc is literally the blueprint for service discovery, and the whole point is naming and structuring DNS records so a client can find a list of named instances of a service it wants, using standard DNS queries. This mechanism is called DNS-based Service Discovery, or DNS-SD. ๐Ÿ’œ

Here's the big promise: DNS-SD does NOT change the structure of DNS messages. It doesn't add any new operation codes, response codes, resource record types, or any other new DNS protocol values. Zero new DNS vocab, just clever naming ๐Ÿง โœจ

So, how does it actually work? A particular service instance gets described with a DNS SRV [RFC2782] record plus a DNS TXT [RFC1035] record. The SRV record is named <Instance>.<Service>.<Domain> and tells you the target host and port where you can reach that instance. The TXT record with the same name holds extra info about the instance in a structured key/value format, which Section 6 covers. ๐ŸŽ€

To find the instances of a service type, the client sends a query for a DNS PTR [RFC1035] record named <Service>.<Domain>. That gives back a set of zero or more names, and each one is the name of one of those SRV/TXT record pairs we just talked about. It's like a group chat roster, but for servers ๐Ÿ’…

This spec works with both Multicast DNS [RFC6762] and today's existing Unicast DNS server and client software. Bestie-level compatibility ๐Ÿซถ

With Multicast DNS, DNS-SD can give you zero-configuration operation. Just plug in a DNS-SD/mDNS device, and its services get advertised on the local link with no extra user interaction [ZC]. Literally effortless ๐Ÿ˜ญโœจ

With conventional Unicast DNS, you usually need some configuration first. For example, you have to set up the device with the DNS domain(s) where it should advertise its services, and give it the DNS Update [RFC2136] [RFC3007] keys so it's allowed to do that. There's one rare exception: a secure corporate network behind a firewall where no DNS Update keys are needed. There, zero-configuration might work by having the device register its services in a default registration domain learned from the network (see Section 11, "Discovery of Browsing and Registration Domains"). But honestly that's the exception, and security credentials are usually required to perform DNS updates ๐Ÿ”

Also, when you use DNS-SD with Unicast DNS, the Unicast DNS-SD service does NOT have to run on the same DNS server hardware that handles an organization's regular host name lookup. People usually think of "DNS" only as mapping host names to IP addresses, but the RFC2181 folks say "the DNS is a general (if somewhat limited) hierarchical database, and can store almost any kind of data, for almost any purpose" [RFC2181]. Main character energy for DNS ๐Ÿ‘‘ By delegating the _tcp and _udp subdomains, all the DNS-SD workload can get offloaded to a different machine. Whether DNS-SD runs on the main DNS server or not is up to the network administrator, and that flexibility is one of the perks of using DNS ๐Ÿ“

Even when DNS-SD is delegated to a different machine, DNS is still a great choice. It's mature, well understood, has multiple independent implementations from different vendors, a wide selection of books, and an established workforce that knows how to run it. The alternative would make every site in the world install, learn, configure, operate, and maintain some brand-new, unfamiliar server software. Yeah, no thanks ๐Ÿ˜ฉ It seems really unlikely that any other service discovery tech could compete with the ubiquitous deployment DNS already has. If you want the deeper dive, check out Appendix A, "Rationale for Using DNS as a Basis for Service Discovery" ๐Ÿ“š

This document is written for two audiences. First, developers making application software that offers or accesses network services. Second, developers making DNS-SD libraries that implement the advertising and discovery mechanisms. For both groups, reading the entire document is helpful ๐Ÿ’– If you're an application dev, this doc gives you guidance on choosing instance names, service names, and other stuff that shapes a good overall user experience. It also helps to understand the underlying DNS mechanisms, so you know their capabilities and limits (e.g., name length limits) ๐Ÿงš If you're a library dev writing software that constructs the DNS records (to advertise a service) and generates the DNS queries (to discover and use a service), knowing the ultimate user-experience goals helps you design APIs that actually hit them โœจ

2. Conventions and Terminology Used in This Document ๐ŸŒธ

Okay, important stuff: the key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in "Key words for use in RFCs to Indicate Requirement Levels" [RFC2119]. These are the official requirement levels, so read them like they're serious ๐Ÿ”ฅ

3. Design Goals โœจ

okay so a good service discovery protocol needs a LOT of stuff, but three things are the absolute most important ๐Ÿ’…

  • (i) The ability to query for services of a certain type in a certain logical domain, and receive in response a list of named instances (network browsing or "Service Instance Enumeration"). ๐Ÿซถ
  • (ii) Given a particular named instance, the ability to efficiently resolve that instance name to the required information a client needs to actually use the service, i.e., IP address and port number, at the very least (Service Instance Resolution). ๐Ÿ”ฅ
  • (iii) Instance names should be relatively persistent. Like, if a user picks their default printer from a list of options today, they should still be able to print on that printer tomorrow ๐Ÿ–จ๏ธ even if the IP address and/or port number where the service lives have changed. And they (or their software) shouldn't have to do step (i), the initial network browsing, a second time. ๐Ÿ™„

Also, if this is going to be a big success, the protocol has to be so simple to implement that basically any device that can do IP can handle the service discovery software too. no excuses ๐Ÿ’–

All of this gets explored in more detail in the rest of the doc. There's also a deeper dive in "Requirements for a Protocol to Replace the AppleTalk Name Binding Protocol (NBP)" [RFC6760]. That one pulls from two decades of AppleTalk experience to come up with a list of universal requirements that apply to basically any service discovery protocol. the research is immaculate ๐ŸŒธ


4. Service Instance Enumeration (Browsing)

okay so traditional DNS SRV records [RFC2782] are good for finding instances of a type of service when all the instances are basically interchangeable and give the client the same service ๐Ÿ“

For example, SRV records with the (hypothetical) name _http._tcp.example.com. would let a client discover servers implementing the _http._tcp service (aka web servers) for the example.com. domain. The unstated assumption is that all these servers serve the same set of web pages, so it doesn't matter to the client which one it uses, as long as it picks one at random according to the weight and priority rules in the DNS SRV specification [RFC2782]. โœจ

Other kinds of service are way less interchangeable ๐Ÿ™ˆ If a word processing app looked up the (hypothetical) SRV record _ipp._tcp.example.com. to find the list of Internet Printing Protocol (IPP) [RFC2910] printers at Example Co., picking one at random and printing on it would probably not be what the user wanted. Yikes.

The rest of this section explains how SRV records can be used a little differently, so a user can discover the names of all the available instances of a given type of service and then pick the exact one they want from that list. main character energy ๐Ÿ‘‘

4.1. Structured Service Instance Names

this doc borrows the logical service-naming syntax and semantics from DNS SRV records, but adds one level of indirection ๐Ÿงš Instead of asking for records of type "SRV" with the name _ipp._tcp.example.com., the client asks for records of type "PTR" (a pointer from one name to another in the DNS namespace) [RFC1035].

Think of the domain name _ipp._tcp.example.com. like an absolute path to a folder in a file system. Then the DNS-SD PTR lookup is like listing that folder to see everything inside it ๐Ÿ“‚ (Remember that domain names are written in reverse order compared to path names. An absolute path starts with the root on the left and reads left to right, but a fully qualified domain name starts with the root on the right and reads right to left. If _ipp._tcp.example.com. were written as a file system path, it would be /com/example/_tcp/_ipp.) The result of a PTR lookup for the name "<Service>.<Domain>" is a set of zero or more PTR records giving Service Instance Names of this form:

Service Instance Name = <Instance> . <Service> . <Domain>

For why the components are in this order, check out Appendix B, "Ordering of Service Instance Name Components". ๐ŸŽ€

4.1.1. Instance Names

The <Instance> part of a Service Instance Name is a user-friendly name made of arbitrary Net-Unicode text [RFC5198]. It MUST NOT contain ASCII control characters (byte values 0x00-0x1F and 0x7F) [RFC20], but otherwise it can contain any characters, no restrictions. That includes spaces, uppercase, lowercase, punctuation (dots too!), accented characters, non-Roman text, and anything else Net-Unicode can represent. ๐ŸŒˆ For why the <Instance> name should be something a user can see and read, instead of an invisible machine-generated ID, read Appendix C, "What You See Is What You Get".

The <Instance> part of a service's name on the network SHOULD be configurable by whoever sets up the service, so they can give it a helpful name. However, the device or service SHOULD NOT make the user configure a name before it can be used. A sensible default name can, in lots of cases, let the device or service be accessed with zero manual setup at all ๐Ÿซถ The default name should be short and descriptive, and it SHOULD NOT include the device's Media Access Control (MAC) address, a serial number, or any similar unreadable hex string just to make the name globally unique. ๐Ÿ’€ For why <Instance> names don't need to be (and SHOULD NOT be) made unique at the factory, see Appendix D, "Choice of Factory-Default Names".

The <Instance> part of the Service Instance Name is stored directly in the DNS as a single DNS label of canonical precomposed UTF-8 [RFC3629] "Net-Unicode" (Unicode Normalization Form C) [RFC5198] text. For more on text encodings, see Appendix E, "Name Encodings in the Domain Name System". ๐Ÿ”ฅ

DNS labels are currently capped at 63 octets. UTF-8 can take up to four octets per Unicode character, so in the worst case the <Instance> part could be limited to fifteen Unicode characters. BUT the Unicode characters that take more octets in UTF-8 tend to be the rarer ones, and they tend to pack more meaning per character, so it's not as scary as it sounds โœจ

Also, any character in the commonly used 16-bit Unicode Basic Multilingual Plane [Unicode6] can be encoded in no more than three octets of UTF-8. So an instance name can hold up to 21 Kanji characters, which is plenty expressive for most purposes ๐ŸŽŒ

4.1.2. Service Names

The <Service> part of a Service Instance Name is a pair of DNS labels, following the convention already set for SRV records [RFC2782]. The first label is an underscore followed by the Service Name [RFC6335]. The Service Name says what the service does and what application protocol it uses to do it. The second label is either "_tcp" (for application protocols that run over TCP) or "_udp" (for all others). For more details, see Section 7, "Service Names". ๐Ÿง

4.1.3. Domain Names

The <Domain> part of a Service Instance Name says which DNS subdomain those names are registered in. It can be "local.", which means "link-local Multicast DNS" [RFC6762], or it can be a regular Unicast DNS domain name, like "ietf.org.", "cs.stanford.edu.", or "eng.us.ibm.com." Since Service Instance Names aren't host names, they aren't bound by the usual host name rules [RFC1033] [RFC1034] [RFC1035], so rich-text service subdomains are allowed and encouraged. For example:

Building 2, 1st Floor  .  example  .  com  .
Building 2, 2nd Floor  .  example  .  com  .
Building 2, 3rd Floor  .  example  .  com  .
Building 2, 4th Floor  .  example  .  com  .

Because Service Instance Names aren't limited by host name rules, this document recommends storing them in the DNS and sending them over the wire as straightforward canonical precomposed UTF-8 [RFC3629] "Net-Unicode" (Unicode Normalization Form C) [RFC5198] text. ๐Ÿ’– If the DNS server gives a negative response for the name in question, client software MAY choose to retry the query using the "Punycode" algorithm [RFC3492] to convert the UTF-8 name to an IDNA "A-label" [RFC5890]. It starts with the top-level label, then keeps issuing the query, with more and more labels converted to IDNA A-labels each time. If it has converted every label to an IDNA A-label and the query still fails, it gives up ๐Ÿ˜ญ


4.2. User Interface Presentation

The names that come back from the Service Instance Enumeration PTR lookup get shown to the user in a list, so they can pick one (or more). Usually, only the first label is shown, which is the user-friendly <Instance> part of the name ๐ŸŒธ

In the common case, the <Service> and <Domain> are already known to the client software, since the user already gave them implicitly by choosing the service they want and the domain to look in. Still, the software handling the response should be careful not to make invalid assumptions, because it is possible (though rare) for an enumeration in one domain to return names of services in a different domain. Similarly, when using subtypes (see Section 7.1, "Selective Instance Enumeration"), the <Service> of the discovered instance may not be exactly the same as the <Service> that was requested. ๐Ÿ‘€

For more on user-interface considerations for Service Instance Enumeration (browsing), see Appendix F, "'Continuous Live Update' Browsing Model". ๐Ÿฆ‹

Once the user has picked their named instance, the Service Instance Name may be used right away, or saved in some persistent user-preference data structure for later. It depends on what's appropriate for the application in question. โœจ

4.3. Internal Handling of Names โœจ

okay so, if client software takes the <Instance>, <Service>, and <Domain> bits of a Service Instance Name and smushes them into one string ๐Ÿซ , there's a catch. The <Instance> part can contain any characters, dots included, so you MUST take proper precautions to keep the DNS label boundaries intact. Client software can do this in a few ways, like character escaping. ๐Ÿ’…

This document recommends that when you glue the three parts together, any dots in the <Instance> part get escaped the classic DNS text-file way: put a backslash in front of each literal dot (so "." becomes \.). Same vibe for backslashes in the <Instance> part, which get escaped with another backslash (so \ becomes \\). ๐ŸŽ€

Once that's done, the three components can be safely concatenated. The backslash escaping lets literal dots (escaped) be told apart from label-separator dots (not escaped), and the final string can go straight into standard DNS APIs like res_query(), which reads the backslash-escaped string exactly as intended. Iconic. ๐Ÿฆ‹


5. Service Instance Resolution ๐Ÿ”

When a client wants to contact a particular service, identified by a Service Instance Name it already found through Service Instance Enumeration (browsing), it queries for the SRV and TXT records of that name. The SRV record tells you the port number and target host name where the service lives. The TXT record gives extra info about the service, as described in Section 6, "Data Syntax for DNS-SD TXT Records". ๐Ÿ“

SRV records are literally the main character here, because they remove the need for preassigned port numbers. There are only 65535 TCP port numbers, and they're traditionally handed out one per application protocol [RFC6335]. The X Window System got a whole block of 64 TCP ports (6000-6063). Giving each instance of a service on one machine its own port is totally sensible, but handing every app its own big static range, like X did, is not a practical way to do it. On any given host, most TCP ports are reserved for services that will never run on that host in its lifetime. That's very poor use of the limited port space ๐Ÿ˜ญ.

With SRV records, each host dynamically allocates its available port numbers to the services that are actually running there and need them, then advertises those port numbers via SRV records. Allocating listening ports locally, per host, as needed uses the port space way better than today's centralized global allocation. ๐ŸŒธ

In the event that more than one SRV is returned, clients MUST correctly interpret the priority and weight fields -- i.e., lower-numbered priority servers should be used in preference to higher-numbered priority servers, and servers with equal priority should be selected randomly in proportion to their relative weights. However, in the overwhelmingly common case, a single advertised DNS-SD service instance is described by exactly one SRV record, and in this common case the priority and weight fields of the SRV record SHOULD both be set to zero. ๐Ÿ‘‘


6. Data Syntax for DNS-SD TXT Records ๐Ÿง

Some services found through Service Instance Enumeration need more than just an IP address and port number to fully identify the service instance. For example, printing via the old Unix LPR (port 515) protocol [RFC1179] often specifies a queue name [BJP]. That queue name is usually short and cryptic and doesn't need to be shown to the user. It should be treated the same way as the IP address and port: it's another piece of addressing info needed to pin down one specific instance of a service being offered by some piece of hardware. ๐Ÿ–จ๏ธ

Similarly, a file server may have multiple volumes, each identified by its own volume name, and a web server typically has multiple pages, each identified by its own URL. In these cases, the extra data is stored in a TXT record with the same name as the SRV record. What that additional data means and how it's used is service-dependent, but the overall syntax of the data in the TXT record is standardized, as described below. โœจ

Every DNS-SD service MUST have a TXT record in addition to its SRV record, with the same name, even if the service has no additional data to store and the TXT record contains no more than a single zero byte. This lets a service have explicit control over the Time to Live (TTL) of its (empty) TXT record, rather than using the default negative caching TTL, which would otherwise be used for a "no error no answer" DNS response. ๐Ÿซถ

Note that this requirement for a mandatory TXT record applies exclusively to DNS-SD service advertising, i.e., services advertised using the PTR+SRV+TXT convention specified in this document. It is not a requirement of SRV records in general. The DNS SRV record datatype [RFC2782] may still be used in other contexts without any requirement for accompanying PTR and TXT records. ๐Ÿ’œ

6.1. General Format Rules for DNS TXT Records ๐Ÿงฉ

A DNS TXT record can be up to 65535 (0xFFFF) bytes long. The total length is indicated by the length given in the resource record header in the DNS message. There's no way to tell from the data alone how long it is (there's no length count at the start, and no terminating NULL byte at the end). ๐Ÿ™ˆ

Heads up: when using Multicast DNS [RFC6762], the maximum packet size is 9000 bytes, including the IP header, UDP header, and DNS message header. That puts an upper limit on the size of TXT records of about 8900 bytes. In practice, the maximum sensible size of a DNS-SD TXT record is way smaller, typically at most a few hundred bytes, as described below in Section 6.2. ๐ŸŒˆ

The format of the data within a DNS TXT record is one or more strings, packed together in memory without any intervening gaps or padding bytes for word alignment. Each constituent string is a single length byte, followed by 0-255 bytes of text data. ๐Ÿ“

These format rules for TXT records are defined in Section 3.3.14 of the DNS specification [RFC1035] and aren't specific to DNS-SD. DNS-SD adds additional rules for what data should be stored in those constituent strings when used for DNS-SD service advertising, i.e., when describing services advertised using the PTR+SRV+TXT convention specified in this document. ๐Ÿฆ‹

An empty TXT record containing zero strings is not allowed [RFC1035]. DNS-SD implementations MUST NOT emit empty TXT records. DNS-SD clients MUST treat the following as equivalent:

  • A TXT record containing a single zero byte (i.e., a single empty string).
  • An empty (zero-length) TXT record (this is not strictly legal, but should one be received, it should be interpreted as the same as a single empty string).
  • No TXT record (i.e., an NXDOMAIN or no-error-no-answer response).

6.2. DNS-SD TXT Record Size ๐Ÿ“

The total size of a typical DNS-SD TXT record is intended to be small, 200 bytes or less. ๐ŸŒธ

In cases where more data is justified (e.g., LPR printing [BJP]), keeping the total size under 400 bytes should allow it to fit in a single 512-byte DNS message [RFC1035]. ๐Ÿ–จ๏ธ

In extreme cases where even this is not enough, keeping the size of the TXT record under 1300 bytes should allow it to fit in a single 1500-byte Ethernet packet. ๐Ÿ’…

Using TXT records larger than 1300 bytes is NOT RECOMMENDED at this time. ๐Ÿšซ

Real-world warning, bestie: some Ethernet hardware vendors offer chipsets with Multicast DNS [RFC6762] offload, so computers can sleep and still be discoverable on the network. Early versions of these chipsets were sometimes quite limited. For example, some were (unwisely) limited to handling TXT records no larger than 256 bytes, which meant LPR printer services with larger TXT records did not work. Developers should be aware of this real-world limitation, and should understand that even hardware which is otherwise perfectly capable may have low-power and sleep modes that are more limited. ๐Ÿ˜ญ๐Ÿ”ฅ

6.3. DNS TXT Record Format Rules for Use in DNS-SD ๐Ÿ’–

okay so DNS-SD uses DNS TXT records to stash arbitrary key/value pairs that carry extra info about the named service ๐ŸŽ€ Each pair gets its own constituent string inside the TXT record, written as key=value (no quotation marks, obvs). Everything up to the first = is the key (Section 6.4). Everything after the first = to the end of the string, including any later = signs, is the value (Section 6.5). You don't need quotes around the value, even if it has spaces, = signs, or other punctuation ๐Ÿ’… Each author writing a DNS-SD profile for finding instances of a particular service type should define the base set of key/value attributes that are valid for that type ๐Ÿงš

Using this standardized key/value syntax is so iconic because it makes the base definitions way easier to expand later by defining new named attributes โœจ If an implementation sees unknown keys in a service TXT record, it MUST silently ignore them. No drama, just skip ๐Ÿ™ˆ

The target host name and TCP (or UDP) port number of the service are given in the SRV record. This information (target host name and port number) MUST NOT be duplicated using key/value attributes in the TXT record. Don't double up on it, bestie ๐Ÿ™…

The whole point of DNS-SD TXT records is to convey a small amount of useful extra info about a service ๐Ÿ“ Ideally, a client shouldn't need to fetch this extra info before it can usefully connect to the service. For a well-designed application protocol, even if the TXT record has nothing in it at all, you should be able to connect to that listening process knowing only the host name, port number, and protocol being used, and then do version or feature negotiation to figure out any further options or capabilities of the service instance ๐Ÿฆ‹ For example, when connecting to an AFP (Apple Filing Protocol) server [AFP] over TCP, the client starts a protocol exchange with the server to find out which version of AFP the server implements and which optional features or capabilities (if any) are available. Main character protocol energy ๐Ÿ‘‘

For protocols with adequate in-band version and feature negotiation, any info in the TXT record should be treated as a performance optimization ๐Ÿš€ When a client discovers lots of instances of a service, the TXT record lets it know some basic info about each instance without opening a TCP connection to every single one and interrogating each service instance separately ๐Ÿ’œ Be careful here: make sure the info in the TXT record agrees with what a client would get by connecting over TCP, or things get messy ๐Ÿ˜ญ

Some legacy protocols have no feature negotiation at all, and in those cases it can be really useful to put necessary info in the TXT record ๐ŸŒˆ For example, when printing using LPR [RFC1179], the LPR protocol gives the client no way to tell whether a particular printer accepts PostScript, what version of PostScript it takes, etc. In that case it's totally appropriate to embed this info in the TXT record [BJP], because the alternative is way worse: passing written instructions around to users, or arcane manual configuration of "/etc/printcap" files, etc. Nobody wants that vibe ๐Ÿ’€

Deciding which keys to define for the TXT record is an engineering call that needs to be made case by case for each service type ๐Ÿ”ฅ For some service types it makes sense to communicate info via the TXT record as well as (or instead of) in-band communication in the application protocol โœจ

6.4. Rules for Keys in DNS-SD Key/Value Pairs ๐Ÿ”‘

The key MUST be at least one character. DNS-SD TXT record strings that begin with an = (so the key is missing) MUST be silently ignored. Not me trying to have a nameless key ๐Ÿ™ƒ

The key SHOULD be no more than nine characters long. This is because keeping packet sizes small is genuinely good for network efficiency ๐ŸŒธ When using DNS-SD together with Multicast DNS [RFC6762], this matters a lot, since multicast traffic is especially expensive on 802.11 wireless networks [IEEEW]. Even with conventional Unicast DNS, small TXT records help responses fit inside the original DNS 512-byte size limit [RFC1035]. Also, each constituent string of a DNS TXT record is limited to 255 bytes, so super long keys eat up the space left for that key's values ๐Ÿ˜ค

Keys in key/value pairs can be as short as a single character ๐Ÿฆ‹ A key name only needs to be unique and unambiguous within the context of the service type it's defined for. A key name is meant to be a machine-readable identifier, NOT a human-readable essay explaining what a parameter is for, with a URL pointing to a web page that gives even more details about the spec. Be concise, queen ๐Ÿ‘‘ For ease of development and debugging, mnemonic textual names are valuable, but overly verbose keys are wasteful and inefficient, which is exactly why the recommendation is to keep them to nine characters or fewer ๐Ÿงš

The characters of a key MUST be printable US-ASCII values (0x20-0x7E) [RFC20], excluding = (0x3D).

Spaces in the key are significant, whether leading, trailing, or in the middle. So don't include any spaces unless you really mean it ๐Ÿ™…

Case is ignored when interpreting a key, so papersize=A4, PAPERSIZE=A4, and Papersize=A4 are all identical. Same key, different outfit, still iconic ๐Ÿ’…

If there's no = in a DNS-SD TXT record string, then it's a boolean attribute, simply identified as being present, with no value ๐ŸŽ€

A given key SHOULD NOT appear more than once in a TXT record. The reason for this simplifying rule is to make it easier to build client libraries that parse the TXT record into an internal data structure (like a hash table or dictionary object that maps from keys to values) and then expose that abstraction to client code ๐Ÿงฉ The rule that a key can't show up more than once simplifies these abstractions, since they don't have to support returning more than one value for a given key โœจ

If a client receives a TXT record containing the same key more than once, then the client MUST silently ignore all but the first occurrence of that attribute. For client implementations that process a DNS-SD TXT record from start to end, placing key/value pairs into a hash table keyed by the key, this means that if the implementation tries to add a new key/value pair and finds an entry with the same key already there, the new entry gets silently discarded instead ๐Ÿ—‘๏ธ Client implementations that look up key/value pairs by searching the TXT record for the requested key should search from the start and just return the first matching key they find ๐Ÿ”

When examining a TXT record for a given key, there are four categories of results that may come back ๐Ÿ’œ

  • Attribute not present (Absent)
  • Attribute present, with no value (e.g., passreq, meaning password required for this service)
  • Attribute present, with empty value (e.g., PlugIns=, meaning the server supports plugins, but none are presently installed)
  • Attribute present, with non-empty value (e.g., PlugIns=JPEG,MPEG2,MPEG4)

Each author writing a DNS-SD profile for finding instances of a particular service type should define how to interpret these different kinds of results ๐ŸŒˆ For example, for some keys there may be a natural true/false boolean interpretation:

  • Absent implies 'false'
  • Present implies 'true'

For other keys, it may make sense to define other semantics, like value/no-value/unknown:

  • Present with value implies that value. (e.g., Color=4 for a four-color ink-jet printer, or Color=6 for a six-color ink-jet printer)
  • Present with empty value implies 'false'. (e.g., not a color printer)
  • Absent implies 'Unknown'. (e.g., a print server connected to some unknown printer, where the print server doesn't actually know whether the printer does color or not. That gives a very bad user experience and should be avoided wherever possible ๐Ÿ˜ฌ)

Note that this is a hypothetical example, not an example of actual key/value keys used by DNS-SD network printers. Those are documented in the "Bonjour Printing Specification" [BJP] ๐Ÿ–จ๏ธ

6.5. Rules for Values in DNS-SD Key/Value Pairs ๐ŸŒท

If there's an = in a DNS-SD TXT record string, then everything after the first = to the end of the string is the value. The value can contain any eight-bit values, including =. The value MUST NOT be enclosed in additional quotation marks or any similar punctuation. Any quotation marks, or leading or trailing spaces, are part of the value, so they count ๐Ÿซถ

The value is opaque binary data. Often the value for a particular attribute will be US-ASCII [RFC20] or UTF-8 [RFC3629] text, but it's legal for a value to be any binary data ๐Ÿง 

Generic debugging tools should generally display all attribute values as a hex dump, with accompanying text next to it showing the UTF-8 interpretation of those bytes. The exception is attributes where the debugging tool has built-in knowledge that the value is some other kind of data ๐Ÿ”

Authors defining DNS-SD profiles SHOULD NOT generically convert binary attribute data types into printable text using hexadecimal representation, Base-64 [RFC4648], or Unix-to-Unix (UU) encoding, just to make the data look printable in a generic debugging tool. Doing that only bloats the size of the TXT record, without making the data any more understandable to someone looking at it in a generic debugging tool ๐Ÿ™„

6.6. Example TXT Record ๐ŸŽ€

The TXT record below contains three syntactically valid key/value strings. (The meaning of these key/value pairs, if any, would depend on the definitions for the service in question that is using them.) โœจ

-------------------------------------------------------
| 0x09 | key=value | 0x08 | paper=A4 | 0x07 | passreq |
-------------------------------------------------------

6.7. Version Tag โœจ

Okay so, if you're writing a DNS-SD profile, it is recommended that you include an attribute shaped like txtvers=x, where x is a decimal version number written in US-ASCII [RFC20] text (think txtvers=1 or txtvers=8) ๐ŸŽ€. Define it in your spec, and require it to be the first key/value pair in the TXT record. Why? Because if the spec ever needs to change, this tiny tag helps clients stay backwards compatible with older implementations ๐Ÿซถ. Even if you don't see any incompatible changes coming, a version number is useful insurance in case they become unavoidable [RFC6709]. Clients SHOULD ignore TXT records with a txtvers number higher (or lower) than the version(s) they know how to interpret ๐Ÿ™…โ€โ™€๏ธ.

Also, the txtvers number describes the version of the spec that governs the defined keys and what those keys mean for that particular TXT record. It is NOT the version of the application protocol the client will use if it later decides to contact that service ๐Ÿ’…. Ideally, every DNS-SD TXT record spec starts at txtvers=1 and stays there forever โœจ. Improvements can be made by defining new keys that older clients silently ignore ๐Ÿฆ‹. The only reason to increment the number is if the old spec is found to be so horribly broken that there's no way to do a compatible forward revision. Then the txtvers number has to go up so all the old clients know they should not even try to understand this new TXT record ๐Ÿ’€.

If you need to indicate which version number(s) of the application protocol the service implements, the recommended key for that is protovers ๐ŸŒธ.


6.8. Service Instances with Multiple TXT Records ๐Ÿงš

Generally speaking, every DNS-SD service instance has exactly one TXT record. However, a particular protocol's DNS-SD advertising spec is allowed to state that it permits multiple TXT records. When that happens, each TXT record describes a different variant of the same logical service. All of them are offered using the same underlying protocol on the same port, and they're all described by the same SRV record ๐Ÿ“.

Having multiple TXT records for one service instance is extremely rare. Out of the many hundreds of registered DNS-SD service types [SN], only one actually uses this capability: LPR printing [BJP] ๐Ÿ–จ๏ธ. Here's the deal: a printer conceptually supports multiple logical queue names, and each queue name implements a different page description language. Examples are 80-column monospaced plain text, seven-bit Adobe PostScript, eight-bit ("binary") PostScript, or some proprietary page description language. When multiple TXT records describe multiple logical LPR queue names for the same underlying service, printers include two extra keys in each TXT record. One is qtotal, which gives the total number of TXT records associated with this SRV record. The other is 'priority', which gives the printer's relative preference for that particular TXT record. Clients then pick the most preferred TXT record that meets their needs [BJP].

The only reason multiple TXT records get used is that the LPR protocol lacks in-band feature negotiation, so the client and server can't agree on a data representation for the print job by themselves. That means this info has to be passed out-of-band, using DNS-SD TXT records instead. Future protocol designs should not follow this bad example by copying this shortcoming of the LPR printing protocol ๐Ÿ™„.


7. Service Names ๐ŸŽ€

The <Service> portion of a Service Instance Name is a pair of DNS labels. It follows the convention already set up for SRV records [RFC2782] ๐Ÿ’•.

The first label is an underscore character followed by the Service Name [RFC6335]. The Service Name tells you what the service does and what application protocol it uses to do it ๐Ÿ‘‘.

For applications using TCP, the second label is _tcp.

For applications using any transport protocol other than TCP, the second label is _udp. This covers all the other transport protocols, like User Datagram Protocol (UDP), Stream Control Transmission Protocol (SCTP) [RFC4960], Datagram Congestion Control Protocol (DCCP) [RFC4340], Adobe's Real Time Media Flow Protocol (RTMFP), and so on. Honestly? In hindsight, the SRV spec probably shouldn't have used _tcp and _udp at all. It should have used a single _srv label to carve out a subdomain of the DNS namespace for this purpose ๐Ÿค”. But that spec is already published and deployed, so there's no benefit in changing established practice now. _srv might be aesthetically nicer than _udp, but it's not a user-visible string. All that's needed protocol-wise is (i) a label that can form a DNS delegation point, and (ii) a label short enough not to eat up too much space in the packet. On both counts, _udp and _srv are equally good. So it makes sense to use _tcp for TCP-based services and _udp for every other transport protocol. (Those are often encapsulated over UDP these days anyway!) That's better than defining a new subdomain for every new transport protocol ๐ŸŒˆ.

Quick note: this use of _udp for every non-TCP protocol applies ONLY to DNS-SD service advertising, meaning services advertised with the PTR+SRV+TXT convention in this document. It's not a requirement of SRV records in general. Other specs that are independent of DNS-SD and aren't meant to interoperate with DNS-SD records aren't constrained by how DNS-SD works, even if they also use the DNS SRV record datatype [RFC2782]. They're free to define their own naming conventions as they see fit ๐Ÿฆ‹.

The rules for Service Names [RFC6335] say they may be no more than fifteen characters long (not counting the mandatory underscore). They can only consist of letters, digits, and hyphens. They must begin and end with a letter or digit, must not contain consecutive hyphens, and must contain at least one letter. That last rule exists to block Service Names like "80" or "6000-6063", which could be mistaken for port numbers or port number ranges ๐Ÿ™ˆ. Uppercase and lowercase letters are both fine for mnemonic clarity, but case is ignored for comparison, so the strings "HTTP" and "http" refer to the same service ๐Ÿ”ฅ.

Choosing a Service Name well matters, and the choice isn't always as obvious as it looks ๐Ÿ‘€.

In many cases, the Service Name just names the on-the-wire message format and semantics being used. FTP is "ftp", IPP printing is "ipp", and so on โœจ.

But it's super common to "borrow" an existing protocol and repurpose it for a new task. That's totally sensible engineering, but it doesn't mean the new protocol provides the same semantic service as the old one, even if it borrows the same message formats ๐Ÿคทโ€โ™€๏ธ. For example, the network music sharing protocol implemented by iTunes on Macintosh and Windows is built on HTTP GET commands. Still, that does not mean it's sensible or useful to access one of these music servers by connecting to it with a standard web browser ๐ŸŽถ. So the DNS-SD service that iTunes advertises (and browses for) is _daap._tcp (Digital Audio Access Protocol), NOT _http._tcp ๐Ÿ’….

If iTunes advertised _http._tcp service, iTunes servers would show up in conventional web browsers (Safari, Camino, OmniWeb, Internet Explorer, Firefox, Chrome, etc.). That's of little use, since an iTunes music library offers no HTML pages with human-readable content a browser could display ๐Ÿ˜ญ. Going the other way, if iTunes browsed for _http._tcp service, it would discover generic web servers, like the embedded web servers in printers. That's also of little use, since printers generally don't have much music to offer ๐Ÿ–จ๏ธ๐ŸŽต.

Same deal with other protocols. Sun Microsystems's Network File System (NFS) is built on top of Sun Microsystems's Remote Procedure Call (Sun RPC) mechanism. But that doesn't mean it makes sense for an NFS server to advertise that it provides "Sun RPC" service ๐Ÿ™ƒ. Likewise, Microsoft's Server Message Block (SMB) file service is built on top of Netbios running over IP. That doesn't mean an SMB file server should advertise "Netbios-over-IP" service ๐Ÿ—‚๏ธ. The DNS-SD name of a service needs to capture both the "what" (semantics) and the "how" (protocol implementation), because a client needs to know both to use the service meaningfully. Saying a service was built on Sun RPC is no help if the client has no idea what the service actually does ๐Ÿง .

Another common question: should the service type iTunes advertises be _daap._http._tcp? Nope, that would also be incorrect ๐Ÿ™…โ€โ™€๏ธ. Similarly, if you're implementing a network service that happens to use the Simple Object Access Protocol [SOAP], you don't need to feel pressured into putting "_soap" somewhere in the Service Name ๐Ÿ’–. Part of the confusion is that _tcp or _udp showing up in the <Service> portion has led people to assume the visible structure of <Service> should mirror the private internal structure of how the protocol was implemented. That's not right ๐Ÿ™ˆ. All that's required is that the service be identified by some unique opaque Service Name. Making it English text that's at least a little descriptive of what the service does might be convenient, but it's by no means essential โœจ.

7.1. Selective Instance Enumeration (Subtypes) ๐Ÿ’…

Okay bestie, so this doc is NOT trying to build some super fancy query language ๐Ÿ™…โ€โ™€๏ธ No Turing complete stuff, no regex, nothing like that. And honestly? We don't think it's needed ๐Ÿ’–

But there are a few situations where narrowing down the results is lowkey so useful โœจ For example, a lot of network printers have a web-based UI for management and admin, using HTML/HTTP ๐Ÿ–จ๏ธ A web browser that wants to find every advertised web page sends a query for "_http._tcp.<Domain>". But sometimes people only want to manage printers, not browse every web page out there ๐Ÿ™ˆ So we define the "_printer" subtype of "_http._tcp", and to find only the pages advertised with that subtype, the browser sends a query for "_printer._sub._http._tcp.<Domain>". It's giving precision ๐ŸŽฏ

The Safari browser on Mac OS X 10.5 "Leopard" and later uses subtypes exactly like this ๐ŸŽ If an "_http._tcp" service is found through both "_printer._sub._http._tcp" browsing and "_http._tcp" browsing, it shows up in the "Printers" section of Safari's UI ๐Ÿ–จ๏ธ If it's only found through "_http._tcp" browsing, it shows up in the "Webpages" section instead ๐ŸŒธ You can see this for yourself on Mac OS X by running the commands below to advertise two "fake" services. The instance "A web page" lands in the "Webpages" section of Safari's Bonjour list, and "A printer's web page" lands in the "Printers" section ๐Ÿฆ‹

dns-sd -R "A web page"           _http._tcp          local 100
dns-sd -R "A printer's web page" _http._tcp,_printer local 101

Here's the tea: the advertised web page's Service Instance Name doesn't change just because of subtypes ๐Ÿซถ It's still something like "The Server._http._tcp.example.com.", and it's still findable with a normal browsing query for "_http._tcp" services. The subdomain where HTTP server SRV records are registered is what defines the namespace where HTTP server names have to be unique ๐Ÿ  Extra subtypes (like "_printer") on top of a basic service type (like "_http._tcp") just let clients ask for a narrower set of results. They do NOT create more namespace ๐Ÿ’œ

In DNS zone file syntax, the instance "A web page" gets advertised with one PTR record, while "A printer's web page" gets advertised with two: the main service type and the extra subtype โœจ Even though that second one is advertised two different ways, both PTR records point at the same SRV+TXT record pair ๐Ÿ‘‘

; One PTR record advertises "A web page"
_http._tcp.local. PTR A\032web\032page._http._tcp.local.

; Two different PTR records advertise "A printer's web page"
_http._tcp.local. PTR A\032printer's\032web\032page._http._tcp.local.
_printer._sub._http._tcp.local.
                  PTR A\032printer's\032web\032page._http._tcp.local.

Subtypes make the most sense when different kinds of client need to browse at two levels of granularity ๐Ÿงš In our example there are two kinds of HTTP client: general web browsers that want every web page, and printer management tools that only want the web UI pages that printers advertise ๐Ÿ–จ๏ธ The set of HTTP servers on the network is the same either way. The only difference is that some clients want all of them, while others only want the subset whose job is printer administration ๐ŸŽ€

Subtypes are only appropriate in this two-level setup, where some clients want the full set of services of a given type and other clients only want some subset ๐Ÿ™Œ Generally speaking, if no client wants the whole set, then using the subtype mechanism isn't necessary or desirable. If every client only browses for one particular subtype, and no client browses for the parent type, then a brand new Service Name should be defined for that logical service, and software should just advertise and browse for that service type directly ๐Ÿ’… Also, just because a service happens to be built on some other underlying protocol, like HTTP, Sun RPC, or SOAP, doesn't mean it makes sense to define it as a subtype of "_http", "_sunrpc", or "_soap" ๐Ÿ™…โ€โ™€๏ธ That would only be useful if some class of client said, "I want to find a service on the network, and I don't care what it does, as long as it does it using the SOAP XML RPC mechanism." ๐Ÿ˜ญ

Subtype strings don't have to start with an underscore, though they often do โœจ Just like the TXT record key/value pairs, the list of possible subtypes (if there are any, including whether some or all of them begin with an underscore) gets defined and specified separately for each basic service type ๐ŸŒˆ

Subtype strings (like "_printer" in the example above) can be built from arbitrary 8-bit data values ๐Ÿ“ A lot of the time those values are UTF-8 [RFC3629] text, or even plain ASCII [RFC20] like in the example above, but they don't have to be. Just note that even when you use arbitrary 8-bit data for subtype strings, DNS name comparisons are still case-insensitive. So, for example, the byte values 0x41 and 0x61 count as equivalent for subtype comparison purposes ๐Ÿ‘€

7.2. Service Name Length Limits ๐Ÿ“

Remember how Service Names are allowed to be no more than fifteen characters long? ๐Ÿ’… The reason is to save bytes in the domain name, because both the network administrator (picking service domain names) and the end user (picking instance names) need that room ๐Ÿซถ

A fully qualified domain name can be up to 255 bytes long, plus one byte for the final terminating root label at the end. Domain names used by DNS-SD look like this:

                 <sn>._tcp . <servicedomain> . <parentdomain>.
    <Instance> . <sn>._tcp . <servicedomain> . <parentdomain>.
<sub>._sub . <sn>._tcp . <servicedomain> . <parentdomain>.

The first one is the name used for PTR queries. The second one is a Service Instance Name, which is the name of the service's SRV and TXT records ๐Ÿงš The third one is a subtype browsing name, meaning the name of a PTR record pointing to a Service Instance Name (see Section 7.1, "Selective Instance Enumeration") โœจ

The Service Name <sn> can be up to 15 bytes, plus the underscore and length byte, for a total of 17. Including "_udp" or "_tcp" and its length byte, that makes 22 bytes ๐Ÿฆ‹

The instance name <Instance> can be up to 63 bytes. Including the length byte the DNS format uses when the name is stored in a packet, that makes 64 bytes ๐ŸŽ€

When you're using subtypes, the subtype identifier is allowed to be up to 63 bytes, plus the length byte, making 64. Including "_sub" and its length byte, that makes 69 bytes ๐Ÿ’œ

Usually, DNS-SD service records get placed into their own subdomains beneath a company's existing domain name ๐Ÿข Since those subdomains are meant to be reached through graphical user interfaces (not typed on a command line), they tend to be long and descriptive ๐Ÿ™ˆ Including the length byte, the user-visible service domain can be up to 64 bytes ๐ŸŒธ

Okay so, of our available 255 bytes, we've now accounted for 69+22+64 = 155 bytes ๐Ÿงฎ That leaves 100 bytes for the organization's existing domain name <parentdomain>. When it's used with Multicast DNS, <parentdomain> is "local.", which easily fits ๐Ÿซถ When parent domains are 100 bytes or less, full DNS-SD functionality is available with no restrictions โœจ When parent domains are longer than 100 bytes, the protocol risks going over the maximum possible length of domain names, which causes failures ๐Ÿ˜ญ In that case, picking short <servicedomain> names can help avoid overflows ๐Ÿ’… If the <servicedomain> and <parentdomain> are both too long, then service instances with long instance names won't be discoverable or resolvable, and applications that use long subtype names might fail ๐Ÿ’€

Because of this constraint, we choose to limit Service Names to 15 characters or less ๐Ÿ‘‘ Allowing more characters wouldn't increase the expressive power of the protocol, and it would needlessly shrink the maximum <parentdomain> length that can be used safely ๐Ÿ™…โ€โ™€๏ธ

Also, <Instance> name lengths affect how many services of a given type can be discovered in a given <servicedomain> ๐Ÿ”ฅ The largest Unicast DNS response that can be sent (typically using TCP, not UDP) is 64 kB. With DNS name compression, a Service Instance Enumeration PTR record needs 2 bytes for the (compressed) name, plus 10 bytes for type, class, ttl, and rdata length. The rdata of the PTR record needs up to 64 bytes for the <Instance> part of the name, plus 2 bytes for a name compression pointer to the common suffix, making a maximum of 78 bytes total. So with maximum-sized <Instance> names, up to 839 instances of a given service type can be discovered in a given <servicedomain> ๐Ÿงš

Multicast DNS aggregates response packets, so it doesn't have the same hard limit ๐ŸŒˆ In practice, though, it's also useful for up to a few hundred instances of a given service type, but probably not thousands ๐Ÿฆ‹

Still, showing even 100 instances in a flat list is probably too many to be helpful to a typical user ๐Ÿ™ˆ If a network has more than 100 instances of a given service type, it's probably a good idea to split those services into logical subdomains, like by building, by floor, by department, and so on ๐Ÿข๐Ÿ’–

8. Flagship Naming โœจ

okay so sometimes there are a bunch of network protocols that all do basically the same job ๐Ÿ–จ๏ธ like the printing world has LPR [RFC1179] and IPP [RFC2910], and both get paper coming out of a printer in pretty much the same way. then on top of that, lots of printer vendors send their own proprietary page description language (PDL) data over TCP port 9100, which we're calling the "pdl-datastream" protocol generically ๐Ÿ’…. ideally we'd have just ONE printing protocol and it'd be so good nobody felt the need to invent a new one ๐Ÿฅบ but reality is multiple legacy protocols exist, so service discovery has to deal with that bestie ๐Ÿซถ

many printers do all three: LPR, IPP, and pdl-datastream. so for the clients that only speak one of those, all three get advertised ๐ŸŒธ

BUT some clients speak two or even all three. when a client looks for all three service types, it finds three distinct services (an LPR service, an IPP service, and a pdl-datastream service) and they all end up making paper come out of the SAME physical printer ๐Ÿ˜ญ

so in a situation like this, where several protocols all do effectively the same thing, a client can browse for every service type it supports and show all the discovered instance names in one single aggregated list โœจ if the same instance name shows up more than once because that one entity supports more than one service type (like a single printer that does multiple printing protocols), the duplicates should be suppressed so the name only appears once in the list ๐ŸŽ€ then when the user says "I want to print on this named printer," the printing client is the one responsible for picking whichever protocol will get the job done best. the user should NOT have to manually choose between LPR and IPP, obviously ๐Ÿ™ˆ

as described so far, this all works really well. but okay, consider this plot twist ๐Ÿ‘€ some future printer only supports IPP printing, and some other future printer only supports pdl-datastream printing.

the namespaces for different service types are intentionally disjoint ๐Ÿฆ‹ (it's acceptable and actually desirable to have both a file server called "Sales Department" and a printer called "Sales Department"). however, it's NOT desirable, in the common case, to let two different printers both be called "Sales Department" just because they use different printing protocols ๐Ÿ’€

to guard against that, when two or more network protocols do roughly the same logical thing, one of them gets declared the "flagship" of the whole fleet of related protocols ๐Ÿ‘‘ usually the flagship is the oldest and/or best-known protocol in the set.

if a device doesn't implement the flagship protocol, then it instead creates a placeholder SRV record (priority=0, weight=0, port=0, target host = host name of device) with that name ๐Ÿงš if, when it tries to create this SRV record, it finds that a record with the same name already exists, then it knows that name is already taken by some other entity that implements at least one protocol from the fleet, so it MUST choose another. wait, let me fix that, because I'm being sloppy: the original says "it must choose another," so I'm keeping the lowercase "must" and the rule's force stays exactly the same ๐Ÿ’… if no SRV record exists yet, then creating it stakes a claim to that name, so future devices in the same protocol fleet will detect a conflict when they try to use it ๐Ÿ”ฅ

Note: When used with Multicast DNS [RFC6762], the target host field of the placeholder SRV record MUST NOT be the empty root label. The SRV record needs a real target host name so the Multicast DNS conflict detection rules can actually work. If two different devices created placeholder SRV records that both used a null target host name (just the root label), those two SRV records would look like they agree with each other, and no conflict would be detected ๐Ÿ˜ฑ

by defining a common well-known flagship protocol for the class, future devices that might not even know about each other's protocols still get a shared spot where they can coordinate and verify that names are unique ๐Ÿซถ

no PTR record gets created to advertise the presence of empty flagship SRV records, because they don't represent a real service being advertised. so they are not (and should not be) discoverable via Service Instance Enumeration (browsing) ๐Ÿ™…โ€โ™€๏ธ


9. Service Type Enumeration ๐ŸŒˆ

in general, a normal client isn't interested in finding every service on the network, just the ones it knows how to use ๐Ÿ’–

BUT for problem diagnosis and network management tools, it can be super useful for network admins to find the list of advertised service types on the network, even if the Service Names are just opaque identifiers and not very informative on their own ๐Ÿ•ต๏ธโ€โ™€๏ธ

so there's a special meta-query for this. a DNS query for PTR records with the name _services._dns-sd._udp.<Domain> gives you a set of PTR records, where the rdata of each one is the two-label <Service> name plus the same domain, e.g. _http._tcp.<Domain> ๐Ÿ“ including the domain in the PTR rdata allows for slightly better name compression in Unicast DNS responses, but only the first two labels matter for service type enumeration. those two-label service types can then be used to build subsequent Service Instance Enumeration PTR queries, in this <Domain> or others, to discover instances of that service type ๐ŸŽ€


10. Populating the DNS with Information ๐Ÿ“

how a service's PTR, SRV, and TXT records make their way into the DNS is outside the scope of this document, but for illustrative purposes, here are some examples ๐Ÿงšโ€โ™€๏ธ

on some networks, the administrator might manually enter the records into the name server's configuration file ๐Ÿ› ๏ธ

a network monitoring tool could output a standard zone file to be read into a conventional DNS server. for example, a tool that can find networked PostScript laser printers using AppleTalk NBP could find the list of printers, talk to each one to find its IP address, PostScript version, installed options, etc., and then write out a DNS zone file describing those printers and their capabilities using DNS resource records. that info would then be available to IP-only clients that implement DNS-SD but not AppleTalk NBP ๐Ÿ’œ

a printer manager device that knows about printers on the network through some other management protocol could also output a zone file or use DNS Update [RFC2136] [RFC3007] ๐ŸŒธ

or, a printer manager device could implement enough of the DNS protocol to answer DNS queries directly, and Example Co.'s main DNS server could delegate the _ipp._tcp.example.com. subdomain to the printer manager device ๐Ÿ‘‘

IP printers could use Dynamic DNS Update [RFC2136] [RFC3007] to automatically register their own PTR, SRV, and TXT records with the DNS server ๐Ÿ–จ๏ธโœจ

zeroconf printers answer Multicast DNS queries on the local link for their own PTR, SRV, and TXT names ending with .local. [RFC6762] ๐Ÿฆ‹


11. Discovery of Browsing and Registration Domains (Domain Enumeration) ๐Ÿ—บ๏ธ

one of the big motivations for DNS-based Service Discovery is letting a visiting client (like a Wi-Fi-equipped [IEEEW] laptop, tablet, or mobile phone) that arrives on a new network discover what services are available there, with zero manual configuration ๐Ÿฅน the same logic that says discovering services without manual config is a good idea also says discovering recommended registration and browsing domains without manual config is a similarly good idea ๐Ÿ’–

this discovery is done with DNS queries, using Unicast or Multicast DNS. five special RR names are reserved for this purpose:

        b._dns-sd._udp.<domain>.
       db._dns-sd._udp.<domain>.
        r._dns-sd._udp.<domain>.
       dr._dns-sd._udp.<domain>.
       lb._dns-sd._udp.<domain>.

by doing PTR queries for these names, a client can learn, respectively:

  • A list of domains recommended for browsing.
  • A single recommended default domain for browsing.
  • A list of domains recommended for registering services using Dynamic Update.
  • A single recommended default domain for registering services.
  • The "legacy browsing" or "automatic browsing" domain(s). sophisticated client apps that care about presenting domain choices to the user use the answers from the previous four queries to discover the domains to show. in contrast, lots of current apps browse without specifying an explicit domain, letting the OS automatically pick an appropriate domain for them ๐Ÿค– it's for this class of app that the "automatic browsing" query exists, so the network admin can tell client OSes which domain(s) should be used automatically for these apps ๐ŸŒˆ

these domains are purely advisory ๐Ÿซถ the client or user is free to register services and/or browse in any domains. the point of these special queries is to let software build a UI that shows a useful list of suggestions, so the user can make an informed pick, or ignore the suggestions and type in their own choice โœจ

the <domain> part of the Domain Enumeration query name may be local. (meaning "perform the query using link-local multicast"), or it may be learned some other way, like the DHCP "Domain" option (option code 15) [RFC2132], the DHCP "Domain Search" option (option code 119) [RFC3397], or IPv6 Router Advertisement Options [RFC6106] ๐ŸŒธ

the <domain> part of the query name can also be derived a different way, from the host's IP address ๐Ÿงฎ the host takes its IP address and computes the logical AND of that address and its subnet mask, to get the 'base' address of the subnet (the 'network address' of that subnet, or equivalently, the IP address of the 'all-zero' host address on that subnet). then it constructs the conventional DNS "reverse mapping" name for that base address and uses it as the <domain> part for the queries above. for example, if a host has the address 192.168.12.34 with the subnet mask 255.255.0.0, then the 'base' address of the subnet is 192.168.0.0, and to discover the recommended automatic browsing domain(s) for devices on this subnet, the host issues a DNS PTR query for the name lb._dns-sd._udp.0.0.168.192.in-addr.arpa. ๐ŸŽ€

equivalent address-derived Domain Enumeration queries should also be done for the host's IPv6 address(es) ๐Ÿ’…

address-derived Domain Enumeration queries SHOULD NOT be done for IPv4 link-local addresses [RFC3927] or IPv6 link-local addresses [RFC4862] ๐Ÿ™…โ€โ™€๏ธ (link-local addresses don't tell you much about a real domain, so skip them, bestie)

sophisticated clients may do Domain Enumeration queries both in "local." and in one or more unicast domains, using both name-derived and address-derived queries, and then show the user a combined result that aggregates the info from all sources ๐Ÿ”ฅ

12. DNS Additional Record Generation โœจ

okay so DNS has this super efficiency feature ๐Ÿงš where a DNS server can tuck extra records into the additional section of a DNS message. the client didn't ask for these, but the server has good reason to think the client might ask for them soon, so including them saves the client from having to send more queries. it's giving helpful friend who already grabbed your snacks ๐Ÿ“

This section recommends which additional records SHOULD be generated to improve network efficiency, for both Unicast and Multicast DNS-SD responses. ๐Ÿ’œ

Note that while servers SHOULD add these additional records for efficiency purposes, as with all DNS additional records, it is the client's responsibility to determine whether or not to trust them. ๐Ÿซถ

Generally speaking, stub resolvers that talk to a single recursive name server for all their queries will trust all records they receive from that recursive name server (whom else would they ask?) ๐Ÿ’… Recursive name servers that talk to multiple authoritative name servers should verify that any records they receive from a given authoritative name server are "in bailiwick" for that server, and ignore them if not. ๐ŸŒธ

Clients MUST be capable of functioning correctly with DNS servers (and Multicast DNS Responders) that fail to generate these additional records automatically, by issuing subsequent queries for any further record(s) they require. ๐Ÿ”ฅ The additional-record generation rules in this section are RECOMMENDED for improving network efficiency, but are not required for correctness. โœจ

12.1. PTR Records ๐ŸŽ€

When including a DNS-SD Service Instance Enumeration or Selective Instance Enumeration (subtype) PTR record in a response packet, the server/responder SHOULD include the following additional records:

  • The SRV record(s) named in the PTR rdata.
  • The TXT record(s) named in the PTR rdata.
  • All address records (type "A" and "AAAA") named in the SRV rdata.

12.2. SRV Records ๐Ÿฆ‹

When including an SRV record in a response packet, the server/responder SHOULD include the following additional records:

  • All address records (type "A" and "AAAA") named in the SRV rdata.

12.3. TXT Records ๐ŸŒˆ

When including a TXT record in a response packet, no additional records are required. ๐Ÿ’–

12.4. Other Record Types ๐Ÿงš

In response to address queries, or other record types, no new additional records are recommended by this document. ๐Ÿ™ˆ

13. Working Examples ๐Ÿ’…

The following examples were prepared using standard unmodified nslookup and standard unmodified BIND running on GNU/Linux. ๐Ÿ“

Note: In real products, this information is obtained and presented to the user using graphical network browser software, not command-line tools. However, if you wish, you can try these examples for yourself as you read along, using the nslookup command already available on most Unix machines. ๐Ÿ’€

13.1. What web pages are being advertised from dns-sd.org? ๐Ÿ‘‘

nslookup -q=ptr _http._tcp.dns-sd.org.
_http._tcp.dns-sd.org
             name = Zeroconf._http._tcp.dns-sd.org
_http._tcp.dns-sd.org
             name = Multicast\032DNS._http._tcp.dns-sd.org
_http._tcp.dns-sd.org
             name = Service\032Discovery._http._tcp.dns-sd.org
_http._tcp.dns-sd.org
             name = Stuart's\032Printer._http._tcp.dns-sd.org

Answer: There are four, called "Zeroconf", "Multicast DNS", "Service Discovery", and "Stuart's Printer". ๐ŸŽ€

Note that nslookup escapes spaces as "\032" for display purposes, but a graphical DNS-SD browser should not. ๐Ÿซถ

13.2. What printer-configuration web pages are there? ๐Ÿ–จ๏ธ

nslookup -q=ptr _printer._sub._http._tcp.dns-sd.org.
_printer._sub._http._tcp.dns-sd.org
             name = Stuart's\032Printer._http._tcp.dns-sd.org

Answer: "Stuart's Printer" is the web configuration UI of a network printer. ๐ŸŒธ

13.3. How do I access the web page called "Service Discovery"? ๐Ÿฆ‹

nslookup -q=any "Service\032Discovery._http._tcp.dns-sd.org."
Service\032Discovery._http._tcp.dns-sd.org
               priority = 0, weight = 0, port = 80, host = dns-sd.org
Service\032Discovery._http._tcp.dns-sd.org
               text = "txtvers=1" "path=/"
dns-sd.org     nameserver = ns1.dns-sd.org
dns-sd.org     internet address = 64.142.82.154
ns1.dns-sd.org internet address = 64.142.82.152

Answer: You need to connect to dns-sd.org port 80, path "/". The address for dns-sd.org is also given (64.142.82.154). ๐ŸŒˆ

14. IPv6 Considerations ๐ŸŒธ

IPv6 has only minor differences from IPv4. ๐Ÿ’–

The address of the SRV record's target host is given by the appropriate IPv6 "AAAA" address records instead of (or in addition to) IPv4 "A" records. ๐Ÿงš

Address-based Domain Enumeration queries are performed using names under the IPv6 reverse-mapping tree, which is different from the IPv4 reverse-mapping tree and has longer names in it. โœจ

15. Security Considerations ๐Ÿ”ฅ

Since DNS-SD is just a specification for how to name and use records in the existing DNS system, it has no specific additional security requirements over and above those that already apply to DNS queries and DNS updates. ๐Ÿ˜ญ

For DNS queries, DNS Security Extensions (DNSSEC) [RFC4033] should be used where the authenticity of information is important. ๐Ÿ”

For DNS updates, secure updates [RFC2136] [RFC3007] should generally be used to control which clients have permission to update DNS records. ๐Ÿ›ก๏ธ

16. IANA Considerations ๐ŸŒˆ

IANA manages the namespace of unique Service Names [RFC6335]. ๐Ÿ’…

When a protocol service advertising specification includes subtypes, these should be documented in the protocol specification in question and/or in the "notes" field of the registration request sent to IANA. In the event that a new subtype becomes relevant after a protocol specification has been published, this can be recorded by requesting that IANA add it to the "notes" field. For example, vendors of network printers advertise their embedded web servers using the subtype _printer. This allows printer management clients to browse for only printer-related web servers by browsing for the _printer subtype. While the existence of the _printer subtype of _http._tcp is not directly relevant to the HTTP protocol specification, it is useful to record this usage in the IANA registry to help avoid another community of developers inadvertently using the same subtype string for a different purpose. The namespace of possible subtypes is separate for each different service type. For example, the existence of the _printer subtype of _http._tcp does not imply that the _printer subtype is defined or has any meaning for any other service type. ๐Ÿฆ‹

When IANA records a Service Name registration, if the new application protocol is one that conceptually duplicates existing functionality of an older protocol, and the implementers desire the Flagship Naming behavior described in Section 8, then the registrant should request that IANA record the name of the flagship protocol in the "notes" field of the new registration. For example, the registrations for "ipp" and "pdl-datastream" both reference "printer" as the flagship name for this family of printing-related protocols. ๐Ÿ‘‘

17. Acknowledgments ๐Ÿซถ

The concepts described in this document have been explored, developed, and implemented with help from Ran Atkinson, Richard Brown, Freek Dijkstra, Ralph Droms, Erik Guttman, Pasi Sarolahti, Pekka Savola, Mark Townsley, Paul Vixie, Bill Woodcock, and others. Special thanks go to Bob Bradley, Josh Graessley, Scott Herscher, Rory McGuire, Roger Pantos, and Kiren Sekar for their significant contributions. ๐Ÿ’–

18. References ๐Ÿ“š

18.1. Normative References ๐ŸŒŸ

[RFC20]     Cerf, V., "ASCII format for network interchange", RFC 20,
            October 1969.

[RFC1033]   Lottor, M., "Domain Administrators Operations Guide", RFC
            1033, November 1987.

[RFC1034]   Mockapetris, P., "Domain names - concepts and
            facilities", STD 13, RFC 1034, November 1987.

[RFC1035]   Mockapetris, P., "Domain names - implementation and
            specification", STD 13, RFC 1035, November 1987.

[RFC2119]   Bradner, S., "Key words for use in RFCs to Indicate
            Requirement Levels", BCP 14, RFC 2119, March 1997.

[RFC2782]   Gulbrandsen, A., Vixie, P., and L. Esibov, "A DNS RR for
            specifying the location of services (DNS SRV)", RFC 2782,
            February 2000.

[RFC3492]   Costello, A., "Punycode: A Bootstring encoding of Unicode
            for Internationalized Domain Names in Applications
            (IDNA)", RFC 3492, March 2003.

[RFC3629]   Yergeau, F., "UTF-8, a transformation format of ISO
            10646", STD 63, RFC 3629, November 2003.

[RFC3927]   Cheshire, S., Aboba, B., and E. Guttman, "Dynamic
            Configuration of IPv4 Link-Local Addresses", RFC 3927,
            May 2005.

[RFC4862]   Thomson, S., Narten, T., and T. Jinmei, "IPv6 Stateless
            Address Autoconfiguration", RFC 4862, September 2007.

[RFC5198]   Klensin, J. and M. Padlipsky, "Unicode Format for Network
            Interchange", RFC 5198, March 2008.

[RFC5890]   Klensin, J., "Internationalized Domain Names for
            Applications (IDNA): Definitions and Document Framework",
            RFC 5890, August 2010.

[RFC6335]   Cotton, M., Eggert, L., Touch, J., Westerlund, M., and S.
            Cheshire, "Internet Assigned Numbers Authority (IANA)
            Procedures for the Management of the Service Name and
            Transport Protocol Port Number Registry", BCP 165, RFC
            6335, August 2011.

18.2. Informative References โœจ

okay so these are the background reads, bestie ๐Ÿ“š you don't have to implement any of them, but they're the receipts behind the whole spec ๐Ÿ’…

[AFP]       Mac OS X Developer Library, "Apple Filing Protocol
            Programming Guide", <http://developer.apple.com/
            documentation/Networking/Conceptual/AFP/>.

[BJ]        Apple Bonjour Open Source Software,
            <http://developer.apple.com/bonjour/>.

[BJP]       Bonjour Printing Specification,
            <https://developer.apple.com/bonjour/
            printing-specification/bonjourprinting-1.0.2.pdf>.

[IEEEW]     IEEE 802 LAN/MAN Standards Committee,
            <http://standards.ieee.org/wireless/>.

[NIAS]      Cheshire, S., "Discovering Named Instances of Abstract
            Services using DNS", Work in Progress, July 2001.

[NSD]       "NsdManager | Android Developer", June 2012,
            <http://developer.android.com/reference/android/
            net/nsd/NsdManager.html>.

[RFC1179]   McLaughlin, L., "Line printer daemon protocol", RFC 1179,
            August 1990.

[RFC2132]   Alexander, S. and R. Droms, "DHCP Options and BOOTP
            Vendor Extensions", RFC 2132, March 1997.

[RFC2136]   Vixie, P., Ed., Thomson, S., Rekhter, Y., and J. Bound,
            "Dynamic Updates in the Domain Name System (DNS UPDATE)",
            RFC 2136, April 1997.

[RFC2181]   Elz, R. and R. Bush, "Clarifications to the DNS
            Specification", RFC 2181, July 1997.

[RFC2910]   Herriot, R., Ed., Butler, S., Moore, P., Turner, R., and
            J. Wenn, "Internet Printing Protocol/1.1: Encoding and
            Transport", RFC 2910, September 2000.

[RFC4960]   Stewart, R., Ed., "Stream Control Transmission Protocol",
            RFC 4960, September 2007.

[RFC3007]   Wellington, B., "Secure Domain Name System (DNS) Dynamic
            Update", RFC 3007, November 2000.

[RFC4340]   Kohler, E., Handley, M., and S. Floyd, "Datagram
            Congestion Control Protocol (DCCP)", RFC 4340, March
            2006.

[RFC3397]   Aboba, B. and S. Cheshire, "Dynamic Host Configuration
            Protocol (DHCP) Domain Search Option", RFC 3397, November
            2002.

[RFC4033]   Arends, R., Austein, R., Larson, M., Massey, D., and S.
            Rose, "DNS Security Introduction and Requirements", RFC
            4033, March 2005.

[RFC4648]   Josefsson, S., "The Base16, Base32, and Base64 Data
            Encodings", RFC 4648, October 2006.

[RFC4795]   Aboba, B., Thaler, D., and L. Esibov, "Link-local
            Multicast Name Resolution (LLMNR)", RFC 4795, January
            2007.

[RFC6106]   Jeong, J., Park, S., Beloeil, L., and S. Madanapalli,
            "IPv6 Router Advertisement Options for DNS
            Configuration", RFC 6106, November 2010.

[RFC6281]   Cheshire, S., Zhu, Z., Wakikawa, R., and L. Zhang,
            "Understanding Apple's Back to My Mac (BTMM) Service",
            RFC 6281, June 2011.

[RFC6709]   Carpenter, B., Aboba, B., Ed., and S. Cheshire, "Design
            Considerations for Protocol Extensions", RFC 6709,
            September 2012.

[RFC6760]   Cheshire, S. and M. Krochmal, "Requirements for a
            Protocol to Replace the AppleTalk Name Binding Protocol
            (NBP)", RFC 6760, February 2013.

[RFC6762]   Cheshire, S. and M. Krochmal, "Multicast DNS", RFC 6762,
            February 2013.

[SN]        IANA, "Service Name and Transport Protocol Port Number
            Registry", <http://www.iana.org/assignments/
            service-names-port-numbers/>.

[SOAP]      Mitra, N., "SOAP Version 1.2 Part 0: Primer", W3C
            Proposed Recommendation 24 June 2003,
            <http://www.w3.org/TR/2003/REC-soap12-part0-20030624>.

[Unicode6]  The Unicode Consortium. The Unicode Standard, Version
            6.0.0, (Mountain View, CA: The Unicode Consortium, 2011.
            ISBN 978-1-936213-01-6)
            <http://www.unicode.org/versions/Unicode6.0.0/>.

[ZC]        Cheshire, S. and D. Steinberg, "Zero Configuration
            Networking: The Definitive Guide", O'Reilly Media, Inc.,
            ISBN 0-596-10100-7, December 2005.

Appendix A. Rationale for Using DNS as a Basis for Service Discovery ๐Ÿงš

Okay so, over the years people have come up with LOTS of ways to do network service discovery over IP ๐Ÿ™„ but none of them ever became ubiquitous. Like, not even close to how everywhere DNS servers, clients, and infrastructure are today ๐Ÿ˜ญ

The big win of using DNS as the base for service discovery is that it gets to ride on all that existing stuff: the servers, the clients, the protocols, the infrastructure, and the expertise people already have ๐Ÿซถ Network analyzer tools already know how to decode and display DNS packets for debugging, so that's a freebie too โœจ

For ad hoc networks like Zeroconf environments, peer-to-peer multicast protocols are the right call ๐Ÿฆ‹ Running DNS-SD over Multicast DNS [RFC6762] gives you zero-configuration ad hoc service discovery, and it keeps the DNS-SD semantics and record types described here. Iconic ๐Ÿ’œ

In bigger networks, though, a high volume of enterprise-wide IP multicast traffic might not be wanted ๐Ÿ™…โ€โ™€๏ธ So any credible service discovery protocol for larger networks has to offer a way to aggregate registrations and lookups at a central server (or servers) instead of relying only on multicast. That means someone has to write, debug, deploy, and maintain some aggregation server software ๐Ÿ› ๏ธ It also means a registration protocol has to be implemented and deployed so clients can register with that central server. Here's the plot twist: basically every company with an IP network already runs a DNS server, and DNS already has a dynamic registration protocol [RFC2136] [RFC3007] ๐Ÿคฏ Since everyone already has to run and maintain DNS anyway, it makes total sense to lean on that expertise instead of learning, operating, and maintaining a whole separate registration server. Main character energy ๐Ÿ‘‘

Also, reminder, using the same software and protocols doesn't have to mean using the same physical box ๐Ÿ“ฆ The DNS-SD service discovery functions don't need to live on the same hardware that handles the company's DNS name service. The "_tcp.<Domain>" and "_udp.<Domain>" subdomains can be delegated to a different machine. Even then, it's still the same familiar DNS server software, with the same configuration file syntax, the same log file format, and so on ๐Ÿ’–

Service discovery also needs to provide appropriate security ๐Ÿ”’ Good news: DNS already has existing security mechanisms [RFC4033] ๐Ÿซก

In summary, this is the whole vibe:

  • Service discovery requires a central aggregation server. DNS already has one: a DNS server. โœจ
  • Service discovery requires a service registration protocol. DNS already has one: DNS Dynamic Update. ๐ŸŒธ
  • Service discovery requires a query protocol. DNS already has one: DNS queries. ๐Ÿ”
  • Service discovery requires security mechanisms. DNS already has security mechanisms: DNSSEC. ๐Ÿ”
  • Service discovery requires a multicast mode for ad hoc networks. Using DNS-SD in conjunction with Multicast DNS provides this, using peer-to-peer multicast instead of a DNS server. ๐Ÿฆ‹

It just makes more sense to use software every network already needs, instead of deploying an entire parallel system just for service discovery ๐Ÿ’… periodt.


Appendix B. Ordering of Service Instance Name Components ๐ŸŽ€

Okay so people keep asking why services are named with DNS Service Instance Names in this shape ๐Ÿค”

Service Instance Name = <Instance> . <Service> . <Domain>

instead of this shape:

Service Instance Name = <Service> . <Instance> . <Domain>

There are three reasons it's better to put the parent domain as the most-significant (rightmost) part of the name, then the abstract service type, and then the specific instance name as the least-significant (leftmost) part. We'll go through them in Sections B.1, B.2, and B.3 ๐Ÿงšโ€โ™€๏ธ

B.1. Semantic Structure ๐ŸŒณ

Browsing ("Service Instance Enumeration") is basically listing the leaves of a tree ๐ŸŒฒ A given domain offers zero or more services, and for each service type there may be zero or more instances of that service.

The user already knows what kind of service they want ๐Ÿ™Œ If they're running an FTP client, they're looking for FTP servers. If they have a document to print, they're looking for things that speak some known printing protocol. The user also knows which organizational or geographical domain they want to search in. (Nobody wants one giant flat list of every single printer on the planet, even if that were possible ๐Ÿ˜ญ) What the user doesn't know ahead of time is whether the service they want is offered in that domain, and if so, how many instances there are and what they're called ๐Ÿคทโ€โ™€๏ธ

So having the instance names be the leaves of the tree fits this semantic model perfectly โœจ

If the service types were the terminal leaves instead, the user would have to know the domain name and the service instance name, but have no idea what the service actually does ๐Ÿ’€ We'd argue that's a way less useful model.

B.2. Network Efficiency ๐Ÿ“ฆ

When a DNS response has multiple answers, name compression works way better if all the names share a common suffix ๐Ÿ—œ๏ธ If lots of answers in one packet have the same <Service> and <Domain>, then each Service Instance Name can be written as just the <Instance> part, followed by a two-byte compression pointer that references an earlier appearance of "<Service>.<Domain>". That efficiency wouldn't be possible if the <Service> component came first in each name ๐Ÿ™ˆ

B.3. Operational Flexibility ๐Ÿงฉ

This name structure lets subdomains be delegated along logical service boundaries ๐Ÿฐ For example, the network administrator at Example Co. could delegate the "_tcp.example.com." subdomain to a different machine, so the box handling service discovery doesn't have to be the one handling all the other day-to-day DNS work. (It can be the same machine if the administrator wants, but they're totally free to choose otherwise ๐Ÿ’โ€โ™€๏ธ)

It also gets even better: if the admin wants to hand off everything related to IPP printers to a machine dedicated to that job, they can just delegate the "_ipp._tcp.example.com." subdomain to that machine ๐Ÿ–จ๏ธ Security policies are also easy to set per zone or per subdomain. For example, the admin might turn on DNS Dynamic Update [RFC2136] [RFC3007] for printers registering in "_ipp._tcp.example.com.", but not for other zones or subdomains ๐Ÿ” That kind of easy flexibility just wouldn't exist if the <Service> component came first in each name ๐Ÿฆ‹

Appendix C. What You See Is What You Get โœจ

Okay so some service discovery protocols split the real service identifier from the name the user actually sees ๐Ÿ™ˆ The real identifier is an opaque unique ID, usually a long string of hex digits, that a typical user should never have to look at ๐Ÿ’€ The name on screen is just one of the decorative, ephemeral attributes stuck onto that opaque ID.

The problem? It decouples what the user perceives from what's actually happening on the network ๐Ÿ˜ญ

  • What happens if two service instances have different unique IDs but somehow got the same user-visible name? If two of them show up in an on-screen list with the same name, how does the user know which is which? ๐Ÿค”
  • Say a printer breaks down, and the user swaps in another printer of the same make and model, configuring it with the exact same name as the old one: "Stuart's Printer" ๐Ÿ–จ๏ธ Now when they try to print, the dialog says their default printer is "Stuart's Printer" โœจ They browse the network and see a printer called "Stuart's Printer," but when they print, they're told "Stuart's Printer" can't be found ๐Ÿ’€ The hidden unique ID the software is hunting for doesn't match the hidden unique ID of the new printer, even though the apparent name and logical purpose are the same. To fix it, the user usually has to delete the print queue they made and create a new (apparently identical) one so it picks up the right hidden ID. Hidden info the user can't see makes for a confusing, frustrating experience, and showing them long, ugly hex strings and making them decode what they mean is even worse ๐Ÿ˜ฉ
  • Say an existing printer gets moved to a new department and given a new name and a new function. Changing the user-visible name doesn't change its hidden unique ID. Users who made a print queue for it are still accessing the same hardware by its unique ID, even though the logical service that hardware used to offer has ceased to exist ๐Ÿซ 

Fixing all this requires the user or administrator to know about the supposedly hidden unique ID and set its value correctly whenever hardware is moved, repurposed, or replaced... which totally contradicts the whole idea that it's hidden and humans never need to touch it ๐Ÿ™ƒ Making the user understand this expert behind-the-scenes stuff is just one more burden when they're already trying to figure out why their computers and network devices aren't working as expected.

These anomalies and counterintuitive behaviors can be eliminated by keeping a tight, bidirectional, one-to-one mapping between what the user sees on the screen and what's really happening "behind the curtain" ๐ŸŽ€ If something is configured incorrectly, that should be apparent in the familiar everyday interface everyone understands, not in some little-known, rarely used "expert" interface ๐Ÿ’…

In summary: in DNS-SD the user-visible name is also the primary identifier for a service. If the user-visible name changes, then conceptually the service being offered is a different logical service, even if the hardware offering it stayed the same. If the user-visible name doesn't change, then conceptually the service being offered is the same logical service, even if new hardware came in to replace some old equipment ๐Ÿฆ‹

Are there arguments on both sides? Absolutely ๐ŸŒˆ Still, the designers of any service discovery protocol have to choose between hidden primary identifiers and visible ones, and these are the reasons we went with visible. We're not pretending visible identifiers have no disadvantages. We considered both alternatives, and we believe the few disadvantages of visible identifiers are far outweighed by the many problems caused by hidden ones ๐Ÿ‘‘


Appendix D. Choice of Factory-Default Names

Okay, so when a DNS-SD service is advertised using Multicast DNS [RFC6762], if there's already another service of the same type advertising with the same name, automatic name conflict resolution kicks in ๐Ÿ”ฅ As described in the Multicast DNS specification [RFC6762], upon detecting a conflict, the service should:

  1. Automatically select a new name (typically by appending or incrementing a digit at the end of the name),
  2. Try advertising with the new name, and
  3. Upon success, record the new name in persistent storage.

This renaming behavior is super important, because it's the key to providing user-friendly instance names in the out-of-the-box factory-default configuration ๐Ÿงš Some product developers apparently haven't realized this, because some products today ship with a factory-default name that's distinctly unfriendly, full of random-looking characters, such as the device's Ethernet address in hexadecimal ๐Ÿ™ˆ That's unnecessary and undesirable, because the whole point of a user-visible name is that it should be friendly and meaningful to human users. If the name isn't unique on the local network, the protocol will fix that as necessary ๐Ÿ’–

It's kinda ironic that so many of the devices with this design mistake are network printers, given that these same printers also support AppleTalk-over-Ethernet at the same time, with nice user-friendly default names (plus automatic conflict detection and renaming) ๐Ÿ’€ Some examples of good factory-default names are:

   Brother 5070N
   Canon W2200
   HP LaserJet 4600
   Lexmark W840
   Okidata C5300
   Ricoh Aficio CL7100
   Xerox Phaser 6200DX

To make the case for why adding long, ugly factory-unique serial numbers to the end of names is neither necessary nor desirable, let's look at three situations: the user has (a) only one network printer, (b) two network printers, or (c) many network printers ๐Ÿซถ

  • (a) If the user has only one network printer, a simple name like (to use a vendor-neutral example) Printer is way more user-friendly than an ugly name like Printer_0001E68C74FB. Tacking hexadecimal goop onto the end to make sure the name is unique is totally irrelevant to a user who only has one printer anyway ๐Ÿ™„
  • (b) If the user gets a second network printer, having the new printer detect that the name Printer is already in use and automatically name itself Printer (2) instead gives a great user experience โœจ For most people, remembering that the old printer is "Printer" and the new one is "Printer (2)" is easy and intuitive. Seeing one printer called Printer_0001E68C74FB and another called Printer_00306EC3FD1C is a lot less helpful ๐Ÿ˜ญ
  • (c) In a network with ten network printers, seeing a list of ten names all of the form Printer_xxxxxxxxxxxx has effectively taken what was supposed to be a list of user-friendly rich-text names (supporting mixed case, spaces, punctuation, non-Roman characters, and other symbols) and turned it into just about the worst user interface imaginable: a list of incomprehensible random-looking strings of letters and digits ๐Ÿ’€ In a network with a lot of printers, it would be advisable for the people setting up the printers to take a moment to give each one a descriptive name. But if they don't, presenting users with a list of sequentially numbered printers is a much more desirable default experience than showing a list of raw Ethernet addresses ๐ŸŒธ

Appendix E. Name Encodings in the Domain Name System

Okay, so although the original DNS specifications [RFC1033] [RFC1034] [RFC1035] recommend that host names contain only letters, digits, and hyphens (because of the limitations of the typing-based user interfaces of that era), Service Instance Names are not host names ๐Ÿฆ‹ Users generally access a service by selecting it from a list presented by a user interface, not by typing in its Service Instance Name. "Clarifications to the DNS Specification" [RFC2181] directly discusses allowable character sets in Section 11 ("Name syntax"), and explicitly states that the traditional letters-digits-hyphens rule applies only to conventional host names ๐Ÿค“ Here's what it says:

   Occasionally it is assumed that the Domain Name System serves only
   the purpose of mapping Internet host names to data, and mapping
   Internet addresses to host names.  This is not correct, the DNS is
   a general (if somewhat limited) hierarchical database, and can
   store almost any kind of data, for almost any purpose.

   The DNS itself places only one restriction on the particular
   labels that can be used to identify resource records.  That one
   restriction relates to the length of the label and the full name.
   The length of any one label is limited to between 1 and 63 octets.
   A full domain name is limited to 255 octets (including the
   separators).  The zero length full name is defined as representing
   the root of the DNS tree, and is typically written and displayed
   as ".".  Those restrictions aside, any binary string whatever can
   be used as the label of any resource record.  Similarly, any
   binary string can serve as the value of any record that includes a
   domain name as some or all of its value (SOA, NS, MX, PTR, CNAME,
   and any others that may be added).  Implementations of the DNS
   protocols must not place any restrictions on the labels that can
   be used.  In particular, DNS servers must not refuse to serve a
   zone because it contains labels that might not be acceptable to
   some DNS client programs.

Note that just because DNS-based Service Discovery supports arbitrary UTF-8-encoded names doesn't mean any particular user or administrator is obliged to use that capability ๐Ÿ’… Any user is totally free to keep naming their services using only letters, digits, and hyphens, with no spaces, capital letters, or other punctuation ๐ŸŒˆ

Appendix F. "Continuous Live Update" Browsing Model โœจ

okay bestie, this one is my favourite ๐Ÿ’– DNS-SD is designed with a really specific vibe in mind, especially when you pair it with ad hoc Multicast DNS. That vibe is how service discovery behaves in a network that keeps changing under your feet ๐Ÿฆ‹

A lot of other service discovery protocols seem to quietly assume a usage model that goes like this:

  • (a) client software calls the service discovery API,
  • (b) the discovery code spends a few seconds collecting a list of the instances that are available at that exact moment, and then
  • (c) the client shows that list so the user can pick one. ๐Ÿ“‹

Honestly, on the surface that sounds totally reasonable ๐Ÿ™„ The problem is that it's too optimistic. It only imagines the success case, where the software instantly finds the exact service the user wants.

Picture this: someone is hunting for a particular printer, and that printer is switched off or not plugged in. The user has to fix the problem first, and then smash a "refresh" button to find out whether it worked ๐Ÿ˜ญ Nothing in networking happens instantly, and packets can get lost, which means retransmissions, so a search usually takes a few seconds. The result is a pretty typical experience:

  • (a) an empty window pops up,
  • (b) a searchlight animation sweeps back and forth for ten seconds, and then
  • (c) after those ten seconds, a static list shows up with whatever was found. ๐Ÿ”ฆ

And every time someone clicks "refresh", they get another ten-second wait. Even worse, the list is already going stale the second it appears on screen ๐Ÿ’€

The DNS-SD designers had a much better experience in mind, with some very different properties:

  1. Showing the first list of discovered services should be effectively instantaneous, so typically 0.1 seconds, not 10 seconds. โšก
  2. The list should never be stale or out-of-date from the moment it appears. It should be 'live' and keep updating as new services get discovered. Because of delays, packet losses, and retransmissions, it's normal for a few stragglers to trickle in during the next few seconds after the initial list shows up with most of the services. Even after that list settles, it should stay 'live'. At any later time, whether that's minutes, hours, or even days, if a new service of the wanted type shows up, it should appear in the list automatically. No "refresh" button, no extra clicks, nothing ๐Ÿ™Œ
  3. People get used to leaving service discovery windows open and expect them to show what's actually on the network right now. That gives us another requirement: deletion of stale services. A static snapshot is simple, since a service is either in the list or it isn't. But a live list that keeps growing means the corollary is also true: when a service goes away, it needs to disappear from the list. Otherwise the list just keeps piling up old data over time, and you'd need a periodic "refresh" (or closing and reopening the whole thing) to fix it. Nobody wants that, bestie ๐Ÿ™…โ€โ™€๏ธ
  4. Leaving windows open for ages also means the window should update not only when services come and go, but also when the client machine's own configuration and connectivity change. For example, if someone opens a service discovery window while the machine has no network connectivity, the window will usually look empty. When they plug in an Ethernet cable or join an 802.11 [IEEEW] wireless network, the window should fill up with discovered services all by itself, no action needed. If they unplug the Ethernet cable or turn off 802.11 wireless, every service found through that interface should automatically vanish ๐Ÿซฅ And if they move from one 802.11 wireless access point to another, the window should drop the services from the old access point and add the ones from the new one, automatically. Main character energy for the UI, honestly ๐Ÿ‘‘

Appendix G. Deployment History ๐Ÿš€

Okay, so here's the story of how this all came together, and it's kind of iconic ๐ŸŒˆ

In July 1997, Stuart Cheshire first floated the idea of running the AppleTalk Name Binding Protocol [RFC6760] over IP, in an email to the net-thinkers@thumper.vmeng.com mailing list. After that, and after related IETF discussions, the IETF Zeroconf working group got chartered in September 1999. A bunch of working group and informal IETF discussions followed, and several Internet-Drafts got written. They were loosely related to DNS and multicast in general, but none of them really tackled the service discovery part of NBP ๐Ÿคทโ€โ™€๏ธ

In April 2000, Stuart Cheshire registered the IPv4 multicast address 224.0.0.251 with IANA and started writing code to test and develop the idea of doing NBP-like service discovery with Multicast DNS. That work got documented in a group of three Internet-Drafts ๐ŸŽ€

  • "Requirements for a Protocol to Replace the AppleTalk Name Binding Protocol (NBP)" [RFC6760] is an overview of how AppleTalk NBP worked. Lots of people in the IETF community had little first-hand experience with AppleTalk, and confusion over what NBP actually did was causing confusion about what an IP-based replacement would need. So this doc cleared that up ๐Ÿง 
  • "Discovering Named Instances of Abstract Services using DNS" [NIAS], which later became this document, proposed a way to do NBP-like service discovery using DNS-compatible names and record types. This is the one that turned into the DNS-SD spec, bestie โœจ
  • "Multicast DNS" [RFC6762] specifies how to carry those DNS-compatible queries and responses over IP multicast, for zero-configuration environments where there was no conventional Unicast DNS server available. ๐Ÿ“ก

In 2001, an update to Mac OS 9 added resolver library support for host name lookup using Multicast DNS. If a user typed a name like "MyPrinter.local." into any networking software that used the standard Mac OS 9 name lookup APIs, those APIs would recognise it as a dot-local name and look it up by sending simple one-shot Multicast DNS queries to 224.0.0.251:5353. So users could type "MyPrinter.local." into a web browser to see a printer's status and configuration page, or type "MyPrinter.local." into the printer setup utility to create a print queue for that printer ๐Ÿ–จ๏ธ๐Ÿ’…

Multicast DNS responder software with full service discovery first started shipping to end users in volume with Mac OS X 10.2 "Jaguar" in August 2002. Network printer makers had historically supported AppleTalk in their printers, and they were receptive to IP-based technology that offered similar ease of use, so they started adopting Multicast DNS shortly after ๐ŸŒธ

In September 2002, Apple released the source code for the mDNSResponder daemon as Open Source under Apple's standard Apple Public Source License (APSL). ๐Ÿ“

Multicast DNS responder software became available for Microsoft Windows users in June 2004, with the launch of Apple's "Rendezvous for Windows" (now "Bonjour for Windows"). It came both as an executable (a downloadable installer for end users) and as Open Source, since it was one of the supported platforms in Apple's cross-platform code in the publicly accessible mDNSResponder CVS source code repository [BJ] ๐Ÿ’ป

In August 2006, Apple re-licensed the cross-platform mDNSResponder source code under the Apache License, Version 2.0. ๐Ÿฆ‹

Multicast DNS is now implemented in a whole range of devices, on top of desktops and laptops running Mac OS X and Microsoft Windows. You'll find it in Apple's "AirPort" wireless base stations, iPhone and iPad, and in home gateways from other vendors, network printers, network cameras, TiVo DVRs, etc. It's everywhere, periodt ๐ŸŒ

The Open Source community has produced lots of independent Multicast DNS implementations. Some are in C, like Apple's mDNSResponder daemon, and others are in a variety of languages, including Java, Python, Perl, and C#/Mono. ๐Ÿงš

In January 2007, the IETF published the Informational RFC "Link-Local Multicast Name Resolution (LLMNR)" [RFC4795]. It's substantially similar to Multicast DNS, but it's incompatible in some small but important ways. Most notably, the LLMNR design explicitly left out support for service discovery, which made it an unsuitable candidate for replacing AppleTalk NBP [RFC6760]. Not it, bestie ๐Ÿ™…โ€โ™€๏ธ

Multicast DNS and DNS-Based Service Discovery were originally focused on zero-configuration environments without a conventional Unicast DNS server. But DNS-Based Service Discovery also works with Unicast DNS servers. It uses DNS Update [RFC2136] [RFC3007] to create service discovery records, and standard DNS queries to look them up. Apple's Back to My Mac service, launched with Mac OS X 10.5 "Leopard" in October 2007, uses DNS-Based Service Discovery over Unicast DNS [RFC6281] โ˜๏ธ

In June 2012, Google's Android operating system added native support for DNS-SD and Multicast DNS with the android.net.nsd.NsdManager class in Android 4.1 "Jelly Bean" (API Level 16) [NSD]. ๐Ÿค–๐Ÿ’œ

Authors' Addresses ๐ŸŽ€

Stuart Cheshire
Apple Inc.
1 Infinite Loop
Cupertino, CA  95014
USA

Phone: +1 408 974 3207
EMail: cheshire@apple.com


Marc Krochmal
Apple Inc.
1 Infinite Loop
Cupertino, CA  95014
USA

Phone: +1 408 974 4368
EMail: marc@apple.com
๐Ÿ“ฆ where this page comes from