Einführung

Mit Dynamischem DNS (DDNS) kann man DNS Einträge zur Laufzeit verändern. So kann z. B. ein DHCP Server autoomatisch zu jedem DHCP Client ein DNS Eintrag erstellen. Ein anderer Anwendungszweck ist das bereitstellen eines DNS-Eintrags (z. B. A oder AAAA Records) für eine sich oft wechselnde IP-Adresse, damit diese immer unter dem selben Namen erreichbar ist. Bekannte Anbieter solcher Dynamischen DNS Services sind dyn.com oder noip.com. So einen Dienst kann man aber auch selber betreiben.

Voraussetzungen

Als Voraussetzung für diese Anleitung braucht man einen konfigurierten Bind Nameserver. In dieser Anleitung ist der DNS-Server zuständig für die Zone example.org. Bei mir läuft der Nameserver auf Debian 6.

Keys erstellen

Mit dnssec-keygen kann man sich einen Schlüssel erstellen, welcher später dazu dient, sich beim DNS Server zu authentifizieren:

$ /usr/sbin/dnssec-keygen -a HMAC-SHA512 -b 512 -n HOST foobar.example.org
Kfoobar.example.org.+157+12900

Nach dem Generieren der Schlüssel hat man zwei neue Dateien:

$ ls -l *example.org*
-rw------- 1 root root 123 May 22 14:37 Kfoobar.example.org.+157+12900.key
-rw------- 1 root root 229 May 22 14:37 Kfoobar.example.org.+157+12900.private

Der Key ist symmetrisch und daher in beiden Dateien der gleiche. Er ist base64 kodiert und könnte so aussehen:

$ cat Kfoobar.example.org.+157+51053.private
Algorithm: 157 (HMAC-SHA512)
Key: GFzIGlzdCBkZXIgZ2VoZWltZSBTY2hsw7xzc2VsLgpEZW5rc3RlIGljaCBwdWJsaXppZXJlIGRlbiBPcmlnaW5hbGtleSBoaWVyPwpWaWVsIFNwYXNzCg==
Bits: AAA=
Created: 20130522130759
Publish: 20130522130759
Activate: 20130522130759

Nameserver konfigurieren

Der generierte Schlüssel muss dem Nameserver hinterlegt werden. Wir definieren einen neuen Key, welcher in der Datei /etc/bind/named.keys abgelegt wird:

$ awk '/Key/{ print "key foobar.example.org {\n \
algorithm HMAC-SHA512;\n  secret \"", $2, "\";\n};"  }' \
Kfoobar.example.org.+157+12900.private | sudo tee -a /etc/bind/named.keys

Diese Datei darf natürlich nur vom User bind gelesen werden. Zudem benötigt dieser User Schreibberechtigungen auf dem Verzeichnis /etc/bind:

$ sudo chmod 600 /etc/bind/named.keys
$ sudo chown -R bind.bind /etc/bind

Die Datei /etc/bind/named.keys sieht dann so aus:

$ sudo cat /etc/bind/named.keys
key foobar.example.org {
algorithm HMAC-SHA512;
secret "GFzIGlzdCBkZXIgZ2VoZWltZSBTY2hsw7xzc2VsLgpEZW5rc3RlIGljaCBwdWJsaXppZXJlIGRlbiBPcmlnaW5hbGtleSBoaWVyPwpWaWVsIFNwYXNzCg==";
};

In dieser Datei können mehrere Keys gespeichert werden.

Damit Bind von den Keys kennt, fügen wir folgende Zeile vor den Zonendefinitionen in der Datei /etc/bind/named.conf.local ein:

include "/etc/bind/named.keys";

Berechtigungen für A Record

Damit jetzt dieser Key ein A Record verändern darf, fügt man die Option update-policy in der Zonendefinition ein:

zone "example.org" {
type master;
file "/etc/bind/db.example.org";
update-policy {
grant foobar.example.org name foobar.example.org A;
};
};

Somit darf der Key foobar.example.org den Eintrag A Record von foobar.example.org verändern.

Änderungen übernehmen

Zuletzt startet man den Nameserver neu und prüft das Logfile auf Fehlermeldungen:

$ sudo /etc/init.d/bind9 restart
$ sudo less /var/log/daemon.log

DNS Server dynamisch updaten

Das Keyfile mit der Endung .private kopiert man auf den Client in z.B. das /etc Verzeichnis. Der Key sollte nur für den User lesbar sein, welcher das Skript ausführt, damit nicht andere User auf dem System die DNS-Einträge ändern können.

Mit nsupdate kann man den DNS Server während der Laufzeit verändern. Die Verbindung zum DNS-Server wird wie folgt hergestellt:

$ nsupdate -k /etc/Kfoobar.example.org.+157+51053.private

So ändert man einen Eintrag:

server ns.example.org
zone example.org
update delete foobar.example.org
update add foobar.example.org 60 A 10.23.5.42
send

Diese Befehle fügt dem Nameserver ns.example.org in der Zone example.org einen neuen A Record mit dem Namen foobar.example.org hinzu. Die TTL ist 60 Minuten (1 Stunde) und die dazugehörige IP Adresse lautet 10.23.5.42.

Das kann man mit einem Skript automatisieren:

#!/usr/bin/env bash
#  
# ddns-updater - Update dynamic dns entries  
#

CONF=${1:-/etc/ddns-updater.conf}. $CONF

if [[ -z “$KEYFILE” || -z “$NAMESERVER” || -z “$ZONE” \  
|| -z “$HOSTNAME” || -z “$TTL” ]]  
then  
echo “Error loading configuration file $CONF”  
exit 1  
fi

IPADDR=${CUSTOMIP:-$(dig myip.opendns.com @resolver1.opendns.com +short)}IPADDROLD=$(dig $HOSTNAME @$NAMESERVER +short)
if [[ “$IPADDR” == “$IPADDROLD” ]]  
then  
exit  
fi

(  
echo "server $NAMESERVER"  
echo "zone $ZONE"  
echo "update delete $HOSTNAME"  
echo "update add $HOSTNAME $TTL A $IPADDR"  
echo "send"  
) | nsupdate -v -k $KEYFILE

Die dazugehörige Konfigurationsdatei sieht so aus:

#
# ddns-updater.conf
#

KEYFILE="/etc/Kfoobar.example.org.+157+51053.private"  
NAMESERVER="ns.example.org"  
ZONE="example.org"  
HOSTNAME="foobar.example.org"  
TTL="60"  
#CUSTOMIP="10.42.23.5"

Zuerst prüft das Skript, ob es mit einer mitgegebenen Konfigurationsdatei aufgerufen wurde. Sonst wird die Standardkonfiguration aus /etc/ddns-updater.conf geladen. Danach wird die öffentliche IP-Adresse von OpenDNS bezogen ( dig +short myip.opendns.com @resolver1.opendns.com, thx @Danilo). Falls sich die IP Adresse geändert hat, wird nsupdate gestartet und der A Record aktuallisiert. Dabei werden die in der Sektion Variables verwendete Angaben verwendet. Um selbst eine IP Adresse zu definieren kann man diese mit der Option CUSTOMIP setzen.

Das Skript ist auch in meinem Scripts-Repository auf GitHub zu finden: ddns-updater.

Automatisiert updaten

Die Keys kann man z. B. unter /usr/local/etc oder direkt unter /etc speichern und das Skript unter /usr/local/bin. Danach genügt folgender Crontab Eintrag, welcher den A Record alle 60 Minuten (immer 5 nach) auf den neusten Stand bringt:

5 * * * * /usr/local/bin/ddns-updater