DynDNS

Update April 2015:

Vor ein paar Monaten habe ich mich dieser (Dyn)DNS Problematik mal angenommen. Ich wollte einfach eine Lösung die für ein paar Jahre funktioniert, und an der ich nicht mehr rum basteln muss. Ich habe mir Alternativen zu Bind angeschaut und mich am Ende für PowerDNS entschieden (die andere Alternative wäre djbdns gewesen). Ein Grund PowerDNS zu nehmen, war das unter den Backends (also der Teil in dem die DNS Daten liegen – zonefiles bei Bind) auch MySQL war. Die Idee meine DNS Daten in einer Tabelle zu haben gefiel mir. Das ist sicherlich nicht so toll wenn man das letzte Quäntchen Performance raus kitzeln will, aber für meine paar Domains wird’s da kein Engpass geben.

Ich habe zwei DNS Server aufgesetzt (in verschiedenen IP Bereichen) damit ich auch DE Domains verwalten kann (DENIC will das so – ist ja auch vernünftig) Zuerst hatte ich versucht die MySQL Server zu synchronisieren, das geht schon Grundsätzlich, aber verschlüsselt hab ich es letztlich nicht hinbekommen irgendwas wollte da immer nicht. Und eine VPN zwischen den Servern nur um MySQL darüber zu synchronisieren hielt ich für übertrieben.

Die Synchronisation läuft jetzt über Zonetransfers ab, zwar unverschlüsselt, aber mit Secrets abgesichert, im Grunde als ähnlich wie bei Bind.

Der DynDNS Part war jetzt aber deutlich schöner zu realisieren. Ein kleines PHP Skript das mit der FritzBox spricht und dann in der MySQL Datenbank die Einträge updated. Die DynDNS Accounts sind statisch in der Datei eingetragen, man könnte die auch in eine Tabelle schreiben, aber ich wollte das Skript schon einfach halten (vielleicht kommen die Accounts noch irgendwann in die Datenbank). Das Skript erzeugt auch eine Logdatei, die benutze ich unteranderem dazu per Shellscript zu schauen wie alt die DynDNS Records sind. So kann ich in meinem Nagios checken ob sich eine der Boxen zu lange nicht gemeldet hat.

Das ganze läuft jetzt für mich und ein paar Freunde und Bekannte seit ein paar Monaten ohne irgendwelche Probleme. Naja jetzt wo ich noch mal drüber geschaut hab, ist halt in einer halben Stunde zusammen geschrieben worden, könnte man noch etwas verschönern.

Das PHP Skript

