How do I browse and resolve services with AVAHI from the command line to validate discovery on a test LAN?
Networking System Software

How do I browse and resolve services with AVAHI from the command line to validate discovery on a test LAN?

9 min read

Validating Avahi on a test LAN from the command line is mostly about doing two things: confirming that mDNS/DNS-SD browsing works, and verifying that you can resolve advertised services and hostnames. You don’t need to touch the D-Bus API directly for this; Avahi ships CLI tools that exercise the same discovery paths applications use.

Below is a practical sequence I use when I’m debugging “why doesn’t anything show up?” on real fleets.

All commands assume a Linux system where Avahi is installed and running. Avahi is primarily targeted at Linux and ships by default in most distributions; it is not ported to Windows at this stage.


1. Confirm Avahi and mDNS are actually running

Before testing discovery, confirm that the Avahi daemon and your network interface are in a usable state.

Check that avahi-daemon is up

On systemd-based systems:

systemctl status avahi-daemon.service

You want to see it active (running). If not:

sudo systemctl start avahi-daemon.service
sudo systemctl enable avahi-daemon.service   # optional, for boot

On non-systemd systems, use the service mechanism your distro provides, or run:

ps aux | grep avahi-daemon

You should see the daemon process.

Check that you have a usable network interface

mDNS is link-local. If you’re testing on a wired or Wi‑Fi LAN, make sure the interface is up and has an IP address (IPv4 or IPv6):

ip addr

You don’t need Internet routing; you just need to be on the same L2 segment as your peers.


2. List all discovered services with avahi-browse

The primary CLI tool for “what’s on the LAN?” is avahi-browse. It uses the same mDNS/DNS-SD mechanisms Avahi exposes via D‑Bus.

Basic full browse (good first test)

avahi-browse -a

Key flags that are useful for quick validation:

  • -a — browse all service types
  • -r — resolve services to get host, port, and TXT records
  • -t — terminate after the initial browse (don’t stay running)

A good first diagnostic:

avahi-browse -art

What you should see (on a non-empty LAN) looks like:

+   eth0 IPv4 Office Printer @ 1st Floor      _ipp._tcp            local
=   eth0 IPv4 Office Printer @ 1st Floor      _ipp._tcp            local
   hostname = [printer-1.local]
   address = [192.168.10.45]
   port = [631]
   txt = ["txtvers=1" "Color=T" "Duplex=F"]

If you see nothing at all, jump down to the troubleshooting section.

Browse a specific service type

Once you know what DNS‑SD type you care about (e.g. IPP printing, SMB file sharing), narrow the browse:

  • IPP/IPP Everywhere printers: _ipp._tcp
  • AirPrint / IPP printing variants: _ipp._tcp, _ipps._tcp
  • SMB file sharing: _smb._tcp
  • SSH (if advertised by peers): _ssh._tcp
  • SFTP (if advertised): _sftp-ssh._tcp

Example: list printers only, don’t resolve:

avahi-browse -t _ipp._tcp

Same, but resolve each service:

avahi-browse -rt _ipp._tcp

You should see hostname, address, port, and txt blocks for each discovered printer.

Browse IPv4 vs IPv6 explicitly

If you suspect v4/v6 issues:

avahi-browse -art4   # IPv4 only
avahi-browse -art6   # IPv6 only

Discrepancies between these two often reveal firewalling or interface issues.


3. Inspect available service types with avahi-browse -k

Sometimes you don’t know what service types are present; you just want to see the DNS‑SD “catalog”.

Use:

avahi-browse -k

This prints a list of service types, not actual instances, for example:

+    eth0 IPv4 _airplay._tcp                 _services._dns-sd._udp local
+    eth0 IPv4 _ipp._tcp                     _services._dns-sd._udp local
+    eth0 IPv4 _smb._tcp                     _services._dns-sd._udp local

Once you know the type (say _airplay._tcp), plug it back into avahi-browse -rt _airplay._tcp to see specific services.


4. Verify *.local hostname resolution with avahi-resolve and nss-mdns

