When you’re managing a network, you may experience an occurrence of xkcd 927, where finding out which DNS server you’re using for naming resolution leads you down a rabbit hole of different programs calling each other, configuration files you can’t edit and yet aren’t centrally managed, and lots and lots of pain. In this article, I demonstrate how you can use the resolvectl
command to inspect a network.
Ol’ [un]reliable
All roads lead to Rome, and all Google searches asking for DNS resolution information lead to /etc/resolv.conf
. The man page for resolv.conf
states: “The resolver configuration file contains information that is read by the resolver routines the first time they are invoked by a process.”
Oracle 6’s system administrator handbook says:
1 2 3 4 5 6 |
This file usually contains a line specifying the search domains and up to three lines that specify the IP addresses of DNS server. The following entries from /etc/resolv.conf configure two search domains and three DNS servers: search us.mydomain.com mydomain.com nameserver 192.168.154.3 nameserver 192.168.154.4 nameserver 10.216.106.3 |
The man page continues on to state: “If this file does not exist, only the name server on the local machine will be queried, and the search list contains the local domain name determined from the hostname.”
Makes sense, right? Let’s see what /etc/resolv.conf
contains on a modern Ubuntu 22.04 machine:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
# Do not edit. # This file might be symlinked as /etc/resolv.conf. If you're looking at # /etc/resolv.conf and seeing this text, you have followed the symlink. # This is a dynamic resolv.conf file for connecting local clients to the # internal DNS stub resolver of systemd-resolved. This file lists all # configured search domains. # Run "resolvectl status" to see details about the uplink DNS servers # currently in use. # Third party programs should typically not access this file directly, but only # through the symlink at /etc/resolv.conf. To manageresolv.conf in a # different way, replace this symlink by a static file or a different symlink. # See systemd-resolved.service(8) for details about the supported modes of # operation for /etc/resolv.conf. nameserver 127.0.0.53 options edns0 trust-ad search . |
It’s not as simple as that. If you believe the man page, you’d either have a fully functional local DNS server or a non-working name resolution. Also, you might notice that /etc/resolv.conf
is a symlink, and dynamically generated. This raises a question. By whom, and more importantly, from where? In /etc/resolv.conf
, you see you can run resolvectl status
to get more information.
Resolvectl
The man page for resolvectl
says: “resolvectl
may be used to resolve domain names, IPv4 and IPv6 addresses, DNS resource records and services with the systemd-resolved.service(8)
resolver service.”
Indeed, resolvectl
is a one-stop-shop for all of your local DNS needs. Similar to dig
, for instance, resolvectl
can easily fetch you the A and AAAA resource records for a domain.
1 2 3 4 5 6 7 8 |
$ resolvectl query www.youtube.com www.youtube.com: 172.217.169.174 172.217.17.238 ...a bunch of other IPs... 216.58.212.46 (youtube-ui.l.google.com) -- Information acquired via protocol DNS in 1.0912s. -- Data is authenticated: no |
Querying an IP address instead of a domain can, similar to the -x
option in dig
, gets you the PTR record of that IP address. The resolvectl
command can also query MX records with the query -t MX
option, resolve services and retrieve PGP and TLS keys.
But what about finding out which DNS server your machine uses when performing name resolution? If you run the command from the /etc/resolv.conf
, then you can see which actual DNS servers your machine uses:
1 2 3 4 5 6 7 8 9 10 11 |
$ resolvectl status Global Protocols: -LLMNR -mDNS -DNSOverTLS DNSSEC=no/unsupported resolv.conf mode: foreign Current DNS Server: 8.8.8.8 DNS Servers: 8.8.8.8 1.1.1.1 Link 2 (eth0) Current Scopes: none Protocols: -DefaultRoute +LLMNR -mDNS -DNSOverTLS DNSSEC=no/unsupported |
You see here that your resolv.conf mode is foreign, which means it’s managed by another package and, in this situation, the nameservers you’re getting come from the DHCP server.
Yet that creates a bit of a Catch-22. If your /etc/resolv.conf
isn’t a configuration file for name resolving and is instead dynamically generated, then what configuration is it dynamically generated from?
It’s resolved (not resolve)
After much searching, your tired eyes wander around the Google searches. All of a sudden, you see it. Arch’s wiki says to edit resolved.conf
(notice the “d” in “resolved”) not resolve.conf
.
Yes, the way to set a static manual DNS server for your local needs is by editing /etc/systemd/resolved.conf
, and specifically, preferably by adding stub files in the /etc/systemd/resolved.conf.d
folder. (Yes, that’s two files with almost the same name, one completely obsolete and useless, defaulting to nothing more than a dynamically generated and symlinked “we’ve moved” banner.)
There’s another, easier, less painful way we can see why your /etc/resolv.conf
says 127.0.0.1:53, and that’s seeing what’s listening on that port:
1 2 3 |
$ sudo ss -tulnp4 | grep 53 udp UNCONN 0 0 127.0.0.53%lo:53 0.0.0.0:* users:(("systemd-resolve",pid=104,fd=13)) tcp LISTEN 0 4096 127.0.0.53%lo:53 0.0.0.0:* users:(("systemd-resolve",pid=104,fd=14)) |
Here, you can see it’s systemd-resolve
, which resolvectl
uses, that listens on port 53 and handles name resolution by sending requests to the nameservers you see in resolvectl status
.
Systemd-resolved
To be entirely fair, the use of the traditional /etc/resolv.conf
file for configuring DNS resolution in Linux systems has not been entirely discontinued. However, the introduction of systemd-resolved
, a component of the systemd init system, has provided an alternative approach to DNS configuration (refer again to xkcd 927).
The full arsenal of features of systemd-resolved
are out of the scope of this article. To summarize, systemd-resolved
is a system service that manages network name resolution and provides DNS caching. It’s designed to be a centralized DNS resolver for all applications running on a Linux system. Instead of relying on individual applications to handle DNS resolution, systemd-resolved takes over this responsibility, simplifying the configuration and management process.
The /etc/resolv.conf
file has historically been the standard location for configuring DNS servers in Linux. However, it was prone to being overwritten by network management tools, making it challenging to maintain custom DNS server configurations. To address this issue, and provide a more consistent and reliable method for DNS configuration, systemd-resolved
introduced its own configuration file: /etc/systemd/resolved.conf
.
The resolved.conf
file allows you to specify DNS server addresses, domain search domains, and other DNS-related options. When systemd-resolved.service
starts, it reads this configuration file and dynamically generates the /run/systemd/resolve/resolv.conf
file, which is then symlinked to /etc/resolv.conf
. This dynamic generation ensures that the /etc/resolv.conf
file always reflects the current DNS configuration defined in /etc/systemd/resolved.conf
.
Here’s a quick setup of a drop-in configuration file for systemd-resolved
to add another DNS server for your machine to use.
Create the /etc/systemd/resolved.conf.d
folder:
1 |
$ sudo mkdir -p /etc/systemd/resolved.conf.d |
Create a stub file with your DNS configuration. In this example, I’m creating a singular new DNS server and cache enabling:
1 2 3 4 5 |
$ sudo cat <<EOF > /etc/systemd/resolved.conf.d > [Resolve] > Cache=yes > DNS=192.168.1.100 > EOF |
Restart systemd-resolved:
1 |
$ sudo systemctl restart systemd-resolved.service |
Check the results using resolvectl status:
1 2 3 4 5 6 7 8 9 |
Global Protocols: -LLMNR -mDNS -DNSOverTLS DNSSEC=no/unsupported resolv.conf mode: foreign Current DNS Server: 192.168.1.100 DNS Servers: 192.168.1.100 8.8.8.8 1.1.1.1 Link 2 (eth0) Current Scopes: none Protocols: -DefaultRoute +LLMNR -mDNS -DNSOverTLS DNSSEC=no/unsupported |
That’s it! You’ve successfully added a static DNS server to use for name resolution!
Conclusion
I think Linux gets unfairly blamed for being confusing.
Part of that, I assume, is the freedom you get. Straight out of a fresh installation, you’re free to do (and break) whatever you want with your system. There are few warnings and, with the correct rights, no limitations. Yet there are some points in my sysadmin career in which I’ve questioned whether something couldn’t be done better, or at least less confusingly. In the case of setting up name resolution, many people asked themselves the same questions, and just as many decided to do something about it.
Configuring local DNS resolution in Linux can be a daunting task, but with the right knowledge and understanding, you can navigate the complexities with confidence. In this article, I demonstrated the traditional /etc/resolv.conf
file and its limitations, as well as the introduction of systemd-resolved
, a centralized DNS resolver that simplifies the configuration process.
Remember to explore the documentation and man pages for further details on specific commands and configuration options.
Happy resolving!
1 Comment
Petru · 2023-07-17 at 16:42
Very interesting article. Thanks for writing it, Konstantin! 🙂