Dynamische DNS-Updates mit Bind

5 minute read

Manchmal habe ich ja komische Ideen von Dingen, die ich unbedingt brauche. Vor einiger Zeit schon hatte ich mir in den Kopf gesetzt mal unbedingt Dienste wie DynDNS abzulösen und das ganze selbst in die Hand zu nehmen.

Nun bin ich in der sehr komfortablen Situation, dass mein Hoster es mir ermöglicht fast alle Details des DNS zu ändern, so dass ich auch meine eigenen Nameserver eintragen kann. Nun bin ich kein Experte auf dem Gebiet der .eu-Regularien, weiß aber, dass für .de-Domains zwei Nameserver aus unterschiedlichen Class-C-Netzen notwendig sind. Das erhört die Hürde also noch ein wenig…

Aber wozu hat man Freunde, die genauso bekloppt sind und auch einen eigenen Server haben. So kann man das Problem dann sehr elegant mit der Master-Slave-Replikation von Bind lösen, aber dazu später mehr.

Zunächst einmal gilt es Bind zu installieren und die grundlegende Konfiguration vorzunehmen. Ich arbeite mit der Version 9.3.4, die zwar nicht brandaktuell ist, aber bei meiner Lieblingsdistribution zum Lieferumfang gehört.

apt-get install bind9 dnsutils

Nun wechseln wir in das Verzeichnis /etc/bind, um dort die entsprechenden Dateien anzulegen bzw. zu bearbeiten. Zunächst bearbeiten wir die named.conf.local. Eine Beispielconfiguration könnte wie folgt aussehen:

// // Do any local configuration here // // vi: ts=4 sw=4 // Consider adding the 1918 zones here, if they are not used in your // organization //include "/etc/bind/zones.rfc1918"; zone "schnuckelig.eu" { type master; notify no; file "/etc/bind/db.schnuckelig.eu"; };

Zeile 13 gibt an, dass wir für die Zone/Domain der Masterserver sind und sich die Details in der Datei /etc/bind/db.schnuckelig.eu befinden. Des weiteren verschicken wir keine Benachrichtigunten an sekundäre Nameserver (Zeile 12).

Da wir uneren Server automatsich aktualisieren wollen ist es sicher ratsam über Sicherheit ein wenig nachzudenken. Wir müssen, naja, wollen, ja den Zugriff beschränken. Das können wir über eine IP (blöd) oder anderweitige Authentifizierung machen.

Wir müssen uns nun für eines der Verschlüsselungsverfahren entscheiden, symmetrisch (TSIG) oder asymetrisch (SIG(0)). Beides hat vor und Nachteile, ich habe mich aber für die etwas aufwändigere, aber schnuckeligere Variante entschieden, also asymetrisch. Im LAN würde ich wegen der einfacheren Konfiguration wohl eher TSIG nehmen.

