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 is no way to tell directly from the data alone how long it is (e.g. there is no length count at the start, or terminating NULL byte at the end).
The format of the data within a DNS TXT record is zero or more strings, packed together in memory without any intervening gaps or padding bytes for word alignment.
The format of each constituent string within the DNS TXT record is a single length byte, followed by 0-255 bytes of text data.
These format rules are defined in Section 3.3.14 of RFC 1035, and are not specific to DNS-SD. DNS-SD simply specifies a usage convention for what data should be stored in those constituent strings.
DNS-SD uses DNS TXT records to store arbitrary name/value pairs conveying additional information about the named service. Each name/value pair is encoded as it's own constituent string within the DNS TXT record, in the form "name=value". Everything up to the first '=' character is the name. Everything after the first '=' character to the end of the string (including subsequent '=' characters, if any) is the value. Specific rules governing names and values are given below. Each author defining a DNS-SD (Rendezvous) profile for discovering instances of a particular type of service should define the base set of name/value attributes that are valid for that type of service. Using this standardized name/value syntax within the TXT record makes it easier for these base definitions to be expanded later by defining additional named attributes. If an implementation sees unknown attribute names in a service TXT record, it SHOULD silently ignore them.
The TCP (or UDP) port number of the service, and target host name, are given in the SRV record. This information target host name and port number MUST NOT be duplicated using name/value attributes in the TXT record.
The intention of DNS-SD TXT records is convey a small amout of useful additional information about a service. Ideally it SHOULD NOT be necessary for a client to retrieve this additional information before it an usefully establish a connection to the service. For a well-designed TCP-based application protocol, it should be possible, knowing only the host name and port number, to open a connection to that listening process, and then perform version- or feature-negotiation to determine the capabilities of the service instance. For example, when connecting to an AppleShare server over TCP, the client enters into a protocol exchange with the server to determine which version of the AppleShare protocol the server implements, and which optional features or capabilities (if any) are available. For a well-designed application protocol, clients should be able to connect and use the service even if there is no information at all in the TXT record. In this case, the information in the TXT record should be viewed as a performance optimization when a client discovers many instances of a service, the TXT record allows the client to know some rudimentary information about each instance without having open a TCP connection to each one and interrogate every service instance separately. Extreme care should be taken when doing this to ensure that the information in the TXT record is in agreement with the information retrieved by a client connecting over TCP.
There are legacy protocols which provide no feature negotiation capability, and in these cases it may be useful to convey necessary information in the TXT record. For example, when printing using the old Unix LPR (port 515) protocol, the LPR service provides no way for the client to determine whether a particular printer accepts PostScript, or what version of PostScript, etc. In this case it is appropriate to embed this information in the TXT record, because the alternative is worse passing around written instructions to the users, arcane manual configuration of "/etc/printcap" files, etc.
The total size of a typical DNS-SD TXT record is intended to be small 100 bytes or less.
In cases where more data is justified (e.g. LPR printing), keeping the total size under 400 bytes should allow it to fit in a single standard 512-byte DNS message. (This standard DNS message size is defined in RFC 1035.)
In extreme cases where even this is not enough, keeping 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.
The "Name" MUST be at least one character. Strings beginning with an '=' character (i.e. the name is missing) SHOULD be silently ignored.
The characters of "Name" MUST be printable US-ASCII values (0x20-0x7E), excluding '=' (0x3D).
Spaces in the name are significant, whether leading, trailing, or in the middle so don't include any spaces unless you really indend that!
Case is ignored when interpreting a name, so "papersize=A4", "PAPERSIZE=A4" and "Papersize=A4" are all identical.
If there is no '=', then it is a boolean attribute, and is simply identified as being present, with no value.
When examining a TXT record for a given named attribute, there are therefore four broad categories of result which may be returned:
Unless specified otherwise by a particular DNS-SD (Rendezvous) profile, a given attribute name may appear at most once in a TXT record. If a client receives a TXT record containing the same attribute name more than once, then the client SHOULD 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 name/value pairs into a hash table, using the name as the hash table key, this means that if the implementation attempts to add a new name/value pair into the table and finds an entry with the same name already present, then the new entry being added should be silently discarded instead. For client implementations that retrieve name/value pairs by searching the TXT record for the requested name, they should search the TXT record from the start, and simply return the first matching name they find.
Each author defining a DNS-SD (Rendezvous) profile for discovering instances of a particular type of service should define the interpretation of these different kinds of result. For example, for some keys, there may be a natural boolean interpretation:
For other keys it may be sensible to define other semantics, such as:
(Note that this is a hypothetical example, not an example of real name/value keys for printing.)
As a general rule, names that contain no dots are defined as part of the open-standard definition written by the person or group defining the DNS-SD (Rendezvous) profile for discovering that particular service type. Vendor-specific extensions should be given names of the form "keyname.company.com=value", using a domain name legitimately registered to the person or organization creating the vendor-specific key. This reduces the risk of accidental conflict if different organizations each define their own vendor-specific keys.
If there is an '=', then everything after the first '=' to the end of the string is the value. The value can contain any eight-bit values including '='. Leading or trailing spaces are part of the value, so don't put them there unless you intend them to be there. Any quotation marks around the value are part of the value, so don't put them there unless you intend them to be part of the value.
The value is opaque binary data. Often the value for a particular attribute will be US-ASCII (or UTF-8) text, but it is legal for a value to be any binary data. For example, if the value of a key is an IPv4 address, that address should simply be stored as four bytes of binary data, not as a variable-length 7-15 byte ASCII string giving the address represented in textual dotted decimal notation.
Generic debugging tools should generally display all attribute values as if they were UTF-8 text, except for attributes where the debugging tool has embedded knowledge that the value is some other kind of data.
Authors defining DNS-SD (Rendezvous) profiles SHOULD NOT convert binary attribute data types into printable text (e.g. using hexadecimal, Base64 or UU encoding) merely for the sake of making the data be printable text when seen in a generic debugging tool. Doing this simply bloats the size of the TXT record, without truly making the data any more understandable to someone looking at it in a generic debugging tool.
------------------------------------------------------------------- | 0x0A | name=value | 0x08 | paper=A4 | 0x12 | Rendezvous Is Cool | -------------------------------------------------------------------
It is recommended that authors defining DNS-SD (Rendezvous) profiles include an attribute of the form "version=xxx" in their definition, and require it to be the first name/value pair in the TXT record. This information in the TXT record can be useful help clients maintain backwards compatibility with older implementations if becomes necessary to change or update the specification over time. Even if the profile author doesn't anticipate the need for any future incompatible changes, having a version number in the specification provides useful insurance should incompatible changes become unavoidable. Clients should ignore TXT records with a version number higher (or lower) than the version(s) they know how to interpret.
Do not assume that all current Apple products using Rendezvous present a model example of how to structure Rendezvous TXT records. Like all companies, Apple sometimes works under severe time pressure, and some of the current Apple Rendezvous products were written in a great hurry. Consequently you should not assume that any particular behaviour of a current Apple Rendezvous product necessarily constitutes an endorsement that that behaviour is correct, or an acceptable model to emulate.
Jaguar's DNSServiceDiscovery.h APIs are, like most Unix APIs, based on C strings. How then does a client encode multiple pascal strings containing name/value pairs using a single C string? The answer is that Jaguar's DNSServiceDiscovery.h APIs use ASCII 1 as the boundary marker between constituent strings within the DNS TXT record. This value can be inserted into a C string using '\001', as shown below:
DNSServiceRegistrationCreate(..., "a=1\001b=2\001c=3", ...);
The results returned from DNSServiceResolverResolve() return the TXT data similarly encoded, so that each name/value pair except the last is followed by ASCII 1, and the last is followed (as usual for a C string) by ASCII 0.
See SamplemDNSClient.c in the Darwin Open Source Code for simple sample code showing how to do this.
This encoding as C strings means that binary values containing the value 0 or 1 cannot be used with this API. For clients wishing to create binary values in TXT records, the registration can be created with an empty TXT record, and then the DNSServiceRegistrationUpdateRecord() call can be used to update the TXT record, as shown below.
DNSServiceRegistrationUpdateRecord(ref, 0, len, buffer, ttl);
The buffer passed to this call is used as-is without interpretation or modification, so it is the client's responsibility to ensure that it is a properly formatted DNS TXT record.
To obtain the raw binary-format TXT record associated with a service, without interpretation or modification, the client should use the standard Unix res_query() call. Unfortunately, in OS X 10.2 and 10.2.1, the res_query() call does not work with local multicast Rendezvous names (names ending in ".local."). This bug has been fixed, and is planned for an upcoming OS X update.
Client applications that really really need to obtain raw binary-format TXT records for local multicast Rendezvous names right right now, and can't wait for the OS X update, can embed the Darwin mDNSResponder source code directly in their application, and use that API do do the record lookup. This course of action is recommended only for the very bold (and impatient).
Currently only one key is defined for _http._tcp service; the "path" key. The value of the path key is everything that comes after the optional port number in an HTTP URL, as defined in section 3.2.2 of RFC 2616 ("HTTP/1.1"):
3.2.2 http URL http_URL = "http:" "//" host [ ":" port ] [ abs_path [ "?" query ]]
If you are writing a web browser, then the path key gives you the text that should appear directly after "GET " in an HTTP "GET" request.
If you are writing a tool to generate a URL to send to a web browser for display, then you should generate a URL of the form shown below, where {host} and {port} are obtained from the information in the service's SRV record, and {path} is obtained from the "path" key in the TXT record.
http://{host}:{port}{path}
The path key in the TXT record MUST include the leading slash of the abs_path, e.g. the following is a legal DNS-SD TXT record for an _http._tcp service:
path=/thepage.html
If the path key is missing, or present with no value or empty value, or otherwise invalid, then the path is assumed to be "/".