DNS fürs LAN mit dynamischen Clients via DHCP

Manch einer kennt das Problem: Man verwaltet ein LAN zu Hause oder im Büro und neben den Client Computern gibt es einige Dinge, wie Drucker, NAS oder verschiedene Server, die lokal erreichbar sind. Um diese Teilnehmer leicht über ihren Namen zu erreichen, kann man deren IP-Adressen in der lokalen Datei /etc/hosts auf seinem Linux Rechner eintragen. Von diesen privaten Abkürzungen haben nur die übrigen Benutzer im Netzwerk nichts. Ein lokaler DNS Server wäre da schon sehr praktisch. Diesen werden wir jetzt in 3 aufeinander aufbauenden Schritten einrichten.In dieser Anleitung gehe ich von einem Ubuntu Server 10.4 aus, im Grunde ist die Installation für die meisten Linux Distributionen gleich. Lediglich die Pfade zu diversen Dateien können sich ändern. Außerdem werde ich nicht auf alle Optionen im Detail eingehen. Ziel dieser Anleitung ist, ein funktionierendes Basis-System zu konfigurieren.

Vorbereitungen

In dieser Anleitung gehen wir von ein paar Fakten aus:

  • Name des Servers: myserver
  • IP des Servers: 192.168.0.1
  • Domain des Servers und der Clients (via DHCP): mylan.local
  • DNS Server des Providers: 208.67.222.222 und 208.67.220.220

1. Caching DNS Server

