AVAHI vs systemd-resolved: what are the security considerations and hardening options for each (exposure, interfaces, publishing)?
Networking System Software

AVAHI vs systemd-resolved: what are the security considerations and hardening options for each (exposure, interfaces, publishing)?

13 min read

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

RankOptionBest ForPrimary StrengthWatch Out For
1AVAHI (with nss-mdns)Linux-first Bonjour/Zeroconf service discoveryMature mDNS/DNS-SD daemon with D-Bus API and static XML publishingCan expose services broadly on the LAN if you publish carelessly
2systemd-resolved (with mDNS enabled)Central DNS resolver on systemd-based distrosUnified stub resolver, DNSSEC, DNS over TLS, plus optional mDNSmDNS behavior is more opaque; fewer per-service publishing controls
3AVAHI + systemd-resolved (coexistence)Mixed environments needing fine-grained discovery and modern DNSLets AVAHI own service discovery while resolved handles DNSMisconfiguration 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
  • Participates only on selected interfaces (usually all “LAN” interfaces except loopback; can be restricted).
  • Advertises:
    • The host’s .local hostname (if configured)
    • Any static services defined under /etc/avahi/services/*.service
    • Any dynamically registered services via the D-Bus API

This means:

  • Anyone on the same L2 segment can:
    • See your host’s published services.
    • Query for _ipp._tcp printers, _afpovertcp._tcp file 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/services XML 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 with nsswitch.conf so 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 mdns or mdns4 early in hosts: in /etc/nsswitch.conf, a malicious peer can spoof .local names 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.

Hardening AVAHI: Concrete Steps

  • Control interfaces:
    • Use allow-interfaces= or deny-interfaces= in avahi-daemon.conf to limit which NICs participate (e.g., LAN only, not VPN or untrusted Wi-Fi).
  • 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.
  • Minimize static services:
    • Keep /etc/avahi/services/ minimal and reviewable.
    • Avoid embedding sensitive metadata in TXT records.
  • Harden nss-mdns behavior:
    • Place mdns4 after files and possibly after dns in /etc/nsswitch.conf if you want to prioritize traditional DNS for non-.local names.
    • Ensure only .local is routed to mDNS, not arbitrary domains.
  • 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 the resolve NSS module (hosts: files resolve dns etc.).
    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.
  • D-Bus and systemd’s resolvectl
    Tools like resolvectl talk to systemd-resolved over 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-resolved can 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._proto records with TXT fields.
    • Policy knobs are about whether to use mDNS, not what to publish.
  • 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 misconfigure systemd-resolved to 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.
  • 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.

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 .local names.

Interfaces & Attack Surface

  • AVAHI D-Bus + /etc/avahi/services for service publishing.
  • nss-mdns for .local hostname 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.conf reflects that decision.
    • Confirm that systemd-resolved’s mDNS support is off or appropriately scoped when AVAHI is in charge.
  • 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 .local and mDNS. systemd-resolved owns everything else.”
  • Configure nsswitch.conf accordingly:

    • Example:

      hosts: files mdns4_minimal [NOTFOUND=return] resolve dns
      

      or similar, depending on your distro, so .local hits 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 .local in ways that conflict with AVAHI (details depend on systemd version/distro defaults).
  • Apply AVAHI hardening:

    • Restrict interfaces in avahi-daemon.conf.
    • Tighten D-Bus policies for publishing.
    • Keep /etc/avahi/services/ minimal and reviewed.

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/services lean, 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.

Next Step

Get Started