-
-
Save howanghk/f955764f33bf9db7a86c to your computer and use it in GitHub Desktop.
Invited by Matthew Prince (https://twitter.com/eastdakota/status/453542354117754882), I am switching to Cloudflare DDNS. However it's difficult to configure my dd-wrt router to update my Dynamic DNS host name with Cloudflare. So I ended up with my router calling a PHP script hosted on my website.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
// ----- dd-wrt DDNS settings: ----- | |
// DDNS Service: Custom | |
// DYNDNS Server: <your web server domain> (e.g. www.example.com) | |
// User Name: <anything> | |
// Password: <anything> | |
// Host Name: <your DDNS hostname> (e.g. home.example.com) | |
// URL: /cloudflare_ddns_updater.php?email=<your cloudflare account email>&apikey=<your cloudflare client api key>&domain=<your domain>&host=<your DDNS hostname> | |
// (e.g.: /[email protected]&apikey=123456789012345678901234567890&domain=example.com&host=home.example.com) | |
// Input parameters | |
$email = empty($_REQUEST['email']) ? '' : $_REQUEST['email']; | |
$apikey = empty($_REQUEST['apikey']) ? '' : $_REQUEST['apikey']; | |
$domain = empty($_REQUEST['domain']) ? '' : $_REQUEST['domain']; | |
$host = empty($_REQUEST['host']) ? $domain : $_REQUEST['host']; | |
$newip = empty($_REQUEST['ip']) ? i2c_realip() : $_REQUEST['ip']; | |
header('Content-Type: text/plain;charset=utf-8'); | |
if (empty($email) || empty($apikey) || empty($domain) || empty($host)) | |
{ | |
die('Missing parameter(s), you must specify email, apikey, domain and host'); | |
} | |
// Does host matches domain? | |
if (strrpos($host, $domain) !== (strlen($host) - strlen($domain))) | |
{ | |
die('Host name do not seems to match domain'); | |
} | |
// Do we really need to update? | |
$dns = dns_get_record($host, DNS_A); | |
if (!empty($dns)) | |
{ | |
if (isset($dns[0]['ip'])) | |
{ | |
$oldip = $dns[0]['ip']; | |
if ($oldip == $newip) | |
{ | |
die($host . ' is pointing to ' . $oldip . ' already, no updated needed.'); | |
} | |
} | |
} | |
// Step 1: Get DNS records list from CloudFlare | |
$result = cloudflare_api(array( | |
'email' => $email, | |
'tkn' => $apikey, | |
'a' => 'rec_load_all', | |
'z' => $domain | |
)); | |
if (!is_array($result) || empty($result['result']) || $result['result'] !== 'success') | |
{ | |
die('Calling rec_load_all for zone "' . $domain . '" failed! CloudFlare response: ' . print_r($result, true)); | |
} | |
$records = $result['response']['recs']['objs']; | |
// Step 2: Find record for hostname | |
$record = null; | |
foreach ($records as $rec) | |
{ | |
if (($rec['type'] == 'A') && ($rec['name'] == $host)) | |
{ | |
$record = $rec; | |
break; | |
} | |
} | |
if (empty($record)) | |
{ | |
die('Cannot find DNS record for "' . $host . '". CloudFlare response: ' . print_r($result, true)); | |
} | |
// Do we really need to update? | |
if ($record['content'] == $newip) | |
{ | |
die($host . ' is set to ' . $record['content'] . ' already, no updated needed. Please be patient while DNS propagates.'); | |
} | |
// Step 3: Update host IP address on CloudFlare | |
$result = cloudflare_api(array( | |
'email' => $email, | |
'tkn' => $apikey, | |
'a' => 'rec_edit', | |
'z' => $domain, | |
'type' => $record['type'], | |
'id' => $record['rec_id'], | |
'name' => $record['name'], | |
'content' => $newip, | |
'ttl' => $record['ttl'], | |
'service_mode' => $record['service_mode'] | |
)); | |
if (!is_array($result) || empty($result['result']) || $result['result'] !== 'success') | |
{ | |
die('Calling rec_edit for "' . $host . '" failed! CloudFlare response: ' . print_r($result, true)); | |
} | |
echo 'Done'; | |
exit; | |
// ---------- Utility functions below ---------- // | |
function cloudflare_api($data) | |
{ | |
// Initialize curl with URL | |
$ch = curl_init(); | |
curl_setopt($ch, CURLOPT_URL, 'https://www.cloudflare.com/api_json.html'); | |
//curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); | |
// Assign POST data to curl | |
curl_setopt($ch, CURLOPT_POST, true); | |
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data)); | |
// Get response without header | |
curl_setopt($ch, CURLOPT_HEADER, 0); | |
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); | |
$response = curl_exec($ch); | |
// Close curl | |
curl_close($ch); | |
$arr = json_decode($response, true); | |
if (is_null($arr)) | |
{ | |
// JSON decode fail, return raw response string | |
return $response; | |
} | |
else | |
{ | |
return $arr; | |
} | |
} | |
// From http://hk.php.net/source.php?url=/include/ip-to-country.inc | |
function i2c_realip() | |
{ | |
// No IP found (will be overwritten by for | |
// if any IP is found behind a firewall) | |
$ip = FALSE; | |
// If HTTP_CLIENT_IP is set, then give it priority | |
if (!empty($_SERVER["HTTP_CLIENT_IP"])) { | |
$ip = $_SERVER["HTTP_CLIENT_IP"]; | |
} | |
// User is behind a proxy and check that we discard RFC1918 IP addresses | |
// if they are behind a proxy then only figure out which IP belongs to the | |
// user. Might not need any more hackin if there is a squid reverse proxy | |
// infront of apache. | |
if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) { | |
// Put the IP's into an array which we shall work with shortly. | |
$ips = explode (", ", $_SERVER['HTTP_X_FORWARDED_FOR']); | |
if ($ip) { array_unshift($ips, $ip); $ip = FALSE; } | |
for ($i = 0; $i < count($ips); $i++) { | |
// Skip RFC 1918 IP's 10.0.0.0/8, 172.16.0.0/12 and | |
// 192.168.0.0/16 | |
if (!preg_match('/^(?:10|172\.(?:1[6-9]|2\d|3[01])|192\.168)\./', $ips[$i])) { | |
if (version_compare(phpversion(), "5.0.0", ">=")) { | |
if (ip2long($ips[$i]) != false) { | |
$ip = $ips[$i]; | |
break; | |
} | |
} else { | |
if (ip2long($ips[$i]) != -1) { | |
$ip = $ips[$i]; | |
break; | |
} | |
} | |
} | |
} | |
} | |
// Return with the found IP or the remote address | |
return ($ip ? $ip : $_SERVER['REMOTE_ADDR']); | |
} | |
?> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
nice work @howanghk ! I must admit I hacked mine together rather quickly, so I like that you've gone to the trouble of documenting the DD-WRT settings and other improvements.