Ein eigener dynamischer DNS Dienst

Im heutigen Post möchte ich mich dem Thema widmen, wie man einen eigenen dynamsichen DNS-Dienst einrichtet. Was wird benötigt, um einen solchen Dienst aufsetzen zu können? Nun es wird ein Router benötigt, der eigene dynamische DNS Dienste unterstützt – wie z.B. die AVM Fritz!Box. Dazu wird noch ein Webspace mit PHP und MySQL sowie eine eigene Domain benötigt. Um sich dem Ganzen bewusst zu werden, was das hier eigentlich werden soll: Am Ende – nach der finalen Implementierung – soll eine Subdomain aufgerufen werden, welche wiederum eine Weiterleitung zu der eigenen IP-Adresse zu Hause liefert. Legen wir als Erstes die Datenbanken an. Für dies könnte folgendes Script verwendet werden, das über  phpmyadmin importiert werden kann.

SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
SET time_zone = "+00:00";

/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!40101 SET NAMES utf8 */;

CREATE TABLE IF NOT EXISTS `authentication` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `user` varchar(64) NOT NULL,
  `password` varchar(64) NOT NULL,
  `is_active` tinyint(4) NOT NULL DEFAULT '0',
  PRIMARY KEY (`id`),
  UNIQUE KEY `user` (`user`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1 AUTO_INCREMENT=4 ;

CREATE TABLE IF NOT EXISTS `dyndns` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `user` varchar(64) NOT NULL,
  `password` varchar(64) NOT NULL,
  `ip_addr` varchar(64) NOT NULL,
  `remote_addr` varchar(64) NOT NULL,
  `timestamp` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  UNIQUE KEY `user_ip` (`user`,`ip_addr`,`remote_addr`),
  UNIQUE KEY `only_user` (`user`),
  KEY `user_key` (`user`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1 AUTO_INCREMENT=3 ;

/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;

Nun da wir die Datenbank haben, können wir uns Gedanken über die eigentliche Script-Implementierung machen. Um die Implementierung angehen zu können, müssen wir unsere Domain / Subdomain auf ein Webspace leiten. Hier wird eine PHP-Scriptdatei erstellt, im Tutorial nutze ich einfach die Standard „index.php“. Der Inhalt dieses PHP-Scripts könnte wie folgt aussehen:

<?php
	$dbname = "dyndns";
	$connection = mysql_connect("localhost", "UnserBenutzer", "UnserPasswort");
	if (!$connection)
		die("Could not connect to database: " .mysql_error());
		
	$selectedDb = mysql_select_db($dbname, $connection);
	if (!$selectedDb)
		die("Could not use " .$dbname. ": " .mysql_error());
	
	if (isset($_REQUEST['user']) && strlen($_REQUEST['user']) > 0 && 
		isset($_REQUEST['pass']) && strlen($_REQUEST['pass']) > 0 && 
		isset($_REQUEST['ip']) && strlen($_REQUEST['ip']) > 0)
	{
		$query = "SELECT COUNT(id) AS entries 
				  FROM authentication 
				  WHERE authentication.user = '" .mysql_real_escape_string($_REQUEST['user']). "' 
				  AND authentication.password = '" .mysql_real_escape_string(md5($_REQUEST['pass'])). "'";
				  
		$response = mysql_query($query);
		$entries = 0;
		while ($row = mysql_fetch_array($response)) {
			$entries += $row['entries'];
		}
		
		if ($entries > 0) {
			$query = "INSERT INTO dyndns (user, password, ip_addr, remote_addr) 
					  VALUES('" .mysql_real_escape_string($_REQUEST['user']). "', 
							 '" .mysql_real_escape_string(md5($_REQUEST['pass'])). "', 
							 '" .mysql_real_escape_string($_REQUEST['ip']). "', 
							 '" .mysql_real_escape_string($_SERVER['REMOTE_ADDR']). "') 
					  ON DUPLICATE KEY UPDATE user=VALUES(user), password=VALUES(password), 
							 ip_addr=VALUES(ip_addr), remote_addr=VALUES(remote_addr)";
					
			mysql_query($query);
			echo 'success';
		}
	}
	else 
	{
		if (isset($_REQUEST['user']) && strlen($_REQUEST['user']) > 0) {
			$query = "SELECT ip_addr AS ip 
					  FROM  dyndns 
					  LEFT OUTER JOIN authentication AS auth ON auth.user = dyndns.user 
					  WHERE auth.user = '" .mysql_real_escape_string($_REQUEST['user']). "'
					  LIMIT 0,1";
		} else {
			$query = "SELECT ip_addr AS ip 
					  FROM dyndns 
					  LEFT OUTER JOIN authentication AS auth ON auth.user = dyndns.user 
					  WHERE auth.is_active = 1
					  LIMIT 0,1";
		}
				  
		$response = mysql_query($query);
		while ($row = mysql_fetch_array($response)) {
			header('Location: https://' .$row['ip']);
			break;
		}
		
		echo 'Kein aktiver DynDNS Eintrag existiert!';
	}
?>

Hier wird eine Datei für Beides verwendet. Werden die Parameter „user“, „pass“ und „ip“ gesetzt – und wenn diese Informationen korrekt sind – wird die Einstellung in der Datenbank geschrieben. Werden diese Parameter nicht übergeben oder nur der Parameter „user“ wird eine Weiterleitung ausgeführt. So ist dieses System für multiple Weiterleitungen ausgelegt. In der Datenbanktabelle „authentication“ müssen nun die Benutzer angelegt werden. Für den Passwort-Hash können verschiedene MD5 Generatoren, welche über Google schnell gefunden werden, genutzt werden. Nun bleibt noch die Frage offen, wie das ganze im Router eingerichtet wird. Direkt als Hinweis: Dieser Blog Post bezieht sich auf AVM Fritz!Box Geräte mit aktueller Firmware. Hier ist die Einstellung in der Erweiterten Ansicht unter Internet / Freigaben / Dynamic DNS zu finden. Nach fertiger Konfiguration sollte dies z.B. wie folgt aussehen:

FritzBox-DynDnsAber welche Werte befinden sich hier wirklich? Nun hier haben wir unter Dynamic DNS-Anbieter die Auswahl auf „Benutzerdefiniert“. Anschließend müssen wir die Update-URL angeben. Diese muss auf unser PHP-Script zeigen und die Parameter „user“, „pass“ und „ip“ mitgeben. Für „ip“ wird hier als Parameter „<ipaddr>“ (mit den <>, ohne die „“) verwendet. So wird von der Fritz!Box automatisch der Parameter für die aktuelle IP-Adresse ersetzt. Alternativ kann diese natürlich auf PHP-Script Seiten mittels $_SERVER[‚REMOTE_ADDR‘] abgerufen werden, wenn ein Script diese Daten verändern möchte.

Ich verwende hier Benutzer und Passwort in der URL weil ich verschiedene Benutzer und mehrere IP-Adressen auf meinem dynamischen DNS Dienst verwenden möchte. Natürlich kann auch die Standard HTTP-Authentifizierung über .htaccess / .htpasswd Dateien verwendet werden. Wenn dies der Fall ist müssen diese Informationen in den Feldern „Benutzername“ und „Kennwort“. Im Feld „Domainname“ wird der Name der Domain angegeben, über welchen unser dynamischer DNS Dienst läuft.

Aber wie die endgültige Implementierung erfolgt, bleibt natürlich jedem selbst überlassen. Sollte dies über die HTTP-Authentifizierung erfolgen macht es Sinn, zwei getrennte Dateien zu nutzen, damit die „index.php“-Datei direkt die Weiterleitung übernehmen kann. Natürlich ist es auf diesem Wege auch möglich mehrere DNS-Daten zu erfassen.

Bei Fritz!Box Geräten ist es so, dass die IP-Adresse direkt nach jedem Erhalt einer neuen IP-Adresse dieses Script aufruft.