<?php
// call : https://<dnsserver_url>/dyndns.php?ipaddr=<ipaddr>&username=<username>&password=<pass>&domain=<domain>&ip6addr=<ip6addr>
$accounts[] = array("user"=>"name_des_users", "pass"=>"passwort_des_users", "host"=>"fqdn_des_dyndns_records");
$fp = fopen("/var/log/dyndns.log", "a");
fwrite($fp, "\n[".time()." - ".date('M d H:i:s Y') ."] ". $_SERVER['REMOTE_ADDR']. " called DynDns with " .$_SERVER['REQUEST_URI'] . " by " . $_SERVER['HTTP_USER_AGENT'] );
// find account
$account = NULL;
foreach( $accounts AS $acc ){
  if( isset($_REQUEST['username']) && isset($_REQUEST['domain']) && strcasecmp($acc['user'],$_REQUEST['username'])==0 && strcasecmp($acc['host'],$_REQUEST['domain'])==0 ) $account = $acc;
}
if( count($account)==NULL ){
  fwrite($fp, "\n[".time()." - ".date('M d H:i:s Y') ."] ". $_SERVER['REMOTE_ADDR']. " Username and/or Domain not found. Quit here." );
  fclose($fp);
  die("badauth");
}
fwrite($fp, "\n[".time()." - ".date('M d H:i:s Y') ."] ". $_SERVER['REMOTE_ADDR']. " Account found." );
// check password
if( !isset($_REQUEST['password']) || strcmp($account['pass'],$_REQUEST['password'])!=0 ){
  fwrite($fp, "\n[".time()." - ".date('M d H:i:s Y') ."] ". $_SERVER['REMOTE_ADDR']. " Password wrong. Quit here." );
  fclose($fp);
  die("badauth");
}
fwrite($fp, "\n[".time()." - ".date('M d H:i:s Y') ."] ". $_SERVER['REMOTE_ADDR']. " Auth successful." );
// check if ip overgiven
// TODO: if ip/ipv6 not given, delete the entries from database
if( !isset($_REQUEST['ipaddr']) && !isset($_REQUEST['ip6addr']) ){
  fwrite($fp, "\n[".time()." - ".date('M d H:i:s Y') ."] ". $_SERVER['REMOTE_ADDR']. " No ip given. Quit here." );
  fclose($fp);
  die("noip");
}
// mysql connect
$mysqli = new mysqli("localhost", "pdns", "<mysql_pdns_user_password>", "pdns");
if ($mysqli->connect_errno) {
  fwrite($fp, "\n[".time()." - ".date('M d H:i:s Y') ."] ". $_SERVER['REMOTE_ADDR']. " MySQL server connect failed. Quit here. " . $mysqli->connect_error );
  fclose($fp);
  $mysqli->close();
  die('Error');
}
// ipv6
if( isset($_REQUEST['ip6addr']) ){
  if( filter_var($_REQUEST['ip6addr'], FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) ){
    $ip = $_REQUEST['ip6addr'];
    $rs = $mysqli->query("SELECT id, content FROM records WHERE name = '".$account['host']."' AND type = 'AAAA';");
    // soa updaten (serial+1)
    $rs_soa = $mysqli->query("SELECT id, content, domain_id FROM records WHERE name = 'dayz.net' AND type = 'SOA';");
    $row_soa = $rs_soa->fetch_assoc();
    $ser = preg_replace("/.*dayz\.net\.[ ]([0-9]*)[ ].*/", "$1", $row_soa['content']);
    $content = preg_replace("/(.*dayz\.net\.[ ])[0-9]*([ ].*)/", "$1###$2", $row_soa['content']);
    $content = str_replace( "###", ($ser+1), $content );
    if( $rs->num_rows==0){
      // create entry
      $sql = "INSERT INTO records ( domain_id, name, type, content, ttl, auth) VALUES ( ".$row_soa['domain_id'].", '".$account['host']."', 'AAAA', '".$ip."', 60, 1 );";
      $mysqli->query( $sql );
      $mysqli->query("UPDATE records SET content = '".$content."' WHERE id = ".$row_soa['id'].";");
      fwrite($fp, "\n[".time()." - ".date('M d H:i:s Y') ."] ". $_SERVER['REMOTE_ADDR']. " Record (Host) not found, created ip v6 record." );
    }else{
      $row_a = $rs->fetch_assoc();
      if( strcasecmp($row_a['content'],$ip)==0 ){
        fwrite($fp, "\n[".time()." - ".date('M d H:i:s Y') ."] ". $_SERVER['REMOTE_ADDR']. " Ip v6 not changed. Skipping." );
      }else{
        // update
        $mysqli->query("UPDATE records SET content = '".$ip."' WHERE id = ".$row_a['id'].";" );
        $mysqli->query("UPDATE records SET content = '".$content."' WHERE id = ".$row_soa['id'].";");
        fwrite($fp, "\n[".time()." - ".date('M d H:i:s Y') ."] ". $_SERVER['REMOTE_ADDR']. " Ip v6 updated." );
      }
    }
  }else{
    fwrite($fp, "\n[".time()." - ".date('M d H:i:s Y') ."] ". $_SERVER['REMOTE_ADDR']. " Ip v6 address not valid. Skipping." );
  }
}else{
  fwrite($fp, "\n[".time()." - ".date('M d H:i:s Y') ."] ". $_SERVER['REMOTE_ADDR']. " No Ip v6 address found. Skipping." );
}
// ipv4
if( isset($_REQUEST['ipaddr']) ){
  if( filter_var($_REQUEST['ipaddr'], FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) ){
    $ip = $_REQUEST['ipaddr'];
    $rs = $mysqli->query("SELECT id, content FROM records WHERE name = '".$account['host']."' AND type = 'A';");
    // soa updaten (serial+1)
    $rs_soa = $mysqli->query("SELECT id, content, domain_id FROM records WHERE name = 'dayz.net' AND type = 'SOA';");
    $row_soa = $rs_soa->fetch_assoc();
    $ser = preg_replace("/.*dayz\.net\.[ ]([0-9]*)[ ].*/", "$1", $row_soa['content']);
    $content = preg_replace("/(.*dayz\.net\.[ ])[0-9]*([ ].*)/", "$1###$2", $row_soa['content']);
    $content = str_replace( "###", ($ser+1), $content );
    if( $rs->num_rows==0){
      // create entry
      $mysqli->query("INSERT INTO records ( domain_id, name, type, content, ttl, auth) VALUES ( ".$row_soa['domain_id'].", '".$account['host']."', 'A', '".$ip."', 60, 1 );");
      $mysqli->query("UPDATE records SET content = '".$content."' WHERE id = ".$row_soa['id'].";");
      fwrite($fp, "\n[".time()." - ".date('M d H:i:s Y') ."] ". $_SERVER['REMOTE_ADDR']. " Record (Host) not found, created ip v4 record." );
    }else{
      $row_a = $rs->fetch_assoc();
      if( strcasecmp($row_a['content'],$ip)==0 ){
        fwrite($fp, "\n[".time()." - ".date('M d H:i:s Y') ."] ". $_SERVER['REMOTE_ADDR']. " Ip v4 not changed. Skipping." );
      }else{
        // update
        $mysqli->query("UPDATE records SET content = '".$ip."' WHERE id = ".$row_a['id'].";" );
        $mysqli->query("UPDATE records SET content = '".$content."' WHERE id = ".$row_soa['id'].";");
        fwrite($fp, "\n[".time()." - ".date('M d H:i:s Y') ."] ". $_SERVER['REMOTE_ADDR']. " Ip v4 updated." );
      }
    }
  }else{
    fwrite($fp, "\n[".time()." - ".date('M d H:i:s Y') ."] ". $_SERVER['REMOTE_ADDR']. " Ip v4 address not valid. Skipping." );
  }
}else{
  fwrite($fp, "\n[".time()." - ".date('M d H:i:s Y') ."] ". $_SERVER['REMOTE_ADDR']. " No Ip v4 address found. Skipping." );
}
$mysqli->close();
fwrite($fp, "\n[".time()." - ".date('M d H:i:s Y') ."] ".$_SERVER['REMOTE_ADDR'] ." host ".$account['host']." done." );
fclose($fp);
echo "good ".$ip;
?> 

