Bug 12734 - resolver failures without even sending a query.
Summary: resolver failures without even sending a query.
Status: RESOLVED FIXED
Alias: None
Product: glibc
Classification: Unclassified
Component: libc (show other bugs)
Version: 2.13
: P2 critical
Target Milestone: ---
Assignee: Ulrich Drepper
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2011-05-05 13:31 UTC by Matthias Andree
Modified: 2014-06-13 14:43 UTC (History)
1 user (show)

See Also:
Host:
Target:
Build:
Last reconfirmed:
fweimer: security-


Attachments
code to demonstrate the bug (456 bytes, text/plain)
2011-05-05 13:31 UTC, Matthias Andree
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Matthias Andree 2011-05-05 13:31:15 UTC
Created attachment 5707 [details]
code to demonstrate the bug

(I've observed this on eglibc 2.13 and glibc 2.11.3 and confirmed it's still present in Git.)

Problem: res_search() can return -1 with h_errno == HOST_NOT_FOUND without ever having attempted a nameserver query even when it should have sent one.

In particular, this affects hostname resolution of "localhost" (without dots) if RES_DEFNAMES isn't set.  (Use case: a security-sensitive application strips this flag to avoid the domain search and to avoid getting bogus localhost.example.org results that might not point to 127.0.0.1/::1.)

Pseudo code, without error checking:

res_init();
_res.options &= ~RES_DEFNAMES;
int result = res_search("localhost", C_IN, T_A, buf, sizeof buffer);

This is an important portability issue from BSD or Solaris to Linux and affects, for instance, Postfix 2.8.X.

Compare the glibc source code lines 323 ff. <http://sourceware.org/git/?p=glibc.git;a=blob;f=resolv/res_query.c;h=5ff352e2fc6056bad92238df1fb0c826f48a2f51;hb=HEAD#l323> against FreeBSD, lines 371 ff. in <http://www.freebsd.org/cgi/cvsweb.cgi/src/lib/libc/resolv/res_query.c?annotate=1.6;only_with_tag=MAIN>.

I've attached a test program, show-resolv.c, to demonstrate the problem.

To compile: gcc -ggdb3 -O -std=gnu99 -pedantic -Wall -o show-resolv show-resolv.c -lresolv

To run: strace -e recv,send,recvfrom,sendto ./show-resolv

You will see that no DNS packets are sent to the nameserver configured in /etc/resolv.conf.

Actual output (no send/recv stuff!):

$ strace -e recv,send,recvfrom,sendto ./show-resolv 
default _res.options = 802C1
stripped _res.options = 80241
res search result: -1, h_errno: 1 (Unknown host)

Expected output:

$ strace -e recv,send,recvfrom,sendto ./show-resolv
default _res.options = 802C1
stripped _res.options = 80241
sendto(3, "\34\264\1\0\0\1\0\0\0\0\0\0\tlocalhost\0\0\1\0\1", 27, MSG_NOSIGNAL, NULL, 0) = 27
recvfrom(3, "\34\264\205\200\0\1\0\1\0\0\0\0\tlocalhost\0\0\1\0\1\300\f\0\1\0"..., 512, 0, {sa_family=AF_INET, sin_port=htons(53), sin_addr=inet_addr("192.168.0.4")}, [16]) = 43
res search result: 43

Of course the recvfrom details may differ with /etc/resolv.conf configuration.
And instead of 43, any positive number that makes it plausible we've received a successful reply to a DNS query for localhost IN A is valid, should there be gratuitious other records returned from the name server.

Please fix the resolver so that it actually sends a query for bare hostnames (without any dots, inner or trailing), localhost is a valid TLD.
Comment 1 Petr Baudis 2011-05-05 16:02:24 UTC
I'm looking at

 479         /*
 480          * If the name has any dots at all, and no earlier 'as-is' query
 481          * for the name, and "." is not on the search list, then try an as-is
 482          * query now.
 483          */
 484         if (dots && !(tried_as_is || root_on_list)) {

I wonder why the dots check is there?

(However, I also wonder, if you want to ensure no search, wouldn't it be much more natural to use a FQDN rather than a one-off disabling of RES_DEFNAMES?)
Comment 2 Matthias Andree 2011-05-05 16:35:47 UTC
I haven't checked where the source or the dots check originated.

Using a "fully-qualified domain name" would sidestep the bug but let's not introduce workarounds if we can fix the bug and I contend that localhost by itself arguably already is a FQDN.

I have not found Internet standards prohibiting single-level domain names (unlikely though they may be), but I have found RFC 1912 and RFC 2606 that sanction localhost.
Comment 3 Petr Baudis 2011-05-05 16:56:00 UTC
FQDN has a clear definition - it ends with a dot. Otherwise, it may be by default subject to various relative searches.

(Not disputing that there is a bug, I just wanted to clarify this.)
Comment 4 Matthias Andree 2011-05-05 18:25:18 UTC
Let's not go hair splitting about FQDN or not: suppressing the relative searches along the "search" list from /etc/resolv.conf is what this is all about. And if it were working, the difference between "localhost" and "localhost." were entirely theoretical, because either way we'd look up "localhost" in the root (".") zone. :-)
Comment 5 Ulrich Drepper 2011-05-07 17:06:31 UTC
Pointing to any *BSD is irrelevant.  Code like that is in BIND, too, though and that I backported as far as necessary.
Comment 6 Matthias Andree 2011-05-07 22:03:51 UTC
(In reply to comment #5)
> Pointing to any *BSD is irrelevant.  Code like that is in BIND, too, though and
> that I backported as far as necessary.

In order to assist distributors with cherry-picking the fix:
Is the patch in <http://sourceware.org/git/?p=glibc.git;a=commitdiff;h=f87dfb1f11c01f2ccdc40d81e134cd06b32e28e8> all that's needed?