Ich hatte es schon lange versprochen, es wurde auch schon per Kommentar eingefordert und doch bin ich bisher nicht dazu gekommen: Die Erklärung, wie man für einen selbstgehosteten DynDNS-Dienst den Client so konfiguriert, dass er seinen DNS-Eintrag dynamisch aktualisieren kann.
In der folgenden Erklärung gehe ich davon aus, dass der Server, wie in dem Artikel debian | selbstgehosteter DynDNS-Dienst beschrieben, konfiguriert und funktionsfähig ist. Denn dann können wir uns an den Client-Teil machen.
Wie immer gibt es verschiedene Wege eine Aktualisierung anzustossen. Ich möchte aufzeigen, wie man es via eines http-Aufrufes erledigen kann. Ausgangspunkt dafür ist bei mir ein OpenWRT-Router, in dessen DynDNS-Konfiguration ich auch selber einen Dienst mit einer eigenen URL konfigurieren kann. Dazu sind auf dem Server zwei Dinge notwendig: Einmal ein Webserver, der sich auf CGI-Skripte versteht (in meinem Fall ein Apache, der in der Default-Konfiguration bereits CGI-Skripte unterstützt) und als zweites ein Perl-Skript, welches ich bei Bahut gefunden habe und welches im Verzeichnis /usr/lib/cgi-bin abgelegt werden möchte.
#!/usr/bin/perl ## Use nsupdate to update a DDNS zone. ## (This could be done with the Net::DNS module. It ## would be more portable (Windows, etc.), but also ## more complicated. So I chose the nsupdate utility ## that comes with Bind instead.) # "mi\x40alma.ch", 2013 use strict; my $VERSION = 0.2; my $debug = 1; my $title = "DDNS update"; my $server = "localhost"; my $nsupdate = "/usr/bin/nsupdate -v -d"; use CGI qw(:standard); my $q = new CGI; my $CR = "\r\n"; print $q->header(), $q->start_html(-title => $title), $q->h1($title); if (param("debug")) { $debug = 1; }; my $host = param("host"); my $secret = param("secret"); my $ip = param("ip") || $ENV{"REMOTE_ADDR"}; my $time = localtime(time); foreach ($host, $secret, $ip) { s/[^A-Za-z0-9\.\/\+=]//g; # sanitize, just in case... unless (length($_)) { die "Missing or bad parameters. host='$host', secret='$secret', ip='$ip'\n"; } } my $commands = qq{ server $server update delete $host. update add $host. 60 A $ip update add $host. 60 TXT "Updated by $0 v. $VERSION, $time" send }; print $q->p("sending update commands to $nsupdate:"), $CR, $q->pre($commands), $CR; open( NSUPDATE, "| $nsupdate -y hmac-md5:$host:$secret" ) or die "Cannot open pipe to $nsupdate : $!\n"; print NSUPDATE $commands or die "Error writing to $nsupdate : $!\n"; close NSUPDATE or die "Error closing $nsupdate : $!\n"; print $q->p("Done:"), $CR; my @result = `host -t ANY $host`; foreach (@result) { print $q->pre($_), $CR; } if ($debug) { # also log received parameters my @lines; for my $key (param) { my @values = param($key); push @lines, "$key=" . join(", ", @values); } warn join("; ", @lines), "\n"; } print $q->end_html, $CR; __END__
Um jetzt den ersten Test zu machen, kann man auf dem Server direkt folgende Zeile ausführen:
/usr/lib/cgi-bin/update.cgi host=client1.dyndns.controlc.de secret=fR49NctF3h1a/BCqcMGyw ip=1.1.1.1
Bekommt man hier keine Fehlermeldung zu sehen, dann scheint das Update bereits funktioniert zu haben. Genauer kann man es von jedem beliebigen Rechner aus auf der Kommandozeile mit
host client1.dyndns.controlc.de
herausfinden, ob die IP-Adresse 1.1.1.1 angezeigt wird.
Jetzt kann man einen Schritt weiter gehen und versuchen über einen beliebigen Browser den DNS-Eintrag zu aktualisieren. Dazu gibt man einfach die URL ein:
http://dns-server.dyndns.controlc.de/cgi-bin/update.cgi?host=client1.dyndns.controlc.de&secret=fR49NctF3h1a/BCqcMGyw&ip=1.1.1.1
Es muß also der komplette DNS-Name, der vorher definierten „secret“-Eintrag und die aktuelle IP übergeben werden.
Diese Art der Aktualisierung kann dann auch genutzt werden, um einen OpenWRT-Router dazu zu überreden seine aktuelle öffentliche IP-Adresse in den DNS-Server einzutragen. Die OpenWRT-Einstellungen wie folgt aus:
Die einzugebende URL lautet dabei
http://dns-server.dyndns.controlc.de/cgi-bin/update.cgi?host=[DOMAIN]&secret=[PASSWORD]&ip=[IP]
Wobei die Einträge in den eckigen Klammern dynamisch ersetzt werden durch die Angaben in dem DynDNS-Dialog. Der Benutzername wird dabei nicht beachtet/genutzt, so dass es egal ist, was man dort reinschreibt.
Ich denke, damit ist geklärt, wie man seinen selbst gehostetet DynDNS-Dienst aktuell halten kann. Eine andere Methode wäre übrigens das Ausführen eines BASH-Scriptes mit Hilfe eines Cron-Jobs oder als post-up-Eintrag in der Datei /etc/network/interfaces usw.
wie kriegt man dieses update script mit ddclient zum laufen ?
Das oben aufgeführte Skript wird gar nicht vom Client aufgerufen, sondern liegt auf dem Server in einem vom Webserver genutzten Verzeichnis (damit der Client per HTTP/S darauf zugreifen kann). Ich kenne ddclient nicht und kann Dir deshalb keine vorgefertigte Lösung präsentieren, aber Du musst ddclient nur beibringen auf die gezeigte URL zuzugreifen und den entsprechenden Syntax für das Ausfüllen der Datenfelder an das von ddclient gewünschte Format anpassen.
Habe die Anleitung genau so gemacht wie Sie hier steht.
Bekomme aber im log folgendes angezeigt:
Aug 18 15:04:53 gerber-stefan named[22890]: client ::1#46840: request has invalid signature: TSIG home.dyndns.gerberstefan.de: tsig verify failure (BADKEY)
Desweiteren wenn ich das script ausführe bekomme ich diese Ausgabe zum Schluss:
root@gerber-stefan:/etc/bind# /usr/lib/cgi-bin/update.cgi host=home.dyndns.gerber-stefan.de secret=/Yj43R5khX4/5SPmLyTE== ip=1.1.1.1
…
could not find enclosing zone
Error closing /usr/bin/nsupdate -v -d :
root@gerber-stefan:/etc/bind#
Vielleicht hat ja einer eine Idee was falsch läuft
Habe den Fehler gefunden.
Wenn Ihr ein Sonderzeichen in der Domain habt so wie ich gerber-stefan.de Funktioniert das update script nicht. Ich habe einfach im Script die Zeile 41 auskommentiert:
# s/[^A-Za-z0-9\.\/\+=]//g;
Und schon Funktioniert alles.
Hallo Stefan,
Schön das Du das Problem für Dich lösen konntest und vielen Dank für den Hinweis!