Das Shell-Skript für Nagios

#!/bin/bash

case $1 in
  --help | -h )
    echo "Usage: check_dyndns_age [hostname] [warn] [crit]"
    echo " [warn] and [crit] are max age in days"
    echo " Example: check_dyndns_age flybox.dayz.net 2 5"
    exit 3
  ;;
    * )
  ;;
esac

if [ ! "$1" -o ! "$2" -o ! "$3" ]; then
  echo "Usage: check_dyndns_age [hostname] [warn] [crit]"
  echo " [warn] and [crit] are max age in days"
  echo " Example: check_dyndns_age flybox.dayz.net 2 5"
  echo " Unknown: Options missing"
  exit 3
fi

warn=`echo $(($2*24))`
crit=`echo $(($3*24))`
if [ "$warn" -gt "$crit" -o "$warn" -eq "$crit" ]; then
  echo "Unknown: [crit] must be larger than [warn]"
  exit 3
fi

lastupdate=`grep "host $1 done" /var/log/dyndns.log | tail -n1 | sed 's/\[\([0-9]*\).*/\1/'`

if [ ! "$lastupdate" ]; then
  echo "Hostname $1 not found in DynDNS Database."
  exit 2
fi

now=$(date +%s)
age_in_minutes=`echo $((($now-$lastupdate)/60))`
if [ $age_in_minutes -lt 60 ]; then
  age_in_hours=1
  message="DynDNS record for host '$1' is $age_in_minutes minutes old.| $1="$age_in_hours";$warn;$crit;0;0"
else
  age_in_hours=`echo $((($age_in_minutes)/60))`
  message="DynDNS record for host '$1' is $age_in_hours hours old.| $1="$age_in_hours";$warn;$crit;0;0"
fi

if [ "$age_in_hours" -lt "$warn" -o "$age_in_hours" -eq "$warn" ]; then
  echo "OK. $message";
  exit 0
elif [ "$age_in_hours" -gt "$warn" -a "$age_in_hours" -lt "$crit" ]; then
  echo "Warning. $message";
  exit 1
