Zero Configuration Networking: The Definitive Guide

6.2. The Command-Line Tool

The dns-sd tool can be run with a number of command-line options that allow you to specify the task the tool should perform. Figure 6-2 shows the available options.

Figure 6-2. Options for the command-line tool

The first two options , -E and -F, return a list of the domains recommended for registering and browsing services, respectively. Normally, on your home network, the only domain you're likely to see is local. However, if your network administrator has created the Domain Enumeration records described in Chapter 5, then you may also see other recommended domains. These recommended domains are not an exhaustive list. You are free to browse any domain you wish and to register services in any domain for which you have the proper credentials. The domain enumeration functions are simply provided so that software can present a useful list of recommended defaults to users, instead of the users always having to know the domains in advance and manually type them in. The goal of Zeroconf software is zero configuration networking; DNS-SD lets the user discover services, so it should likewise let the user discover the domains where those services can be discovered.

The third option, -B, browses for all instances of a given type in a specified domain. Having discovered a list of service instances, you may then want to know more about one of them, and this is done by resolving it with the -L (lookup) option.

The fifth option, -R, allows you to register (advertise) a service. If you have some service running on your machine that is not yet Zeroconf-enabled, you can manually advertise on its behalf using the -R option. You should use this option responsibly. You can easily create a service advertisement for a service that doesn't really exist, which is fine for testing but could be very confusing for other users on your network.

The sixth option, -P, lets you create a proxy advertisement for a service running on some other machine.

The seventh option, -Q, is for testing arbitrary queries for any DNS name, resource record type, and resource record class, not necessarily DNS-SD names and record types.

The remaining options are specialized automated testing routines that most developers should never need to use. They're used by developers working on the Darwin open source project, for testing and verifying changes to the mDNSResponder daemon code itself.

6.2.1. Browsing

There is a bit of a chicken-and-egg decision of whether to start by presenting browsing for services or registering services. If no services are registered, there is nothing to browse for. On the other hand, without a browser present, it is difficult to confirm that a service has been registered. Fortunately, today there are many existing applications and devices that advertise services with DNS-SD, so we'll start by browsing to discover some of those services.

The general form for the browse command is:

dns-sd -B <Type> <Domain>

Type should be of the form discussed in Chapter 4. In other words, an application protocol name followed by either ._tcp or ._udp. To browse for advertised web pages suitable for viewing in a web browser, enter _http._tcp for Type. This is exactly what Safari does to discover the list of advertised web pages, and you should see the same list that Safari displays. If you have a reasonably modern network printer, network camera, or even a TiVo on your network, you should see it appear in the list. If you have a Mac with Personal Web Sharing turned on and the user's web page content modified from the out-of-the-box default, you should see that too appear as an advertised page.

Omitting the Domain argument or giving the empty string means to use the default domain, which usually means just local, unless you are on a network that is advertising a legacy browse domain (see Chapter 5).

For another example, if there are one or more Macintosh or Windows machines on your local link sharing music via iTunes, you can browse for them. If you are using either operating system, you can share music yourself by starting iTunes and configuring Sharing from the preferences window, as shown in Figure 6-3.

The protocol iTunes uses to share music is the Digital Audio Access Protocol (DAAP) . Browse to discover instances of this service type using the command:

dns-sd -B _daap._tcp

Depending on what is currently running, the results should look something like this:

% dns-sd -B _daap._tcp Browsing for _daap._tcp Timestamp A/R Flags if Domain Service Type Instance Name 11:31:40.084 Add 2 5 local. _daap._tcp. Martian NetDrive Music 11:32:07.105 Add 2 5 local. _daap._tcp. Dim Sum Music 11:32:56.211 Add 2 5 local. _daap._tcp. Mu Shu's Music 11:33:13.785 Add 2 5 local. _daap._tcp. Session Casts 11:33:40.186 Rmv 0 5 local. _daap._tcp. Mu Shu's Music

You can browse for other service types, such as _ftp._tcp, _telnet._tcp, and _ssh._tcp. You can find the list of registered service types at http://www.dns-sd.org/ServiceTypes.html.

Figure 6-3. Sharing music with iTunes

Remember that this is still part of the "interface with Zeroconf" part of the process. DNS-SD will discover the service for you, but to use it you still need a client that implements that protocol.

6.2.2. Registering (Advertising) a Service

Here is the template for the service registration command:

dns-sd -R <Name> <Type> <Domain> <Port> [<TXT>...]

Name is the user-friendly name of the service instance, such as "Dan's music." You can also just use the empty string "" for the name, and the registration will automatically use the system-wide default name, as set in Sharing Preferences on Mac OS X.

