debian | selbstgehosteter DynDNS-Dienst – der Client-Teil

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:
custom DynDNS in OpenWRT
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.

5 Gedanken zu „debian | selbstgehosteter DynDNS-Dienst – der Client-Teil

    1. controlc.de Beitragsautor

      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.

      Antworten
  1. Stefan

    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

    Antworten
    1. Stefan

      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.

      Antworten

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.