elif [ "$age_in_hours" -gt "$crit" -o "$age_in_hours" -eq "$crit" ]; then
  echo "Critical. $message";
  exit 2
else
  echo "Unknown: should never happend."
  exit 3
fi 

 

Alles ab hier ist älter und nicht mehr aktuell!

Einleitung

Wer DynDNS (ge)braucht wird wissen was es ist, also spar ich mir den Erklär-Bär-Teil diesmal.

Für Fritz!OS 05.50 braucht man das nicht mehr so kompliziert zu machen, da geht es einfacher, ein passendes Skript steht weiter unten bei den Updates.

Dies ist mein zweiter Versuch einen DynDNS Service zu bauen. Als erstes hatte ich versucht einen Webservice zu bauen und dann bei meinem Router, einer FritzBox, diesen als DynDNS einzutragen. Serverseitig klappte alles super, aber meine FritzBox machte scheinbar immer nur ein Update, beim zweiten Update gab es einen Fehler und dann versuchte es die FritzBox nicht weiter.

Also hab‘ ich eine andere Möglichkeit gesucht und gefunden. Folgendes braucht man:

  • Fritzbox mit aktivierter Fernwartung.
  • Eine feste IPv6 Adresse an der FirtzBox (zum Beispiel per IPv6 Tunnel bei z.B. SixXS)
  • Einen Server im Internet der:
    • eine (feste) IPv6 Adresse hat.
    • Cronjobs bietet.
    • PHP installiert hat.
    • (Bind) nsupdate binaries installiert hat.
    • host (nstools) installiert hat.
    • Bind Nameserver mit delegierter (Sub)Domain und aktiviertem Update per Authkey (optional als dedizierter Server).

Und so gehts:

Mein Internet Server führt per Cronjob regelmässig ein PHP-Skript aus. Das PHP-Skript baut über IPv6 eine Verbindung zur FirtzBox auf. Die IPv6 Adresse der FirtzBox ist fest da sie das Ende eines IPv6 Tunnels ist. Dann loggt sich das Script erst per HTTP Auth ein, um die Loginseite der FirtzBox zu bekommen, übernimmt die SessionID aus der Loginseite, baut aus der SessionID und dem Passwort per MD5 das POST-Loginfeld. Damit loggt sich das Skript ein und holt die Indexseite der FirtzBox auf der auch die aktuelle IPv4 steht. Dann parst das Skript die IPv4 Adresse und schaut per nslookup nach ob sich die IPv4 verändert hat. Wenn sich die IPv4 geändert hat, baut das Skript ein nsupdate-Skript mit dem AuthKey und updated den Nameserver per nsupdate. Der Nameserver kann auch auf einem anderem Server laufen, solange man die per nsupdate aktualisieren kann.

Fritzbox

Ich hab‘ meinen IPv6 Tunnel von SixXS, weil es den kostenlos gibt und die FritzBox dafür schon ein Profil hat. Bei SixXS als neuer User anmelden, NIC-Handle beantragen, dann ein paar Stunden bis zur Freischaltung warten. Dann einen IPv6 Tunnel beantragen, auch hier wieder warten (bei mir 1 Tag) dann ist bekommt man das Passwort für den Tunnel. Dann noch die Fernwartung aktivieren.

(Name)Server im Internet

Für den Internetserver eine IPv6 besorgen, entweder vom Provider und wenn der nicht will/kann müsst ihr hier wohl auch einen Tunnel einrichten. Bind als Nameserver installieren, am besten gleich in einer change-root-umgebung. Eine Domain als Primary-Zone einrichten, hier reicht auch eine Subdomain und Update per AuthKey konfigurieren. Es kann auch nur ein einzelner Host als updateberechtigt konfiguriert werden.

Alle Parameter ins PHP-Skript eintragen. Cronjob fürs PHP-Skrit einrichten und gegebenenfalls noch ein Logfile anlegen. Bei mir läuft das Skript alle 5 Minuten und ich hab‘ die Meldung bei unveränderter IP rausgenommen. Läuft seit Ende Februar 2012 ohne Probleme sauber durch.

Und hier mein nsupdate.php Skript:

<?php
/* ******************************************************
*                                                      *
*   IPv4 Abfrage ueber IPv6 via FritzBox Fernwartung   *
*                                                      *
* **************************************************** */

