Who reads /etc/resolv.conf?

DNS client libraries do.

C libraries contain DNS clients that wrap up name-to-address lookups in the DNS protocol and hand them over to proxy DNS servers to do all of the grunt work of query resolution. There are a lot of these DNS clients. The one that is in the main C runtime library of your operating system will very likely be the one from ISC's BIND. But there are a whole load of others from Daniel J. Bernstein's dns library through c-ares to adns.

Although several of them contain their own native configuration mechanisms, they generally have a BIND library compatibility mode where they read resolv.conf, which is the configuration file for the ISC's BIND C client library.

The NSS is layered on top of this, and is configured by nsswitch.conf. One of the things that NSS lookups can invoke internally is the DNS client, and nsswitch.conf is read by the NSS code in the C library to determine whether and where lookups are handed to the DNS client and how to deal with the various responses.

(There is a slight complication to this idea caused by the Name Services Cache Dæmon, nscd. But this simply adds an extra upper-layer client in the C library, speaking an idiosyncratic protocol to a local server, which in its turn acts as a DNS client speaking the DNS protocol to a proxy DNS server. systemd-resolved adds similar complications.)

systemd-resolved, NetworkManager, connman, dhcpcd, resolvconf, and others adjust the BIND DNS client configuration file to switch DNS clients to talk to different proxy DNS servers on the fly. This is out of scope for this answer, especially since there are plenty of answers on this WWW site already dealing with the byzantine details that such a mechanism involves.

The more traditional way of doing things in the Unix world is to run a proxy DNS server either on the machine itself or on a LAN. Hence what the FreeBSD manual says about normally configured systems, where the default action of the DNS client library in the absence of resolv.conf matches what Unix system administrators normally have, which is a proxy DNS server listening on (The FreeBSD manual for resolv.conf is actually doco that also originates from ISC's BIND, and can of course also be found where the BIND DNS client library has been incorporated into other places such as the GNU C library.)

Further reading

  • Daniel J. Bernstein. The dns library. cr.yp.to.
  • Jonathan de Boyne Pollard (2017). What DNS name qualification is. Frequently Given Answers.
  • Jonathan de Boyne Pollard (2004). What DNS query resolution is . Frequently Given Answers.
  • Jonathan de Boyne Pollard (2001). The Big Picture for "djbdns". Frequently Given Answers.
  • Jonathan de Boyne Pollard (2000). "content" and "proxy" DNS servers. Frequently Given Answers.

From the far better FreeBSD man page, resolv.conf:

 The resolver configuration file contains information that is read by the
 resolver routines the first time they are invoked by a process.

 On a normally configured system this file should not be necessary.  The
 only name server to be queried will be on the local machine, the domain
 name is determined from the host name, and the domain search path is
 constructed from the domain name.