<?php
// Based on the hard work of Mitchel Haan
// https://haanenterprises.com/2013/04/host-your-own-dynamic-dns-using-php-and-cpanel-apis/
//
// usage:
// http://username:password@website.com/dyndns.php?hostname=remote&myip=192.168.1.1
//
// per the settings below, the above will update the IP remote.example.com to 192.168.1.1
// myip is not required, will default to the remote IP calling the script
//
// most dyndns clients will work with a custom url setting. you will likely need to only
// provide the subdomain and not the full address.
// (ie: with this script, hostname=remote instead of hostname=remote.example.com
//
// primeiro você precisa criar o hostname (A NAME record) no servidor. Use o
// "Simple DNS Zone Editor" do cPanel para isso e/ou checar se o hostname existe.
//
// Erro "no hosts found" ao evocar o script significa que tal hostname não foi achado.
// Se o script estiver rodando em algum lugar da internet, teste com:
// http://nome_de_usuario:senha@exemplo.com.br/atualiza.php?hostname=teste
//
//
// Resposta do script se tudo OK:
//
// teste
// Update successful: teste.ryan.com.br. (187.78.217.99)
//
// Total cPanel API call time: 2.256665 seconds
//
//
/***** Variables *****/
#The username and password used by the updater to send the request.
#HTTP Basic authentication
$php_auth_user='nome_de_usuario';
$php_auth_pw='senha';
#The url of the cpanel server
$dyndnsCpanel = 'https://exemplo.com.br:2083';
#username and password used to login to cpanel
$dyndnsCpanelUser = 'usuario_cpanel';
$dyndnsCpanelPass = 'senha_cpanel';
#the main domain name of the account on cpanel
$dyndnsDomain = 'exemplo.com.br';
#the base domain of which the subdomain has a dynamic ip
$dyndnsRemoteHostDomain = '.exemplo.com.br.';
// Plain text output
header('Content-type: text/plain');
if (!isset($_SERVER['PHP_AUTH_USER'])) {
header('WWW-Authenticate: Basic realm="CPanel DynDyns"');
header('HTTP/1.0 401 Unauthorized');
die('Authentication Required.');
}
if(!($_SERVER['PHP_AUTH_USER']==$php_auth_user && $_SERVER['PHP_AUTH_PW']==$php_auth_pw)) {
sleep(10);
die('Invalid Credentials');
}
// Make sure a host was specified
if (empty($_GET['hostname']))
die('Must specify host');
define('DYNDNS_ALLHOSTS', "");
// Validate IP address
if (!filter_var($ip, FILTER_VALIDATE_IP))
die('Invalid IP address');
// Get and validate ttl
$ttl = $_GET['ttl'];
if (!is_numeric($ttl) || $ttl < 60) $ttl = 300; // Create class object $dyn = new DynDnsUpdater(); // Connection information $dyn->setCpanelHost($dyndnsCpanel);
$dyn->setDomain($dyndnsDomain);
$dyn->setHostDomain($dyndnsRemoteHostDomain);
// Set username
$dyn->setCpanelUsername($dyndnsCpanelUser);
// Set password
$dyn->setCpanelPassword($dyndnsCpanelPass);
$dyn->updateHost($_GET['hostname'], $ip);
if ($dyn->apiCallTime > 0.0)
{
echo "\nTotal cPanel API call time: {$dyn->apiCallTime} seconds\n";
}
// End of processing
exit;
/**********************************/
/*** Function definitions below ***/
/**********************************/
class DynDnsUpdater
{
public $apiCallTime;
private $curl;
private $cpanelHost;
private $cpanelUsername;
private $cpanelPassword;
private $domain;
private $hostDomain;
/***** Constructor / Destructor *****/
function __construct()
{
// Create curl object
$this->curl = curl_init();
$curlDefaults = array(
CURLOPT_SSL_VERIFYPEER => false, // Allow self-signed certs
CURLOPT_SSL_VERIFYHOST => false, // Allow certs that do not match the hostname
CURLOPT_RETURNTRANSFER => true, // Return contents
);
curl_setopt_array($this->curl, $curlDefaults);
$this->apiCallTime = 0.0;
}
function __destruct()
{
// Release curl object
curl_close($this->curl);
}
/***** Setters *****/
function setCpanelHost($host)
{
$this->cpanelHost = $host;
}
function setCpanelUsername($username)
{
$this->cpanelUsername = $username;
}
function setCpanelPassword($password)
{
$this->cpanelPassword = $password;
}
function setDomain($domain)
{
$this->domain = $domain;
}
function setHostDomain($domain)
{
$this->hostDomain = $domain;
}
/***** Public Functions *****/
public function updateHost($host, $ip)
{
$hosts = $this->getHost($host);
if ($hosts === false)
return false;
foreach ($hosts as $hostInfo)
{
if ($hostInfo['address'] == $ip)
{
echo "No update required: {$hostInfo['name']} ($ip)\n";
return true;
}
$updateParams = array(
'cpanel_jsonapi_module' => 'ZoneEdit',
'cpanel_jsonapi_func' => 'edit_zone_record',
'domain' => $this->domain,
'Line' => $hostInfo['Line'],
'type' => $hostInfo['type'],
'address' => $ip
);
$result = $this->cpanelRequest($updateParams);
if ($result)
echo "Update successful: {$hostInfo['name']} ($ip)\n";
else
echo "Update failed: {$hostInfo['name']}\n";
}
}
/***** Private Functions *****/
private function getHost($host)
{
echo $host."\n";
$fetchzoneParams = array(
'cpanel_jsonapi_module' => 'ZoneEdit',
'cpanel_jsonapi_func' => 'fetchzone_records',
'domain' => $this->domain,
'customonly' => 1
);
$result = $this->cpanelRequest($fetchzoneParams);
if (empty($result['data']))
return false;
// Get the payload
$zoneFile = $result['data'];
$hosts = array();
foreach ($zoneFile as $line)
{
/***** echo $line['name']."\n"; *****/
if ( ($line['type'] == 'A') &&
($host == DYNDNS_ALLHOSTS || (strcasecmp($line['name'], $host.$this->hostDomain) === 0)) )
{
$hosts[] = $line;
}
}
if (!empty($hosts))
return $hosts;
else
echo "No hosts found\n";
return false;
}
private function cpanelRequest($params)
{
if (empty($this->curl) || empty($params))
return false;
curl_setopt($this->curl, CURLOPT_URL, $this->cpanelHost.'/json-api/cpanel?'.http_build_query($params));
curl_setopt($this->curl, CURLOPT_HTTPHEADER, array( 'Authorization: Basic ' . base64_encode($this->cpanelUsername.':'.$this->cpanelPassword)) );
$result = curl_exec($this->curl);
$this->apiCallTime += curl_getinfo($this->curl, CURLINFO_TOTAL_TIME);
$error = false;
// Check for valid result
if ($result === false)
{
echo curl_error($this->curl)."\n";
// If curl didn't return anything, there's nothing else to check
return false;
}
// Check for error code
if (curl_getinfo($this->curl, CURLINFO_HTTP_CODE) != '200')
{
$err = curl_getinfo($this->curl, CURLINFO_HTTP_CODE);
echo "Error $err\n";
$error = true;
}
// Attempt to process result
$jsonResult = json_decode($result, true);
if (empty($jsonResult))
{
echo "Invalid JSON: \n".$result."\n";
return false;
}
// Check for cpanelresult object
if (isset($jsonResult['cpanelresult']))
{
$jsonResult = $jsonResult['cpanelresult'];
}
else
{
$error = true;
}
// Check for cpanel error
if (isset($jsonResult['error']))
{
echo $jsonResult['error']."\n";
$error = true;
}
if ($error)
{
// No sense going past here... no more information to get
return false;
}
return $jsonResult;
}
}
?>
Jefferson, acompanho seu blog desde os tempos do portal (hoje “https://ryan.com.br/dvd_portal.htm”) e adoro muito tanto o que escreve como a forma como escreve.
Nunca achei necessário intervir antes pois a grande maioria dos temas são novidade ou fora da minha área de atuação mas neste caso acho que tenho algumas informações que podem, ou não, ser interessantes.
Você pode editar este comentário a vontade, retirando o que não for pertinente, que não vou ficar incomodado. Muito pelo contrário, vou me sentir orgulhoso se passar pelo seu “filtro” pessoal.
Com relação ao tema endereço IP não seria mais “correto” utilizar os termos público/privado ao invés de externo/interno?
Em ambos os casos são endereços IP (um número de 32 bits) mas o que difere sua função seria a possibilidade dos endereços públicos serem roteáveis pelos equipamentos da Internet enquanto os privados não, embora todos eles são roteáveis de maneira geral mas os endereços privados são bloqueados pelos equipamentos da rede mundial.
Você ainda me surpreendeu ao utilizar os termos externo/interno pois o que normalmente tenho visto por aí são válido/inválido. Tá, eu sei que externo/interno cabe bem melhor no contexto do tema do que válido/inválido e também sei que você é experto o suficiente para saber a diferença, mas porque não público/privado? Nem acho que seria necessário alterar a sua explicação para usar estes termos.
De qualquer forma, muito obrigado pela oportunidade de me expressar a respeito do tema.
Sidmar.
Sidmar,
Somente mais ou menos uma hora depois de publicar o texto eu me lembrei de que geralmente se usa o termo “ip público”. Eu escrevi externo porque na ocasião eu estava trabalhando com várias fontes que chamavam de “external” e nenhuma que chamava de “public”, daí fiquei “contaminado” pelo termo. Entretanto Eu fiquei matutando se deveria mudar o texto e fiquei em dúvida, porque o IP externo nem sempre é literalmente “público”. “Válido/Inválido” no contexto da minha explicação soa ainda pior. Eu ainda não decidi o que fazer a respeito.
Mas obrigado pela contribuição.