[Bug nscd/33539] New: when nscd cannot resolve, libc falls back to no-nscd and both continue in parallel

vcaron at bearstech dot com sourceware-bugzilla@sourceware.org
Mon Oct 13 15:48:04 GMT 2025


https://sourceware.org/bugzilla/show_bug.cgi?id=33539

            Bug ID: 33539
           Summary: when nscd cannot resolve, libc falls back to no-nscd
                    and both continue in parallel
           Product: glibc
           Version: 2.36
            Status: UNCONFIRMED
          Severity: normal
          Priority: P2
         Component: nscd
          Assignee: unassigned at sourceware dot org
          Reporter: vcaron at bearstech dot com
                CC: drepper.fsp at gmail dot com
  Target Milestone: ---

Dear maintainer,

I observed a behaviour which seems to be at least undocumented, and maybe not
whished for.

This happends with a program using a regular gethostbyname() on a host with
nscd running, and none of the 'nameserver' in /etc/resolv.conf will respond :
* +0s program connects to nscd
* ... nscd does its nameserver alternation + retry stuff ...
* +5s program disconnects from nscd
* ... program does its nameserver alternation + retry stuff ...
* ... nscd continues its nameserver alternation + retry stuff ...

That +5s seems to be hardwired from what I could infer with my tests. I see 2
problems :

* there's a slight and un-necessary DNS query amplification while both the
program and nscd continue in parallel
* the program does not experience the expected timeout (which is
count(nameserver)*timeout*attempts, and double this if you have at least a
'search' entry - see https://sourceware.org/bugzilla/show_bug.cgi?id=22514 for
this peculiar behaviour)

To reproduce, I set up this /etc/resolv.conf :

    search search.local
    nameserver 10.1.2.1
    nameserver 10.1.2.2
    options timeout:1 attempts:2

Then I "fail" the DNS access (blocking output creates an immediate "forbidden"
fail, blocking input creates the timeout) :

    iptables -A INPUT -s 10.1.2.1 -j DROP
    iptables -A INPUT -s 10.1.2.2 -j DROP

I then launch a program with strace to see its behaviour (trace edited) :

# strace -tt -e trace=connect,close,sendto,recvmsg,recvfrom perl -e
'gethostbyname("test.net")'
...
17:25:33.450901 connect(3, {sa_family=AF_UNIX,
sun_path="/var/run/nscd/socket"}, 110) = 0
17:25:33.451023 sendto(3, "\2\0\0\0\4\0\0\0\t\0\0\0test.net\0", 21,
MSG_NOSIGNAL, NULL, 0) = 21
17:25:38.457562 close(3)                = 0
17:25:38.457745 connect(3, {sa_family=AF_INET, sin_port=htons(53),
sin_addr=inet_addr("10.1.2.1")}, 16) = 0
17:25:38.457905 sendto(3, "\231\0\1\0\0\1\0\0\0\0\0\0\4test\3net\0\0\1\0\1",
26, MSG_NOSIGNAL, NULL, 0) = 26
17:25:39.459434 connect(4, {sa_family=AF_INET, sin_port=htons(53),
sin_addr=inet_addr("10.1.2.2")}, 16) = 0
17:25:39.459791 sendto(4, "\231\0\1\0\0\1\0\0\0\0\0\0\4test\3net\0\0\1\0\1",
26, MSG_NOSIGNAL, NULL, 0) = 26
17:25:40.461530 sendto(3, "\231\0\1\0\0\1\0\0\0\0\0\0\4test\3net\0\0\1\0\1",
26, MSG_NOSIGNAL, NULL, 0) = 26
17:25:41.463056 sendto(4, "\231\0\1\0\0\1\0\0\0\0\0\0\4test\3net\0\0\1\0\1",
26, MSG_NOSIGNAL, NULL, 0) = 26
17:25:42.464393 close(3)                = 0
17:25:42.464534 close(4)                = 0
17:25:42.464834 connect(3, {sa_family=AF_INET, sin_port=htons(53),
sin_addr=inet_addr("10.1.2.1")}, 16) = 0
17:25:42.464951 sendto(3,
"\264[\1\0\0\1\0\0\0\0\0\0\4test\3net\6search\5loc"..., 39, MSG_NOSIGNAL, NULL,
0) = 39
17:25:43.466470 connect(4, {sa_family=AF_INET, sin_port=htons(53),
sin_addr=inet_addr("10.1.2.2")}, 16) = 0
17:25:43.466606 sendto(4,
"\264[\1\0\0\1\0\0\0\0\0\0\4test\3net\6search\5loc"..., 39, MSG_NOSIGNAL, NULL,
0) = 39
17:25:44.467899 sendto(3,
"\264[\1\0\0\1\0\0\0\0\0\0\4test\3net\6search\5loc"..., 39, MSG_NOSIGNAL, NULL,
0) = 39
17:25:45.469344 sendto(4,
"\264[\1\0\0\1\0\0\0\0\0\0\4test\3net\6search\5loc"..., 39, MSG_NOSIGNAL, NULL,
0) = 39
17:25:46.470758 close(3)                = 0
17:25:46.470860 close(4)                = 0
17:25:46.473071 +++ exited with 0 +++

