#1127331 libnss-mdns: DNS tried before mDNS despite configuration for mdns4_minimal first

Package:
libnss-mdns
Source:
libnss-mdns
Description:
NSS module for Multicast DNS name resolution
Submitter:
황병주
Date:
2026-02-07 10:53:04 UTC
Severity:
normal
Tags:
#1127331#5
Date:
2026-02-07 01:54:21 UTC
From:
To:
mDNS name resolution via libnss-mdns is completely broken on Debian trixie
with glibc 2.41. The NSS module is loaded but never called, causing .local
hostnames to fall through to DNS instead of being resolved via mDNS.

** Background **

glibc 2.41 changed NSS module loading to resolve all possible NSS function
symbols at load time (not just the ones relevant to the requested database).
Since libnss-mdns only provides hosts-related functions, glibc fails to find
symbols like _nss_mdns4_minimal_getpwnam_r, _nss_mdns4_minimal_getgrent_r,
etc., and marks every missing symbol as "fatal". As a result, the module is
effectively treated as UNAVAIL, and the [NOTFOUND=return] directive in
nsswitch.conf is never triggered.

** Steps to reproduce **

1. Install libnss-mdns and avahi-daemon on Debian trixie (glibc 2.41).
2. Ensure /etc/nsswitch.conf contains:
   hosts: files mdns4_minimal [NOTFOUND=return] dns
3. Have another host advertising via mDNS on the local network.
4. Run: getent hosts <hostname>.local

** Expected result **

The .local hostname is resolved via mDNS (e.g., 192.168.0.25).

** Actual result **

The hostname is resolved via DNS, returning an incorrect address (in my
case,
an ISP DNS hijacking address 218.38.137.27 instead of 192.168.0.25).

** Diagnosis **

avahi-daemon and the avahi socket work correctly:

  $ avahi-resolve -4 -n pluto.local
  pluto.local     192.168.0.25

  $ echo "RESOLVE-HOSTNAME-IPV4 pluto.local" | nc -U
/run/avahi-daemon/socket
  + 2 0 pluto.local 192.168.0.25

But NSS-based resolution bypasses mDNS entirely:

  $ getent hosts pluto.local
  218.38.137.27   pluto.local

strace confirms the .so files are loaded but no avahi socket connection is
attempted — the process goes straight to DNS:

  $ strace -e trace=openat,connect getent hosts pluto.local
  (opens libnss_mdns4_minimal.so.2 successfully)
  (opens libnss_mdns6_minimal.so.2 successfully)
  (no AF_UNIX connect to /run/avahi-daemon/socket)
  (connects to DNS server on port 53)

LD_DEBUG reveals the root cause — glibc tries to resolve all NSS functions
and marks each missing one as fatal:

  $ LD_DEBUG=symbols getent hosts pluto.local 2>&1 | grep fatal | head -5
  symbol=_nss_mdns4_minimal_endaliasent; ... undefined symbol (fatal)
  symbol=_nss_mdns4_minimal_endetherent; ... undefined symbol (fatal)
  symbol=_nss_mdns4_minimal_endgrent; ... undefined symbol (fatal)
  symbol=_nss_mdns4_minimal_endhostent; ... undefined symbol (fatal)
  symbol=_nss_mdns4_minimal_endnetent; ... undefined symbol (fatal)

The library only exports hosts-related symbols, which is expected:

  $ nm -D /lib/x86_64-linux-gnu/libnss_mdns4_minimal.so.2 | grep ' T '
  _nss_mdns4_minimal_gethostbyaddr_r
  _nss_mdns4_minimal_gethostbyname2_r
  _nss_mdns4_minimal_gethostbyname3_r
  _nss_mdns4_minimal_gethostbyname4_r
  _nss_mdns4_minimal_gethostbyname_r

Note: The same libnss-mdns version works correctly on Ubuntu 24.04 which
ships glibc 2.39, confirming that this is a glibc 2.41 compatibility issue.

** Possible fix **

Either libnss-mdns needs to be rebuilt/patched to be compatible with glibc
2.41's new module loading behavior, or this may need to be addressed on the
glibc side as a backward compatibility regression. I'm filing against
libnss-mdns first, but please reassign to glibc if appropriate.

#1127331#10
Date:
2026-02-07 10:50:58 UTC
From:
To:
Control: retitle -1 libnss-mdns: DNS tried before mDNS despite configuration for mdns4_minimal first
Control: tags -1 + moreinfo

I was unable to reproduce this on a trixie machine.

Steps:

1. Install libnss-mdns and avahi-daemon on Debian trixie (glibc 2.41)
. Have another host ($OTHER) with mDNS, on the same network
3. Edit /etc/nsswitch.conf to contain:
    hosts: files dns
4. getent hosts $OTHER.local; echo $? -> no output, exit status 2
5. Edit /etc/nsswitch.conf to contain:
    hosts: files mdns4_minimal [NOTFOUND=return] dns
6. getent hosts $OTHER.local; echo $? -> resolved, exit status 0

But, something that I *do* observe in this configuration is that a
strace'd getent process does a connect() to my DNS server (in my case
it's systemd-resolved) *before* connecting to the Avahi socket:

$ strace -e openat,connect getent hosts remnant.local
...
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libnss_mdns4_minimal.so.2", O_RDONLY|O_CLOEXEC) = 3
connect(3, {sa_family=AF_INET, sin_port=htons(53), sin_addr=inet_addr("127.0.0.53")}, 16) = 0
connect(3, {sa_family=AF_INET, sin_port=htons(53), sin_addr=inet_addr("127.0.0.53")}, 16) = 0
connect(3, {sa_family=AF_INET, sin_port=htons(53), sin_addr=inet_addr("127.0.0.53")}, 16) = 0
openat(AT_FDCWD, "/etc/hosts", O_RDONLY|O_CLOEXEC) = 3
connect(3, {sa_family=AF_INET, sin_port=htons(53), sin_addr=inet_addr("127.0.0.53")}, 16) = 0
connect(3, {sa_family=AF_FILE, path="/run/avahi-daemon/socket"}, 110) = 0
REDACTED  remnant.local

I think that could result in the same symptom that you reported, where an
ISP DNS server that (inappropriately) intercepts resolution of .local
names results in the ISP's DNS resolution being used before
mdns4_minimal gets an opportunity to step in.

I wonder whether this means that glibc is doing multiple lower-level NSS
lookups for a single higher-level getent operation, only some of which
are of a form implemented by mdns4_minimal, and as a result DNS
effectively takes precedence over mDNS even though the configuration
says the opposite?
really mean it. I think this should be read as "fatal to this particular
attempt to resolve the symbol", and not as "fatal to any attempt to look
up NSS".

     smcv