(Dieser Teil stammt im Prinzip von https://help.ubuntu.com/community/BIND9ServerHowto#Configuring_BIND9) Zuerst installieren wir den DNS Daemon bind9. ~# apt-get install bind9 Die Konfiguration liegt in /etc/bind/ und ist in die Dateien named.conf,named.conf.options und named.conf.local aufgeteilt, im Prinzip können alle Konfigurationen aber auch direkt in /etc/bin/named.conf erfolgen. Für ein erstes Erfolgserlebnis editieren wir named.conf.options und fügen die DNS Server unseres ISP im Block forwardershinzu, sodass die Datei etwa so aussieht:

options {
        directory "/var/cache/bind";
        forwarders {
                208.67.222.222;
                208.67.220.220;
        };
        auth-nxdomain no;    # conform to RFC1035
        listen-on-v6 { any; };
};

Jetzt müssen wir unserem Server noch beibringen, dass er seinen eigenen DNS Dienst abfragt. Dazu editieren wir /etc/resolv.confund fügen als ersten, obersten Eintrag den Selbstverweis hinzu:

nameserver 127.0.0.1
nameserver 208.67.222.222
nameserver 208.67.220.220
domain mylan.local
search mylan.local

Jetzt den DNS Server neu starten und testen: ~# /etc/init.d/bind9 restart ~# dig -x 127.0.0.1Die Ausgabe sollte etwa so aussehen:

; <<>> DiG 9.7.0-P1 <<>> -x 127.0.0.1
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 59273
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 1, ADDITIONAL: 0

[...]

;; Query time: 18 msec
;; SERVER: 81.3.216.100#53(81.3.216.100)
;; WHEN: Wed Aug  8 11:49:02 2012
;; MSG SIZE  rcvd: 84

Den Test wiederholen wir diesmal mit einem Namen (und daher ohne den Parameter x), wie z.B. ~# dig google.com Man beachte hier die Anfragedauer (Query time), wiederhole die Anfrage und beachte die deutlich kürzere Zeit. Das ist das Zeichen, dass das Caching des Servers funktioniert. In der Konfiguration des DHCP Servers trägt man jetzt folgende Werte ein, sofern diese nicht schon gesetzt sind (entweder global oder im betreffenden subnetBereich):

ddns-domainname "mylan.local";
option domain-name-servers 192.168.0.1;

Zum Testen nimmt man jetzt einen beliebigen Client (von dem aus man zurzeit nicht arbeiten muss) und sendet von diesem einen neuen DHCP-Request (je nach Betriebssystem oder einfach die Netzwerkverbindung neu aufbauen). Der Client sollte jetzt den Server als DNS-Server verwenden.

2. Lokaler DNS

Der nächste Schritt ist es, die Aufgabe, die üblicherweise die lokale Datei /etc/hosts für einen einzelnen Rechner erledigt, jetzt zentral im ganzen Netz zu konfigurieren. Dazu müssen wir dem DNS-Server einige Namen und die zugehörigen IP-Adressen beibringen. Wir wollen zum Beispiel, dass unser Server myservervon allen unter seinem Namen gefunden werden kann. Für dieses Szenario gehen wir von folgenden Rechnern (mit statischen IP-Adressen) aus:

  • Server myserver: 192.168.0.1
  • Router router: 192.168.0.99
  • Drucker printer: 192.168.0.10
  • Test-Server (in einem eigenen Subnetz) devserver: 192.168.2.2

Für den DNS-Server müssen wir nun zwei Zonen definieren (ich will hierüber nicht zu sehr ins Detail gehen): eine für Forward-Lookups (welche IP Adresse hat der Rechner mit einem bestimmten Namen) und eine für Reverse-Lookups (welchen Namen hat der Rechner mit einer bestimmten IP). Wir editieren die Datei /etc/bind/named.conf.localund definieren die zwei Zonen:

zone "mylan.local" {
        type master;
        file "/var/lib/bind/db.mylan.local";
};

zone "168.192.in-addr.arpa" {
        type master;
        file "/var/lib/bind/db.192.168";
};

Die zweite Zone wird für die Reverse-Lookups verwendet. Der Name muss die Form des umgekehrten IP-Adressbereichs, gefolgt von dem Suffix .in-addr.arpa haben. Wir haben hier absichtlich nicht 0.168.192.in-addr.arpa gewählt, da wir 2 Subnetze in unserer Zone verwalten werden. (Ist das nicht notwendig, so kann man natürlich noch eine 0 voranstellen.) Die Zonen-Definitionen liegen bei Ubuntu standardmäßig in /var/lib/bind/. Dort hat der bind-daemon bei aktiviertem AppArmor Schreibrechte. Wenn kein AppArmor aktiviert ist oder man mit der Konfiguration von AppArmor vertraut ist, so kann man natürlich einen anderen Speicherort wählen. Wichtig bei den Zonen-Konfigurationen ist der Parameter serial: Sein Wert muss mit jeder Änderung immer erhöht werden. Da wir in Abschnitt 3 einen automatischen Update-Mechanismus (via DHCP) aktivieren werden, sollte man anfangs einfach fortlaufende Nummern vergeben. Wenn man nicht vorhat, die in Abschnitt 3 geplante Erweiterung zu konfigurieren, empfiehlt es sich, das aktuelle Datum und die Uhrzeit zu verwenden, z.B. 201208081944 für die Änderungen am 8. August 2012 um 19:44) Die Zonen-Konfiguration für den Forward-Lookup sollte in unserem Beispiel etwa so aussehen:

$ORIGIN .
$TTL 86400      ; 1 day
mylan.local           IN SOA  myserver.mylan.local. hostmaster.mylan.local. (
                                1          ; serial
                                21600      ; refresh (6 hours)
                                3600       ; retry (1 hour)
                                604800     ; expire (1 week)
                                3600       ; minimum (1 hour)
                                )
                        NS      myserver.mylan.local.
$ORIGIN mylan.local.
myserver                  A       192.168.0.1
router                    A       192.168.0.99
printer                   A       192.168.0.10
devserver                 A       192.168.2.2

Für den Reverse-Lookup:

$ORIGIN .
$TTL 86400      ; 1 day
168.192.in-addr.arpa    IN SOA  myserver.mylan.local. hostmaster.mylan.local. (
                                1          ; serial
                                21600      ; refresh (6 hours)
                                3600       ; retry (1 hour)
                                604800     ; expire (1 week)
                                3600       ; minimum (1 hour)
                                )
                        NS      myserver.mylan.local.
$ORIGIN 168.192.in-addr.arpa.
0.1                     PTR     myserver.mylan.local
0.99                    PTR     router.schmidt.local
0.10                    PTR     printer.schmidt.local
2.2                     PTR     devserver.schmidt.local

