<?php
/**
* Dynamic DNS update script
*
* This script takes a username and password and uses the BIND command "nsupdate"
* to update a BIND installation with the remote IP of the request
*
* Steve Allison 2014 -- http://www.nooblet.org/blog/2014/php-dynamic-dns/
*
**/
// Various settings
$settings = array(
"domain" => "dyndns.example.com",
"nsupdate" => "/usr/bin/nsupdate",
"nameserver" => "192.168.0.1",
"keyfile" => "include/Kweb1.example.com.+165+60641.private",
"ttl" => "60",
"logdir" => "log/"
);
// Access Control List
$acl = array(
"customer1" => "YRnog2nMaXyzumya2VQX",
"customer2" => "27iAsCPAqdVHGf3CVGa4",
"customer2" => "tdo2WHLAi454xwMLwOA6",
"customer4" => "4AAkBgMCvyig4yGTtAyD",
);
// Removes unwanted characters from the GET request, probably malicious
function escapeString($string) {
return strtr($string,
array(
";" => '_',
"," => '_',
"\n" => '_',
"\r" => '_',
"\\" => '_',
)
);
}
// Logs string to file, creates logdir with .htaccess file if necessary
function logString($string) {
global $settings, $_SERVER;
if (!file_exists($settings['logdir'])) {
mkdir($settings['logdir']);
file_put_contents($settings['logdir'] . "/.htaccess", "order allow,deny\ndeny from all\n");
}
if (file_exists($settings['logdir'])) {
file_put_contents($settings['logdir'] . "/access_" . date('Ym') . ".log", sprintf("[%s] (%15s) %s\n", date(DATE_RFC822), $_SERVER['REMOTE_ADDR'], $string), FILE_APPEND);
}
}
// Check we have the arrays available, or die a quick death
if ((!isset($_GET)) || (!isset($_SERVER)) || (!array_key_exists('REMOTE_ADDR', $_SERVER))) {
header('HTTP/1.0 500 Internal Server Error');
print("500 Internal Server Error\n");
die();
}
// Get remote IP
$remoteip = $_SERVER['REMOTE_ADDR'];
// Check that all variables are available to PHP
if ((!array_key_exists('id', $_GET)) || (!array_key_exists('key', $_GET))) {
header('HTTP/1.0 400 Bad Request');
print("400 Bad Request\n");
logString("Bad request (required GET field missing): " . $_SERVER['REQUEST_URI']);
die();
}
// define our 2 main variables
$id = escapeString($_GET['id']);
$key = escapeString($_GET['key']);
// If any are null, die
if ((!$id) || (!$key)) {
header('HTTP/1.0 400 Bad Request');
print("400 Bad Request\n");
logString("Bad request (required GET field empty): " . $_SERVER['REQUEST_URI']);
die();
}
// If there is no entry, or the key doesn't match, die
if ((!$acl[$id]) || (strcmp($acl[$id],$key)) != 0) {
header('HTTP/1.0 403 Forbidden');
print("403 Forbidden");
logString("Forbidden: " . $_SERVER['REQUEST_URI']);
die();
}
// Perform DNS request to fetch current IP, the extra '.' is to disable appending local domain to request
$currentip = gethostbyname($id . "." . $settings['domain'] . ".");
// Check if an update is required, if not, die
if (strcmp($currentip,$remoteip) == 0) {
header("Content-Type: text/plain");
print("No update required.");
die();
}
// Check nsupdate exists
if (!file_exists($settings['nsupdate'])) {
header('HTTP/1.0 500 Internal Server Error');
print("500 Internal Server Error");
logString("Error: " . $settings['nsupdate'] . " is not a valid nsupdate binary");
die();
}
// Run nsupdate
$pipe = popen($settings['nsupdate'] . " -d -D -k " . $settings['keyfile'], 'w');
// Pass update string
fwrite($pipe, "server " . $settings['nameserver'] . "\n");
//fwrite($pipe, "debug yes\n");
fwrite($pipe, "zone " . $settings['domain'] . "\n");
fwrite($pipe, "update delete " . $id . "." . $settings['domain'] . " A\n");
fwrite($pipe, "update add " . $id . "." . $settings['domain'] . " " . $settings['ttl'] . " A " . $remoteip . "\n");
//fwrite($pipe, "show\n");
fwrite($pipe, "send\n");
// Close pipe
$int = pclose($pipe);
// log to file
logString("Success: " . $id);
header("Content-Type: text/plain");
print("Request submitted.\n" . $id . " => " . $remoteip . "\n");