// parameter und passwoerter

$fb_ipv6 = "[2001:xxxx:xxxx:xxxx::]";                                   // IPv6 (Fest da Tunnelende)
$fb_fp = "450";                                                         // Fernwartungsport
$fb_htuser = "xxxxxx";                                                  // HTTP basic access authentication USERNAME
$fb_htpass = "xxxxxxx";                                                 // HTTP basic access authentication PASSWORT
$fb_pass = "xxxxxxx";                                                   // Fernwartungspasswort
$fb_url = 'https://'.$fb_ipv6.':'.$fb_fp;                               // URL der Fernwartung der FritzBox
$dyndns_hostname = "host.example.net";                                  // DynDNS Hostname
$nsupdatekey = "xxxxxxxxxxxxxxxxxx";                                    // Bind NSUPDATE KEY
$logzeile = "nsupdate.php script - - [".date("d/M/o:H:i:s O")."] ";     // Logzeilenanfang

// HTTP basic access authentication & SessionID holen

$fb_curl = curl_init($fb_url.'/cgi-bin/webcm?getpage=../html/login_sid.xml');
curl_setopt($fb_curl, CURLOPT_SSL_VERIFYPEER, false);                          // selbst signiertes zertifikat akzeptieren
curl_setopt($fb_curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($fb_curl, CURLOPT_USERPWD, $fb_htuser.':'.$fb_htpass);             // HTTP basic access authentication
$login = curl_exec($fb_curl);
$session_status_simplexml = simplexml_load_string($login);

// In FritzBox einloggen

$challenge = $session_status_simplexml->Challenge;
$response = $challenge . '-' . md5(mb_convert_encoding($challenge . '-' . $fb_pass, "UCS-2LE", "UTF-8"));               // md5(pw)
curl_setopt($fb_curl, CURLOPT_POSTFIELDS, "login:command/response={$response}&getpage=../html/de/menus/menu2.html");    // post login
preg_match('/name="sid" value="([0-9a-f]*)"/', curl_exec($fb_curl), $matches); // sid parsen
if(isset($matches[1]) && $matches[1] != '0000000000000000'){
$SID = $matches[1];
}else{
echo $logzeile."failed. login not successful.\n";
die();
}

// Fernwartungsindexseite holen

curl_setopt($fb_curl, CURLOPT_URL, $fb_url.'/home/home.lua?sid='.$SID);        // URL der indexseite
curl_setopt($fb_curl, CURLOPT_POSTFIELDS, "&getpage=../html/de/menus/menu2.html");      // Login command entfernen
$indexpage = curl_exec($fb_curl);                                              // Indexseite holen
curl_close($fb_curl);                                                          // Verbindung zur FritzBox schliessen

// IPv4 aus der Fernwartungsindexseite parsen (Erg: $ip[0])

preg_match('((?:\d{1,3}\.){3}\d{1,3})i', strip_tags($indexpage), $ip);

// Bind Nameserver nach DynDNS Hostname abfragen

$oldip = rtrim(`/usr/bin/dig $dyndns_hostname A +short @127.0.0.1 | /usr/bin/tail -1`);
if($oldip AND !preg_match('((?:\d{1,3}\.){3}\d{1,3})i', $oldip, $hit)){        // nicht Leer aber keine IP also Fehler beim Abfrage
echo $logzeile."failed. Nameserver didnt return a IP (maybe down).\n";
die();
}

// Checken ob die IP sich geaendert hat

if($oldip==$ip[0]){
echo $logzeile."ok. ip not changed.\n";
die();
}

// NSUPDATE-Skript vorbereiten

$updateskript="server 127.0.0.1\nupdate delete ".$dyndns_hostname."\nupdate add ".$dyndns_hostname.". 60 A ".$ip[0]."\nsend\nquit";

// NSUPDATE durchfuehren

$nsupdate = popen('/usr/bin/nsupdate -y nsupdate_key:'.$nsupdatekey, 'w');
fwrite($nsupdate, $updateskript);
pclose($nsupdate);
echo $logzeile."ok. ip changed. dnydnshost updated to its new ip (".$ip[0].")\n";       // msg ausgeben

?>

Update 25. Juli 2012

Das Skript läuft bei mir jetzt seid Ende Februar 2012 es gab nur zwei Störungen. Bei beiden schien das Skript irgendwie hängen zu bleiben und dardurch stand der Cronjob der das Skripz alle 5 Minuten anstößt. Sollte es nochmal passieren, werd ich einen kleinen fix einbauen. Zum Beispiel erst zu checken ob noch ein alter Job läuft und den gegebenenfalls beenden. Sonnst gibst nicht viel zu berichten, läuft halt.

Update 19. August 2012

Weil sich das Skript doch alle paar Wochen mal hängen bleibt (ich vermute weil die Fritzbox nicht stabil genug läuft) hab ich eine kleine Erweiterung im crontab eingebaut, die dafür sorgt das das Skript notfalls abgebrochen wird. Hier der Auszug aus meiner crontab:

*/5 * * * * /usr/bin/timeout -k 120s 120s /usr/bin/php /usr/share/webapps/nsupdate.php >> /var/log/nsupdate.log 2>&1

Update 12. Oktober 2012

Das ‚timeout‘ Update hats scheinbar gebracht. Seit dem keine Zwischenfälle mehr, alles läuft so wie es soll. Damit ist es also ein Install&Forget Service ;)

