avahi & nsswitch.conf – mdns4 and Subdomain Resolution from Peers

avahinetworkingzeroconf

Following up on unanswered comments in this question.

I'm trying to use zeroconf/bonjour for a home network specialty network device which needs to pass through certain traffic to additional devices – zeroconf with extra hostnames seems like the easiest and most flexible approach if I can get it work.

My first passes at avahi-deamon deflated my hopes in that perhaps only one name can be registered per host. But then I found the above-linked SO post with its references that suggested to me that it might just be a configuration. I believe I configured my system according to the recommendations, but name resolution by teriary-domain from the same device or other machines still isn't working. So I can't tell if I'm just doing it wrong or if it isn't possible and I've misunderstood the documentation.

With hosts: files mdns4 [NOTFOUND=return] resolve [!UNAVAIL=return] dns in /etc/nsswitch.conf – Is this one change on a single host expected to fix name resolution on all networked clients? Or this is only expected to fix each client's name-resolution strategy, and must be applied to all clients that wish to participate in non-minimal zeroconf name resolution?

These might be stupid questions, but I'm basing it on the belief that avahi uses nss to figure out if it should respond to a zeroconf name resolution query, or whatever. Plus, if it worked locally but not from other machines, I would have confidence that it needed to be applied everywhere – but since it isn't even working to resolve the names locally (where the configuration IS changed) then I figure I just have it wrong. What can I expect to work?

Best Answer

Technically, the requested/previous behavior is against mDNS spec; so understand the compatibility issues that presents. You'll need to either use explicit mappings or third-party tools with Avahi to get the desired out come now.

You could also use an older version of nss-mdns that should do the trick(it appears to resolve to the host before forwarding to Avahi, subsequent versions seemed to have removed such support). But this would only work for each system configured this way, see below for detailed explanation.

Against spec

RFC 6762, Section 3 - Multicast DNS Names:

This document allows any computer user to elect to give their computers link-local Multicast DNS host names of the form: "single-dns-label.local.". ... This document recommends a single flat namespace for dot-local host names, (i.e., the names of DNS "A" and "AAAA" records, which map names to IPv4 and IPv6 addresses), but other DNS record types (such as those used by DNS-Based Service Discovery [RFC6763]) may contain as many labels as appropriate for the desired usage.

That seems to imply that subdomains are not officially supported for mDNS. Which also seems to be re-inforced with other implementations / platforms:

Windows does not support this:

My only disappointment is that the windows implementation of Bonjour/Avahi does not support the aliases that this implementation announces, it will only see the main avahi hostname normally announced (ie server.local in our example above).

macOS does not support this:

It returns an error if the name has more than two labels, as in the case of foo.bar.local.

The README for nss-mdns does reference some rules that the minimal variants use to decide if they should be sent to Avahi to handle. I came across this comment on the nss-mdns github repo that provides some dates for context:

The two-label limit heuristic was implemented in Mac OS X v10.5, released 2007-10-26 The unicast SOA heuristic was implemented in Mac OS X v10.6, released 2009-08-28

These rules were introduced in the 0.11 release of nss-mdns at the start of 2018, a little over a decade since the previous 0.10 release, relevant changelog note:

nss-mdns now implements standard heuristics for detecting .local unicast resolution and will automatically disable resolution when a local server responds to .local requests

Your referenced AskUbuntu question says the change was introduced possibly from Ubuntu 18.10 release, which is understandable as 18.04 would have been an LTS release making the update less likely to be approved.

This reveals that nss-mdns was previously not following such due to the lack of maintenance/updates for so long, both of those changes by Apple were added after the 0.10 release of nss-mdns. As the relevant github issue clarifies with reverse lookup logic and the drawbacks/risks it was causing.

There was a long standing bug report for mdns being handed queries to resolve which blocked until timeout before falling back to standard DNS, which understandably caused quite a few problems for users, notably those interacting with non-mdns .local FQDNs from Microsoft Active Directory.