This scenario should generate a 2 attempts * 2 nameservers * (1 + 1 search) *
1s = 8s timeout from the p.o.v of the program, but it sees 13s.

And here is the trace of nscd during the same test :

# strace -tt -e trace=connect,sendto,recvmsg,recvfrom -f -p $(pidof nscd)
...
[pid 329029] 17:25:33.451532 connect(11, {sa_family=AF_INET,
sin_port=htons(53), sin_addr=inet_addr("10.1.2.1")}, 16) = 0
[pid 329029] 17:25:33.451701 sendto(11,
"91\1\0\0\1\0\0\0\0\0\0\4test\3net\0\0\1\0\1", 26, MSG_NOSIGNAL, NULL, 0) = 26
[pid 329029] 17:25:34.453057 connect(12, {sa_family=AF_INET,
sin_port=htons(53), sin_addr=inet_addr("10.1.2.2")}, 16) = 0
[pid 329029] 17:25:34.453368 sendto(12,
"91\1\0\0\1\0\0\0\0\0\0\4test\3net\0\0\1\0\1", 26, MSG_NOSIGNAL, NULL, 0) = 26
[pid 329029] 17:25:35.454761 sendto(11,
"91\1\0\0\1\0\0\0\0\0\0\4test\3net\0\0\1\0\1", 26, MSG_NOSIGNAL, NULL, 0) = 26
[pid 329029] 17:25:36.456366 sendto(12,
"91\1\0\0\1\0\0\0\0\0\0\4test\3net\0\0\1\0\1", 26, MSG_NOSIGNAL, NULL, 0) = 26
[pid 329029] 17:25:37.458303 connect(11, {sa_family=AF_INET,
sin_port=htons(53), sin_addr=inet_addr("10.1.2.1")}, 16) = 0
[pid 329029] 17:25:37.458452 sendto(11,
"M:\1\0\0\1\0\0\0\0\0\0\4test\3net\6search\5loc"..., 39, MSG_NOSIGNAL, NULL, 0)
= 39
[pid 329029] 17:25:38.458781 connect(12, {sa_family=AF_INET,
sin_port=htons(53), sin_addr=inet_addr("10.1.2.2")}, 16) = 0
[pid 329029] 17:25:38.459037 sendto(12,
"M:\1\0\0\1\0\0\0\0\0\0\4test\3net\6search\5loc"..., 39, MSG_NOSIGNAL, NULL, 0)
= 39
[pid 329029] 17:25:39.460233 sendto(11,
"M:\1\0\0\1\0\0\0\0\0\0\4test\3net\6search\5loc"..., 39, MSG_NOSIGNAL, NULL, 0)
= 39
[pid 329029] 17:25:40.461559 sendto(12,
"M:\1\0\0\1\0\0\0\0\0\0\4test\3net\6search\5loc"..., 39, MSG_NOSIGNAL, NULL, 0)
= 39
[pid 329029] 17:25:41.463102 sendto(10,
"\2\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\377\377\377\377\377\377\377\0\0\0\0\1\0\0\0",
32, MSG_NOSIGNAL, NULL, 0) = -1 EPIPE (Broken pipe)
[pid 329028] 17:25:57.310741 sendto(10,
"\2\0\0\0\377\377\377\377\0\0\0\0\0\0\0\0\377\377\377\377\377\377\377\377\0\0\0\0\0\0\0\0"...,
36, MSG_NOSIGNAL, NULL, 0) = 36
[pid 329030] 17:25:57.606371 sendto(10,
"\2\0\0\0\377\377\377\377\0\0\0\0\0\0\0\0\377\377\377\377\0\0\0\0", 24,
MSG_NOSIGNAL, NULL, 0) = 24

I understand the fallback mechanism (nscd might be broken for some reason), but
shouldn't nscd give up as soon as the client closes its socket (at 17:25:38.457
in the example) ? If it continnues, it has no connected socket to send its
answer back (thus the EPIPE).

And as an admin, I'd rather have some way of making sure DNS solving will have
a predictable timeout. That +5s in this condition surprised me. It might
minimally be fixed by mentioning this fallback at +5s in resolv.conf's man page
(where everything about timeout and errors is explained).

Would it be possible for instance for the stub resolver to wait for nscd to
fail all of its attempts, get an explicit return from nscd for this condition,
and in this case not falling back to direct solving ? The idea is that if nscd
failed to solve and succeeded to report this condition to its client, there's
no need to retry solving without nscd.

-- 
You are receiving this mail because:
You are on the CC list for the bug.


More information about the Glibc-bugs mailing list