Skip to content

Instantly share code, notes, and snippets.

@howanghk
Forked from kdallas/index.php
Last active February 26, 2017 03:48
Show Gist options
  • Save howanghk/f955764f33bf9db7a86c to your computer and use it in GitHub Desktop.
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.
<?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.: /cloudflare_ddns_updater.php?email=me@example.com&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']);
}
?>
@kdallas
Copy link

kdallas commented Feb 26, 2017

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment