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?

7 min read

On a Linux test LAN, the fastest way to sanity‑check AVAHI service discovery is to drive it directly from the command line. You can browse mDNS/DNS‑SD services, resolve individual records, and verify that *.local hostnames work across “normal” CLI tools via nsswitch.

Below is a practical, command‑driven workflow I use when validating discovery in real fleets.


1. Confirm Avahi and mDNS basics are working

AVAHI is a system which facilitates service discovery on a local network via the mDNS/DNS-SD protocol suite. Before you start browsing services, make sure:

  • The avahi-daemon is running.
  • Your firewall allows mDNS multicast (UDP 5353 to 224.0.0.251).
  • nss-mdns is installed and wired into nsswitch.conf if you want *.local lookups from regular tools.

Check that avahi-daemon is running

systemctl status avahi-daemon.service

You want to see active (running). If it’s disabled on a minimal image:

sudo systemctl enable --now avahi-daemon.service

On legacy/non-systemd systems, look for an init script like /etc/init.d/avahi-daemon.

Verify multicast basics (optional but useful)

On one machine, run:

sudo tcpdump -ni any udp port 5353

Then on another machine, run any avahi-browse command (next section). You should see mDNS traffic. No packets usually means firewall or network isolation issues.


2. Listing and browsing services with avahi-browse

The primary API for Avahi is D-Bus, but for validation you don’t need to touch D-Bus directly; the avahi-browse CLI is a front-end that uses the same mechanisms you would use via the library or D-Bus calls such as avahi_service_browser_new().

See all advertised service types

To check what kinds of services are visible on the LAN:

avahi-browse -a

Key flags:

  • -a – browse for all services.
  • -t – terminate after the initial result set (otherwise it stays running and prints changes live).
  • -r – immediately resolve each service into hostname, address, and port.

Example:

avahi-browse -art

This is my default “what’s out there?” command. Typical output:

+   eth0 IPv4 HP LaserJet 400 color M451nw          _ipp._tcp            local
+   eth0 IPv4 MyTimeMachine                         _afpovertcp._tcp     local
+   eth0 IPv4 devbox SSH                            _ssh._tcp            local
=   eth0 IPv4 devbox SSH                            _ssh._tcp            local
   hostname = [devbox.local]
   address  = [192.168.1.42]
   port     = [22]
   txt      = []

Lines starting with:

  • + – service appeared.
  • - – service disappeared.
  • = – resolved service with full details.

Use cases:

  • On a test LAN, run avahi-browse -art on multiple hosts to confirm they see the same service set.
  • Watch for expected test services (e.g., _ipp._tcp for printers, _smb._tcp for SMB shares).

Browse a specific service type

To validate one application or daemon, browse just its service type. For example, to verify SSH and a custom test service:

avahi-browse -rt _ssh._tcp
avahi-browse -rt _mytest._tcp

