Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

dyndns: Add LuaDNS provider #4663

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
161 changes: 142 additions & 19 deletions src/etc/inc/dyndns.class
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@
* - HN (hn.org) -- incomplete checking!
* - Hover (www.hover.com)
* - Loopia (loopia.se)
* - LuaDNS (luadns.com)
* - Name.com (name.com)
* - Name.com IPv6 (name.com)
* - Namecheap (namecheap.com)
Expand Down Expand Up @@ -135,6 +136,7 @@
* HN.org - Last Tested: 12 July 2005
* Hover - Last Tested: 15 February 2017
* Loopia - Last Tested: 21 August 2019
* LuaDNS - Last Tested: 10 December 2023
* Name.com - Last Tested: 5 Dec 2021
* Name.com IPv6 - Last Tested: 5 Dec 2021
* Namecheap - Last Tested: 31 August 2010
Expand Down Expand Up @@ -260,6 +262,8 @@
case 'cloudns':
case 'godaddy':
case 'godaddy-v6':
case 'luadns':
case 'luadns-v6':
if (!$dnsUser) $this->_error(3);
if (!$dnsPass) $this->_error(4);
if (!$dnsHost) $this->_error(5);
Expand Down Expand Up @@ -342,6 +346,7 @@
case 'godaddy-v6':
case 'he-net-v6':
case 'linode-v6':
case 'luadns-v6':
case 'mythicbeasts-v6':
case 'name.com-v6':
case 'noip-free-v6':
Expand Down Expand Up @@ -388,16 +393,17 @@
$this->_dnsMaxCacheAgeDays = 25;
}
}
$this->_logPrefix = gettext("Dynamic DNS") . " {$this->_dnsService} ({$this->_FQDN}): ";
if ($this->_dnsVerboseLog) {
log_error(sprintf(gettext('Dynamic DNS (%1$s): running get_failover_interface for %2$s. found %3$s'), $this->_FQDN, $dnsRequestIf, $this->_dnsRequestIf));
log_error($this->_logPrefix . sprintf(gettext('running get_failover_interface for %1$s. found %2$s'), $dnsRequestIf, $this->_dnsRequestIf));
}
$this->_dnsRequestIfIP = get_interface_ip($dnsRequestIf);
$this->_dnsDummyUpdateDone = false;
$this->_forceUpdateNeeded = $forceUpdate;