Type is the service type, just as with browsing.

Domain can be local, or any other domain where you have the credentials and authority to perform Dynamic DNS updates. If the Dynamic DNS server for that domain requires cryptographic authentication, then your cryptographic credentials need to be stored in the Mac OS X System Keychain (or equivalent on other platforms) for the mDNSResponder daemon to access them. As with browsing, the domain parameter can be the empty string, meaning "pick a sensible default for me," which is usually local unless you've used the Bonjour Preference Pane or similar tool to set a default registration domain.

Port is used to specify the TCP or UDP port number where the service can be reached. After the port number, you can give optional key/value pairs that are stored in the service's TXT record and delivered to clients when they resolve the service. This section contains several examples of registering services.

If clients seem unable to connect to a service, check your firewall settings. You can have a service correctly listening on a port, advertise it with DNS-SD, and discover it with clients, but all that will be in vain if the firewall then blocks all the incoming connection requests. This is, after all, the purpose of a firewallto prevent services running on your machine from receiving inbound connection requests directed to them. If you want services running on your machine to be able to receive inbound connection requests, you need to either turn off the firewall or at least add a rule allowing inbound connections to that specific port number.

Returning to our iTunes music example introduced in the previous section, we can now register a "fake" DAAP service that iTunes will discover and display in its sidebar list. Of course, if there is no real DAAP service running at the address you specify, there will be nothing there for iTunes to actually connect to, but the purpose of this example is to demonstrate how you can use the dns-sd tool to test your application's browsing code, possibly before you've even implemented the server part of the protocol. Register an instance named Mu Shu's Music like this:

% dns-sd -R "Mu Shu's Music" _daap._tcp "" 9904 Registering Service Mu Shu's Music._daap._tcp port 9904 Got a reply for Mu Shu's Music._daap._tcp.local.: Name now registered and active

Because the name of the service instance contained spaces, the string "Mu Shu's Music" is enclosed in double quotes. When you enter:

dns-sd -R "Mu Shu's Music" _daap._tcp local 9904

you will immediately see the second line indicating that the request to register the service has been initiated. There will be a short pause while the system probes the network to ensure that your chosen name is not already in use, and then you will see the confirmation that the name is registered and active. This is typical of the way in which you will programmatically work with the DNS-SD APIs as well. You will send a request and wait for a callback. The APIs in each language have been implemented so as not to lock the application while it waits for a response.

If you have iTunes installed and have configured the preferences to view shared music, Mu Shu's Music will now appear in your Shared Music folder. (See Figure 6-4.)

Of course, as there's no real service there, attempts to connect will fail and display an error message like the one shown in Figure 6-5.

You can also confirm that Mu Shu's Music has been successfully registered without using iTunes, by opening a second terminal window and browsing for services of type _daap._tcp using the command:

dns-sd -B _daap._tcp

Figure 6-4. Registered music appears in iTunes

Figure 6-5. Error when no implementation is present

One of the entries should include a timestamp, Add, and the text Mu Shu's Music. Terminate the process that you used to register Mu Shu's Music by selecting that window and pressing Ctrl-C. Your browser window should now display a line with a timestamp, Rmv (meaning remove), and the text Mu Shu's Music. Start up the process again and the service instance should once again appear in the browser list as having been added.

Using the dns-sd command in this way, you can, with just a single one-line command, create advertisements for (possibly nonexistent) services that will be discovered and show up in your application's browsing user interface. This can be a great debugging aid while developing Zeroconf applications, because with minimal effort, you can get quick feedback on the effects of your actions.

You should use care when creating fake service advertisements. Doing it on your own private closed network for testing is one thing, but doing it on a network with other users is likely to make you unpopular. The novelty of seeing fake services that don't really work wears off very quickly.

As a second example, suppose you are hosting a wiki on your computer. A wiki is a web site in which every web page is editable by anyone with access. Users can add and modify pages using a standard web browser. You could define and register a new protocol named wiki, but the existing HTTP protocol already supports wikis and requires nothing out of the ordinary to display and modify pages. Wikis come in many flavors and are implemented in Perl, Python, Java, Smalltalk, and many other languages. None of this matters to end users who will be exclusively interacting with the wiki using a web browser. Accordingly, the right protocol type to advertise is _http._tcp. This protocol type says, "This resource is an HTML page, fetched via HTTP, suitable for viewing in a conventional web browser." Since a wiki page fits that description, _http._tcp is the right service type to advertise.

Start up your wiki. This example uses the FitNesse wiki available at http://www.fitnesse.org. To start this particular wiki running on port 9097, type the following command in the directory that contains the wiki code:

sh run.sh -p 9097

Now, anyone can connect to the wiki if they know the name of the host on which it is running or the IP address, as well as the port that has been selected, but even in a small group of people, publicizing this information can be a hassle. You can tell people, but they forget. You can email the information, but emails get deleted or filed away in folders. You can write it on a Post-It note and stick it on the wall, but that rapidly becomes an untidy mess. DNS-SD lets you advertise it so that a descriptive name appears right in the user's web browser. Since the FitNesse wiki does not yet advertise itself via DNS-SD, you can manually advertise on its behalf using the dns-sd command:

dns-sd -R "Bonjour Wiki " _http._tcp "" 9097

Anyone using a Zeroconf-enabled web browser will now see a link to "Bonjour Wiki" appear in their server list. This is especially helpful in settings where you cannot be certain that the machine hosting the wiki will necessarily retain the same IP address, for example, because it is using DHCP. Collaborators can just discover the wiki by name and be connected, as shown in Figure 6-6.

Figure 6-6. Advertising a web server as a DNS-SD service of type _http._tcp

Figure 6-6 shows that when a user selects "Bonjour Wiki" from the drop-down list, it is resolved to the domain hargau.local. along with the registered port number 9097. This name resolution is the topic of the next section.

There are some limitations to advertising on behalf of the FitNesse wiki server using the dns-sd command. For instance, we have two processes running instead of one, and we have to take care to make sure that when the server is running, the dns-sd command is running, and when the server is stopped, the dns-sd command is stopped too. It is much better, in the long term, if the DNS-SD registration call is integrated into the FitNesse wiki server itself. What the dns-sd command gives us is the ability, with just a simple one-line command, to evaluate the user experience of seeing the server automatically appear in the web browser and then to evaluate, based on that, whether it's worth taking the next step and doing the work to integrate the registration code into the software in question.

6.2.3. Resolving

Browsing gives you the name of nearby services of a specified service type, but before you can attempt to connect to a service, you need to know at least the address and port number to connect to. You may also want to know the hostname and other miscellaneous attributes that are stored in the service's TXT record. Every time you connect to a service in Safari's Bonjour list, Safari is resolving the service and then connecting to it. Using the command line, the general form of the command is this:

dns-sd -L <Name> <Type> <Domain>

Name, Type, and Domain are the same name, type, and domain as discovered in the browsing step. Note that you should not necessarily assume that the discovered type and domain will be the type and domain you originally browsed for. Usually they will be, but not always. For example, it's possible in certain cases to browse one domain (e.g., local) and discover advertisements for services that exist in another domain (e.g., apple.com.). By taking care to store the name, type, and domain reported in the browse result, and passing all three back to the resolve call, you can ensure that your application will work correctly in these cases.

We can resolve an instance of HTTP service in the "local" domain called "Bonjour Wiki" using the following command:

dns-sd -L "Bonjour Wiki" _http._tcp local

The response looks like this:

13:17:52.498 Bonjour\032Wiki._http._tcp.local. can be reached at HarGau.local.:9097

Because this is a text-oriented command-line interface, spaces are escaped as \032, following the standard DNS escaping convention. In a GUI, escaping is not needed and all punctuation characters and spaces are displayed just as themselves, the way they should be.

If you resolve an iTunes music service, in addition to the name, service type, host, and port on which the service is running, the TXT record is also returned:

% dns-sd -L "Dim Sum Music" _daap._tcp local Lookup Dim Sum Music._daap._tcp.local 11:43:11.063 Dim\032Sum\032Music._daap._tcp.local. can be reached at SuiMai.local.:3689 TXT \0x09txtvers=1\0x0EVersion=196608\0x13iTSh Version=131073\0x17M...

The key/value pairs in this example show that txtvers=1, Version=196608, and iTSh Version=131073. When one copy of iTunes connects to another, these values let it determine, before it even attempts to open the TCP connection, if the other speaks a compatible version of DAAP.

The TXT record keys in Apple's iChat application are a little more self-explanatory. The service type for iChat AV's Bonjour advertisements is _presence._tcp. We can simulate an iChat Bonjour advertisement for someone named "Sam Jones" with status "away," as shown here:

% dns-sd -R "Sam Jones" _presence._tcp "" 9092 txtvers=1 status=dnd Registering Service Sam Jones._presence._tcp port 9092 txtvers=1 status=dnd Got a reply for Sam Jones._presence._tcp.local.: Name now registered and active