If you know your app publishes _myapp._tcp via a D-Bus client or via /etc/avahi/services/*.service, this is the quickest check that it’s visible.


3. Resolving individual services with avahi-browse and avahi-resolve

If you already know a service name and type, you can resolve it directly instead of browsing everything.

Resolve a specific service instance

Workflow:

  1. List instances:

    avahi-browse -t _ipp._tcp
    
  2. Pick one service name, then resolve:

    avahi-browse -rt _ipp._tcp
    

The -r flag triggers the equivalent of avahi_service_resolver_new() under the hood, giving you hostname, IP, port, and TXT records in one shot.

Resolve hostnames and addresses directly

Avahi ships a pair of small tools for resolution:

  • avahi-resolve-host-name
  • avahi-resolve-address

These talk mDNS directly and don’t depend on nsswitch configuration.

Resolve a *.local host:

avahi-resolve-host-name devbox.local

Typical output:

devbox.local    192.168.1.42

Reverse lookup:

avahi-resolve-address 192.168.1.42

If these work but ping devbox.local fails, that’s a nsswitch/nss-mdns problem (next section), not an mDNS/Avahi problem.


4. Validating *.local hostname resolution via nss-mdns

For “normal” command line tools (ping, ssh, curl) to resolve hostname.local, you need:

  • The nss-mdns project installed.
  • mdns (or mdns4/mdns6) configured in /etc/nsswitch.conf under hosts.

Install nss-mdns

Example on Debian/Ubuntu:

sudo apt-get install avahi-daemon libnss-mdns

On Fedora/RHEL-like:

sudo dnf install avahi avahi-tools nss-mdns

Check your distro docs; the names are similar but not always identical.

Configure /etc/nsswitch.conf

Look for the hosts: line. A common working pattern:

hosts: files mdns4_minimal [NOTFOUND=return] dns mdns4

Or, more simply:

hosts: files mdns4 dns

Save the file, then test:

getent hosts devbox.local
ping -c1 devbox.local
ssh devbox.local

If getent works but avahi-resolve-host-name doesn’t, you’re looking at DNS instead of mDNS; check that you’re using the exact hostname.local advertised by Avahi (case-insensitive, but spelling matters).

If avahi-resolve-host-name works and getent does not, the issue is purely nsswitch configuration.


5. Publishing a simple test service via /etc/avahi/services

For LAN validation, I often publish a dummy TCP service with no application behind it. AVAHI supports static service definitions via XML in /etc/avahi/services, which is simpler than writing a custom publisher for a quick test.

Create a test service file

On one host, create:

sudo mkdir -p /etc/avahi/services
sudo nano /etc/avahi/services/test-http.service

Example content:

<?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>

Save and either restart or reload Avahi:

sudo systemctl reload avahi-daemon.service || sudo systemctl restart avahi-daemon.service

Verify publication from another host

On a different machine on the same test LAN:

avahi-browse -rt _http._tcp

You should see something like:

=   eth0 IPv4 devbox Test HTTP                     _http._tcp           local
   hostname = [devbox.local]
   address  = [192.168.1.50]
   port     = [8080]
   txt      = ["path=/"]

This end‑to‑end check confirms:

  • avahi-daemon is running and reading /etc/avahi/services.
  • Multicast routing/firewall between the two hosts is correct.
  • The resolver can turn the service into a reachable IP/port.

6. Using avahi-browse for domain and wide-area checks

In more complex setups (e.g., where you integrate with wide-area DNS-SD), you want to understand browsing domains. Avahi exposes those via a domain browser, equivalent to calling avahi_domain_browser_new() programmatically.

List browsing domains

avahi-browse -D

This prints browsing domains (often just local on simple test LANs). If you expect a custom domain (e.g., _services._dns-sd._udp.example.com) and don’t see it, your wide-area setup isn’t wired correctly yet.

For command line validation on a small test LAN, you’ll mostly stay in local, but it’s useful to know domains exist when debugging odd cross‑subnet or VPN setups.


7. Step‑by‑step checklist for a clean test LAN validation

If you just want a linear procedure, here’s the condensed flow:

  1. Check daemon state

    systemctl status avahi-daemon.service
    
  2. Confirm basic browsing

    On one host:

    avahi-browse -art
    
  3. Publish a simple service

    On another host, add /etc/avahi/services/test-http.service as shown above and reload Avahi.

  4. Verify service visibility

    On the first host:

    avahi-browse -rt _http._tcp
    
  5. Resolve the hostname directly

    Take the hostname from the output (e.g., devbox.local):

    avahi-resolve-host-name devbox.local
    
  6. Validate nsswitch‑based resolution

    Ensure nss-mdns is installed and hosts: in /etc/nsswitch.conf includes mdns4/mdns. Then:

    getent hosts devbox.local
    ping -c1 devbox.local
    

If all of that passes, Avahi-based discovery is working correctly from the command line on your test LAN. Anything beyond that tends to be application‑specific (how your service publishes and interprets TXT records, whether your app reacts to services appearing/disappearing, etc.), but the core mDNS/DNS-SD plumbing is validated.


Where to go next

Once you’re comfortable with the CLI tools, the next step is usually to:

  • Integrate programmatically using the D-Bus APIs (for dynamic registration and browsing, analogous to avahi_service_browser_new() and avahi_service_resolver_new()).
  • Use XML service definitions in /etc/avahi/services for static services you maintain as system components.
  • Keep an eye on Avahi’s releases and technical notes (e.g., changes in 0.8 related to D-Bus/avahi-core behavior) via the project’s docs/NEWS and GitHub repositories.

Get Started