
AVAHI vs systemd-resolved: what are the security considerations and hardening options for each (exposure, interfaces, publishing)?
Administrators often treat AVAHI and systemd-resolved as interchangeable “mDNS things,” but from a security and hardening perspective they solve different problems, expose different surfaces, and need different mitigations. If you’re trying to reason about exposure, interfaces, and publishing behavior, you have to evaluate them separately and then decide how they should coexist on your LAN.
Quick Answer: The best overall choice for Bonjour/Zeroconf-style service discovery with explicit control over what you publish is AVAHI. If your priority is centralizing name resolution, DNSSEC, and split-horizon DNS on modern Linux then systemd-resolved is often a stronger fit. For *tightly locked-down hosts that still need .local resolution but minimal service broadcast, consider AVAHI + nss-mdns with restricted publishing.
At-a-Glance Comparison
| Rank | Option | Best For | Primary Strength | Watch Out For |
|---|---|---|---|---|
| 1 | AVAHI (with nss-mdns) | Linux-first Bonjour/Zeroconf service discovery | Mature mDNS/DNS-SD daemon with D-Bus API and static XML publishing | Can expose services broadly on the LAN if you publish carelessly |
| 2 | systemd-resolved (with mDNS enabled) | Central DNS resolver on systemd-based distros | Unified stub resolver, DNSSEC, DNS over TLS, plus optional mDNS | mDNS behavior is more opaque; fewer per-service publishing controls |
| 3 | AVAHI + systemd-resolved (coexistence) | Mixed environments needing fine-grained discovery and modern DNS | Lets AVAHI own service discovery while resolved handles DNS | Misconfiguration can cause resolution conflicts or unexpected *.local leakage |
Comparison Criteria
We evaluated AVAHI and systemd-resolved on three security-focused axes:
-
Exposure Model:
What is visible on the LAN, on which interfaces, and using which multicast addresses/ports. This includes what a passive attacker can see and what a malicious peer can probe. -
Interfaces & Attack Surface:
Local APIs (D-Bus, NSS, CLI tools), network ports, privilege separation, and how much logic runs in long-lived daemons versus one-shot helpers. -
Publishing & Policy Controls:
How you control what gets advertised or resolved (service types, hostnames, domains), how easy it is to misconfigure, and what hardening knobs exist (ACLs, interface filters, domain restrictions).
The sections below walk each option through this lens, then close with a decision framework.
Detailed Breakdown
1. AVAHI (Best overall for controlled mDNS/DNS-SD service discovery)
AVAHI ranks as the top choice because it cleanly separates service discovery (mDNS/DNS-SD) from general DNS resolution, exposes a clear D-Bus API, and lets you explicitly decide what to publish via /etc/avahi/services or your own D-Bus client.
Exposure Model
On a typical Linux host, avahi-daemon:
- Listens on:
- UDP 5353 on IPv4 multicast
224.0.0.251 - UDP 5353 on IPv6 multicast
ff02::fb
- UDP 5353 on IPv4 multicast
- Participates only on selected interfaces (usually all “LAN” interfaces except loopback; can be restricted).
- Advertises:
- The host’s
.localhostname (if configured) - Any static services defined under
/etc/avahi/services/*.service - Any dynamically registered services via the D-Bus API
- The host’s
This means:
- Anyone on the same L2 segment can:
- See your host’s published services.
- Query for
_ipp._tcpprinters,_afpovertcp._tcpfile shares, etc.
- AVAHI does not cross routers by default. Exposure is limited to the local link unless you explicitly set up proxying.
From a security perspective, AVAHI is “loud” only to the extent you choose to publish. A default desktop often publishes minimal information; a poorly configured file server may expose everything.
Interfaces & Attack Surface
Key interfaces:
-
D-Bus API (primary integration surface)
AVAHI’s documentation explicitly recommends using the D-Bus API for browsing and registering services:“an extensive D-Bus interface for browsing and registering mDNS/DNS-SD services using avahi-daemon. We recommend using this API for software written in any language other than C (e.g. Python).”
Security implications:
- Access is mediated by the D-Bus bus (system bus), so you can restrict which processes/users may publish or browse via D-Bus policy.
- If you allow arbitrary untrusted code to talk to the D-Bus API, it can publish misleading services or spam the LAN.
-
/etc/avahi/servicesXML definitions
Static service files are root-managed. This is a security win:- Normal users cannot trivially add persistent advertised services.
- Reviewable configs live under
/etc, which matches standard distro hardening patterns.
-
*nss-mdns (for .local resolution)
Not strictly part of AVAHI but typically paired. nss-mdns integrates withnsswitch.confso standard tools (ping hostname.local,ssh host.local) resolve via mDNS.
Security implications:- Resolution is local-link only; no queries leave the LAN.
- If you put
mdnsormdns4early inhosts:in/etc/nsswitch.conf, a malicious peer can spoof.localnames by answering faster than the expected host.
-
Privilege model and sandboxing
AVAHI is usually packaged as a system service:- Runs as a dedicated, non-root user in most distributions.
- Uses capabilities and sandboxing (systemd unit options) depending on distro.
- Limited direct file access (mostly
/etc/avahi/,/var/run/avahi-daemon/, etc.).
What it does well
-
Fine-grained publishing control:
You can:-
Restrict published services to a known minimal set via
/etc/avahi/services. -
Use D-Bus policies so only privileged services can publish dynamically.
-
Avoid running multiple mDNS stacks. AVAHI’s docs explicitly discourage embedding another mDNS implementation in normal desktop apps:
“We dissuade from using this API in normal desktop applications since it is not a good idea to run multiple mDNS stacks simultaneously on the same host.”
That guidance is a security and correctness win: one stack means one policy surface.
-
-
Clear interoperability boundary:
AVAHI is Bonjour/Zeroconf-compatible. If you harden it sensibly:- macOS/iOS clients still see your printers, shares, etc.
- You don’t need a custom discovery protocol or open extra ports.
Tradeoffs & Limitations
-
LAN peers can see your advertised metadata:
Anything you publish is visible to anyone plugged into the same broadcast domain. If you publish:- Server names that leak internal roles (“backup-db-01.local”).
- TXT records with sensitive hints (internal IPs, environment tags).
…you’re giving a passive attacker an inventory.
-
Trust model is “everyone on the LAN is potentially hostile”:
mDNS has no built-in auth. Attackers can:- Answer queries faster than legitimate hosts.
- Publish fake printers or services to phish credentials or traffic.
AVAHI can’t cryptographically defend against that; your mitigation is network segmentation and limiting what you rely on mDNS for.
-
Coexistence complexity:
If systemd-resolved also tries to handle.local(depending on distro config), you can end up with resolution conflicts. You need a clear division:- AVAHI + nss-mdns handles
.local. - systemd-resolved handles everything else.
- AVAHI + nss-mdns handles
Hardening AVAHI: Concrete Steps
- Control interfaces:
- Use
allow-interfaces=ordeny-interfaces=inavahi-daemon.confto limit which NICs participate (e.g., LAN only, not VPN or untrusted Wi-Fi).
- Use
- Restrict who can publish via D-Bus:
- Tighten system D-Bus policies so only trusted services/users can call
org.freedesktop.Avahi.Server.AddService()etc.
- Tighten system D-Bus policies so only trusted services/users can call
- Minimize static services:
- Keep
/etc/avahi/services/minimal and reviewable. - Avoid embedding sensitive metadata in TXT records.
- Keep
- Harden nss-mdns behavior:
- Place
mdns4afterfilesand possibly afterdnsin/etc/nsswitch.confif you want to prioritize traditional DNS for non-.local names. - Ensure only
.localis routed to mDNS, not arbitrary domains.
- Place
- Network-level controls:
- On shared/untrusted segments, consider blocking or rate-limiting multicast where feasible, or segmenting critical hosts onto a more trusted VLAN.
Decision Trigger: Choose AVAHI as your primary tool if you want explicit, reviewable LAN service discovery and you prioritize clear control over what gets published and which processes can publish. Treat mDNS as a “local convenience bus” and lock it down using D-Bus policy, interface filters, and minimal service definitions.
2. systemd-resolved (Best for centralizing DNS with optional mDNS)
systemd-resolved is the strongest fit here because it centralizes DNS resolution, DNSSEC, and DNS-over-TLS for the host, with mDNS as an optional feature rather than the core mission.
Exposure Model
By default, systemd-resolved:
- Exposes a local stub resolver on
127.0.0.53:53. - Speaks to configured upstream DNS servers (per-link via systemd-networkd or NetworkManager).
- May support:
- DNS-over-TLS to upstreams.
- DNSSEC validation.
- Multicast DNS (
.local) resolution if enabled.
From a network exposure perspective:
- It does not typically advertise services. It primarily resolves names.
- If mDNS is enabled, it will:
- Query on the same multicast addresses/ports as AVAHI.
- Possibly answer for local hostnames.
The risk surface is mostly outbound DNS traffic plus local API surfaces, not service broadcasting.
Interfaces & Attack Surface
Key interfaces:
-
glibc NSS via
nsswitch.conf
systemd-resolved normally integrates via theresolveNSS module (hosts: files resolve dnsetc.).
Security implications:- All consumers of getaddrinfo()/gethostbyname() are effectively trusting
systemd-resolved’s logic. - Misconfigurations (e.g., sending certain domains to untrusted upstreams) can leak information.
- All consumers of getaddrinfo()/gethostbyname() are effectively trusting
-
D-Bus and systemd’s
resolvectl
Tools likeresolvectltalk tosystemd-resolvedover D-Bus.
Mitigations:- Policy around who can change DNS settings is controlled at the systemd and D-Bus level.
- Normal users can typically just query, not reconfigure upstream servers.
-
Upstream DNS / DoT / DNSSEC
systemd-resolvedcan be configured to:- Use secure channels (DoT).
- Validate DNSSEC, preventing some spoofing attacks.
- Apply per-link DNS and routing domains.
This is where systemd-resolved shines: you can constrain which domains go to which servers, and validate integrity.
What it does well
-
Centralized, policy-driven DNS:
All applications on the host use a single resolver. Hardening benefits:- You can enforce DNSSEC verification for all apps.
- You can prevent apps from bypassing system config (if you avoid hard-coded DNS in app configs).
- Split-horizon DNS policies are centralized.
-
Limited mDNS commitments:
If you don’t enable mDNS, systemd-resolved:- Doesn’t send multicast discovery traffic.
- Doesn’t publish services.
- Keeps your host quieter on the LAN.
If you do enable mDNS, it’s usually only for hostname resolution, not for service discovery.
Tradeoffs & Limitations
-
Less granular mDNS control:
Compared to AVAHI, systemd-resolved is not a service publishing framework:- You can’t define rich
_service._protorecords with TXT fields. - Policy knobs are about whether to use mDNS, not what to publish.
- You can’t define rich
-
Visibility and debugging:
systemd-resolved’s behavior (DNS routing, cache) can be harder for some teams to reason about, especially in mixed environments where:- VPNs override DNS.
- Some domains use DoT, others don’t.
- mDNS conflicts with other stacks (AVAHI, libdns_sd).
Complexity itself is a security concern when misconfigurations can leak queries to the wrong DNS.
-
Single point of failure for resolution:
If you misconfiguresystemd-resolvedto trust a malicious or misrouted upstream, all apps that use the system resolver inherit that risk.
Hardening systemd-resolved: Concrete Steps
- Control mDNS usage:
- If AVAHI owns mDNS, disable mDNS in systemd-resolved, or vice versa. Avoid two stacks racing for
.local.
- If AVAHI owns mDNS, disable mDNS in systemd-resolved, or vice versa. Avoid two stacks racing for
- Set strict DNSSEC and DoT policies:
- Enable DNSSEC validation and treat failures conservatively for sensitive hosts.
- Use DNS-over-TLS to trusted resolvers where appropriate.
- Per-link DNS scoping:
- Use per-interface DNS servers and routing domains so only specific traffic goes to specific DNS services (e.g., corporate VPN).
- Limit configuration access:
- Restrict who can call
resolvectl dns,resolvectl domain, etc., via sudo policies and D-Bus privileges.
- Restrict who can call
Decision Trigger: Choose systemd-resolved as your primary resolver if you want tight control over how the host queries upstream DNS and validates responses, and you prioritize DNSSEC/DoT and split-horizon behavior over rich Bonjour/Zeroconf service discovery.
3. AVAHI + systemd-resolved (Best for mixed environments with fine-grained control)
AVAHI + systemd-resolved stands out for complex fleets because it lets you specialize:
- AVAHI handles mDNS/DNS-SD service discovery and optional mDNS hostname resolution (via nss-mdns).
- systemd-resolved handles unicast DNS, DNSSEC, and upstream policy.
This is what many Linux distributions aim for in practice, but it needs deliberate hardening to avoid conflicts and surprises.
Exposure Model
In this combined setup:
-
AVAHI:
- Listens on UDP 5353 multicast.
- Publishes services you explicitly define.
- Browses LAN services via D-Bus.
-
systemd-resolved:
- Exposes a local stub resolver.
- Talks to upstream DNS.
- May or may not handle mDNS.
Properly configured:
- Service exposure on the LAN is only through AVAHI.
- DNS queries to the internet or upstreams are centrally handled by systemd-resolved.
- You avoid double-publishing or double-answering
.localnames.
Interfaces & Attack Surface
- AVAHI D-Bus +
/etc/avahi/servicesfor service publishing. - nss-mdns for
.localhostname resolution (if you want AVAHI to answer those). - systemd-resolved for all non-.local lookups, DNSSEC, and DoT.
Attack surface is clear and separated, which is what you want in a hardened system.
What it does well
-
Best-of-both-worlds specialization:
- AVAHI: Bonjour/Zeroconf discovery with controlled publishing.
- systemd-resolved: hardened DNS policy and validation.
-
Predictable behavior for admins:
ping host.local→ mDNS via nss-mdns + AVAHI.ping host.example.com→ unicast DNS via systemd-resolved.
-
Scoped trust and exposure:
- LAN neighbor trust is limited to mDNS and services you intentionally publish.
- External DNS trust is managed by systemd-resolved policy, not by each app.
Tradeoffs & Limitations
-
Configuration complexity:
You must:- Explicitly decide which component owns
.local. - Ensure
nsswitch.confreflects that decision. - Confirm that systemd-resolved’s mDNS support is off or appropriately scoped when AVAHI is in charge.
- Explicitly decide which component owns
-
Operational coordination:
When updating AVAHI or systemd, changes to D-Bus policy, unit sandboxing, or resolver behavior can interact in surprising ways. You want:- Good release hygiene (read docs/NEWS, release pages).
- System-level tests that cover hostname resolution and service discovery.
Hardening the combined setup: Concrete Steps
-
Define the boundary:
- Decide: “AVAHI + nss-mdns own
.localand mDNS. systemd-resolved owns everything else.”
- Decide: “AVAHI + nss-mdns own
-
Configure
nsswitch.confaccordingly:-
Example:
hosts: files mdns4_minimal [NOTFOUND=return] resolve dnsor similar, depending on your distro, so
.localhits mDNS via nss-mdns first, and other names go to systemd-resolved.
-
-
Turn off competing mDNS in systemd-resolved:
- Ensure systemd-resolved is not also trying to publish or resolve
.localin ways that conflict with AVAHI (details depend on systemd version/distro defaults).
- Ensure systemd-resolved is not also trying to publish or resolve
-
Apply AVAHI hardening:
- Restrict interfaces in
avahi-daemon.conf. - Tighten D-Bus policies for publishing.
- Keep
/etc/avahi/services/minimal and reviewed.
- Restrict interfaces in
Decision Trigger: Choose AVAHI + systemd-resolved if you want Bonjour-compatible discovery on the LAN and at the same time enforce modern DNS security features for everything outside the local link, and you’re willing to maintain a clear separation of responsibilities.
Final Verdict
From a security and hardening standpoint:
-
Use AVAHI when the core requirement is Linux-first Bonjour/Zeroconf service discovery and you care about explicit control over what gets published. Harden it by limiting interfaces, tightening D-Bus access, keeping
/etc/avahi/serviceslean, and treating the LAN as hostile. -
Use systemd-resolved as the host’s default DNS resolver when you need DNSSEC, DoT, and centralized upstream policy. Keep its mDNS role either disabled or clearly scoped; its primary security value is in DNS, not service discovery.
-
Combine AVAHI + systemd-resolved when you need both: rich service discovery on the LAN and hardened, policy-driven DNS to upstreams. The critical hardening move is to avoid running multiple mDNS stacks in parallel and to decide unambiguously who owns
.local.
In all cases, your security posture depends less on the choice of daemon and more on:
- How loudly you publish on the LAN.
- How strictly you control who can publish.
- How carefully you route and validate DNS to upstreams.
- How you segment your networks and treat the local link from a trust perspective.
If you treat AVAHI as the mDNS/DNS-SD plumbing and systemd-resolved as the DNS policy engine, you can design a configuration that is both interoperable with Bonjour and defensible in real-world LANs.