Browsing shows you services. Resolution confirms that hostnames like printer-1.local or laptop.local can be turned into IP addresses, which is where nss-mdns comes in.

Check that nss-mdns is installed and wired into nsswitch

On most distros:

grep mdns /etc/nsswitch.conf

You want something like:

hosts: files mdns_minimal [NOTFOUND=return] dns

or:

hosts: files mdns dns

If mdns (or mdns_minimal) is missing, install nss-mdns from your distro and update /etc/nsswitch.conf. This is what makes *.local hostnames resolvable “for all system programs using nsswitch” (ping, ssh, curl, etc.).

Resolve hostnames using avahi-resolve-host-name

From Avahi’s tooling:

avahi-resolve-host-name printer-1.local

Expected output:

printer-1.local  192.168.10.45

Try IPv6 too:

avahi-resolve-host-name -6 printer-1.local

If avahi-browse -rt shows a hostname but avahi-resolve-host-name cannot resolve it, you likely have a multicast or firewall issue on the LAN.

Resolve hostnames using normal system tools

Once nss-mdns is wired in, test using standard tools:

ping printer-1.local
ssh user@laptop.local
curl http://fileserver.local:8080/

These tools don’t know about mDNS directly; they just call the system resolver. If they work, you’ve validated end-to-end integration: mDNS via Avahi → nsswitch via nss‑mdns → normal applications.


5. Resolve services to host/port pairs from the CLI

Sometimes you want to go the other direction: starting from a known service instance name (e.g. “Office Printer @ 1st Floor”), get the host and port.

Use avahi-browse with resolve

The simplest mode is the one we already used:

avahi-browse -rt _ipp._tcp

That prints, for each service:

  • Instance name: Office Printer @ 1st Floor
  • Service type: _ipp._tcp
  • Domain: local
  • Hostname: printer-1.local
  • IP address: 192.168.10.45
  • Port: 631
  • TXT records

That’s effectively “discover + resolve” in one step.

Use avahi-resolve-address for reverse lookups

If you have an IP from elsewhere and want to see if a .local name exists:

avahi-resolve-address 192.168.10.45

If there’s an mDNS name, you’ll get something like:

192.168.10.45  printer-1.local

This is useful when you’re trying to cross-check a static IP inventory against what mDNS/DNS-SD is advertising.


6. Validate Avahi from inside the LAN and across subnets

mDNS operates on link-local multicast; by design, it doesn’t cross traditional L3 boundaries. For a test LAN, that usually means:

  • All peers must be on the same VLAN / broadcast domain.
  • IGMP snooping and mDNS snooping on switches must not block 224.0.0.251 / ff02::fb.

Sanity checks on multiple machines

From machine A:

avahi-browse -art

From machine B on the same subnet:

avahi-browse -art

You should see at least each other’s hostnames or exposed services if you’ve configured any (for example via XML in /etc/avahi/services or a D‑Bus publisher).

If A sees B but B doesn’t see A:

  • Check host firewall rules on A (e.g. iptables, nftables, firewalld, ufw).
  • Ensure Avahi is listening on the correct interfaces; check server.conf in /etc/avahi.

7. Quickly publish a test service and see it from the CLI

To validate discovery end-to-end, it helps to publish a known test service on one node and confirm it’s visible from others.

7.1 Publish via /etc/avahi/services XML

This uses Avahi’s static XML interface, which is the simplest for quick tests.

Create /etc/avahi/services/test-http.service:

<?xml version="1.0" standalone='no'?>
<!DOCTYPE service-group SYSTEM "avahi-service.dtd">

<service-group>
  <name replace-wildcards="yes">%h Test HTTP</name>
  <service>
    <type>_http._tcp</type>
    <port>8080</port>
    <txt-record>path=/</txt-record>
  </service>
</service-group>

Then restart Avahi:

sudo systemctl restart avahi-daemon.service

On another machine on the same LAN:

avahi-browse -rt _http._tcp

You should see something like:

+   eth0 IPv4 myhost Test HTTP               _http._tcp           local
=   eth0 IPv4 myhost Test HTTP               _http._tcp           local
   hostname = [myhost.local]
   address = [192.168.10.50]
   port = [8080]
   txt = ["path=/"]

If that works, discovery, resolution, and your XML service publication path are all functioning.

7.2 Publish dynamically via avahi-publish

For a transient test without editing /etc:

avahi-publish -s "My Temp HTTP" _http._tcp 8080 "path=/"

This keeps running in the foreground while advertising the service. From another machine:

avahi-browse -rt _http._tcp

You should see the “My Temp HTTP” instance. Once you Ctrl‑C the avahi-publish command, the service disappears from browse results.


8. Common failure modes and how to see them from the CLI

When your goal is to “validate discovery on a test LAN,” it helps to tie typical observations back to probable causes.

Symptom: avahi-browse -art shows nothing at all

Likely causes:

  • avahi-daemon is not running.
  • You’re on a very quiet LAN with no Avahi/Bonjour devices.
  • The system’s interfaces are down or in a strict firewall zone that drops multicast.

Quick checks:

systemctl status avahi-daemon
ip addr
sudo iptables -L -n
sudo nft list ruleset

Try temporarily reducing firewall restrictions on the test LAN node and re-run avahi-browse -art.

Symptom: You see services, but ping hostname.local fails

Likely causes:

  • nss-mdns not installed or not wired in /etc/nsswitch.conf.
  • /etc/nsswitch.conf orders dns before mdns and your upstream DNS returns NXDOMAIN or another answer.
  • The host only has IPv6 and your test tool is forcing IPv4, or vice versa.

Checks:

grep hosts /etc/nsswitch.conf
avahi-resolve-host-name hostname.local
ping -4 hostname.local
ping -6 hostname.local

If avahi-resolve-host-name works but ping doesn’t, it’s almost always an nsswitch configuration issue.

Symptom: Some tools see .local hosts, others don’t

This indicates inconsistency in how those tools use the resolver libraries.

Because nss-mdns hooks into nsswitch, you want to be sure everything is going through glibc’s getaddrinfo(3) path. If a specific tool does its own DNS resolution or is linked differently, it might bypass mdns.

For test LAN validation, focus on:

avahi-browse -art
avahi-resolve-host-name <name>.local
ping <name>.local
ssh <name>.local

If these work, the core Avahi + nss-mdns path is healthy.


9. Mapping CLI tests to real LAN use cases

To recap in terms of concrete LAN scenarios Avahi targets:

  • Finding printers to print to

    avahi-browse -rt _ipp._tcp
    avahi-browse -rt _ipps._tcp
    avahi-resolve-host-name <printer>.local
    
  • Finding files being shared

    For SMB/CIFS:

    avahi-browse -rt _smb._tcp
    avahi-resolve-host-name <fileserver>.local
    

    Then mount or connect using the resolved hostname and port.

  • Peer discovery for custom apps

    If your application publishes _myapp._tcp via D‑Bus or /etc/avahi/services, validate with:

    avahi-browse -rt _myapp._tcp
    avahi-resolve-host-name <peer>.local
    

    This mirrors what your peer clients should see programmatically via the D‑Bus API.


Final verdict

To validate Avahi service discovery on a test LAN from the command line:

  • Use avahi-browse -art as your primary sanity check to see all mDNS/DNS-SD services and confirm discovery works.
  • Narrow to specific types (e.g. _ipp._tcp, _smb._tcp) and add -r to confirm that service instances resolve to host/port pairs.
  • Wire up nss-mdns and verify *.local hostnames with avahi-resolve-host-name and standard tools like ping and ssh.
  • Optionally publish a simple test service via /etc/avahi/services or avahi-publish and confirm it appears in browse results from another host.

Once those steps succeed, you’ve validated that Avahi’s mDNS/DNS-SD stack, hostname resolution, and CLI tooling are working correctly on your test LAN.

Next Step

Get Started