Es empfiehlt sich, für die Details dieser Konfigurationen weitere Tutorials zu dem Thema zu lesen, z.B. http://www.linuxhomenetworking.com/wiki/index.php/Quick_HOWTO_:_Ch18_:_C... oder https://help.ubuntu.com/community/BIND9ServerHowto#Zone_File Zum Übernehmen der Änderungen ist noch ein Neustart des DNS-Servers nötig ~# /etc/init.d/bind9 restart Wenn die Zonen konfiguriert sind, kann man mit einem einfachen ping myserver die Namensauflösung testen. Sollten Probleme auftreten, ist es ratsam, der Sache mit dem Befehl dig myserver.mylan.local auf den Grund zu gehen. An dieser Stelle möchte ich noch einmal darauf hinweisen, dass mylan.local unbedingt als Domäne und damit als Suchpfad an die DHCP-Clients verteilt werden muss. Das kann man auf dem Client-PC in der Datei /etc/resolv.confüberprüfen.

3. Dynamischer DNS mit DHCP

Da wir jetzt schon statische Rechner im LAN adressieren können, wäre es jetzt eventuell auch noch wünschenswert, per DHCP konfigurierte Clients mit Namen zu kennen und zu erreichen. (Dieses Feature empfiehlt sich vor allem bei Druckern und anderen netzwerkfähigen Geräten, die oft nur eine umständliche Netzwerkkonfiguration erlauben. Besonders angenehm ist es aber beim schnellen Dateiaustausch zwischen zwei PCs, wenn ein Laptop spontan auf Besuch ist.) Dazu müssen wir dem DHCP-Server erlauben, die DNS-Datenbank zu erweitern, indem wir die allgemeine Konfiguration erweitern:

ddns-updates on;
ddns-update-style interim;
ignore client-updates;
include "/etc/bind/rndc.key";

Mit der Option ignore client-updates; verhindern wir lästige Fehlermeldungen im Syslog durch manche Windows-Clients. Der Schlüssel, der bei der Installation von bind9 an der Stelle /etc/bind/rndc.keyabgelegt wird, dient der einfachen Sicherung der Kommunikation zwischen den beiden Diensten. Der DHCP-Daemon muss Leserechte auf diese Datei besitzen. Gegebenenfalls müssen hier die Rechte im Filesystem und bei AppArmor angepasst werden. In der Regel sieht die Datei etwa so aus:

key "rndc-key" {
        algorithm hmac-md5;
        secret "someLongHashValue==";
};

Wichtig ist hier der Name rndc-key, unter dem wir nach dem Einfügen der Datei in die Konfiguration des Servers den Schlüssel referenzieren, denn jetzt müssen wir dem DHCP-Server noch die DNS-Zonen beibringen, die er aktualisieren soll. Dafür erweitern wir die DHCP-Konfiguration:

zone mylan.local. {
 primary 127.0.0.1;
 key rndc-key;
}
zone 168.192.in-addr.arpa. {
 primary 127.0.0.1;
 key rndc-key;
}

Hier verwenden wir die selben Zonennamen, wie bei der Konfiguration des DNS Servers, deklarieren den Primären DNS Server für die Zonen und den verwendeten Key (über dessen Namen). Damit der DNS-Server den Key ebenso kennt und verwendet, erweitern wir jetzt die Konfiguration des DNS-Servers. Zur Verwendung des Keys erweitern wir die globale named.conf, sodass sie ca. so aussieht:

include "/etc/bind/rndc.key";
include "/etc/bind/named.conf.options";
include "/etc/bind/named.conf.local";
include "/etc/bind/named.conf.default-zones";

Nun erlauben wir noch ein Update der DNS-Zonen in /etc/bind/named.conf.localund erweitern jede Zone extra um die Zeile

        allow-update { key "rndc-key"; };

