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.
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)