To get that old behaviour, I think you may need to revert back to 0.10 of nss-mdns.

One further gotcha is that in 2020, while Windows 10 is said to be improving it's mDNS support, Android is still lacking it (beyond developers explicitly configuring for such within their apps). There is workarounds such as Unbound or CoreDNS which both have plugins to forward a Unicast DNS query to a Multicast one, however Avahi needs to be configured so that the hosts advertise the published address so that they're discoverable.

Avahi and NSS

Name Service Switch (NSS) is for your local system to handle lookup queries, here it can be deferred to your /etc/hosts, local DNS, systemd-resolved, mDNS and so forth. Most of your software will utilize it, but that is not always the case, especially with some utilities like host, dig, drill, nslookup which all bypass that and query DNS directly.

Avahi does not defer to NSS, but rather NSS defers to Avahi via nss-mdns. Thus it has nothing to do with how external requests via other devices on the network are handled. You can test queries for Avahi without NSS being involved by using avahi-resolve --name myhostname.local --verbose.

I believe other implementations of mDNS can be more strict/limited configuration wise, so keep in mind that regardless any Windows and macOS clients would likely not work, similar to how they may only handle the .local TLD for mDNS.

Configuring Avahi to respond to more than a hostname

You can configure nss-mdns to allow resolving additional labels via /etc/mdns.allow (when not using the minimal variant in your /etc/nsswitch.conf hosts: line). Without this, anything using NSS would likely send a Unicast DNS query instead, skipping mDNS.

After configuration, you may need to restart any process for it to reload that configuration, or you can test with a CLI command like ping. While that does allow for the expected resolving behavior, you'll notice a common timeout response of 5 seconds. Avahi itself is failing to find a hit for the query response, because nothing is setup to respond for that hostname.

Additionally, the file /etc/avahi/avahi-daemon.conf does not support . within the values for host-name or domain-name, these are for single labels. However, you can publish an explicit mapping manually with avahi-publish:

avahi-publish -a -R test.hostname.local 192.168.1.42

And the daemon will respond to this, but does not report it as discoverable via avahi-browse -a. The -R option is important, in that it will allow you to publish for the same IP address (otherwise complains about a local name collision). Alternatively, you can also define these in /etc/avahi/hosts with each line being the IP address followed by a hostname(which can likewise have a .), there should be some comments and examples in an existing file at that location. The file based approach does not have an equivalent to the -R option of avahi-publish, thus specifying an IP address that's already been mapped to a hostname will be ignored. avahi-daemon does not require a restart when modifying this hosts file.

Note that for queries without avahi-resolve to work you would need NSS configured to use a non-minimal mdns variant such as mdns4, scoping to IPv4 (as opposed to mdns which also covers IPv6) can also lead to faster results (as opposed to waiting for the 5 second timeout, and then receiving an IPv4 response, avahi-resolve will respond promptly regardless however). You can also test queries without modifying /etc/nsswitch.conf with getent --service=mdns4 hosts test.hostname.local, change --service value to mdns4_minimal, mdns, etc.

Avahi via D-Bus

Providing explicit IP addresses kind of defeats the purpose a bit, but if the device runs Avahi, you should be able to have it list a series of labels/subdomains to the hostname via a script/program that communicates with Avahi over it's D-Bus API, like this old python one, they moved their answer snippets to a Github repo, which has quite a few forks including one porting to python3 if the old code hasn't aged well. For Docker users, similar can be found on DockerHub when searching for avahi images, I believe there was one that integrated with Traefik and docker labels to expose the containers over mDNS via Avahi.

Avahi for DNS-SD

You can still leverage mDNS for how it's typically used with DNS-SD(Service Disovery) in devices such as printers. You can provide a friendly string as a service name, and indicate the service type. Another device can then use DNS-SD to query for devices of interest and interact with them.

Another alternative that may work is Dynamic DNS (DDNS), which would allow a device to update DNS record for it's IP address. There are also more involved service discovery software like Hashicorp Consul.