Evolution of DNS and the Cursed systemd-resolved
Looking back at our technical beginnings, most of us remember relying on the resolv.conf
file. This small but powerful file was our window into the world of DNS—it was our personal guide, helping us translate domain names into IP addresses. Every administrator, whether experienced or a novice, had to work with it at some point. Then systemd arrived, bringing systemd-resolved, and our beloved resolv.conf
started behaving like an old friend who suddenly decided not to be as reliable as we thought.
Outdated resolv.conf#
Today, we know that resolv.conf
is no longer what it used to be. Instead, its content is generated and managed by systemd-resolved, which by default directs all DNS queries to 127.0.0.53
. For some older admins who haven’t gotten used to this change, it can feel like a leap into the unknown. Why should we trust something that constantly changes and tells us we no longer have full control over our DNS queries?
Many of us who have spent years as system administrators, and gradually some as “DevOps,” are used to having things under control. We know exactly where to find things and how they work. Suddenly, we have this new abstraction that tries to simplify our lives but can actually cause more confusion than benefit. Why should anyone give up control over something as fundamental as DNS?
So, I decided to explore this issue in detail. What exactly does systemd-resolved do? What are its pros and cons? And most importantly, why should we reconsider our views on this new technology? Let’s take a closer look and try to untangle the DNS confusion that seems, inevitably, to be a necessary step forward in our ever-evolving IT world.
How It Actually Works in Linux#
Let’s look at how this process works at the core of Linux. Most C programs in Linux resolve DNS using the standard libc library. This library contains functions like getaddrinfo
, which allow us to look up IP addresses based on domain names. When a program calls this function, libc steps in and starts looking for the necessary information.
But how does it know where to look? That’s where the nsswitch.conf
file comes in. This configuration file determines how various services and databases are queried for information in the system. For DNS resolution, it’s key because it specifies which mechanism to use for name lookup. Typically, it contains a record for hosts, for example:
hosts: files dns
This setting tells the system to first look in local files (like /etc/hosts
) and then query DNS servers defined in resolv.conf
. This ensures that if a domain name is available locally, the system will find it faster than making a network query.
So, when getaddrinfo
needs to find the IP address for a domain, it consults nsswitch.conf
to determine which mechanism to use. If dns
is specified, libc tries to use the DNS resolver, which in the past relied on resolv.conf
. This is where our story of innovation begins.
Over time, it became clear that the traditional approach to DNS resolution had its limitations. In today’s IT world, the old system is insufficient. Enter systemd-resolved, which brings several key improvements:
- Simplified management:
systemd-resolved
centralizes DNS management, so all applications can use the same resolver and share DNS information. - Support for multiple protocols: The new system supports not only traditional DNS but also new protocols like mDNS and LLMNR, enabling more efficient local resolution.
- Caching: systemd-resolved implements caching, meaning repeated queries for the same domain name are faster and save network resources.
The old resolving system, while functional, needed modernization. That’s why we’re witnessing the transition to systemd-resolved, which aims to provide a more efficient, faster, and user-friendly way to manage DNS queries in Linux environments.
So, next time you call getaddrinfo
, remember how far we’ve come from the simple resolv.conf
and how much the way we look at DNS resolution has changed.
Example: Resolving a Hostname Using getaddrinfo#
Here’s a simple example in C that uses the modern getaddrinfo
function (instead of the deprecated getaddrinfo
) to resolve the domain name google.com
to its IP addresses:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netdb.h>
#include <arpa/inet.h>
int main() {
const char *hostname = "google.com";
struct addrinfo hints, *res, *p;
int status;
char ipstr[INET6_ADDRSTRLEN];
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC; // AF_INET or AF_INET6 to force version
hints.ai_socktype = SOCK_STREAM;
if ((status = getaddrinfo(hostname, NULL, &hints, &res)) != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(status));
return 1;
}
printf("IP addresses for %s:\n", hostname);
for(p = res; p != NULL; p = p->ai_next) {
void *addr;
char *ipver;
// get the pointer to the address itself,
// different fields in IPv4 and IPv6:
if (p->ai_family == AF_INET) { // IPv4
struct sockaddr_in *ipv4 = (struct sockaddr_in *)p->ai_addr;
addr = &(ipv4->sin_addr);
ipver = "IPv4";
} else { // IPv6
struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)p->ai_addr;
addr = &(ipv6->sin6_addr);
ipver = "IPv6";
}
// convert the IP to a string and print it:
inet_ntop(p->ai_family, addr, ipstr, sizeof ipstr);
printf(" %s: %s\n", ipver, ipstr);
}
freeaddrinfo(res); // free the linked list
return 0;
}
New Beginnings with libnss-resolved#
With the advent of systemd-resolved and its new features, a new library called libnss-resolved
has become a key part of modernizing DNS resolution in Linux. This library is part of the Name Service Switch (NSS) system and provides a faster and more efficient API for DNS queries than the traditional libc.
One of the most significant advantages of libnss-resolved is its ability to provide a faster API for DNS queries. Unlike classic DNS resolvers, which often use synchronous calls and wait for a response, libnss-resolved implements an asynchronous approach, allowing applications to continue running while waiting for DNS results. This is especially useful in modern application architectures where high performance and low latency are expected.
To use this library on your Ubuntu server, simply install the libnss-resolve
package:
sudo apt install libnss-resolve
After installation, you need to edit the nsswitch.conf
file so the system knows to use the new library for DNS resolution, for example:
hosts: mymachines resolve [!UNAVAIL=return] files myhostname dns
This ensures the system will consult libnss-resolve
[^1].
Configuration and Management with systemd-resolved#
The resolved.conf
file plays a key role in configuring which DNS servers the system uses. It’s typically located at /etc/systemd/resolved.conf
and allows you to specify DNS servers, for example:
[Resolve]
DNS=8.8.8.8 8.8.4.4
FallbackDNS=1.1.1.1
After making changes, restart systemd-resolved to apply the new settings:
sudo systemctl restart systemd-resolved
A useful tool that comes with systemd-resolved is the resolvectl
command, which allows you to perform DNS queries and get information about the current state of resolution. For example, to resolve a domain name:
resolvectl query google.com
To get information about the current DNS resolution status:
resolvectl status
In conclusion, while systemd-resolved brings many advantages and simplifies DNS management, it’s understandable that some users may want to revert to the old ways. If you choose to do so, you can either edit the resolved.conf
file or remove the symbolic link in /etc/resolv.conf
and create a new file with your own settings.
Based on my experience, DNS resolution via systemd-resolved is noticeably faster than traditional methods. I consider it a step forward in DNS management.