Update 29. April 2013

Ich hab meine Box auf Fitz!OS 05.50 upgedated und seid der Version funktioniert das einloggen in die Fernwartung anders. Daher hier das neue Skript, netter Nebeneffekt, man braucht kein PHP mehr, ist jetzt nur noch ein Bashskript

#!/bin/sh
Host="[2001:.....:2]:450" # [ipv6]:port
Password="xxx"
Username="xxx"
CURL="/usr/bin/curl -gksm 20"
Host="https://${Host}"
DynDnsName="dyndns.hostname.de" # der dyndns hostname der aktualisiert werden soll
nsupdatekey="xxx"
datum=$(/bin/date +"%d/%b/%Y %H:%M:%S")
logzeile="nsupdate.sh script - - [${datum}] "

Login=$($CURL "${Host}/login_sid.lua")
SID=$(echo "${Login}" | sed -n "s|.*<SID>\([0-9a-f]\{16\}\)</SID>.*|\1|p")
Challenge=$(echo "${Login}" | sed -n "s|.*<Challenge>\([0-9a-f]\{8\}\)</Challenge>.*|\1|p")
Response=$(echo -n "${Challenge}-${Password}" | iconv -f utf-8 -t utf-16le | md5sum -b | sed "s| .*||g")
Login=$($CURL -d "response=${Challenge}-${Response}" -d "username=${Username}" "${Host}/login_sid.lua")
SID=$(echo "${Login}" | sed -n "s|.*<SID>\([0-9a-f]\{16\}\)</SID>.*|\1|p")
NewIPv4=$($CURL "${Host}/home/home.lua?sid=${SID}" | /bin/grep "IP-Adresse: " | /bin/sed -e "s/.*IP-Adresse: \([0-9]\{1,3\}\.[0$
OldIPv4=$(/usr/bin/dig ${DynDnsName} A +short @127.0.0.1 | /usr/bin/tail -1);

if [ "${NewIPv4}" = "${OldIPv4}" ] ;
then
    echo -n ${logzeile}"ok. ip not changed.\n"
else
    # NSUPDATE-Skript vorbereiten
    updateskript="server 127.0.0.1\nupdate delete ${DynDnsName}\nupdate add ${DynDnsName}. 60 A ${NewIPv4}\nsend\nquit";
    echo ${updateskript} | /usr/bin/nsupdate -y nsupdate_key:${nsupdatekey}
    echo -n ${logzeile}"ok. ip changed. dnydnshost updated to its new ip (${NewIPv4})\n"
fi

3 Gedanken zu „DynDNS

  1. Pingback: dynip client für powerdns (the simple way) **UPDATE** – opennerds

    1. Sebastian Beitragsautor

      das array in zeile 3 kann erweitert werden, also für jeden user einen eintrag.
      $accounts[] = array(„user1″=>“name_des_ersten_users“, „pass“=>“passwort_user_2“, „host“=>“fqdn_des_dyndns_records“);
      $accounts[] = array(„user2″=>“name_des_zweiten:users“, „pass“=>“passwort_user_1“, „host“=>“fqdn_des_dyndns_records“);
      usw

      Antworten

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.