// Ensure that we were able to lookup the IP
if (!is_ipaddr($this->_dnsIP)) {
log_error(sprintf(gettext('Dynamic DNS (%1$s) There was an error trying to determine the public IP for interface - %2$s (%3$s %4$s).'), $this->_FQDN, $dnsIf, $this->_if, $this->_dnsIP));
log_error($this->_logPrefix . sprintf(gettext('There was an error trying to determine the public IP for interface - %1$s (%2$s %3$s).'), $dnsIf, $this->_if, $this->_dnsIP));
unlock($dyndnslck);
return;
}
Expand Down Expand Up @@ -459,6 +465,8 @@
case 'hover':
case 'linode':
case 'linode-v6':
case 'luadns':
case 'luadns-v6':
case 'loopia':
case 'mythicbeasts':
case 'mythicbeasts-v6':
Expand Down Expand Up @@ -525,7 +533,7 @@
function _update() {

if ($this->_dnsVerboseLog) {
log_error(sprintf(gettext('Dynamic DNS %1$s (%2$s): _update() starting.'), $this->_dnsService, $this->_FQDN));
log_error($this->_logPrefix . gettext('_update() starting.'));
}

if (strstr($this->_dnsRequestIf, "_vip")) {
Expand Down Expand Up @@ -1672,7 +1680,7 @@
$linode_api = "https://api.linode.com/v4";
$record_type = $this->_useIPv6 ? "AAAA" : "A";
$record_name = $this->_dnsHost == "@" ? "" : $this->_dnsHost;
$err_prefix = gettext("Dynamic DNS") . " {$this->_dnsService} ({$this->_FQDN}): (" . gettext("Error") . ")";
$err_prefix = $this->_logPrefix . "(" . gettext("Error") . ")";
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'Accept: application/json',
Expand Down Expand Up @@ -1792,6 +1800,96 @@
curl_setopt($ch, CURLOPT_URL, 'https://update6.dedyn.io/?hostname=' . $this->_dnsHost);
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Authorization: Token ' . $this->_dnsPass));
break;
case 'luadns':
case 'luadns-v6':
/* LuaDNS REST API: https://www.luadns.com/api.html
*
* For the sake of simplicity, the DNS record must exist
* before it can be updated, since updates require lookup of
* zone and record numerical IDs.
*/
$needsIP = TRUE;
$server = 'https://api.luadns.com/v1';
$recordType = $this->_useIPv6 ? "AAAA" : "A";
$this->_FQDN = ltrim($this->_FQDN, '@.');

/* Common settings */
$headers = array(
'Accept: application/json',
);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_USERPWD, "{$this->_dnsUser}:{$this->_dnsPass}");

/* Lookup Zone ID */
curl_setopt($ch, CURLOPT_URL, "{$server}/zones");
$response = curl_exec($ch);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if ($http_code != 200) {
log_error($this->_logPrefix . gettext("Could not get zone list"));
$curl_error = @curl_error($ch);
$this->_checkStatus($http_code, $curl_error, $response, null);
return false;
}

$zone_id = -1;
foreach (json_decode($response, true) as $zone) {
if ($zone['name'] != $this->_dnsDomain) {
continue;
}

$zone_id = $zone['id'];
if ($this->_dnsVerboseLog) {
log_error("{$zone['name']}: {$zone['id']}");
}
break;
}

if ($zone_id < 0) {
log_error($this->_logPrefix . gettext("Could not find zone"));
return false;
}

/* Lookup Record ID */
curl_setopt($ch, CURLOPT_URL, "{$server}/zones/{$zone_id}/records");
$response = curl_exec($ch);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if ($http_code != 200) {
log_error($this->_logPrefix . gettext("Could not get record list"));
$curl_error = @curl_error($ch);
$this->_checkStatus($http_code, $curl_error, $response, null);
return false;
}

$record_name = "{$this->_FQDN}.";
$record_id = -1;
foreach (json_decode($response, true) as $record) {
if ($record['type'] != $recordType || $record['name'] != $record_name) {
continue;
}

$record_id = $record['id'];
if ($this->_dnsVerboseLog) {
log_error("{$record['name']}: {$record['id']}");
}
break;
}

if ($record_id < 0) {
log_error($this->_logPrefix . gettext("Could not find record"));
return false;
}

$post_data = array();
$post_data['id'] = $record_id;
$post_data['zone_id'] = $zone_id;
$post_data['name'] = $record_name;
$post_data['type'] = $recordType;
$post_data['content'] = $this->_dnsIP;
$post_data['ttl'] = $this->_dnsTTL ? (int)$this->_dnsTTL : 3600;
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($post_data));
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "PUT");
curl_setopt($ch, CURLOPT_URL, "{$server}/zones/{$zone_id}/records/{$record_id}");
break;
default:
break;
}
Expand All @@ -1816,7 +1914,7 @@
$this->_checkStatus($http_code, $curl_error, $data, $header);
}
if ($this->_dnsVerboseLog) {
log_error(sprintf(gettext('Dynamic DNS %1$s (%2$s): _update() ending.'), $this->_dnsService, $this->_FQDN));
log_error($this->_logPrefix . gettext('_update() ending.'));
}
}