Dadurch hat jeder, der den Schlüssel kennt, die Möglichkeit, die Einträge der DNS-Zone zu ändern - so auch unser DHCP Server. Nach einem Neustart des DNS-Servers und des DHCP-Servers wird letzterer dafür sorgen, dass wir auch über neue Clients im Netzwerk Bescheid wissen und sie per DNS erreichen können. Nachdem man einen neuen PC per DHCP eine Adresse zugewiesen hat, kann man diese Aktualisierung einfach testen. Mit dem Befehl named-journalprint können wir die Änderungen verfolgen. In unserem Beispiel also: ~# named-journalprint /var/lib/bind/db.mylan.local.jnl Die Journal-Dateien werden immer im selben Verzeichnis, wie die Zonen-Konfigurationen abgelegt und erhalten die Endung .jnl. Deshalb ist es wichtig, dass der DNS-Server Schreibrecht in dem Verzeichnis hat (was durch AppArmor im Verzeichnis /etc/bind/ verboten ist, aber extra in /var/lib/bind/deswegen erlaubt ist).

Bearbeiten der Einträge bei dynamischem DNS

Wenn wie hier beschrieben die DNS Datenbank dynamisch (mittels DHCP) erweitert wird, ist es nicht ratsam, die Datenbanken manuell zu editieren. Versucht man das, erhält man schnell einen Fehler beim Starten des DNS Servers, der die betroffene Zone vorübergehend deaktiviert. Um daher im laufenden Betrieb einen dynamischen DNS Server gibt es das Tool nsupdate. Da wir unseren Server gegen unbefugte Änderungen gesichert haben, müssen wir diesen Schlüssel auch bei manuellen Änderungen angeben. Für die lokale Administration mittels nsupdate gibt es allerdings bereits einen solchen Schlüssel, der automatisch verwendet wird, wenn wir nsupdate mit der Option -l (local) starten. Der lokale Schlüssel hört auf den Namen "local-ddns" und muss, wie bei der Konfiguration der DHCP Updates, pro Zone freigeschaltet werden. Die Zonenkonfiguration in /etc/bind/named.conf.localsieht daher etwa so aus:

zone "168.192.in-addr.arpa" {
        type master;
        file "/var/lib/bind/db.192.168";
        allow-update { key "rndc-key"; key "local-ddns";};
};

Letztendlich sollte man lieber auf TCP als Protokoll vertrauen (-v), daher rufen wir nsupdate folgendermaßen auf:

nsupdate -v -l

Es erscheint ein Prompt und wir können beginnen den Server zu konfigurieren. Für den Fall, dass nsupdate nicht mit der Option -l gestartet wurde, müssen wir jetzt den Server explizit anzugeben, daher beginnen wir mit server localhost Angenommen, wir wollen jetzt den Host "newhost" mit der IP-Adresse "192.168.1.2" hinzufügen, gehen wir folgendermaßen vor: prereq nxdomain newhost.mylan.local Damit stellen wir sicher, dass der Eintrag noch nicht existiert. update add newhost.mylan.local 86400 A 192.168.1.2 Wir wollen also einen A-Record für den gegebenen Host erstellen. 86400 gibt hierbei die TimeToLive an. Für den Reverse-Lookup müssen wir noch den PTR-Record angeben: update add 2.1.168.192.in-addr.arpa 86400 PTR newhost.mylan.local Wenn alle Änderungen eingetragen sind, schicken wir das ganze mit send an den Server. Bei Problemen lohnt es sich, die Logfiles unter /var/log/daemon.log zu konsultieren, oder bei einer Wiederholung des Vorgangs mit debug weitere Informationen zu erhalten. Über weitere Parameter, Kommandos und vor allem Bedingungen (prereq) geben die man-pages Auskunft.

Weiterführende Links und Quellen

Disclaimer und Haftungsausschluss

Bei dieser Anleitung handelt es sich eher um einen gefilterten, aufbereiteten Bericht meiner persönlichen Erfahrung, als um ein vollständiges technisches Benutzerhandbuch. Ich kann daher keine Garantie auf die Vollständigkeit und Korrektheit abgeben und übernehme auch keine Haftung für eventuell auftretende Schäden. Sollte jemand Fehler beliebiger Art in diesem Artikel finden, bitte ich um eine kurze Nachricht und ich werde die Korrektur einarbeiten. Feedback ist jederzeit willkommen. Ich behalte mir jedoch vor, unqualifizierte Kommentare ohne Angabe von Gründen zu löschen.