Initial 2007 version
authorNico Kaiser <nico@kaiser.me>
Tue, 18 Jun 2013 12:59:11 +0000 (14:59 +0200)
committerNico Kaiser <nico.kaiser@boerse-go.de>
Tue, 18 Jun 2013 12:59:11 +0000 (14:59 +0200)
14 files changed:
README.txt [new file with mode: 0644]
TODO.txt [new file with mode: 0644]
conf/apache/Dyndns.conf [new file with mode: 0644]
conf/bind/Dyndns.conf.include [new file with mode: 0644]
conf/bind/keys/Kdyndns.example.com.+157+00000.key [new file with mode: 0644]
conf/bind/keys/Kdyndns.example.com.+157+00000.private [new file with mode: 0644]
conf/dyndns.hosts [new file with mode: 0644]
conf/dyndns.user [new file with mode: 0644]
htdocs/classes/Dyndns.class.php [new file with mode: 0644]
htdocs/classes/DyndnsHelper.class.php [new file with mode: 0644]
htdocs/classes/DyndnsHosts.class.php [new file with mode: 0644]
htdocs/classes/DyndnsUsers.class.php [new file with mode: 0644]
htdocs/config.php [new file with mode: 0644]
htdocs/index.php [new file with mode: 0644]

diff --git a/README.txt b/README.txt
new file mode 100644 (file)
index 0000000..c1ce6b4
--- /dev/null
@@ -0,0 +1,163 @@
+Introduction
+============
+
+This script takes the same parameters as the original members.dyndns.org 
+server does. It can update a BIND DNS server via "nsupdate".
+
+As it uses the same syntax as the original DynDNS.org servers do, a dynamic DNS server equipped with
+this script can be used with DynDNS compatible clients without having to modify anything on the
+client side.
+
+
+Installation
+============
+
+To mimic the original DynDNS.org behavior, the Script's URL must be
+
+       http://members.dyndns.org/nic/update
+
+You may have to adjust your own DNS configuration to make "members.dyndns.org" point to your own 
+Server and you Web Servers configuration to make "/nic/update" call the PHP script provided in this 
+package.
+
+
+Furthermore, to be able to dynamically update the BIND DNS server, DNS key must be generated with
+the command:
+
+       dnskeygen -n dyndns.example.com -H 512 -h
+
+(Where "dyndns.example.com" is the key name)
+The resulting key (look at the "Key:" line in the resulting Kdyndns.example.com.+157+00000.private)
+must be copied to both, the  config.php  file (along with the key name, see there for details), and 
+the BIND configuration (see below).
+
+
+The key has to be added to the BIND configuration (named.conf), as well as a DNS zone:
+
+
+key dyndns.example.com. {
+       algorithm HMAC-MD5;
+       secret "bvZ....K5A==";
+};
+
+zone "dyndns.example.com" {
+       type master;
+       file "dyndns.example.com.zone";
+       allow-update {
+               key dyndns.example.com.;
+       };
+};
+
+In this case, the zone is also called "dyndns.example.com". The (initial) dyndns.example.com.zone 
+file (located in BIND's cache directory) looks like this:
+
+$TTL 1h 
+@ IN SOA dyndns.example.com. root.example.com. (
+        2007111501      ; serial
+        1h              ; refresh
+        15m             ; retry
+        7d              ; expiration
+        1h              ; minimum
+        )  
+        NS <your dns server>
+
+Remember to change access rights so BIND is able to write to this file.
+
+
+PHP script configuration
+------------------------
+
+The PHP script is called by the DynDNS client, it validates the input and calls "nsupdate" to 
+finally update the DNS with the new data. Its configuration is rather simple, the user database is
+implemented as text file "dyndns.user" with each line containing
+
+       <user>:<password>
+
+Where <password> is crypt'ed like in Apache's htpasswd files. 
+Hosts are assigned to users in using the file  "dyndns.hosts":
+
+       <host>:<user>(,<user>,<user>,...)
+
+(So users can update multiple hosts, and a host can be updated by multiple users).
+
+
+The location of these files must be specified in  "config.php". For security reasons, don't place
+them in your Document root, otherwise every Web user can read them.
+
+
+
+Implementation
+==============
+
+Here you can find details on which capabilities of the DynDNS specification are implemented.
+
+Hostname: members.dyndns.org
+HTTP ports: 80, 8245
+HTTPS port: 443 (not supported!)
+
+
+Usage
+-----
+
+Authentication in URL:
+
+http://username:password@members.dyndns.org/nic/update?hostname=yourhostname&myip=ipaddress&wildcard=NOCHG&mx=NOCHG&backmx=NOCHG
+
+
+Raw HTTP GET Request:
+
+GET /nic/update?hostname=yourhostname&myip=ipaddress&wildcard=NOCHG&mx=NOCHG&backmx=NOCHG HTTP/1.0 
+Host: members.dyndns.org 
+Authorization: Basic base-64-authorization 
+User-Agent: Company - Device - Version Number
+
+Fragment base-64-authorization should be represented by Base 64 encoded username:password string.
+
+
+Implemented fields
+------------------
+
+hostname
+  Comma separated list of hostnames that you wish to update (up to 20 hostnames per request). 
+  This is a required field.
+  Example: hostname=test.dyndns.org,customtest.dyndns.org
+
+myip
+  IP address to set for the update.
+  (If this parameter is not specified, the best IP address the server can determine will be used)
+
+(See http://www.dyndns.com/developers/specs/syntax.html for more details)
+
+
+Return Codes
+------------
+
+good
+  The update was successful, and the hostname is now updated.
+
+badauth
+  The username and password pair do not match a real user.
+
+notfqdn
+  The hostname specified is not a fully-qualified domain name (not in the form hostname.dyndns.org 
+  or domain.com).
+
+nohost
+  The hostname specified does not exist in this user account (or is not in the service specified in 
+  the system parameter)
+
+badagent
+  The user agent was not sent or HTTP method is not permitted (we recommend use of GET request method).
+
+dnserr
+  DNS error encountered
+
+911
+  There is a problem or scheduled maintenance on our side.
+
+(See http://www.dyndns.com/developers/specs/return.html for more details)
+
+
+
+Nico Kaiser
+nico@siriux.net
diff --git a/TODO.txt b/TODO.txt
new file mode 100644 (file)
index 0000000..21ebd29
--- /dev/null
+++ b/TODO.txt
@@ -0,0 +1,8 @@
+TODO
+====
+
+- Implement Wildcards
+- Implement NOCHG
+- Implement more features from DynDNS.org
+- Provide Apache templates (for mod_rewrite, etc.)
+
diff --git a/conf/apache/Dyndns.conf b/conf/apache/Dyndns.conf
new file mode 100644 (file)
index 0000000..8f866dc
--- /dev/null
@@ -0,0 +1,17 @@
+#
+# This is the Apache configuration for the Dyndns package.
+# 
+# An alias is set from  /nic  to /usr/local/Dyndns/htdocs  and a Rewrite rule
+# is added for the  /nic/update  URL.
+#
+Alias /nic /usr/local/Dyndns/htdocs
+
+<Directory /usr/local/Dyndns/htdocs>
+       Options FollowSymLinks
+       AllowOverride None
+       Order allow,deny
+       Allow from all
+       RewriteEngine On
+       RewriteBase /nic
+       RewriteRule ^update$ /nic/index.php    
+</Directory>
diff --git a/conf/bind/Dyndns.conf.include b/conf/bind/Dyndns.conf.include
new file mode 100644 (file)
index 0000000..ce6d33c
--- /dev/null
@@ -0,0 +1,14 @@
+
+key dyndns.example.com. {
+       algorithm HMAC-MD5;
+       secret "bvZfFHkl16wNGL/LuEUAqvlBeue9lw7C8GkHnQucN6jpKDMjOu29zFR6LlO5YlpN
+zYquDBmDSPVddX9SuFIK5A==";
+};
+
+zone "dyndns.org" {
+       type master;
+       file "dyndns.org.zone";
+       allow-update {
+               key dyndns.example.com.;
+       };
+};
\ No newline at end of file
diff --git a/conf/bind/keys/Kdyndns.example.com.+157+00000.key b/conf/bind/keys/Kdyndns.example.com.+157+00000.key
new file mode 100644 (file)
index 0000000..4711196
--- /dev/null
@@ -0,0 +1 @@
+dyndns.example.com. IN KEY 513 3 157 bvZfFHkl16wNGL/LuEUAqvlBeue9lw7C8GkHnQucN6jpKDMjOu29zFR6LlO5YlpNzYquDBmDSPVddX9SuFIK5A==
diff --git a/conf/bind/keys/Kdyndns.example.com.+157+00000.private b/conf/bind/keys/Kdyndns.example.com.+157+00000.private
new file mode 100644 (file)
index 0000000..4bd7e72
--- /dev/null
@@ -0,0 +1,3 @@
+Private-key-format: v1.2
+Algorithm: 157 (HMAC)
+Key: bvZfFHkl16wNGL/LuEUAqvlBeue9lw7C8GkHnQucN6jpKDMjOu29zFR6LlO5YlpNzYquDBmDSPVddX9SuFIK5A==
diff --git a/conf/dyndns.hosts b/conf/dyndns.hosts
new file mode 100644 (file)
index 0000000..12f07b8
--- /dev/null
@@ -0,0 +1,5 @@
+client1.dyndns.example.com:user1,user2
+client2.dyndns.example.com:user1,user2
+user1.dyndns.example.com:user1
+user2.dyndns.example.com:user2
+*.u1.dyndns.example.com:user1
diff --git a/conf/dyndns.user b/conf/dyndns.user
new file mode 100644 (file)
index 0000000..12885a1
--- /dev/null
@@ -0,0 +1,2 @@
+user1:mypassword123
+user2:anotherpassword
diff --git a/htdocs/classes/Dyndns.class.php b/htdocs/classes/Dyndns.class.php
new file mode 100644 (file)
index 0000000..3e46f5c
--- /dev/null
@@ -0,0 +1,239 @@
+<?php
+/*
+ * DynDNS Server Script
+ * Copyright (c) 2007 Nico Kaiser
+ *  
+ * http://siriux.net/
+ */
+require_once(dirname(__FILE__) . '/DyndnsHelper.class.php');
+require_once(dirname(__FILE__) . '/DyndnsHosts.class.php');
+require_once(dirname(__FILE__) . '/DyndnsUsers.class.php');
+
+/**
+ * Simple Dynamic DNS 
+ * 
+ * @package Dyndns
+ * @author Nico Kaiser <nico@siriux.net>
+ * @version $Revision: 13 $
+ */
+class Dyndns {
+       
+       /**
+     * Storage for all configuration variables, set in config.php
+     * @var array 
+     * @access private
+     */
+       var $_config;
+       
+       /**
+        * The user logged in 
+        * @var string
+        * @access private
+        */
+       var $_user;
+       
+       /**
+        * IP the hostnames should point to
+        * @var string
+        * @access private
+        */
+       var $_myIp;
+       
+       /**
+        * Hostnames that should be updated
+        * @var array 
+        * @access private
+        */
+       var $_hostnames;
+       
+       /**
+        * Debug buffer
+        * @var string
+        * @access private
+        */ 
+       var $_debugBuffer;
+       
+       
+       function Dyndns() {
+               /* Default config settings */
+               $this->_config = array (
+                       'hostsFile' => 'dyndns.hosts',          /* Location of the hosts database */
+                       'userFile' => 'dyndns.user',            /* Location of the user database */
+                       'debugFile' => 'dyndns.log',            /* Debug file */
+                       'debug' => false,                                       /* Enable debugging */
+                       
+                       'bind.server' => false,
+                       'bind.zone' => '',
+                       'bind.ttl' => 300,
+                       'bind.key' => '',
+               );
+       }
+       
+       /**
+        * Initializes the Dyndns script
+        */
+       function init() {
+               $this->_users = new DyndnsUsers($this->_config['userFile']);
+               $this->_hosts = new DyndnsHosts($this->_config['hostsFile']);
+               
+               $this->_checkHttpMethod();
+               $this->_checkAuthentication();
+               
+               /* Get IP address, fallback to REMOTE_ADDR */
+               $this->_myIp = DyndnsHelper::getMyIp();
+               if (array_key_exists('myip', $_REQUEST)) {
+                       if (DyndnsHelper::checkValidIp($_REQUEST['myip'])) {
+                               $this->_myIp = $_REQUEST['myip'];
+                       } else {
+                               $this->debug('Invalid parameter myip. Using default REMOTE_ADDR');
+                       }
+               }
+               
+               /* Get hostnames to be updated */
+               $this->_hostnames = array ();
+               if (array_key_exists('hostname', $_REQUEST) && ($_REQUEST['hostname'] != '')) {
+                       $this->_hostnames = explode(',', strtolower($_REQUEST['hostname']));
+                       $this->_checkHostnames();
+               } else {
+                       $this->_returnCode('notfqdn');
+               }
+               
+               $this->_updateHosts();
+                               
+               /* Return "good" code as everything seems to be ok now */
+               $this->_returnCode('good');
+       }
+       
+       /**
+        * Store a value in the config table
+        *
+        * @param string $key
+        * @param mixed $value
+        */
+       function setConfig($key, $value) {
+               $this->_config[$key] = $value;
+       }
+       
+       /**
+        * Get a value from the config table
+     *
+        * @return mixed an arbitrary value
+        */
+    function getConfig($key) {
+               return $this->_config[$key];
+    }
+    
+       /**
+        * Checks if the HTTP method is supported. Currently, only GET is supported,
+        * all other methods will result in a "badagent" code.
+        * 
+        * @access private
+        */
+       function _checkHttpMethod() {
+               /* Only HTTP method "GET" is allowed here */
+               if ($_SERVER['REQUEST_METHOD'] != 'GET') {
+                       $this->debug('ERROR: HTTP method ' . $_SERVER['REQUEST_METHOD'] . ' is not allowed.');
+                       $this->_returnCode('badagent', Array ('HTTP/1.0 405 Method Not Allowed'));
+               }
+       }
+       
+       /**
+        * Handles authentication. Requests HTTP authentication and if user/pw is submitted
+        * check if they are valid
+        * 
+        * @access private
+        */ 
+       function _checkAuthentication() {
+               /* Request user/pw if not submitted yet */
+               if (!isset($_SERVER['PHP_AUTH_USER'])) {
+                       $this->debug('No authentication data sent');
+                       $this->_returnCode('badauth', Array (
+                               'WWW-Authenticate: Basic realm="DynDNS API Access"',
+                               'HTTP/1.0 401 Unauthorized')
+                       );
+               }
+               $user = strtolower($_SERVER['PHP_AUTH_USER']);
+               $password = $_SERVER['PHP_AUTH_PW'];
+               if (! $this->_users->checkCredentials($user, $password)) {
+                       $this->_returnCode('badauth', Array ('HTTP/1.0 403 Forbidden'));
+               }
+               $this->_user = $user;
+       }
+       
+       /**
+        * Checks if all hostnames are valid (FQDN) and belong to the user
+        * 
+        * @access private
+        */
+       function _checkHostnames() {
+               foreach ($this->_hostnames as $hostname) {
+                       if (! DyndnsHelper::checkValidHost($hostname)) {
+                               $this->_returnCode('notfqdn');
+                       }
+                       if (! $this->_hosts->checkUserHost($this->_user, $hostname)) {
+                               $this->_returnCode('nohost');
+                       }
+               }
+       }
+       
+       /**
+        * Updates all hosts
+        * 
+        * @param string hostname Hostname
+        * @param string myip IP address
+        */
+       function _updateHosts() {
+               foreach ($this->_hostnames as $hostname) {
+                       if (! $this->_hosts->update($hostname, $this->_myIp) ) {
+                               $this->_returnCode('dnserr');
+                       }
+               }
+               /* Flush host database (write to hosts file) */
+               if (! $this->_hosts->flush()) {
+                       $this->_returnCode('dnserr');
+               }
+       }
+       
+       /**
+        * Returns a "Return code". The program exits after output.
+        * 
+        * @param string code Return code (like "notfqdn")
+        * @param array additionalHeaders HTTP headers to be added
+        * @param string debugMessage Message for the debug log
+        */
+       function _returnCode($code, $additionalHeaders = Array (), $debugMessage = "") {
+               foreach ($additionalHeaders as $header) {
+                       header($header);
+               }
+               $this->debug('Sending return code: ' . $code);
+               echo $code;
+               $this->_shutdown();
+       }
+       
+       /**
+        * Shuts down, closes files, writes debug output, etc.
+        *
+        * @access private
+        */
+       function _shutdown() {
+               /* Write debug buffer */
+               if ( ($this->_debugBuffer != "") && ($this->_config['debug'])) {
+                       if ($fh = @fopen($this->_config['debugFile'], 'a')) {
+                               fwrite($fh, $this->_debugBuffer);
+                               fclose($fh);
+                       }
+               }
+               exit;
+       }
+       
+       /**
+        * Saves a debug message (if debugging is turned on)
+        * 
+        * @param string message Debug message
+        */
+       function debug($message) {
+               $this->_debugBuffer .= date('M j G:i:s') . ' Dyndns: ' . $message . "\n";
+       }
+}
+?>
\ No newline at end of file
diff --git a/htdocs/classes/DyndnsHelper.class.php b/htdocs/classes/DyndnsHelper.class.php
new file mode 100644 (file)
index 0000000..b8e915f
--- /dev/null
@@ -0,0 +1,79 @@
+<?php
+/*
+ * DynDNS Server Script
+ * Copyright (c) 2007 Nico Kaiser
+ *  
+ * http://siriux.net/
+ */
+
+/**
+ * Collection of useful helper functions
+ * 
+ * @package Dyndns
+ * @author Nico Kaiser <nico@siriux.net>
+ * @version $Revision: 13 $
+ * @static
+ */
+class DyndnsHelper {
+       
+       /**
+        * Simple function to check valid IP address
+        *
+        * @param string IP address
+        * @return boolean True if IP is valid
+        */ 
+       function checkValidIp($ip) {
+               if (! eregi("^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$", $ip)) 
+                       return false;   
+               $tmp = explode(".", $ip);
+               foreach ($tmp as $sub) {
+                       $sub = $sub * 1;
+                       if ($sub < 0 || $sub > 256) return true;
+               }
+               return true;
+       }
+       
+       /**
+        * Simple function to check valid Hostname (FQDN)
+        *
+        * @param string Hostname
+        * @return boolean True if Hostname is valid
+        */ 
+       function checkValidHost($hostname) {
+               return eregi('^[a-z0-9.-]+$', $hostname);
+       }
+       
+       /**
+        * Tries to get the IPv4 of the client
+        *
+        * @param access public
+        * @return string ip 
+        */
+       function getMyIp() {
+               $ip = $_SERVER['REMOTE_ADDR'];
+               /* Some IPv6 Servers add ::ffff: */
+               $ip = preg_replace('/^::ffff:/', '', $ip);
+               return $ip;
+       }
+       
+       /**
+        * Compares if two hostnames are the same, with regard to a wildcard
+        *
+        * @param string host1
+        * @param string host2
+        * @return boolean true or false
+        */
+       function compareHosts($host1, $host2, $wildcard = false) {
+               $a = explode('.', $host1);
+               $b = explode('.', $host2);              
+               if (count($a) != count($b))
+                       return false;
+               for ($i = 0; $i < count($a); $i++) {
+                       if (($wildcard === false) or (($a[$i] != $wildcard) and ($b[$i] != $wildcard)))
+                               if ($a[$i] != $b[$i])
+                                       return false;
+               }
+               return true;
+       }
+}
+?>
\ No newline at end of file
diff --git a/htdocs/classes/DyndnsHosts.class.php b/htdocs/classes/DyndnsHosts.class.php
new file mode 100644 (file)
index 0000000..8c1639d
--- /dev/null
@@ -0,0 +1,194 @@
+<?php
+/*
+ * DynDNS Server Script
+ * Copyright (c) 2007 Nico Kaiser
+ *  
+ * http://siriux.net/
+ */
+
+/**
+ * Host database
+ * 
+ * @package Dyndns
+ * @author Nico Kaiser <nico@siriux.net>
+ * @version $Revision: 13 $
+ */
+class DyndnsHosts {
+       
+       /**
+        * Filename of the hosts file (dyndns.hosts)
+        * @var string 
+        * @access private
+        */
+       var $_hostsFile;
+       
+       /**
+        * Host/Users array:  'hostname' => array ('user1', 'user2', ...)
+        * @var array 
+        * @access private
+        */
+       var $_hosts;
+       
+       /**
+        * List of updates in the format 'hostname' => 'ip'
+        * @var array
+        * @access
+        */
+       var $_updates;
+       
+       /**
+        * This is true if the status / user files were read
+        * @var boolean
+        * @access private
+        */
+       var $_initialized;
+               
+       
+       function DyndnsHosts($hostsFile) {
+               $this->_hostsFile = $hostsFile;
+               $this->_initialized = false;
+               $this->_updates = array ();
+       }
+       
+       /**
+        * Adds an update to the list
+        */
+       function update($hostname, $ip) {
+               if (! $this->_initialized)
+                       $this->_init();
+               
+               $GLOBALS['dyndns']->debug('Update: '.$hostname . ':'.$ip);
+               $this->_updates[$hostname] = $ip;
+               return true;
+       }
+       
+       /**
+        * Checks if the host belongs to the user 
+        * 
+        * @param string user Username
+        * @param string hostname Hostname
+        * @return boolean TRUE if the host belongs to the user
+        */
+       function checkUserHost($user, $hostname) {
+               if ($hostname == 'members.dyndns.org') {
+                       $GLOBALS['dyndns']->debug('Cannot change members.dyndns.org');
+                       return false;
+               }
+               if (! DyndnsHelper::checkValidHost($hostname)) {
+                       $GLOBALS['dyndns']->debug('Invalid host: ' . $hostname);
+                       return false;
+               }
+               if (! $this->_initialized)
+                       $this->_init();
+               if (is_array($this->_hosts)) {
+                       foreach ($this->_hosts as $line) {
+                               if (preg_match("/^(.*?):(.*)/", $line, $matches)) {
+                                       if (DyndnsHelper::compareHosts($matches[1], $hostname, '*') && 
+                                                   in_array($user, explode(',', strtolower($matches[2])))) {
+                                               return true;
+                                       }
+                               }
+                       }
+               }
+               $GLOBALS['dyndns']->debug('Host '.$hostname.' does not belong to user '.$user);
+               return false;
+       }
+       
+       /**
+        * Write cached changes to the status file 
+        * 
+        * @access public
+        */
+       function flush() {
+               return $this->_updateBind();
+       }
+       
+       /**
+        * Initializes the user and status list from the file 
+        * 
+        * @access private
+        */
+       function _init() {
+               if ($this->_initialized) return;
+               $this->_readHostsFile();
+               if (! is_array($this->_hosts)) {
+                       $this->_hosts = Array ();
+               }
+               $this->_initialized = true;
+       }
+       
+       /**
+        * Reads the contents of $_hostsFile into $_hosts
+        * 
+        * @access private
+        */
+       function _readHostsFile() {
+               $lines = @file($this->_hostsFile);
+               if (is_array($lines)) {
+                       $this->_hosts = $lines;
+               } else {
+                       $GLOBALS['dyndns']->debug('Empty hosts file: "' . $this->hostsFile . '"');
+               }
+       }
+       
+       /**
+        * Sends DNS Updates to BIND server
+        * 
+        * @access private
+        */
+       function _updateBind() {
+               $server = $GLOBALS['dyndns']->getConfig('bind.server');
+               $zone = $GLOBALS['dyndns']->getConfig('bind.zone');
+               $ttl = $GLOBALS['dyndns']->getConfig('bind.ttl') * 1;
+               $key = $GLOBALS['dyndns']->getConfig('bind.key');
+               
+               if (! DyndnsHelper::checkValidHost($server)) {
+                       $GLOBALS['dyndns']->debug('ERROR: Invalid bind.server config value');
+                       return false;
+               }
+               if (! DyndnsHelper::checkValidHost($zone)) {
+                       $GLOBALS['dyndns']->debug('ERROR: Invalid bind.zone config value');
+                       return false;
+               }
+               if (! is_int($ttl)) {
+                       $GLOBALS['dyndns']->debug('Invalid bind.ttl config value. Setting to default 300.');
+                       $ttl = 300;
+               }
+               if ($ttl < 60) {
+                       $GLOBALS['dyndns']->debug('bind.ttl is too low. Setting to default 300.');
+                       $ttl = 300;
+               }
+               if (! eregi('^[a-z0-9.-=/]+$', $key)) {
+                       $GLOBALS['dyndns']->debug('ERROR: Invalid bind.key config value');
+                       return false;
+               }
+               
+               /* Create temp file with nsupdate commands */
+               $tempfile = tempnam('/tmp', 'Dyndns');
+               $fh = @fopen($tempfile, 'w');
+               if (! $fh) {
+                       $GLOBALS['dyndns']->debug('ERROR: Could not open temporary file');
+                       return false;
+               }
+               fwrite($fh, "server $server\n");
+               fwrite($fh, "zone $zone\n");
+               $ttl = $GLOBALS['dyndns']->getConfig('bind.ttl');
+               foreach ($this->_updates as $host => $ip) {
+                       fwrite($fh, "update delete $host A\n");
+                       fwrite($fh, "update add $host $ttl A $ip\n");
+               }
+               fwrite($fh, "send\n");
+               fclose($fh);
+               
+               /* Execute nsupdate */
+               $result = exec('/usr/bin/nsupdate -y ' . $key . ' ' . $tempfile . ' 2>&1');
+               unlink($tempfile);
+               if ($result != '') {
+                       $GLOBALS['dyndns']->debug('ERROR: nsupdate returns: ' . $result);
+                       return false;
+               }
+               
+               return true;
+       }
+}
+?>
\ No newline at end of file
diff --git a/htdocs/classes/DyndnsUsers.class.php b/htdocs/classes/DyndnsUsers.class.php
new file mode 100644 (file)
index 0000000..62c90f6
--- /dev/null
@@ -0,0 +1,60 @@
+<?php
+/*
+ * DynDNS Server Script
+ * Copyright (c) 2007 Nico Kaiser
+ *  
+ * http://siriux.net/
+ */
+
+/**
+ * User database
+ * 
+ * @package Dyndns
+ * @author Nico Kaiser <nico@siriux.net>
+ * @version $Revision: 13 $
+ */
+class DyndnsUsers {
+       
+       /**
+        * Filename of the users file
+        * @var string 
+        * @access private
+        */
+       var $_userFile;
+       
+       
+       function DyndnsUsers($userFile) {
+               $this->_userFile = $userFile;
+       }
+       
+       /**
+        * Checks user credentials
+        *
+        * @param string user 
+        * @param string password
+        * @access private
+        */
+       function checkCredentials($user, $password) {
+               $lines = @file($this->_userFile);
+               if (is_array($lines)) {
+                       foreach ($lines as $line) {
+                               if (preg_match("/^(.*?):(.*)/", $line, $matches)) {
+                                       if (strtolower($matches[1]) == strtolower($user)) {
+                                               $salt = substr($matches[2], 0, 2);                              
+                                               if (crypt($password, $salt) == $matches[2]) {
+                                                       $GLOBALS['dyndns']->debug('Login successful for user ' . $user);
+                                                       return TRUE;
+                                               } else {
+                                                       $GLOBALS['dyndns']->debug('Wrong password for user: ' . $user);
+                                               }
+                                       }
+                               }
+                       }
+               } else {
+                       $GLOBALS['dyndns']->debug('Empty user file: "' . $this->_userFile . '"');
+               }
+               $GLOBALS['dyndns']->debug('Unknown user: ' . $user);
+               return FALSE;
+       }
+}
+?>
\ No newline at end of file
diff --git a/htdocs/config.php b/htdocs/config.php
new file mode 100644 (file)
index 0000000..c7205c0
--- /dev/null
@@ -0,0 +1,59 @@
+<?php
+
+@ini_set('display_errors', 0);
+
+if (!isset($dyndns) || !method_exists($dyndns, 'setConfig')) {
+       exit;
+}
+
+
+/* 
+ * Location of the hosts database
+ */
+$dyndns->setConfig('hostsFile', 'conf/dyndns.hosts');
+
+
+/* 
+ * Location of the user database
+ */
+$dyndns->setConfig('userFile', 'conf/dyndns.user');
+
+
+/* 
+ * Enable debugging?
+ */
+$dyndns->setConfig('debug', true);     
+
+
+/* 
+ * Debug filename
+ */
+$dyndns->setConfig('debugFile', '/tmp/dyndns.log');
+                       
+
+/*
+ * Secret Key for BIND nsupdate
+ * <keyname>:<secret>
+ */
+$dyndns->setConfig('bind.key', 'dyndns.example.com:bvZfFHkl16wNGL/LuEUAqvlBeue9lw7C8GkHnQucN6jpKDMjOu29zFR6LlO5YlpNzYquDBmDSPVddX9SuFIK5A==');
+
+
+/*
+ * Address of the BIND server. You can specify any remote DNS server here, 
+ * if the server allows you to update data using bind.key
+ */
+$dyndns->setConfig('bind.server', 'localhost');
+
+
+/*
+ * The BIND zone which retrieves the updates
+ */
+$dyndns->setConfig('bind.zone', 'dyndns.example.com');
+
+
+/*
+ * Dynamic DNS entries will get this TTL
+ */
+$dyndns->setConfig('bind.ttl', '300');
+
+?>
\ No newline at end of file
diff --git a/htdocs/index.php b/htdocs/index.php
new file mode 100644 (file)
index 0000000..5b60f3f
--- /dev/null
@@ -0,0 +1,33 @@
+<?php
+/*
+ * DynDNS Server Script
+ * Copyright (c) 2007 Nico Kaiser
+ *  
+ * http://siriux.net/
+ */
+
+/**
+ * This script takes the same parameters as the original members.dyndns.org 
+ * server does. It can update a BIND DNS server.
+ * 
+ * The syntax is described here:
+ * http://www.dyndns.com/developers/specs/syntax.html
+ * 
+ * Remember: This script must be run as 
+ *     http://members.dyndns.org/nic/update
+ * 
+ * @author Nico Kaiser <nico@siriux.net>
+ * @version $Revision: 13 $
+ */
+
+error_reporting(E_ALL);
+require_once(dirname(__FILE__) . '/classes/Dyndns.class.php');
+
+$GLOBALS['dyndns'] =& new Dyndns();
+$dyndns =& $GLOBALS['dyndns'];
+
+@include(dirname(__FILE__). '/config.php');
+
+$dyndns->init();
+
+?>
\ No newline at end of file