Prevent additional DNS queries when “search” is not set

domain-name-systemglibcresolv.conf

The host in question is running Arch Linux with hostname set to foo.example.org. There is no search directive in /etc/resolv.conf.

If I ping example.com or curl example.com or wget example.com (example.com does not exist, NXDOMAIN), there would be four DNS queries, a pair of A/AAAA queries for example.com and a pair of A/AAAA queries for example.com.example.org.

I am surprised to find out that glibc resolver would try example.com.example.org even when there is no search directive in /etc/resolv.conf.

How could I stop this? Possible solutions / workarounds I have tried:

  • Change the hostname from foo.example.org to foo. The additional queries to example.com.example.org are not sent. But I don't want to change hostname.
  • Add a search invalid directive to /etc/resolv.conf. The additional queries to example.com.example.org are not sent. But example.com.invalid are sent instead. (Note that .invalid are reserved TLD of ICANN)

How could I make the resolving process of example.com stop on first try (NXDOMAIN) without continuing to try example.com.something-else?

Best Answer

First of all, this is the relevant section from resolv.conf(5):

   domain Local domain name.
          Most queries for names within this domain can  use  short  names
          relative to the local domain.  If set to '.', the root domain is
          considered.  If no domain entry is present, the domain is deter‐
          mined  from  the  local hostname returned by gethostname(2); the
          domain part is taken to  be  everything  after  the  first  '.'.
          Finally,  if  the  hostname  does not contain a domain part, the
          root domain is assumed.

   search Search list for host-name lookup.
          The search list is normally determined  from  the  local  domain
          name;  by default, it contains only the local domain name.  This
          may be changed by listing the desired domain search path follow‐
          ing the search keyword with spaces or tabs separating the names.
          Resolver queries having fewer than ndots dots (default is 1)  in
          them  will  be attempted using each component of the search path
          in turn until a match is found.  For environments with  multiple
          subdomains  please  read  options ndots:n below to avoid man-in-
          the-middle attacks and unnecessary  traffic  for  the  root-dns-
          servers.  Note that this process may be slow and will generate a
          lot of network traffic if the servers for the listed domains are
          not local, and that queries will time out if no server is avail‐
          able for one of the domains.

          The search list is currently limited to six domains with a total
          of 256 characters.

Ie, search is not simply off by default; if search is not specified it uses either domain, or if that is also not specified it uses any domain part present in what gethostname(2) returns (ie, anything after the first dot in the local system hostname).

The actual implementation is a little strange, however. What happens in practice (as observed in glibc 2.26) is this:

If there is no search, no domain and the hostname according to gethostname(2) has no domain part, search is disabled.

If, on the other hand, you specify search . (or domain . and no search) it still searches, but the returned result will be the same as if it didn't, it just makes redundant identical queries. (Bug?)

This is kind of weird behavior, the case where "the root domain is assumed" leads to search getting disabled while explicitly specifying the root domain instead generates redundant queries.


As for how to set the system hostname, there are different schools of thought.

Using the FQDN across the board is probably the most obvious approach nowadays, it removes any possible question marks regarding which domain will be used to construct the FQDN.

If you have the system hostname set to just the actual hostname (no domain), you get different values from gethostname(2) and gethostname(3) (the latter dynamically generates the FQDN as necessary by using the resolver, in practice typically matching an entry in /etc/hosts for the local system). Depending on what an application asks for it will get either just the hostname or the FQDN, as can be seen with eg hostname vs hostname --fqdn.

Less expected is how the above choice actually also affects the ability to disable search.
But, strange as it may be, the bottom line seems to be that if you want to globally disable search, whether names you look up are explicitly absolute (have a trailing dot) or not, current glibc versions seem to only properly disable search if gethostname(2) returns a hostname lacking a domain.

Related Topic