4

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?

Zhuoyun Wei
  • 370
  • 2
  • 3
  • 11
  • It may be related to `systemd-resolved`, do you use it? – Patrick Mevzek Apr 12 '18 at 17:54
  • @PatrickMevzek I never configured it. `systemctl status systemd-resolved` shows it is not running, `ps aux | grep systemd-resolved` confirms. But as I read the man page, `ping _gateway` does work. How could I reliably determine it is hijacking the resolving process? – Zhuoyun Wei Apr 12 '18 at 18:02
  • Have a look at `nsswitch.conf` too, this dictates how the name resolution takes place. Try with `hosts: dns [!UNAVAIL=return] files` in it. – Patrick Mevzek Apr 12 '18 at 18:41
  • @PatrickMevzek Changing the line you mentioned disables the special treatment for `ping _gateway`. But additional queries are still sent. Thanks anyway. – Zhuoyun Wei Apr 13 '18 at 03:21
  • Did you try adding a trailing dot to each of the name you query? Does that change the result? – Patrick Mevzek Apr 15 '18 at 01:21
  • @PatrickMevzek Appending a trailing dot stops the additional queires. But I cannot control what the application queries. – Zhuoyun Wei Apr 15 '18 at 08:51

2 Answers2

2

The behavior for appending the hostname's domain if no domain or search is added to /etc/resolv.conf is expected and documented in the man page for resolv.conf.

You get the resolver to stop treating your not fully qualified host name by appending a dot at the end to explicitly state that it is fully qualified.

Hostname in example.org, no domain in /etc/resolv.conf:

[root@test ~]# hostname
test.example.org
[root@test ~]# cat /etc/resolv.conf
nameserver 8.8.8.8

Unqualified hostname lookup has example.org appended:

[root@test ~]# ping -c 1 www
PING www.example.org (93.184.216.34) 56(84) bytes of data.
64 bytes from 93.184.216.34 (93.184.216.34): icmp_seq=1 ttl=57 time=82.8 ms

--- www.example.org ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 82.891/82.891/82.891/0.000 ms

Adding a dot at the end prevents that:

[root@test ~]# ping -c 1 www.
ping: www.: Name or service not known
  • Thanks for pointing out this is a documented behaviour. Alas, some programs running on the host are querying NXDOMAIN names, and I cannot change their code to append dots before sending queries... – Zhuoyun Wei Apr 13 '18 at 03:24
2

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.

Håkan Lindqvist
  • 33,741
  • 5
  • 65
  • 90
  • I used to thought that if `search` is not set, it is off. Thanks for the doc, TIL. When messing around with `resolv.conf` I also tried `search .` (Vim even gave me a warning) and also observed the strange identical queries behavior. (glibc 2.26) – Zhuoyun Wei Apr 13 '18 at 03:29
  • Maybe `ndots:0` could stop this? – Patrick Mevzek Apr 13 '18 at 14:37
  • If most of your queries are ipv4, you can get rid of many of the queries by defining /etc/gai.conf and set preference for ipv4. This will also reduce lookup. [Example](https://github.com/ohdns/centos7_simple_kickstart/blob/master/kickstart/c7_server.cfg#L949) – Aaron Apr 13 '18 at 19:32
  • @PatrickMevzek `options ndots:0` does not help. That option seems to influence only if a domain search should be done before or after the literal name being tried. – Robert Siemer Dec 15 '21 at 03:21
  • As far as I can see there is still no way to disable search. Any news on this? – Robert Siemer Dec 15 '21 at 03:24