Dynamisches DNS mit dem bind DNS server
Der bekannte DNS server bind
erlaubt Konfigurationen die es
ermöglichen, dass clients ihre DNS Einträge selbst verändern können.
Weil einige öffentliche dynamische DNS Services zu einem Bezahlmodell
gewechselt sind und weil ich sowieso meinen eigenen Mail- und Webserver
bei einem Hoster betreibe, suchte ich nach einer Möglichkeit, meinen
eigenen dynamischen DNS Server zu verwenden. Das liegt schon ein paar
Jahre zurück, aber weil das von mir damals verwendete Howto vom Netz
(oder zumindest aus meiner Google-Bubble) verschwunden ist, dokumentiere
ich hier wie ich das gemacht habe.
Die Software läuft bei mir unter Debian Buster zur Zeit dieses
Blog-Eintrags, die Details können sich also bei anderen Systemen ändern.
In den folgenden Beispielen nenne ich die Subdomain für die dynamischen
DNS Einträge dyn.example.com
.
Die Konfigurations-Datei von bind braucht ein zusätzliches include um
die Konfigurations-Datei für die dynamische Domain einzubinden. In
meiner Konfiguration heisst diese Datei named.conf.handedited
.
In dieser Datei braucht es einen Entrag für jeden dynamischen DNS Client
wie folgt:
zone "dyn.example.com" { type master; allow-transfer {none;}; file "/etc/bind/slave/pri.dyn.example.com"; update-policy { grant h1.dyn.example.com. name h1.dyn.example.com. A TXT; grant h2.dyn.example.com. name h2.dyn.example.com. A TXT; [...] }; };
In diesem Beispiel dürfen die Hosts h1
und h2
(und möglicherweise
weitere) ihre eigenen DNS Einträge ändern. Ich erlaube hier dass sie den
A
und TXT
Record ändern. Für IPv6 möchte man hier noch AAAA
dazugeben.
Die Konfigurations-Datei /etc/bind/slave/pri.dyn.example.com
enthält
dann:
dyn.example.com IN SOA ns1.example.com. admin.example.com. ( 2020080100 ; serial 120 ; refresh (2 minutes) 120 ; retry (2 minutes) 120 ; expire (2 minutes) 120 ; minimum (2 minutes) ) NS ns1.example.com. h1 A 127.0.0.1 KEY 512 3 10 ( AwEAAdEvnGmGO4ku+xms4w1c5RWh5BvugiZ4ty9tkIes <more gibberish lines> ); alg = RSASHA512 ; key id = <number>
Die Einträge in spitzen Klammern sind Kommentare und sollten durch die
korrekten Werte in der Zielinstallation ersetzt werden. Die Einträge
A
und KEY
werden von Hand für jeden neuen Host der seine eigene
IP-Adresse setzen können soll eingetragen. Der KEY
ist der
öffentliche Schlüssel (public key) der weiter unten erzeugt wird.
Nach meiner Erfahrung braucht es den A
-Eintrag damit das ganze
funktioniert. Ich setze hier eine localhost Adresse weil der Client
diese später sowieso überschreiben wird. Es ist üblich die Admin
Email-Adresse (wo @
durch einen Punkt ersetzt ist) im SOA-Eintrag an
die Stelle zu setzen wo ich admin.example.com.
eingetragen habe.
Um einen neuen Client Host anzulegen geht man wie folgt vor:
-
Erzeugen eines Schlüsselpaares (öffentlicher / privater Schlüssel, public/private key), bevorzugt passiert das beim Client und dieser sendet nur den öffentlichen Schlüssel an den DNS-Administrator um Sicherheitsprobleme bei der Schlüssel-Übermittlung zu vermeiden:
dnssec-keygen -T key -a RSASHA512 -b 2048 -n HOST newhost.dyn.example.com
Das erzeugt einen privaten und einen öffentlichen Schlüssel. Zu beachten: Der Client braucht beide Schlüssel, sowohl den öffentlichen als auch den privaten, obwohl nur der private Schlüssel dem dynamischen DNS Client übergeben wird!
Das letzte Mal als ich einen neuen Schlüssel erzeugt habe, konnte das Kommando keine Schlüssel mit mehr als 2048 bits erzeugen, obwohl der verwendete Hash-Algorithmus SHA2 modern ist und eine große Bitlänge unterstützt.
-
Damit bind seine Datenbank auf eine Datei schreibt (und man diese editieren darf) muss man bind für diese Domain einfrieren:
rndc freeze dyn.example.com
-
Jetzt darf man das Konfigurationsfile ändern und einen neuen Absatz für einen neuen Host eintragen. Nicht vergessen die
serial
Nummer zu erhöhen:$EDITOR /etc/bind/slave/pri.dyn.example.com
-
Dann nicht vergessen, die Domain wieder aufzutauen:
rndc unfreeze dyn.example.com
Und schließlich nicht vergessen, dem neuen Host die nötigen Berechtigungen in
named.conf.handedited
zu geben.-
Zuletzt muss man wohl dem bind ein
reload
geben:systemctl reload bind9.service
Auf der Client-Seite heisst das Programm um bind mitzuteilen dass sich
die IP-Adresse des Client geändert hat nsupdate
. Man findet diese
Programm für viele Betriebssysteme.
Ich verwende ein simples Script am Client das die Änderung der dynamischen IP Adresse bemerkt und eine Adressänderung bei bind anstößt wenn sich die IP Adresse geändert hat. Nachdem wir unseren eigenen DNS-Server betreiben sind die Chancen groß, dass es dort auch einen eigenen Webserver gibt. Das folgende einfache Script erlaubt es dem Client, seine eigene IP-Adresse rauszufinden (Clients sind oft hinter einer NAT Firewall und wir wollen ja nicht wieder auf ein anderes öffentliches Service angewiesen sein, wenn wir gerade öffentliche dynamische DNS Services losgeworden sind, oder?):
#!/bin/sh echo Content-Type: text/plain echo "" echo $REMOTE_ADDR
Dieses Script installiert man in ein cgi-bin
Verzeichnis auf einem
Webserver. Es liefert dem anfragenden Client seine eigene IP-Adresse (in
Text Format) zurück. Das script heisst bei mir ip.cgi
und ist dann
unter der URL http://example.com/cgi-bin/ip.cgi
in unserem Beispiel
verfügbar. Die URL muss dann unten im Client-Script geändert werden.
Mein bind Script (einige Variablen müssen geändert werden) schaut aus wie folgt (bitte beachten: Das Script geht davon aus dass obiges IP-Adressen Script auf der Domain example.com läuft, das muss natürlich auch geändert werden):
#!/bin/sh ZONE=dyn.example.com DOMAIN=h1.dyn.example.com DNSKEY=/etc/nsupdate/Kh1.dyn.example.com.+010+04711.private NS="ns1.example.com" registered=$(host $DOMAIN $NS 2> /dev/null | grep 'has address' | tail -n1 | cut -d' ' -f4) current=$(wget -q -O- http://example.com/cgi-bin/ip.cgi) [ -n "$current" \ -a "(" "$current" != "$registered" ")" \ ] && { nsupdate -d -v -k $DNSKEY << EOF server $NS zone $ZONE update delete $DOMAIN A update add $DOMAIN 60 A $current send EOF logger -t dyndns -p daemon.notice "Updated dyndns: $registered -> $current" } > /dev/null 2>&1 exit 0
Es sei nochmal darauf hingewiesen, dass der private Schlüssel (in obigem
Beispiel in /etc/nsupdate/Kh1.dyn.example.com.+010+04711.private
nicht ausreicht, das Programm nsupdate
braucht auch den
öffentlichen Schlüssel im selben Verzeichnis wie das des privaten
Schlüssels.