nss-dns4only / libc / disable AAAA lookups

nss-dns4only / libc / disable AAAA lookups

  • Written by Walter Doekes

  • Published on: 2020-05-25

Have you ever noticed how some applications can do AAAA DNS record lookups even though the host has no IPv6 connectivity? That means double DNS lookups for zero profit. Why is that? And how can you disable it?

Problem

To make a long story short, a common combination of circumstances can cause useless gratuitous AAAA lookups:

  • Applications that are IPv6 ready (or applications that don’t care);
  • on hosts using libc;
  • where IPv6 is enabled (net.ipv6.conf.all.disable_ipv6=0) — even though there is no IPv6 router in the network.

Where is that?

Well, with all the microservices around nowadays, it’s likely that’s the case for your nearest Kubernetes node. And it’s also likely there are one or more jobs doing DNS queries every second or more.

Now, I’m all for the adoption of IPv6. But to be realistic, there are simply many hosts are not directly connected to IPv6 yet. And even if they are, it’s still a shame that every lookup is done in twofold.

Details

The problem is in the getaddrinfo libc call. Most applications that connect somewhere, e.g. curl, call getaddrinfo() with the “unspecified” (AF_UNSPEC) address family; i.e. both an IPv4 and an IPv6 response is okay.

In the background, getaddrinfo() will do two DNS record lookups over UDP: one for an (IPv4) A record, and one for an (IPv6) AAAA record. It collects the responses and returns both to the calling application. The application will then try to connect over IPv6 and IPv4 sequentially, depending on which records were returned.

If you’re lucky, your host has no IPv6 address at all (not even a link-local one) and your application passes the AI_ADDRCONFIG parameter (or gets it by default from GNU libc). Then you might only get a single lookup. But in all other cases, you get two lookups. And you always have to wait for the slowest of the two responses.

Solutions

So, can you disable IPv6 lookups for these cases?

Some applications will have an option, like curl has the -4 option. But adding that everywhere is tedious. It would be nice to disable A or AAAA lookups on a host entirely (see also a RedHat libc bug report). However, as you can see in the RFE above, no work appears to have been done in GNU libc since that report was filed in 2016.

Are there any other workarounds then?

I’m glad you asked! Because this issue has other side effects than just increased load and latency, I made a workaround in the form of a nsswitch.conf callback: nss-dns4only

It works by intercepting the getaddrinfo() calls, and turning them into AF_INET lookups:

ret = _nss_dns_gethostbyname3_r(
    lookupname, AF_INET, &result, buffer2, buflen, errnop, herrnop,
    ttlp, NULL);

Try it out. You can download the source or fetch a pre-built Debian package from the nss-dns4only releases page. Installation is described in the README.

(Note that it does not work with libc versions that have no NSS system, like musl libc.)

Disclaimer: Again, I do not wish to hinder the adoption of IPv6 in any way. If there is demand, I’ll gladly help create the inverse: an IPv6-only version that only does AAAA lookups.


Back to overview Newer post: docker unprivileged user / becoming root Older post: gitlab / securing public repositories