Avahi is a daemon you can run on your system for the purpose of discovering or announcing services using DNS-SD. DNS-SD defines how to perform service discovery using DNS SRV and TXT records. Though it can use unicast DNS, its most typical usage is using multicast DNS over zeroconf, i.e link local IPv4/6. If you’ve heard of Apple Bonjour, this is it.

For end-user systems, being able to discover devices in a network using DNS-SD is incredibly helpful. It is often used to discover printers, so you can easily add them to your system. This is a much nicer user experience than having to drudge up the IP address of a printer, which is further complicated by some printers not having a display to provide this information on in the first place.

I already use systemd-resolved and it’s perfectly capable of performing multicast DNS queries and publishing services using DNS-SD. I’d like to cut down on the amount of daemons that run and not have to disable mDNS in systemd-resolved for it to then be provided by Avahi. Systemd-resolved has the nice benefit that I can disable multicast DNS globally or at the connection level using systemd-networkd or NetworkManager (the latter also letting me control whether I want to publish my host recrods, or only do resolving).

GNOME, CUPS and Avahi

The GNOME Control Center Printer applet (and most other desktop environments) uses CUPS. CUPS in turn uses Avahi, assuming it was linked against the Avahi client library and that it’s configured to use it for discovery. This is how it can auto-discover printers, faxes etc.

When I initially went looking this felt like a pretty big stumbling block. Since CUPS is linked against Avahi, it appeared as though we’d have to add an additional way for CUPS to do DNS-SD that wasn’t dependent on the Avahi client library. That is a pretty big piece of work in a C code base I’m not familiar with. I was ready to give up on this as that’s a bit more work than what I was hoping for, when I realised that Avahi provides a D-Bus API.

As luck would have it, when I dug into the Avahi client library I discovered that it uses its own D-Bus API. Since CUPS uses the Avahi client library, its interactions with the Avahi daemon happen entirely over D-Bus. To confirm this was indeed the case, I fired up Bustle and recorded all the interactions on the system bus. When I started the GNOME Control Center, went into the Printers section and then tried to add a printer, I could clearly see the calls from CUPS to the org.freedesktop.Avahi well-known bus name.

Building an Avahi replacement

Because of the Avahi client using D-Bus, I can replace the need for the Avahi daemon by writing my own daemon that implements the Avahi D-Bus API. The daemon can then claim ownership of the org.freedesktop.Avahi bus name and nobody will be any wiser after it.

Since Bustle lets me record a session I now have a pcap and flow chart showing me which parts of the Avahi D-Bus API I need to provide. Looking around a bit in the GNOME Control Center code I also found a few other calls to the Avahi D-Bus API that should be implemented to be able to slot my daemon into place and not break any functionality.

My intent is to build a daemon using godbus that will initially focus on implementing enough of the Avahi D-Bus API to satisfy CUPS. It will in turn use D-Bus and call methods on org.freedesktop.resolve1.Manager, which on my system is provided by systemd-resolved. With systemd-resolved’s DNS-SD support it should also be possible to reimplement the Avahi D-Bus APIs that provide the functionality to publish services.

You might be wondering why I’m not patching providing the Avahi D-Bus API into systemd-resolved. The reason for that is fairly simple: systemd-resolved is written in C. I can read and understand C code, but I have very little experience writing it. In order to be able to experiment with this approach, implementing it as a separate daemon in a language I’m proficient in is a much easier way to go. It has the added advantage that I don’t risk bricking systemd-resolved on my system, which would be painful. Once it’s proven to work and the systemd maintainers don’t object to the idea of providing the Avahi D-Bus API, I might try to implement this functionality in systemd-resolved directly.