glibc getaddrinfo(3) and greener pastures

recently, i've been trying to understand and further configure how my laptop does dns resolution (beyond an immutable /etc/resolv.conf pointing to cloudflare). naturally, i started wondering how linux userland does it.

most languages and things1 boil down to wrapping a libc, and the posix-mandated library call of interest is getaddrinfo(3) (there is also gethostbyname(3), but it is deprecated). i wrote and compiled this, linked against glibc 2.28, and immediately found myself lost in reading its strace. on top of trying to load a bunch of configuration files and shared objects i didn't know existed, glibc pokes the unix domain socket /var/run/ncsd/socket twice!

what is ncsd? james will tell you all about it. regardless, i don't think a libc should hardcode an application check like this. i get that dns caching is important, but it should be all or nothing for a libc. showing preference for a particular caching local resolver is not nothing, and is an abstraction at the mercy of ncsd and its whims.

then, i recompiled, this time linking against musl libc 1.1.21. look at the strace. LOOK AT IT! it's beautiful. i'm convinced this would be noticeably faster than glibc, but proper benchmarking is hard, so i won't be doing that.

there are also some languages that don't wrap around a libc, namely golang, which thankfully honors the /etc/resolv.conf convention. so out of curiosity, i also wrote a functionally equivalent go program (go 1.12.3 linux/amd64, build with CGO_ENABLED=0 to ensure it uses go's resolver), and its strace is a lot saner than the glibc one, although it still looks at more files than musl. (what is /etc/mdns.allow? i don't want to know.)

as an end user, i just want to be able to reasonably understand my linux machine. static lookup in /etc/hosts and resolver preferences in /etc/resolv.conf should be all there is to it, and musl seems to sympathize with me on this. i am also glad that golang, which is becoming more mainstream for networked stuff, is saner in this regard.

to tie loose ends: i settled on dnscrypt-proxy as a local caching resolver, pointed /etc/resolv.conf to it (still immutable so other programs don't mess with it, as they like to do), and have never been happier.

1 i also objdump'd some bind9 utilities like host and dig, and on my machine they use bind9_getaddresses, which calls getaddrinfo if USE_GETADDRINFO. presumably that is the case for however bind-tools is compiled by the official arch linux repositories, because the strace for dig +short looked exactly like glibc getaddrinfo.