In addition to passing in the service name, type, domain, and port, we have provided two key/value pairs that are stored in the service's TXT record. Here, txtvers has been set to 1 and status has been set to dnd (do not disturb). Similarly, we can simulate an iChat Bonjour advertisement for someone named "Jack Smith" with status "available," like this:

% dns-sd -R "Jack Smith" _presence._tcp "" 9093 txtvers=1 status=avail Registering Service Jack Smith._presence._tcp port 9093 txtvers=1 status=avail Got a reply for Jack Smith._presence._tcp.local.: Name now registered and active

You can use the command-line tool to look up Jack Smith:

% dns-sd -L "Jack Smith" _presence._tcp local Lookup Jack Smith._presence._tcp.local 12:01:07.062 Jack\032Smith._presence._tcp.local. can be reached at HarGau.local.:9093 TXT \0x09txtvers=1\0x0Cstatus=avail

Note that when you register a service, you pass the key/value as individual command-line arguments, and the tool builds the correct TXT record for you in the proper DNS TXT record format, with each component prefixed with a length byte. When you resolve a service with dns-sd -L, you see the TXT record in its raw form, with the length byte before each component key/value pair. In this case, you see that the length of the string "txtvers=1" is 9 characters and the length of the string "status=avail" is 12 characters (0x0C in hexadecimal).

Now that we've created our two simulated iChat Bonjour advertisements, we can see what iChat itself makes of them, as shown in Figure 6-7. Jack Smith is shown as available (green circle) and Sam Jones is shown as busy (red square).

Figure 6-7. iChat's browser for local chat service

6.2.4. Proxying

Suppose you'd like to quickly and easily simulate the user experience customers might get with your product if it advertised with DNS-SD, but your product is a hardware device, not a piece of software running on a general-purpose Mac, Linux, or Windows computer. This is where the -P option comes into play. This allows your general-purpose Mac, Linux, or Windows computer to advertise a service that's actually being offered by some other piece of hardware. The proxy advertising command takes this general form:

dns-sd -P <Name> <Type> <Domain> <Port> <Host> <IP> [<TXT>...]

Name, Type, Domain, Port, and TXT are just the same as when advertising with the -R option.

The two new options are IP, the address of the device, and Host, a name for it. Generally speaking, any old name (usually a dot-local name) will do, as long as it is unique. Obviously, you wouldn't ship a product this way, because to use the proxy advertising command you need to know the device's address, and the whole point of Zeroconf is that you shouldn't have to know or care what a device's address is. Nonetheless, this can be an easy way to do a quick demo if you need to convince management why the product should use Zeroconf. Usually, the hardest part of doing this demo is finding the device's IP address to advertise, which sort of makes the point of why you want it to use Zeroconf!

There are some interesting tricks you can play with proxy advertising. For example, the service for which you create a proxy advertisement doesn't even need to be on your local network. You can set up a local proxy for a distant web site somewhere out on the Internet: use the host command to discover the IP address of the public web site. Now, advertise this by registering a service of type _http._tcp with a name of your choosing. The host is a locally unique name that will be set to resolve to the given IP address. In the example shown here, the www.apple.com web page is advertised as a service called "apple," running on a target host called apple.local, which resolves to 17.254.3.183.

% host apple.com apple.com has address 17.254.3.183 % dns-sd -P apple _http._tcp "" 80 apple.local 17.254.3.183 Registering Service apple._http._tcplocal host apple.local port 80 Got a reply for apple._http._tcp.local.: Name now registered and active Got a reply for apple.local: Name now registered and active

Now "apple" will show up in your Bonjour menu in the Safari web browser, as shown in Figure 6-8. You can also reach the same IP address by entering the URL apple.local in the web browser. In either case, the request will be resolved to the IP address and the browser will show the contents associated with www.apple.com.

Figure 6-8. The proxy service appears in the Bonjour list

6.2.5. Monitoring

The remaining command-line options test some of the more arcane areas of DNS-SD functionality, such as the little-known event-notification functionality. For example, if a client wants to be informed of changes in server state, it can initiate a query for the service's TXT record, leave the query running indefinitely, and then the client is notified every time the server's TXT record changes. iChat uses this capability to provide timely updates to Bonjour buddies availability, status messages, and icons, without having to resort to polling to keep this information up to date.

You can witness this by using dns-sd -B _presence._tcp to find the list of iChat users advertised on the network, and then use dns-sd -Q to monitor one of them, like this:

dns-sd -Q cheshire@chesh7._presence._tcp.local txt

Every time the status for that user changes, you'll see a new TXT record result reported.

Категории