Den Schlüssel erstellen wir am einfachsten mit ```dnssec-keygen -a

-b -k -n HOST ``` , wobei der Schlüsselname der FQDN (vollständiger Domainname des Hosts) entsprechen muss. Ich möchte noch darauf hinweisen, dass die Generierung recht lange dauern kann. Im Zweifelsfall auf einen Rechner ausführen, der auch beschäftigt ist, damit ```/dev/random</code> mit genügend Entropie (Unordnung sehr vereinfacht gesagt) versorgt wird. Als Algorithmen stehen und RSAMD5, RSASHA1 und DSA zur Verfügung, wobei ich mich für RSASHA1 mit 1024 Bit entschieden habe. ```bash dnssec-keygen -a RSASHA1 -b 1024 -k -n HOST zuhause.schnuckelig.eu ``` Dadurch werden dann der private Schlüssel ```K++.private``` und der öffentliche Schlüssel K++.key</code> erzeugt. Jetzt müssen wir die Zonendatei erstellen und den öffentlichen Schlüssel dort eintragen. $ORIGIN . $TTL 600 schnuckelig.eu IN SOA ns.schnuckelig.eu. hostmaster.schnuckelig.eu. ( 200804111 ; serial 28800 ; refresh (8 hours) 7200 ; retry (2 hours) 2419200 ; expire (4 weeks) 86400 ; minimum (1 day) ) NS ns.schnuckelig.eu. NS ns.andere-domain.de. MX 10 mail1.schnuckelig.eu. MX 20 mail2.schnuckelig.eu. $ORIGIN schnuckelig.eu. $INCLUDE /etc/bind/Kzuhause.schnuckelig.eu+005+12345.key www A 123.456.789.1 Super, alles toll soweit, jetzt kann es ja losgehen. Noch nicht ganz. Wir müssen jetzt noch in der Zone eintragen wer hier überhaupt etwas aktualisieren darf und was. Es gibt dazu zum einen ```allow-update```, welches aber nur generellen Zugriff gewährt. Ich habe also keine weiteren Möglichkeiten der Rechtevergabe. Besser ist da schon ```update-policy```. Damit kann ich einzelnen Hosts die Rechte genau zuweisen, also nicht nur wer, sondern auch was. Unsere Zone sieht nun also wie folgt aus: // // Do any local configuration here // // vi: ts=4 sw=4 // Consider adding the 1918 zones here, if they are not used in your // organization //include "/etc/bind/zones.rfc1918"; zone "schnuckelig.eu" { type master; notify no; file "/etc/bind/db.schnuckelig.eu"; update-policy { grant zuhause.schnuckelig.eu. name zuhause.schnuckelig.eu. A TXT; } }; Somit kann nur der Rechner zu Hause den A- und TXT-Record aktualisieren. Was uns jetzt noch fehlt ist ein kleines Skript, welches das Update selbstständig durchführt. Kein Problem, das ganze sieht wie folgt aus: ```bash #!/bin/sh # ddns.sh # Update des DNS via nsupdate # Usage: ddns.sh TTL=3600 SERVER= HOSTNAME=zuhause.schnuckelig.eu KEYFILE=Kzuhause.schnuckelig.eu.+005+12345.key IP=$1 nsupdate -v -k $KEYFILE > /dev/null << EOF server $SERVER update delete $HOSTNAME A update add $HOSTNAME $TTL A $IP send EOF ``` Wobei der öffentliche und auch der private Schlüssel in demselben Verzeichnis liegen müssen. Aber wer möchte das schon immer manuell machen müssen. Eleganter wäre es ja dies direkt bei der Einwahl zu erledigen. Nichts leichter als das, mit dem richtigen Betriebssystem zumindest. Alle ausführbaren Dateien in ```/etc/ppp/ip-up.d/``` werden bei der Einwahl ausgeführt und erhalten eine Reihe von interessante Parametern. ```bash #!/bin/sh # # These variables are for the use of the scripts run by run-parts # PPP_IFACE="$1" # PPP_TTY="$2" # PPP_SPEED="$3" # PPP_LOCAL="$4" # PPP_REMOTE="$5" # PPP_IPPARAM="$6" TTL=3600 SERVER= HOSTNAME=zuhause.schnuckelig.eu KEYFILE=Kzuhause.schnuckelig.eu.+005+12345.key /usr/bin/logger -p info "Dynamic DNS update: $PPP_IFACE $PPP_TTY $PPP_LOCAL" nsupdate -d -k $KEYFILE <<-EOF server $SERVER update delete $HOSTNAME A update add $HOSTNAMNE $TTL A $PPP_LOCAL send EOF ``` So, damit wäre auch schon alles erledigt. Zumindest für unseren Teil, aber es fehlt ja noch der Abgleich mit dem secondary name server. Dazu bietet sich eine Master-Slave-Replikation an. Bei Bind muss man dazu den Incremental Zone Transfer (IXFR) einrichten. Das ist relativ einfach für den Master. Dort brauchen wir für die Zone schnuckelig.eu einfach nur notify explicit; also-notify { ; }; </blockcode> anzugeben und schon sind wir fertig. Es können natürlich auch mehrere Adressen angegeben werden. Auf der Slave-Seite ist die Konfiguration auch nicht weiter schwierig. Wir erstellen dazu auch eine analoge Zone mit den notwendigen Slave-Angaben. zone "schnuckelig.eu" { type slave; masters { ; }; allow-notify { ; }; allow-transfer { ; }; file "/etc/bind/db.schnuckelig.eu"; }; </blockcode> Noch mal eben beide Server durchstarten, glücklich sein und genießen :). Einige Punkte sind noch offen. Man könnte sich z. B. überlegen die dynamischen Einträge alle in eine eigene Subdomain zu verlegen und in der Hauptdomain nur per CNAME darauf zu verweisen. Des weiteren ist die Konfiguration sicher nicht die sicherste. Statt die IP-Adresse des Masters einzutragen könnte man TSIG, also dem symmetrischen Verfahren, benutzen. Auch sollte man sicher Optionen wie allow-recursion noch anpassen. Aber das beschreibe ich dann (vielleicht) mal in einem weiteren Beitrag...