Expand All @@ -1832,7 +1930,7 @@
function _remove($existing_ip = NULL) {
$remove_allowed = false;
if ($this->_dnsVerboseLog) {
log_error(sprintf(gettext('Dynamic DNS %1$s (%2$s): _remove() starting.'), $this->_dnsService, $this->_FQDN));
log_error($this->_logPrefix . gettext('_remove() starting.'));
}

if (strstr($this->_dnsRequestIf, "_vip")) {
Expand Down Expand Up @@ -1902,7 +2000,7 @@
function _lookup_current() {
$lookup_allowed = false;
if ($this->_dnsVerboseLog) {
log_error(sprintf(gettext('Dynamic DNS %1$s (%2$s): _listCurrent() starting.'), $this->_dnsService, $this->_FQDN));
log_error($this->_logPrefix . gettext('_listCurrent() starting.'));
}

if (strstr($this->_dnsRequestIf, "_vip")) {
Expand Down Expand Up @@ -1964,7 +2062,7 @@
*/
function _checkLookupStatus($curl_error, $data, $header) {
if ($this->_dnsVerboseLog) {
log_error(sprintf(gettext('Dynamic DNS %1$s (%2$s): _checkLookupStatus() starting.'), $this->_dnsService, $this->_FQDN));
log_error($this->_logPrefix . gettext('_checkLookupStatus() starting.'));
}
$success_str = "(" . gettext("Success") . ") ";
$error_str = "(" . gettext("Error") . ") ";
Expand Down Expand Up @@ -2000,7 +2098,7 @@
}
if (!is_array($this->_existingRecords)){
if ($this->_dnsVerboseLog) {
log_error(sprintf(gettext('Dynamic DNS %1$s (%2$s): _checkLookupStatus() ending. No matching records found.'), $this->_dnsService, $this->_FQDN));
log_error($this->_logPrefix . gettext('_checkLookupStatus() ending. No matching records found.'));
}
}
break;
Expand All @@ -2015,12 +2113,12 @@
*/
function _checkStatus($http_code, $curl_error, $data, $header) {
if ($this->_dnsVerboseLog) {
log_error(sprintf(gettext('Dynamic DNS %1$s (%2$s): _checkStatus() starting.'), $this->_dnsService, $this->_FQDN));
log_error($this->_logPrefix . gettext('_checkStatus() starting.'));
}
$successful_update = false;
$success_str = "(" . gettext("Success") . ") ";
$error_str = "(" . gettext("Error") . ") ";
$status_intro = "phpDynDNS ({$this->_dnsHost}): ";
$status_intro = $this->_logPrefix;

if ($this->_dnsService != 'ods' && !empty($curl_error)) {
$status = gettext("Curl error occurred:") . " {$curl_error}";
Expand Down Expand Up @@ -2993,7 +3091,7 @@
break;
case 'linode':
case 'linode-v6':
$status_intro = gettext("Dynamic DNS") . " {$this->_dnsService} ({$this->_FQDN}): ";
$status_intro = $this->_logPrefix;
$result = json_decode($data,true);
if ($this->_dnsVerboseLog) {
log_error(sprintf(gettext('_checkStatus() results: %1$s'), $data));
Expand Down Expand Up @@ -3064,6 +3162,31 @@
log_error($status_intro . " ( " . gettext("Error message: ") . $result['status'] . " )");
}
break;
case 'luadns':
case 'luadns-v6':
switch ($http_code) {
case '200':
$status = $status_intro . $success_str . gettext("IP Address Updated Successfully!");
$successful_update = true;
break;
case '400':
case '401':
case '403':
case '404':
case '422':
case '429':
/* https://www.luadns.com/api.html#server-error-codes */
$result = json_decode($data, true);
$status = $status_intro . $error_str . $result['status'] . " - " . $result['message'];
break;
default:
/* Don't expect JSON */
$status = $status_intro . "(" . gettext("Unknown Response") . ")";
log_error($status_intro . gettext("PAYLOAD:") . " {$data}");
$this->_debug($data);
break;
}
break;
default:
break;
}
Expand Down Expand Up @@ -3091,7 +3214,7 @@
$this->status = $status;
log_error($status);
if ($this->_dnsVerboseLog) {
log_error(sprintf(gettext('Dynamic DNS %1$s (%2$s): _checkStatus() ending.'), $this->_dnsService, $this->_FQDN));
log_error($this->_logPrefix . gettext('_checkStatus() ending.'));
}
}

Expand Down Expand Up @@ -3150,7 +3273,7 @@
*/
function _detectChange() {
if ($this->_dnsVerboseLog) {
log_error(sprintf(gettext('Dynamic DNS %1$s (%2$s): _detectChange() starting.'), $this->_dnsService, $this->_FQDN));
log_error($this->_logPrefix . gettext('_detectChange() starting.'));
}

$currentTime = time();
Expand Down Expand Up @@ -3251,7 +3374,7 @@
}
function _checkIP() {
if ($this->_dnsVerboseLog) {
log_error(sprintf(gettext('Dynamic DNS %1$s (%2$s): _checkIP() starting.'), $this->_dnsService, $this->_FQDN));
log_error($this->_logPrefix . gettext('_checkIP() starting.'));
}

if ($this->_useIPv6 == true) {
Expand All @@ -3262,20 +3385,20 @@
} else {
$ip_address = dyndnsCheckIP($this->_if);
if (!is_ipaddr($ip_address)) {
log_error(sprintf(gettext('Dynamic DNS %1$s (%2$s): IP address could not be extracted from Check IP Service'), $this->_dnsService, $this->_FQDN));
log_error($this->_logPrefix . gettext('IP address could not be extracted from Check IP Service'));
return 0;
} elseif (is_private_ip($ip_address)) {
log_error(sprintf(gettext('Dynamic DNS %1$s (%2$s): Public IP address could not be extracted from Check IP Service'), $this->_dnsService, $this->_FQDN));
log_error($this->_logPrefix . gettext('Public IP address could not be extracted from Check IP Service'));
return 0;
}
}
if ($this->_useIPv6 == false && is_private_ip(get_interface_ip($this->_if))) {
if ($this->_dnsVerboseLog) {
log_error(sprintf(gettext('Dynamic DNS %1$s (%2$s): %3$s extracted from Check IP Service'), $this->_dnsService, $this->_FQDN, $ip_address));
log_error($this->_logPrefix . "{$ip_address}" . gettext(' extracted from Check IP Service'));
}
} else {
if ($this->_dnsVerboseLog) {
log_error(sprintf(gettext('Dynamic DNS %1$s (%2$s): %3$s extracted from local system.'), $this->_dnsService, $this->_FQDN, $ip_address));
log_error($this->_logPrefix . "{$ip_address}" . gettext(' extracted from local system.'));
}
}
$this->_dnsIP = $ip_address;
Expand Down
1 change: 1 addition & 0 deletions src/etc/inc/globals.inc
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,7 @@ $dyndns_split_domain_types = [
'godaddy', 'godaddy-v6',
'gratisdns',
'linode', 'linode-v6',
'luadns', 'luadns-v6',
"mythicbeasts", "mythicbeasts-v6",
'namecheap',
"name.com", "name.com-v6",
Expand Down
4 changes: 2 additions & 2 deletions src/etc/inc/services.inc
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@
*/


define('DYNDNS_PROVIDER_VALUES', 'all-inkl azure azurev6 citynetwork cloudflare cloudflare-v6 cloudns custom custom-v6 desec desec-v6 digitalocean digitalocean-v6 dnsexit dnsimple dnsimple-v6 dnsmadeeasy dnsomatic domeneshop domeneshop-v6 dreamhost dreamhost-v6 duiadns duiadns-v6 dyfi dyndns dyndns-custom dyndns-static dyns dynv6 dynv6-v6 easydns easydns-v6 eurodns freedns freedns-v6 freedns2 freedns2-v6 glesys gandi-livedns gandi-livedns-v6 godaddy godaddy-v6 googledomains gratisdns he-net he-net-v6 he-net-tunnelbroker hover linode linode-v6 loopia mythicbeasts mythicbeasts-v6 name.com name.com-v6 namecheap nicru nicru-v6 noip noip-v6 noip-free noip-free-v6 onecom onecom-v6 ods opendns ovh-dynhost route53 route53-v6 selfhost spdyn spdyn-v6 strato yandex yandex-v6 zoneedit porkbun porkbun-v6');
define('DYNDNS_PROVIDER_DESCRIPTIONS', 'All-Inkl.com,Azure DNS,Azure DNS (v6),City Network,Cloudflare,Cloudflare (v6),ClouDNS,Custom,Custom (v6),deSEC,deSEC (v6),DigitalOcean,DigitalOcean (v6),DNSexit,DNSimple,DNSimple (v6),DNS Made Easy,DNS-O-Matic,Domeneshop,Domeneshop (v6),DreamHost,Dreamhost (v6),DuiaDns.net,DuiaDns.net (v6),DY.fi,DynDNS (dynamic),DynDNS (custom),DynDNS (static),DyNS,Dynv6,Dynv6 (v6),easyDNS,easyDNS (v6),Euro Dns,freeDNS,freeDNS (v6),freeDNS API Version 2, freeDNS API Version 2 (v6),GleSYS,Gandi LiveDNS,Gandi LiveDNS (v6),GoDaddy,GoDaddy (v6),Google Domains,GratisDNS,HE.net,HE.net (v6),HE.net Tunnelbroker,Hover,Linode,Linode (v6),Loopia,Mythic Beasts,Mythic Beasts (v6),Name.com,Name.com (v6),Namecheap,NIC.RU,NIC.RU (v6),No-IP,No-IP (v6),No-IP (free),No-IP (free-v6),One.com,One.com (v6),ODS.org,OpenDNS,OVH DynHOST,Route 53,Route 53 (v6),SelfHost,SPDYN,SPDYN (v6),Strato,Yandex,Yandex (v6),ZoneEdit,Porkbun,Porkbun (v6)');
define('DYNDNS_PROVIDER_VALUES', 'all-inkl azure azurev6 citynetwork cloudflare cloudflare-v6 cloudns custom custom-v6 desec desec-v6 digitalocean digitalocean-v6 dnsexit dnsimple dnsimple-v6 dnsmadeeasy dnsomatic domeneshop domeneshop-v6 dreamhost dreamhost-v6 duiadns duiadns-v6 dyfi dyndns dyndns-custom dyndns-static dyns dynv6 dynv6-v6 easydns easydns-v6 eurodns freedns freedns-v6 freedns2 freedns2-v6 glesys gandi-livedns gandi-livedns-v6 godaddy godaddy-v6 googledomains gratisdns he-net he-net-v6 he-net-tunnelbroker hover linode linode-v6 loopia luadns luadns-v6 mythicbeasts mythicbeasts-v6 name.com name.com-v6 namecheap nicru nicru-v6 noip noip-v6 noip-free noip-free-v6 onecom onecom-v6 ods opendns ovh-dynhost route53 route53-v6 selfhost spdyn spdyn-v6 strato yandex yandex-v6 zoneedit porkbun porkbun-v6');
define('DYNDNS_PROVIDER_DESCRIPTIONS', 'All-Inkl.com,Azure DNS,Azure DNS (v6),City Network,Cloudflare,Cloudflare (v6),ClouDNS,Custom,Custom (v6),deSEC,deSEC (v6),DigitalOcean,DigitalOcean (v6),DNSexit,DNSimple,DNSimple (v6),DNS Made Easy,DNS-O-Matic,Domeneshop,Domeneshop (v6),DreamHost,Dreamhost (v6),DuiaDns.net,DuiaDns.net (v6),DY.fi,DynDNS (dynamic),DynDNS (custom),DynDNS (static),DyNS,Dynv6,Dynv6 (v6),easyDNS,easyDNS (v6),Euro Dns,freeDNS,freeDNS (v6),freeDNS API Version 2, freeDNS API Version 2 (v6),GleSYS,Gandi LiveDNS,Gandi LiveDNS (v6),GoDaddy,GoDaddy (v6),Google Domains,GratisDNS,HE.net,HE.net (v6),HE.net Tunnelbroker,Hover,Linode,Linode (v6),Loopia,LuaDNS,LuaDNS (v6),Mythic Beasts,Mythic Beasts (v6),Name.com,Name.com (v6),Namecheap,NIC.RU,NIC.RU (v6),No-IP,No-IP (v6),No-IP (free),No-IP (free-v6),One.com,One.com (v6),ODS.org,OpenDNS,OVH DynHOST,Route 53,Route 53 (v6),SelfHost,SPDYN,SPDYN (v6),Strato,Yandex,Yandex (v6),ZoneEdit,Porkbun,Porkbun (v6)');

/* implement ipv6 route advertising daemon */
function services_radvd_configure($blacklist = array()) {
Expand Down