ADMIN

2021

01

2021-01-01T12:00:00

Infrastruktur- und Assetmanagement

PRAXIS

058

Netzwerkmanagement

Open-Source-Tipp

DNS-Auflösung mit systemd-resolved

Cache me

von Thorsten Scherf

Veröffentlicht in Ausgabe 01/2021 - PRAXIS

Mit systemd-resolved steht ein relativ neuer DNS-Stub-Resolver für Linux-Systeme zur Verfügung. Dieser kümmert sich um die Auflösung von IP-Adressen und Hostnamen und legt sie in einem Cache ab, damit nicht jede Anwendung selbst mit dem DNS-Server kommunizieren muss. Der Open-Source-Tipp zeigt, wie Sie system-resolved einsetzen.

Bekanntermaßen kümmert sich auf einem Linux-System der Name Service Switch (NSS) um die Auflösung von Namen. Dies trifft nicht nur auf Benutzer- oder Gruppennamen zu, sondern auch auf Rechnernamen, die es in IP-Adressen und umgekehrt aufzulösen gilt. Anwendungen greifen hierfür auf Funktionen der GNU C Library (glibc) zurück. So existiert für die Auflösung von Hostnamen in IP-Adressen die Funktion getaddrinfo() beziehungsweise getnameinfo() für IP-Adressen in Hostnamen.
 Der NSS ist komplett modular aufgebaut und kann daher unterschiedliche Quellen abfragen, um die Anfragen aufzulösen. Die Quellen sind zusammen mit den jeweiligen Systemdatenbanken in der Datei "/etc/nsswitch.conf" definiert. Für die DNS-Datenbank könnte ein typischer Eintrag wie folgt aussehen:
grep hosts /etc/nsswitch.conf
hosts: files dns
Dieser Eintrag besagt, dass NSS zuerst auf das Modul "files" zurückgreift, um Anfragen nach einer IP-Adresse beziehungsweise einem Hostnamen zu beantworten. Das files-Modul versucht, diese Anfragen anhand von statischen Einträgen aus der Datei "/etc/hosts" aufzulösen. Gelingt dies nicht, kommt das nächste Modul "dns" zum Einsatz. Dieses greift nun auf die Datei "/etc/resolv.conf" zurück, um dort nachzusehen, an welchen DNS-Resolver die Anfrage weiterzuleiten ist. Somit kümmert sich jede Anwendung mithilfe des NSS-Resolvers selbst darum, die Auflösung eines Namens oder einer IP-Adresse durchzuführen. Antworten werden auch nicht gecached, sodass der gleiche Name oder die gleiche IP-Adresse immer wieder über den soeben beschriebenen Mechanismus aufgelöst werden muss.
Bekanntermaßen kümmert sich auf einem Linux-System der Name Service Switch (NSS) um die Auflösung von Namen. Dies trifft nicht nur auf Benutzer- oder Gruppennamen zu, sondern auch auf Rechnernamen, die es in IP-Adressen und umgekehrt aufzulösen gilt. Anwendungen greifen hierfür auf Funktionen der GNU C Library (glibc) zurück. So existiert für die Auflösung von Hostnamen in IP-Adressen die Funktion getaddrinfo() beziehungsweise getnameinfo() für IP-Adressen in Hostnamen.
 Der NSS ist komplett modular aufgebaut und kann daher unterschiedliche Quellen abfragen, um die Anfragen aufzulösen. Die Quellen sind zusammen mit den jeweiligen Systemdatenbanken in der Datei "/etc/nsswitch.conf" definiert. Für die DNS-Datenbank könnte ein typischer Eintrag wie folgt aussehen:
grep hosts /etc/nsswitch.conf
hosts: files dns
Dieser Eintrag besagt, dass NSS zuerst auf das Modul "files" zurückgreift, um Anfragen nach einer IP-Adresse beziehungsweise einem Hostnamen zu beantworten. Das files-Modul versucht, diese Anfragen anhand von statischen Einträgen aus der Datei "/etc/hosts" aufzulösen. Gelingt dies nicht, kommt das nächste Modul "dns" zum Einsatz. Dieses greift nun auf die Datei "/etc/resolv.conf" zurück, um dort nachzusehen, an welchen DNS-Resolver die Anfrage weiterzuleiten ist. Somit kümmert sich jede Anwendung mithilfe des NSS-Resolvers selbst darum, die Auflösung eines Namens oder einer IP-Adresse durchzuführen. Antworten werden auch nicht gecached, sodass der gleiche Name oder die gleiche IP-Adresse immer wieder über den soeben beschriebenen Mechanismus aufgelöst werden muss.
systemd-resolved als DNS-Stub-Resolver
Um dieses Problem zu beheben, gibt es sogenannte Stub-Resolver, oftmals auch einfach als DNS-Forwarder bezeichnet. Einer der bekanntesten dürfte sicherlich dnsmasq [1] sein. Mit systemd-resolved [2] stellt nun auch das systemd-Projekt einen Stub-Resolver zur Verfügung. Eine Besonderheit ist, dass systemd-resolved auf den D-Bus als Messagebus zurückgreift und somit auch dynamisch Konfigurationsanweisungen von Tools empfangen kann, die ebenfalls diesen Messagebus zum Transport von Daten verwenden. Zu diesen Tools zählt natürlich systemd-networkd [3] aus dem eigenen systemd-Ecosystem, aber auch der NetworkManager, den viele Distributionen als Standardwerkzeug zum Setup des Netzwerks einsetzen.
Stub-Resolver wie systemd-resolved sind Programme, die die Anfragen des NSS entgegennehmen und sie dann an einen DNS-Server weiterleiten. Die Antworten des DNS-Servers landen wieder beim Stub-Resolver, der sie im Fall von systemd-resolved zuerst in einem Cache speichert, bevor er sie dann an die anfragende Anwendung weiterleitet. Der Vorteil liegt auf der Hand: Auf einem System existiert nur noch der Stub-Resolver, der für die Auflösung von IP-Adressen und Hostnamen zuständig ist und die DNS-Informationen in einem Cache vorhält, anstatt dass jede Anwendung selbst mit einem DNS-Server kommunizieren muss.
Unter Fedora 33 und höher kommt standardmäßig systemd-resolved als DNS-Resolver zum Einsatz. Wollen Sie das Tool mit einer anderen Distribution testen, stellen Sie zuerst mittels systemctl status systemd-resolved sicher, dass der Service aktiv ist. Für Kompatibilität mit allen Linux-Programmen legt systemd-resolved den Symlink "/etc/resolv.conf" an, der auf die Datei "/run/systemd/resolve/stub-resolv.conf" zeigt. Diese verweist auf den lokalen Stub-Resolver, der auf der IP-Adresse "127.0.0.53" auf Anfragen wartet. Des Weiteren sollte die NSS-Konfigurationsdatei "/etc/nsswitch.conf" natürlich das entsprechende Modul für den Zugriff auf den Stub-Resolver enthalten. Dieses lautet "resolve" und ist wie folgt in der Konfigurationsdatei einzutragen:
grep hosts /etc/nsswitch.conf
hosts: files resolve [!UNAVAIL=return] dns
Achten Sie darauf, dass das NSS-resolve-Modul vor dem dns-Modul aufgeführt ist, da die DNS-Anfragen sonst nicht bei dem lokalen Stub-Resolver landen.
Interface-basierte Konfiguration
systemd-resolved führt DNS-Abfragen auf Basis der DNS-Namen und -Server durch. Diese können dabei sowohl dynamisch als Teil eines DHCP-Leases als auch statisch einem Interface zugeordnet werden. Das folgende Beispiel geht davon aus, dass Sie ein lokales Netzwerk mit dem DNS-Namen "example.com" nutzen, wofür ein lokaler DNS-Server mit der IP-Adresse "192.168.0.1" zuständig ist. Der DHCP-Server für das Netzwerk teilt allen Clients dort dynamisch eine IP-Adresse zu und übermittelt außerdem die DNS-Search-Domain "example.com" und die IP-Adresse des DNS-Servers. Des Weiteren geht das Beispiel davon aus, dass das Clientsystem neben der Ethernet- auch über eine WLAN-Karte verfügt. Alle Anfragen nach DNS-Namen, die sich nicht der Domäne "example.com" zuordnen lassen, werden über das WLAN-Interface gerouted. In den Netzwerkeinstellungen wird der DNS-Server für dieses Interface wieder dynamisch bezogen. Mittels resolvectl können Sie sich dann ansehen, wie systemd-resolved diese Konfiguration auswertet:
resolvectl domain
Global:
Link 2 (wlp3s0): ~.
Link 3 (enp0s25): example.com
 
resolvectl dns
Global:
Link 2 (wlp3s0): 8.8.8.8 4.4.4.4
Link 3 (enp0w25): 192.168.0.1
Über das WLAN-Interface "wlp3s0" werden also alle DNS-Namen aufgelöst, die nicht aus der example.com-Domäne stammen. Hierfür ist die Wildcard "~." verantwortlich. Die DNS-Server, die diesem Interface dynamisch zugeordnet wurden, sind die Google-eigenen Server. Anfragen für Systeme aus dem lokalen Netzwerk hingegen landen beim DNS-Server "192.168.0.1". Dieses Interface verwendet auch die DNS-Search-Domain "example.com", sodass bei der Eingabe eines single-label-Namens, wie beispielsweise "www", sich dieser automatisch nach "www.example.com" expandiert. Setzen Sie mehrere Interfaces mit Search-Domains ein, werden auch mehrere Anfragen parallel erzeugt.
Link-Codes
Manuelle Konfiguration
Mithilfe von resolvectl können Sie Einstellungen natürlich auch manuell vornehmen. Das ist insofern interessant, wenn Sie die benötigten Informationen vielleicht nicht dynamisch von einem DHCP-Server bekommen. Das folgende Beispiel definiert sowohl eine DNS-Search-Domain als auch zwei DNS-Server für das VPN-Interface "tun0":
resolvectl dns tun0 1.2.3.4 5.6.7.8
 
resolvectl domain tun0 mycorp.com
Über die Datei "/etc/systemd/resolved.conf" lassen sich auch globale Einstellungen vornehmen, die dann nicht an ein Interface gebunden sind. Dies entspricht in etwa der Vorgehensweise von nss-dns, bei der unterschiedliche DNS-Server in die globale Resolver-Datei "/etc/resolv.conf" eingetragen und mehrere Abfragen an die DNS-Server versendet werden. An dieser Stelle sei noch erwähnt, dass systemd-resolved auch erweiterte Features wie beispielsweise MulticastDNS, DNSSEC oder auch DNS-OverTLS unterstützt. Diese können Sie entweder statisch in der Datei "/etc/systemd/resolved.conf" oder auch wieder dynamisch mithilfe des Tools resolvectl auf Interface-Ebene festlegen.
Fazit
Der Einsatz von systemd-resolved bringt einige Vorteile mit sich. So bietet der Dienst beispielsweise von Haus aus einen Cache an und übernimmt die DNS-Auflösung. Auch die Interface-basierte Konfiguration ist im Vergleich zu einer globalen Konfiguration mit statischen DNS-Servern für alle Netze ein großer Vorteil.
(jm)