Skip to content
Permalink
Branch: master
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
2327 lines (2260 sloc) 92.4 KB
<?php
/*
* dyndns.class
*
* part of pfSense (https://www.pfsense.org)
* Copyright (c) 2004-2018 Rubicon Communications, LLC (Netgate)
* All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* PHP.updateDNS (pfSense version)
*
* +====================================================+
* Services Supported:
* - DynDns (dyndns.org) [dynamic, static, custom]
* - No-IP (no-ip.com)
* - EasyDNS (easydns.com)
* - DHS (www.dhs.org)
* - HN (hn.org) -- incomplete checking!
* - DynS (dyns.org)
* - ZoneEdit (zoneedit.com)
* - FreeDNS (freedns.afraid.org)
* - FreeDNS IPv6 (freedns.afraid.org)
* - Loopia (loopia.se)
* - StaticCling (staticcling.org)
* - DNSexit (dnsexit.com)
* - OpenDNS (opendns.com)
* - Namecheap (namecheap.com)
* - HE.net (dns.he.net)
* - HE.net IPv6 (dns.he.net)
* - HE.net Tunnelbroker IP update (ipv4.tunnelbroker.net)
* - SelfHost (selfhost.de)
* - Amazon Route 53 (aws.amazon.com)
* - DNS-O-Matic (dnsomatic.com)
* - Custom DDNS (any URL)
* - Custom DDNS IPv6 (any URL)
* - Cloudflare (www.cloudflare.com)
* - Cloudflare IPv6 (www.cloudflare.com)
* - Eurodns (eurodns.com)
* - GratisDNS (gratisdns.dk)
* - City Network (citynetwork.se)
* - GleSYS (glesys.com)
* - DNSimple (dnsimple.com)
* - Google Domains (domains.google.com)
* - DNS Made Easy (www.dnsmadeeasy.com)
* - SPDYN (spdyn.de)
* - SPDYN IPv6 (spdyn.de)
* - All-Inkl (all-inkl.com)
* - DuiaDNS (www.duiadns.net)
* - DuiaDNS IPv6 (www.duiadns.net)
* - Hover (www.hover.com)
* - DreamHost DNS (www.dreamhost.com)
* - ClouDNS (www.cloudns.net)
* - GoDaddy (www.godaddy.com)
* - Azure DNS (azure.microsoft.com)
* +----------------------------------------------------+
* Requirements:
* - PHP version 4.0.2 or higher with the CURL Library and the PCRE Library
* +----------------------------------------------------+
* Public Functions
* - updatedns()
*
* Private Functions
* - _update()
* - _checkStatus()
* - _error()
* - _detectChange()
* - _debug()
* - _checkIP()
* +----------------------------------------------------+
* DynDNS Dynamic - Last Tested: 12 July 2005
* DynDNS Static - Last Tested: NEVER
* DynDNS Custom - Last Tested: NEVER
* No-IP - Last Tested: 20 July 2008
* HN.org - Last Tested: 12 July 2005
* EasyDNS - Last Tested: 20 July 2008
* DHS - Last Tested: 12 July 2005
* ZoneEdit - Last Tested: NEVER
* Dyns - Last Tested: NEVER
* ODS - Last Tested: 02 August 2005
* FreeDNS - Last Tested: 01 May 2016
* FreeDNS IPv6 - Last Tested: 01 May 2016
* Loopia - Last Tested: NEVER
* StaticCling - Last Tested: 27 April 2006
* DNSexit - Last Tested: 20 July 2008
* OpenDNS - Last Tested: 4 August 2008
* Namecheap - Last Tested: 31 August 2010
* HE.net - Last Tested: 7 July 2013
* HE.net IPv6 - Last Tested: 7 July 2013
* HE.net Tunnel - Last Tested: 28 June 2011
* SelfHost - Last Tested: 26 December 2011
* Amazon Route 53 - Last Tested: 04 February 2017
* DNS-O-Matic - Last Tested: 9 September 2010
* Cloudflare - Last Tested: 05 September 2016
* Cloudflare IPv6 - Last Tested: 17 July 2016
* Eurodns - Last Tested: 27 June 2013
* GratisDNS - Last Tested: 15 August 2012
* OVH DynHOST - Last Tested: NEVER
* City Network - Last Tested: 13 November 2013
* GleSYS - Last Tested: 3 February 2015
* DNSimple - Last Tested: 09 February 2015
* Google Domains - Last Tested: 27 April 2015
* DNS Made Easy - Last Tested: 27 April 2015
* SPDYN - Last Tested: 02 July 2016
* SPDYN IPv6 - Last Tested: 02 July 2016
* All-Inkl - Last Tested: 12 November 2016
* DuiaDNS - Last Tested: 25 November 2016
* DuiaDNS IPv6 - Last Tested: 25 November 2016
* Hover - Last Tested: 15 February 2017
* DreamHost - Last Tested: 30 April 2017
* DreamHost IPv6 - Not Yet Tested
* ClouDNS - Last Tested: 22 August 2017
* GoDaddy - Last Tested: 22 November 2017
* GoDaddy IPv6 - Last Tested: 22 November 2017
* DigitalOcean - Not Yet Tested
* Azure DNS - Last Tested: 08 March 2018
* +====================================================+
*
* @author E.Kristensen
* @link http://www.idylldesigns.com/projects/phpdns/
* @version 0.8
* @updated 13 October 05 at 21:02:42 GMT
*
* DNSexit/OpenDNS support and multiwan extension for pfSense by Ermal Luçi
* Custom DNS support by Matt Corallo
*
*/
class updatedns {
var $_cacheFile;
var $_cacheFile_v6;
var $_debugFile;
var $_UserAgent = 'phpDynDNS/0.7';
var $_errorVerbosity = 0;
var $_dnsService;
var $_dnsUser;
var $_dnsPass;
var $_dnsHost;
var $_dnsDomain;
var $_FQDN;
var $_dnsIP;
var $_dnsWildcard;
var $_dnsProxied;
var $_dnsMX;
var $_dnsBackMX;
var $_dnsServer;
var $_dnsPort;
var $_dnsUpdateURL;
var $_dnsZoneID;
var $_dnsTTL;
var $status;
var $_debugID;
var $_if;
var $_dnsResultMatch;
var $_dnsRequestIf;
var $_dnsRequestIfIP;
var $_dnsVerboseLog;
var $_curlIpresolveV4;
var $_curlSslVerifypeer;
var $_dnsMaxCacheAgeDays;
var $_dnsDummyUpdateDone;
var $_forceUpdateNeeded;
var $_useIPv6;
var $_existingRecords;
/*
* Public Constructor Function (added 12 July 05) [beta]
* - Gets the dice rolling for the update.
* - $dnsResultMatch should only be used with $dnsService = 'custom'
* - $dnsResultMatch is parsed for '%IP%', which is the IP the provider was updated to,
* - it is otherwise expected to be exactly identical to what is returned by the Provider.
* - $dnsUser, and $dnsPass indicate HTTP Auth for custom DNS, if they are needed in the URL (GET Variables), include them in $dnsUpdateURL.
* - $For custom requests, $dnsUpdateURL is parsed for '%IP%', which is replaced with the new IP.
*/
function updatedns ($dnsService = '', $dnsHost = '', $dnsDomain = '', $dnsUser = '', $dnsPass = '',
$dnsWildcard = 'OFF', $dnsProxied = false, $dnsMX = '', $dnsIf = '', $dnsBackMX = '',
$dnsServer = '', $dnsPort = '', $dnsUpdateURL = '', $forceUpdate = false,
$dnsZoneID ='', $dnsTTL='', $dnsResultMatch = '', $dnsRequestIf = '',
$dnsID = '', $dnsVerboseLog = false, $curlIpresolveV4 = false, $curlSslVerifypeer = true) {
global $config, $g, $dyndns_split_domain_types;
if (in_array($dnsService, $dyndns_split_domain_types)) {
$this->_FQDN = $dnsHost . "." . $dnsDomain;
} else {
$this->_FQDN = $dnsHost;
}
$this->_cacheFile = "{$g['conf_path']}/dyndns_{$dnsIf}{$dnsService}" . escapeshellarg($this->_FQDN) . "{$dnsID}.cache";
$this->_cacheFile_v6 = "{$g['conf_path']}/dyndns_{$dnsIf}{$dnsService}" . escapeshellarg($this->_FQDN) . "{$dnsID}_v6.cache";
$this->_debugFile = "{$g['varetc_path']}/dyndns_{$dnsIf}{$dnsService}" . escapeshellarg($this->_FQDN) . "{$dnsID}.debug";
$this->_curlIpresolveV4 = $curlIpresolveV4;
$this->_curlSslVerifypeer = $curlSslVerifypeer;
$this->_dnsVerboseLog = $dnsVerboseLog;
if ($this->_dnsVerboseLog) {
log_error(gettext("Dynamic DNS: updatedns() starting"));
}
$dyndnslck = lock("DDNS".$dnsID, LOCK_EX);
if (!$dnsService) $this->_error(2);
switch ($dnsService) {
case 'freedns':
case 'freedns-v6':
if (!$dnsHost) $this->_error(5);
break;
case "namecheap":
if (!$dnsPass) $this->_error(4);
if (!$dnsHost) $this->_error(5);
if (!$dnsDomain) $this->_error(5);
break;
case "cloudflare-v6":
case "cloudflare":
case "gratisdns":
case "hover":
if (!$dnsUser) $this->_error(3);
if (!$dnsPass) $this->_error(4);
if (!$dnsHost) $this->_error(5);
if (!$dnsDomain) $this->_error(5);
break;
case 'route53-v6':
case 'route53':
if (!$dnsZoneID) $this->_error(8);
if (!$dnsTTL) $this->_error(9);
break;
case 'cloudns':
case "godaddy":
case "godaddy-v6":
if (!$dnsUser) $this->_error(3);
if (!$dnsPass) $this->_error(4);
if (!$dnsHost) $this->_error(5);
if (!$dnsDomain) $this->_error(5);
if (!$dnsTTL) $this->_error(9);
break;
case 'digitalocean':
if (!$dnsPass) $this->_error(4);
if (!$dnsHost) $this->_error(5);
if (!$dnsDomain) $this->_error(5);
if (!$dnsTTL) $this->_error(9);
break;
case 'azure':
case 'azurev6':
if (!$dnsUser) $this->_error(3);
if (!$dnsPass) $this->_error(4);
if (!$dnsHost) $this->_error(5);
if (!$dnsZoneID) $this->_error(8);
if (!$dnsTTL) $this->_error(9);
break;
case 'custom':
case 'custom-v6':
if (!$dnsUpdateURL) $this->_error(7);
break;
default:
if (!$dnsUser) $this->_error(3);
if (!$dnsPass) $this->_error(4);
if (!$dnsHost) $this->_error(5);
}
switch ($dnsService) {
case 'he-net-v6':
case 'custom-v6':
case 'spdyn-v6':
case 'route53-v6':
case 'duiadns-v6':
case 'freedns-v6':
case 'cloudflare-v6':
case 'dreamhost-v6':
case 'godaddy-v6':
case 'azurev6':
$this->_useIPv6 = true;
break;
default:
$this->_useIPv6 = false;
}
$this->_dnsService = strtolower($dnsService);
$this->_dnsUser = $dnsUser;
$this->_dnsPass = base64_decode($dnsPass);
$this->_dnsHost = $dnsHost;
$this->_dnsDomain = $dnsDomain;
$this->_dnsServer = $dnsServer;
$this->_dnsPort = $dnsPort;
$this->_dnsWildcard = $dnsWildcard;
$this->_dnsProxied = $dnsProxied;
$this->_dnsMX = $dnsMX;
$this->_dnsZoneID = $dnsZoneID;
$this->_dnsTTL = $dnsTTL;
$this->_if = get_failover_interface($dnsIf);
$this->_checkIP();
$this->_dnsUpdateURL = $dnsUpdateURL;
$this->_dnsResultMatch = $dnsResultMatch;
$this->_dnsRequestIf = get_failover_interface($dnsRequestIf);
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));
}
$this->_dnsRequestIfIP = get_interface_ip($dnsRequestIf);
$this->_dnsMaxCacheAgeDays = 25;
$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));
unlock($dyndnslck);
return;
}
$this->_debugID = rand(1000000, 9999999);
if ($forceUpdate == false && $this->_detectChange() == false) {
$this->_error(10);
} else {
switch ($this->_dnsService) {
case 'glesys':
case 'dnsomatic':
case 'dyndns':
case 'dyndns-static':
case 'dyndns-custom':
case 'dhs':
case 'noip':
case 'noip-free':
case 'easydns':
case 'hn':
case 'zoneedit':
case 'dyns':
case 'ods':
case 'freedns':
case 'freedns-v6':
case 'loopia':
case 'staticcling':
case 'dnsexit':
case 'custom':
case 'custom-v6':
case 'opendns':
case 'namecheap':
case 'he-net':
case 'he-net-v6':
case 'duiadns':
case 'duiadns-v6':
case 'selfhost':
case 'he-net-tunnelbroker':
case 'route53':
case 'route53-v6':
case 'cloudflare':
case 'cloudflare-v6':
case 'eurodns':
case 'gratisdns':
case 'ovh-dynhost':
case 'citynetwork':
case 'dnsimple':
case 'googledomains':
case 'dnsmadeeasy':
case 'spdyn':
case 'spdyn-v6':
case 'all-inkl':
case 'cloudns':
case 'hover':
case 'digitalocean':
case 'godaddy':
case 'godaddy-v6':
case 'azure':
case 'azurev6':
$this->_update();
if ($this->_dnsDummyUpdateDone == true) {
// If a dummy update was needed, then sleep a while and do the update again to put the proper address back.
// Some providers (e.g. No-IP free accounts) need to have at least 1 address change every month.
// If the address has not changed recently, or the user did "Force Update", then the code does
// a dummy address change for providers like this.
sleep(10);
$this->_update();
}
break;
case 'dreamhost':
case 'dreamhost-v6':
$this->_lookup_current();
if (isset($this->status)) {
return;
}
foreach ($this->_existingRecords as $record) {
$this->_remove($record['existing_val']);
$this->_update();
}
break;
default:
$this->_error(6);
break;
}
}
unlock($dyndnslck);
}
/*
* Private Function (added 12 July 05) [beta]
* Send Update To Selected Service.
*/
function _update() {
if ($this->_dnsVerboseLog) {
log_error(sprintf(gettext('Dynamic DNS %1$s (%2$s): _update() starting.'), $this->_dnsService, $this->_FQDN));
}
if (strstr($this->_dnsRequestIf, "_vip")) {
$parentif = get_configured_vip_interface($this->_dnsRequestIf);
$realparentif = convert_friendly_interface_to_real_interface_name($parentif);
} else {
$realparentif = $this->_dnsRequestIf;
}
$ch = curl_init();
if ($this->_useIPv6 == false) {
curl_setopt($ch, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
}
if ($this->_dnsService != 'ods') {
curl_setopt($ch, CURLOPT_USERAGENT, $this->_UserAgent);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($ch, CURLOPT_INTERFACE, 'if!' . $realparentif);
curl_setopt($ch, CURLOPT_TIMEOUT, 120); // Completely empirical
}
switch ($this->_dnsService) {
case 'glesys':
$needsIP = TRUE;
$server = 'https://api.glesys.com/domain/updaterecord/format/json';
curl_setopt($ch, CURLOPT_USERPWD, $this->_dnsUser.':'.$this->_dnsPass);
$post_data['recordid'] = $this->_FQDN;
$post_data['data'] = $this->_dnsIP;
curl_setopt($ch, CURLOPT_URL, $server);
curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
break;
case 'dyndns':
case 'dyndns-static':
case 'dyndns-custom':
$needsIP = FALSE;
if (isset($this->_dnsWildcard) && $this->_dnsWildcard != "OFF") {
$this->_dnsWildcard = "ON";
}
curl_setopt($ch, CURLOPT_USERPWD, $this->_dnsUser.':'.$this->_dnsPass);
$server = "https://members.dyndns.org/nic/update";
$port = "";
if ($this->_dnsServer) {
$server = $this->_dnsServer;
}
if ($this->_dnsPort) {
$port = ":" . $this->_dnsPort;
}
curl_setopt($ch, CURLOPT_URL, $server .$port . '?system=dyndns&hostname=' . $this->_dnsHost . '&myip=' . $this->_dnsIP . '&wildcard='.$this->_dnsWildcard . '&mx=' . $this->_dnsMX . '&backmx=NO');
break;
case 'dhs':
// DHS is disabled in the GUI because the following doesn't work.
$needsIP = TRUE;
$post_data['hostscmd'] = 'edit';
$post_data['hostscmdstage'] = '2';
$post_data['type'] = '4';
$post_data['updatetype'] = 'Online';
$post_data['mx'] = $this->_dnsMX;
$post_data['mx2'] = '';
$post_data['txt'] = '';
$post_data['offline_url'] = '';
$post_data['cloak'] = 'Y';
$post_data['cloak_title'] = '';
$post_data['ip'] = $this->_dnsIP;
$post_data['domain'] = 'dyn.dhs.org';
$post_data['hostname'] = $this->_dnsHost;
$post_data['submit'] = 'Update';
$server = "https://members.dhs.org/nic/hosts";
$port = "";
if ($this->_dnsServer) {
$server = $this->_dnsServer;
}
if ($this->_dnsPort) {
$port = ":" . $this->_dnsPort;
}
curl_setopt($ch, CURLOPT_URL, $server . $port);
curl_setopt($ch, CURLOPT_USERPWD, $this->_dnsUser.':'.$this->_dnsPass);
curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
break;
case 'noip':
case 'noip-free':
$needsIP = TRUE;
$server = "https://dynupdate.no-ip.com/ducupdate.php";
$port = "";
if ($this->_dnsServer) {
$server = $this->_dnsServer;
}
if ($this->_dnsPort) {
$port = ":" . $this->_dnsPort;
}
if (($this->_dnsService == "noip-free") &&
($this->_forceUpdateNeeded == true) &&
($this->_dnsDummyUpdateDone == false)) {
// Update the IP to a dummy value to force No-IP free accounts to see a change.
$iptoset = "192.168.1.1";
$this->_dnsDummyUpdateDone = true;
log_error(sprintf(gettext('Dynamic DNS %1$s (%2$s): Processing dummy update on No-IP free account. IP temporarily set to %3$s'), $this->_dnsService, $this->_dnsHost, $iptoset));
} else {
$iptoset = $this->_dnsIP;
}
curl_setopt($ch, CURLOPT_URL, $server . $port . '?username=' . urlencode($this->_dnsUser) . '&pass=' . urlencode($this->_dnsPass) . '&h[]=' . $this->_dnsHost.'&ip=' . $iptoset);
break;
case 'easydns':
$needsIP = TRUE;
curl_setopt($ch, CURLOPT_USERPWD, $this->_dnsUser.':'.$this->_dnsPass);
$server = "https://members.easydns.com/dyn/dyndns.php";
$port = "";
if ($this->_dnsServer) {
$server = $this->_dnsServer;
}
if ($this->_dnsPort) {
$port = ":" . $this->_dnsPort;
}
curl_setopt($ch, CURLOPT_URL, $server . $port . '?hostname=' . $this->_dnsHost . '&myip=' . $this->_dnsIP . '&wildcard=' . $this->_dnsWildcard . '&mx=' . $this->_dnsMX . '&backmx=' . $this->_dnsBackMX);
break;
case 'hn':
$needsIP = TRUE;
curl_setopt($ch, CURLOPT_USERPWD, $this->_dnsUser.':'.$this->_dnsPass);
$server = "http://dup.hn.org/vanity/update";
$port = "";
if ($this->_dnsServer) {
$server = $this->_dnsServer;
}
if ($this->_dnsPort) {
$port = ":" . $this->_dnsPort;
}
curl_setopt($ch, CURLOPT_URL, $server . $port . '?ver=1&IP=' . $this->_dnsIP);
break;
case 'zoneedit':
$needsIP = FALSE;
curl_setopt($ch, CURLOPT_USERPWD, $this->_dnsUser.':'.$this->_dnsPass);
$server = "https://dynamic.zoneedit.com/auth/dynamic.html";
$port = "";
if ($this->_dnsServer) {
$server = $this->_dnsServer;
}
if ($this->_dnsPort) {
$port = ":" . $this->_dnsPort;
}
curl_setopt($ch, CURLOPT_URL, "{$server}{$port}?host=" . $this->_dnsHost . '&dnsto=' . $this->_dnsIP);
break;
case 'dyns':
$needsIP = FALSE;
$server = "http://www.dyns.net/postscript011.php";
$port = "";
if ($this->_dnsServer) {
$server = $this->_dnsServer;
}
if ($this->_dnsPort) {
$port = ":" . $this->_dnsPort;
}
curl_setopt($ch, CURLOPT_URL, $server . $port . '?username=' . urlencode($this->_dnsUser) . '&password=' . $this->_dnsPass . '&host=' . $this->_dnsHost);
break;
case 'ods':
$needsIP = FALSE;
$misc_errno = 0;
$misc_error = "";
$server = "ods.org";
$port = "";
if ($this->_dnsServer) {
$server = $this->_dnsServer;
}
if ($this->_dnsPort) {
$port = ":" . $this->_dnsPort;
}
$this->con['socket'] = fsockopen("{$server}{$port}", "7070", $misc_errno, $misc_error, 30);
/* Check that we have connected */
if (!$this->con['socket']) {
print "error! could not connect.";
break;
}
/* Here is the loop. Read the incoming data (from the socket connection) */
while (!feof($this->con['socket'])) {
$this->con['buffer']['all'] = trim(fgets($this->con['socket'], 4096));
$code = substr($this->con['buffer']['all'], 0, 3);
sleep(1);
switch ($code) {
case 100:
fputs($this->con['socket'], "LOGIN ".$this->_dnsUser." ".$this->_dnsPass."\n");
break;
case 225:
fputs($this->con['socket'], "DELRR ".$this->_dnsHost." A\n");
break;
case 901:
fputs($this->con['socket'], "ADDRR ".$this->_dnsHost." A ".$this->_dnsIP."\n");
break;
case 795:
fputs($this->con['socket'], "QUIT\n");
break;
}
}
$this->_checkStatus(0, $code);
break;
case 'freedns':
case 'freedns-v6':
$needIP = TRUE;
curl_setopt($ch, CURLOPT_URL, 'https://freedns.afraid.org/dynamic/update.php?' . $this->_dnsPass . '&address=' . $this->_dnsIP);
break;
case 'dnsexit':
$needsIP = TRUE;
curl_setopt($ch, CURLOPT_URL, 'https://www.dnsexit.com/RemoteUpdate.sv?login='.$this->_dnsUser. '&password='.$this->_dnsPass.'&host='.$this->_dnsHost.'&myip='.$this->_dnsIP);
break;
case 'loopia':
$needsIP = TRUE;
if (isset($this->_dnsWildcard) && $this->_dnsWildcard != "OFF") $this->_dnsWildcard = "ON";
curl_setopt($ch, CURLOPT_USERPWD, $this->_dnsUser.':'.$this->_dnsPass);
curl_setopt($ch, CURLOPT_URL, 'https://dns.loopia.se/XDynDNSServer/XDynDNS.php?hostname='.$this->_dnsHost.'&myip='.$this->_dnsIP.'&wildcard='.$this->_dnsWildcard);
break;
case 'opendns':
$needsIP = FALSE;
if (isset($this->_dnsWildcard) && $this->_dnsWildcard != "OFF") $this->_dnsWildcard = "ON";
curl_setopt($ch, CURLOPT_USERPWD, $this->_dnsUser.':'.$this->_dnsPass);
$server = "https://updates.opendns.com/nic/update?hostname=". $this->_dnsHost;
$port = "";
if ($this->_dnsServer) {
$server = $this->_dnsServer;
}
if ($this->_dnsPort) {
$port = ":" . $this->_dnsPort;
}
curl_setopt($ch, CURLOPT_URL, $server .$port);
break;
case 'staticcling':
$needsIP = FALSE;
curl_setopt($ch, CURLOPT_URL, 'https://www.staticcling.org/update.html?login='.$this->_dnsUser.'&pass='.$this->_dnsPass);
break;
case 'dnsomatic':
/* Example syntax
https://username:password@updates.dnsomatic.com/nic/update?hostname=yourhostname&myip=ipaddress&wildcard=NOCHG&mx=NOCHG&backmx=NOCHG
*/
$needsIP = FALSE;
if (isset($this->_dnsWildcard) && $this->_dnsWildcard != "OFF") {
$this->_dnsWildcard = "ON";
}
/*
Reference: https://www.dnsomatic.com/wiki/api
DNS-O-Matic usernames are 3-25 characters.
DNS-O-Matic passwords are 6-20 characters.
All ASCII letters and numbers accepted.
Dots, dashes, and underscores allowed, but not at the beginning or end of the string.
Required: "rawurlencode" http://www.php.net/manual/en/function.rawurlencode.php
Encodes the given string according to RFC 3986.
*/
$server = "https://" . rawurlencode($this->_dnsUser) . ":" . rawurlencode($this->_dnsPass) . "@updates.dnsomatic.com/nic/update?hostname=";
if ($this->_dnsServer) {
$server = $this->_dnsServer;
}
if ($this->_dnsPort) {
$port = ":" . $this->_dnsPort;
}
curl_setopt($ch, CURLOPT_URL, $server . $this->_dnsHost . '&myip=' . $this->_dnsIP . '&wildcard='.$this->_dnsWildcard . '&mx=' . $this->_dnsMX . '&backmx=NOCHG');
break;
case 'namecheap':
/* Example:
https://dynamicdns.park-your-domain.com/update?host=[host_name]&domain=[domain.com]&password=[domain_password]&ip=[your_ip]
*/
$needsIP = FALSE;
$dnspass = trim($this->_dnsPass);
$server = "https://dynamicdns.park-your-domain.com/update?host={$this->_dnsHost}&domain={$this->_dnsDomain}&password={$dnspass}&ip={$this->_dnsIP}";
curl_setopt($ch, CURLOPT_URL, $server);
break;
case 'duiadns':
case 'duiadns-v6':
$needsIP = FALSE;
$server = "https://ipv4.duiadns.net/dyndns.duia?";
curl_setopt($ch, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($ch, CURLOPT_USERPWD, $this->_dnsUser . ':' . $this->_dnsPass);
curl_setopt($ch, CURLOPT_URL, $server . 'hostname=' . $this->_dnsHost . '&myip=' . $this->_dnsIP);
break;
case 'he-net':
case 'he-net-v6':
$needsIP = FALSE;
$server = "https://dyn.dns.he.net/nic/update?";
curl_setopt($ch, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($ch, CURLOPT_URL, $server . 'hostname=' . $this->_dnsHost . '&password=' . $this->_dnsPass . '&myip=' . $this->_dnsIP);
break;
case 'he-net-tunnelbroker':
$needsIP = FALSE;
$server = "https://ipv4.tunnelbroker.net/ipv4_end.php?";
curl_setopt($ch, CURLOPT_USERPWD, $this->_dnsUser . ':' . $this->_dnsPass);
curl_setopt($ch, CURLOPT_URL, $server . 'tid=' . $this->_dnsHost);
break;
case 'selfhost':
$needsIP = FALSE;
if (isset($this->_dnsWildcard) && $this->_dnsWildcard != "OFF") {
$this->_dnsWildcard = "ON";
}
curl_setopt($ch, CURLOPT_USERPWD, $this->_dnsUser.':'.$this->_dnsPass);
$server = "https://carol.selfhost.de/nic/update";
$port = "";
if ($this->_dnsServer) {
$server = $this->_dnsServer;
}
if ($this->_dnsPort) {
$port = ":" . $this->_dnsPort;
}
curl_setopt($ch, CURLOPT_URL, $server .$port . '?system=dyndns&hostname=' . $this->_dnsHost . '&myip=' . $this->_dnsIP . '&wildcard='.$this->_dnsWildcard . '&mx=' . $this->_dnsMX . '&backmx=NO');
break;
case 'route53':
require_once("r53.class");
$r53 = new Route53($this->_dnsUser, $this->_dnsPass);
$apiurl = $r53->getApiUrl($this->_dnsZoneID);
$xmlreq = $r53->getRequestBody($this->_dnsHost, $this->_dnsIP, $this->_dnsTTL);
$httphead = $r53->getHttpPostHeaders($this->_dnsZoneID, "us-east-1", hash("sha256",$xmlreq));
curl_setopt($ch, CURLOPT_HTTPHEADER, $httphead);
if($this->_dnsVerboseLog){
log_error(sprintf("Sending request to: %s", $apiurl));
foreach($httphead as $hv){
log_error(sprintf("Header: %s", $hv));
}
log_error(sprintf("XMLPOST: %s", $xmlreq));
}
curl_setopt($ch, CURLOPT_URL, $apiurl);
curl_setopt($ch, CURLOPT_POSTFIELDS, $xmlreq);
break;
case 'route53-v6':
require_once("r53.class");
$r53 = new Route53($this->_dnsUser, $this->_dnsPass);
$apiurl = $r53->getApiUrl($this->_dnsZoneID);
$xmlreq = $r53->getRequestBodyV6($this->_dnsHost, $this->_dnsIP, $this->_dnsTTL);
$httphead = $r53->getHttpPostHeaders($this->_dnsZoneID, "us-east-1", hash("sha256",$xmlreq));
curl_setopt($ch, CURLOPT_HTTPHEADER, $httphead);
if($this->_dnsVerboseLog){
log_error(sprintf("Sending request to: %s", $apiurl));
foreach($httphead as $hv){
log_error(sprintf("Header: %s", $hv));
}
log_error(sprintf("XMLPOST: %s", $xmlreq));
}
curl_setopt($ch, CURLOPT_URL, $apiurl);
curl_setopt($ch, CURLOPT_POSTFIELDS, $xmlreq);
break;
case 'custom':
case 'custom-v6':
if (strstr($this->dnsUpdateURL, "%IP%")) {$needsIP = TRUE;} else {$needsIP = FALSE;}
if ($this->_dnsUser != '') {
if ($this->_curlIpresolveV4) {
curl_setopt($ch, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
}
if ($this->_curlSslVerifypeer) {
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, TRUE);
} else {
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
}
curl_setopt($ch, CURLOPT_USERPWD, "{$this->_dnsUser}:{$this->_dnsPass}");
}
$server = str_replace("%IP%", $this->_dnsIP, $this->_dnsUpdateURL);
if ($this->_dnsVerboseLog) {
log_error(sprintf(gettext("Sending request to: %s"), $server));
}
curl_setopt($ch, CURLOPT_URL, $server);
break;
case 'cloudflare-v6':
case 'cloudflare':
$this->_FQDN = ltrim($this->_FQDN, '@.');
$isv6 = ($this->_dnsService === 'cloudflare-v6');
$recordType = $isv6 ? "AAAA" : "A";
$needsIP = TRUE;
$dnsServer ='api.cloudflare.com';
$dnsHost = str_replace(' ', '', $this->_dnsHost);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'X-Auth-Email: '.$this->_dnsUser.'',
'X-Auth-Key: '.$this->_dnsPass.'',
'Content-Type: application/json'
));
// Get zone ID
$getZoneId = "https://{$dnsServer}/client/v4/zones/?name={$this->_dnsDomain}";
curl_setopt($ch, CURLOPT_URL, $getZoneId);
$output = json_decode(curl_exec($ch));
$zone = $output->result[0]->id;
if ($zone) { // If zone ID was found get host ID
$getHostId = "https://{$dnsServer}/client/v4/zones/{$zone}/dns_records?name={$this->_FQDN}&type={$recordType}";
curl_setopt($ch, CURLOPT_URL, $getHostId);
$output = json_decode(curl_exec($ch));
$host = $output->result[0]->id;
if ($host) { // If host ID was found update host
$hostData = array(
"content" => "{$this->_dnsIP}",
"type" => "{$recordType}",
"proxied" => $this->_dnsProxied,
"name" => "{$this->_dnsHost}"
);
$data_json = json_encode($hostData);
$updateHostId = "https://{$dnsServer}/client/v4/zones/{$zone}/dns_records/{$host}";
curl_setopt($ch, CURLOPT_URL, $updateHostId);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PUT');
curl_setopt($ch, CURLOPT_POSTFIELDS, $data_json);
}
}
break;
case 'eurodns':
$needsIP = TRUE;
curl_setopt($ch, CURLOPT_USERPWD, $this->_dnsUser.':'.$this->_dnsPass);
$server = "https://update.eurodyndns.org/update/";
$port = "";
if ($this->_dnsPort) {
$port = ":" . $this->_dnsPort;
}
curl_setopt($ch, CURLOPT_URL, $server .$port . '?hostname=' . $this->_dnsHost . '&myip=' . $this->_dnsIP);
break;
case 'gratisdns':
$needsIP = TRUE;
$server = "https://ssl.gratisdns.dk/ddns.phtml";
curl_setopt($ch, CURLOPT_URL, $server . '?u=' . $this->_dnsUser . '&p=' . $this->_dnsPass . '&h=' . $this->_dnsHost . '&d=' . $this->_dnsDomain . '&i=' . $this->_dnsIP);
break;
case 'ovh-dynhost':
$needsIP = FALSE;
if (isset($this->_dnsWildcard) && $this->_dnsWildcard != "OFF") $this->_dnsWildcard = "ON";
curl_setopt($ch, CURLOPT_USERPWD, $this->_dnsUser.':'.$this->_dnsPass);
$server = "https://www.ovh.com/nic/update";
$port = "";
if ($this->_dnsServer) {
$server = $this->_dnsServer;
}
if ($this->_dnsPort) {
$port = ":" . $this->_dnsPort;
}
curl_setopt($ch, CURLOPT_URL, $server .$port . '?system=dyndns&hostname=' . $this->_dnsHost . '&myip=' . $this->_dnsIP . '&wildcard='.$this->_dnsWildcard . '&mx=' . $this->_dnsMX . '&backmx=NO');
break;
case 'citynetwork':
$needsIP = TRUE;
curl_setopt($ch, CURLOPT_USERPWD, $this->_dnsUser.':'.$this->_dnsPass);
$server = 'https://dyndns.citynetwork.se/nic/update';
$port = "";
if ($this->_dnsServer) {
$server = $this->_dnsServer;
}
if ($this->_dnsPort) {
$port = ":" . $this->_dnsPort;
}
curl_setopt($ch, CURLOPT_URL, $server .$port . '?hostname=' . $this->_dnsHost . '&myip=' . $this->_dnsIP);
break;
case 'dnsimple':
/* Uses DNSimple's v2 REST API
Requires the Account ID as the username (found in the URL when pull up the domain)
And an API Token for the password (generated in the User Settings -> API tokens area of the website)
Piggybacks on Route 53's ZoneID field for the DNSimple record ID to update
The DNS record MUST exist before it can update since it performs a PATCH operation
Data sent as JSON over HTTPS */
$needsIP = TRUE;
$server = 'https://api.dnsimple.com/v2/';
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "PATCH");
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Accept: application/json', 'Content-Type: application/json', 'Authorization: Bearer ' . $this->_dnsPass));
curl_setopt($ch, CURLOPT_URL, $server . $this->_dnsUser . '/zones/' . $this->_dnsHost . '/records/' . $this->_dnsZoneID);
curl_setopt($ch, CURLOPT_POSTFIELDS, '{"content":"' . $this->_dnsIP . '","ttl":"' . $this->_dnsTTL . '"}');
break;
case 'godaddy':
case 'godaddy-v6':
/* Uses GoDaddy's REST API
Requires username and Account API sso-key passed in header
Data sent as JSON */
$needsIP = TRUE;
$server = 'https://api.godaddy.com/v1/domains/';
$recordType = $this->_useIPv6 ? "AAAA" : "A";
$url = $server . $this->_dnsDomain . '/records/' . $recordType . '/' . $this->_dnsHost;
$jsondata = '[{"data":"' . $this->_dnsIP . '","ttl":' . $this->_dnsTTL . '}]';
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "PUT");
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'Accept: application/json',
'Content-Type: application/json',
'Authorization: sso-key ' . $this->_dnsUser . ':' . $this->_dnsPass
));
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POSTFIELDS, $jsondata);
break;
case 'googledomains':
$needsIP = FALSE;
$post_data['username:password'] = $this->_dnsUser . ':' . $this->_dnsPass;
$post_data['hostname'] = $this->_dnsHost;
$post_data['myip'] = $this->_dnsIP;
$post_data['offline'] = 'no';
$server = "https://domains.google.com/nic/update";
$port = "";
curl_setopt($ch, CURLOPT_URL, 'https://domains.google.com/nic/update');
curl_setopt($ch, CURLOPT_USERPWD, $this->_dnsUser.':'.$this->_dnsPass);
curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
break;
case 'dnsmadeeasy':
$needsIP = TRUE;
$server = "https://cp.dnsmadeeasy.com/servlet/updateip";
curl_setopt($ch, CURLOPT_URL, $server . '?username=' . $this->_dnsUser . '&password=' . $this->_dnsPass . '&id=' . $this->_dnsHost . '&ip=' . $this->_dnsIP);
break;
case 'spdyn':
case 'spdyn-v6':
$needsIP = FALSE;
curl_setopt($ch, CURLOPT_USERPWD, $this->_dnsUser.':'.$this->_dnsPass);
$server = "https://update.spdyn.de/nic/update";
$port = "";
if ($this->_dnsServer) {
$server = $this->_dnsServer;
}
if ($this->_dnsPort) {
$port = ":" . $this->_dnsPort;
}
curl_setopt($ch, CURLOPT_URL, $server .$port . '?hostname=' . $this->_dnsHost . '&myip=' . $this->_dnsIP);
break;
case 'all-inkl':
$needsIP = FALSE;
$server = 'https://dyndns.kasserver.com/';
curl_setopt($ch, CURLOPT_USERPWD, $this->_dnsUser.':'.$this->_dnsPass);
curl_setopt($ch, CURLOPT_URL, $server . 'myip=' . $this->_dnsIP);
break;
case 'hover':
$needsIP = FALSE;
$port = "";
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 1);
//step 1: login to API
$post_data['username'] = $this->_dnsUser;
$post_data['password'] = $this->_dnsPass;
curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
curl_setopt($ch, CURLOPT_URL, "https://www.hover.com/api/login");
curl_setopt($ch, CURLOPT_HEADER, 1); //return the full headers to extract the cookies
$output = curl_exec($ch);
//extract the cookies
preg_match_all("/^Set-cookie: (.*?);/ism", $output, $cookies);
if( count($cookies[1]) > 0 ){
$cookie_data = implode("; ",$cookies[1]);
}
//step 2: find the id of the A record
$post_data = null;
curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
curl_setopt($ch, CURLOPT_COOKIE, $cookie_data);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_URL, "https://www.hover.com/api/dns");
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'GET');
$output = curl_exec($ch);
preg_match("/^{\"succeeded\":true.*?domain_name\":\"{$this->_dnsDomain}.*?entries.*?{\"id\":\"([^\"]*?)\",\"name\":\"{$this->_dnsHost}\".*?\$/", $output, $hostID);
$hostID = $hostID[1];
preg_match("/^{\"succeeded\":true.*?domain_name\":\"{$this->_dnsDomain}.*?entries.*?{[^\}]*?\"name\":\"{$this->_dnsHost}\".*?content\":\"([^\"]*?)\".*?\$/", $output, $hostIP);
$hostIP = $hostIP[1];
//step 3: update the IP
if ($hostID) {
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 1);
curl_setopt($ch, CURLOPT_COOKIE, $cookie_data);
$post_data['content'] = $this->_dnsIP;
curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PUT');
curl_setopt($ch, CURLOPT_URL, "https://www.hover.com/api/dns/{$hostID}");
log_error("HostID:{$hostID}, OldIP:{$hostIP}");
}
break;
case 'dreamhost':
case 'dreamhost-v6':
$needsIP = TRUE;
$isv6 = ($this->_dnsService === 'dreamhost-v6');
$server = 'https://api.dreamhost.com/';
$post_data['key'] = $this->_dnsPass;
$post_data['unique_id'] = uniqid($this->_dnsHost);
$post_data['cmd'] = 'dns-add_record';
$post_data['format'] = 'json';
$post_data['value'] = $this->_dnsIP;
$post_data['record'] = $this->_dnsHost;
$post_data['type'] = $isv6 ? 'AAAA' : 'A';
$post_data['comment'] = "Updated by pfSense:$this->_dnsUser on ".date('c');
$port = "";
if ($this->_dnsServer) {
$server = $this->_dnsServer;
}
if ($this->_dnsPort) {
$port = ":" . $this->_dnsPort;
}
curl_setopt($ch, CURLOPT_URL, $server . $port);
curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
break;
case 'digitalocean':
// Get record ID
$server = 'https://api.digitalocean.com/v2/domains/';
$url = $server . $this->_dnsDomain . '/records';
curl_setopt($ch, CURLOPT_HTTPHEADER, array("Authorization: Bearer {$this->_dnsPass}"));
curl_setopt($ch, CURLOPT_URL, $url);
$output = json_decode(curl_exec($ch));
if (!is_array($output->domain_records)) {
$output->domain_records = array();
}
foreach($output->domain_records as $dnsRecord) {
// NS records are named @ in DO's API, so check type as well
// https://redmine.pfsense.org/issues/9171
if ($this->_dnsHost == $dnsRecord->name && $dnsRecord->type == 'A') {
$recordID = $dnsRecord->id;
break;
}
}
// Create/update record
if ($recordID == null) {
$url = $server . $this->_dnsDomain . '/records';
} else {
$url = $server . $this->_dnsDomain . '/records/' . $recordID;
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "PUT");
}
$post_data['type'] = 'A';
$post_data['ttl'] = $this->_dnsTTL;
$post_data['name'] = $this->_dnsHost;
$post_data['data'] = $this->_dnsIP;
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
break;
case 'cloudns':
/* Uses ClouDNS REST API
Requires auth-id or sub-auth-id or sub-auth-user */
// Step 1: Find the Record ID
$url = 'https://api.cloudns.net/dns/records.json';
$post_data['auth-id'] = $this->_dnsUser;
$post_data['auth-password'] = $this->_dnsPass;
$post_data['domain-name'] = $this->_dnsDomain;
$post_data['host'] = $this->_dnsHost;
$post_data['type'] = 'a';
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
$output = json_decode(curl_exec($ch));
$recordID = key(get_object_vars($output));
// Step 2: Set the record
$needsIP = TRUE;
$url = 'https://api.cloudns.net/dns/mod-record.json';
$post_data = array();
$post_data['auth-id'] = $this->_dnsUser;
$post_data['auth-password'] = $this->_dnsPass;
$post_data['domain-name'] = $this->_dnsDomain;
$post_data['record-id'] = $recordID;
$post_data['host'] = $this->_dnsHost;
$post_data['record'] = $this->_dnsIP;
$post_data['ttl'] = $this->_dnsTTL;
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
break;
case 'azurev6':
case 'azure':
$hostname = "{$this->_dnsHost}";
$resourceid = trim($this->_dnsZoneID);
$app_id = $this->_dnsUser;
$client_secret = $this->_dnsPass;
$newip = $this->_dnsIP;
$newttl = $this->_dnsTTL;
// ensure resourceid starts with / and has no trailing /
$resourceid = '/' . trim($resourceid, '/');
// extract subscription id from resource id
preg_match('/\\/subscriptions\\/(?<sid>[^\\/]*)/', $resourceid, $result);
$subscriptionid = isset($result['sid']) ? $result['sid'] : '';
if (isset($result['sid'])) {
$subscriptionid = $result['sid'];
} else {
log_error("Azure subscription id not found in resource id");
return false;
}
// find tenant id from subscription id
curl_setopt($ch, CURLOPT_URL, "https://management.azure.com/subscriptions/" . $subscriptionid . "?api-version=2016-09-01");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_HEADER, 1);
curl_setopt($ch, CURLOPT_NOBODY, 1);
$output = curl_exec($ch);
$pattern = '/Bearer authorization_uri="https:\\/\\/login.windows.net\\/(?<tid>[^"]*)/i';
preg_match($pattern, $output, $result);
if (isset($result['tid'])) {
$tenantid = $result['tid'];
} else {
log_error("Tenant ID not found");
return false;
}
// get an bearer token
curl_setopt($ch, CURLOPT_URL, "https://login.microsoftonline.com/" . $tenantid . "/oauth2/token");
curl_setopt($ch, CURLOPT_POST, 1);
$body = "resource=" . urlencode("https://management.core.windows.net/") . "&grant_type=client_credentials&client_id=" . $app_id . "&client_secret=" . urlencode($client_secret);
curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$server_output = curl_exec($ch);
$httpcode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
preg_match("/\"access_token\":\"(?<tok>[^\"]*)\"/", $server_output, $result);
if (isset($result['tok'])) {
$bearertoken = $result['tok'];
} else {
log_error("no valid bearer token");
return false;
}
// Update the DNS record
if ($this->_useIPv6) {
$url = "https://management.azure.com" . $resourceid . "/AAAA/" . $hostname . "?api-version=2017-09-01";
$body = '{"properties":{"TTL":"' . $newttl . '", "AaaaRecords":[{"ipv6Address":"' . $newip . '"}]}}';
} else {
$url = "https://management.azure.com" . $resourceid . "/A/" . $hostname . "?api-version=2017-09-01";
$body = '{"properties":{"TTL":"' . $newttl . '", "ARecords":[{"ipv4Address":"' . $newip . '"}]}}';
}
$request_headers = array();
$request_headers[] = 'Accept: application/json';
$request_headers[] = 'Authorization: Bearer ' . $bearertoken;
$request_headers[] = 'Content-Type: application/json';
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_USERAGENT, $this->_UserAgent);
curl_setopt($ch, CURLOPT_HTTPHEADER, $request_headers);
curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HEADER, 1);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PUT');
break;
default:
break;
}
if ($this->_dnsService != 'ods') {
curl_setopt($ch, CURLOPT_HEADER, 1);
$response = curl_exec($ch);
$header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
$header = substr($response, 0, $header_size);
$data = substr($response, $header_size);
$this->_checkStatus($ch, $data, $header);
@curl_close($ch);
}
}
/**
* Private Function (added 23 Feb 17)
* Send Removal To Selected Service.
*
* Some services do not perform an inplace upgrade. If they do not then the solution
* is to remove the existing record and add a new record.
*
* @param unknown $existing_ip If required, an existing IP address for the record.
*/
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));
}
if (strstr($this->_dnsRequestIf, "_vip")) {
$parentif = get_configured_vip_interface($this->_dnsRequestIf);
$realparentif = convert_friendly_interface_to_real_interface_name($parentif);
} else {
$realparentif = $this->_dnsRequestIf;
}
$ch = curl_init();
if ($this->_useIPv6 == false) {
curl_setopt($ch, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
}
curl_setopt($ch, CURLOPT_USERAGENT, $this->_UserAgent);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($ch, CURLOPT_INTERFACE, 'if!' . $realparentif);
curl_setopt($ch, CURLOPT_TIMEOUT, 120); // Completely empirical
switch ($this->_dnsService) {
case 'dreamhost':
case 'dreamhost-v6':
$server = 'https://api.dreamhost.com/';
$post_data['key'] = $this->_dnsPass;
$post_data['unique_id'] = uniqid($this->_dnsHost);
$post_data['cmd'] = 'dns-remove_record';
$post_data['format'] = 'json';
$post_data['value'] = $existing_ip;
$post_data['record'] = $this->_dnsHost;
$isv6 = ($this->_dnsService === 'dreamhost-v6');
$post_data['type'] = $isv6 ? 'AAAA' : 'A';
$port = "";
if ($this->_dnsServer) {
$server = $this->_dnsServer;
}
if ($this->_dnsPort) {
$port = ":" . $this->_dnsPort;
}
curl_setopt($ch, CURLOPT_URL, $server . $port);
curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
$remove_allowed = true;
break;
default:
break;
}
if ($remove_allowed) {
curl_setopt($ch, CURLOPT_HEADER, 1);
$response = curl_exec($ch);
$header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
$header = substr($response, 0, $header_size);
$data = substr($response, $header_size);
$this->_checkStatus($ch, $data, $header);
@curl_close($ch);
}
}
/**
* Private Function (added 23 Feb 17)
* Retrieves current DNS records from an external API source.
*
* Some services cannot perform new operations without the caller
* providing existing record information.
*/
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));
}
if (strstr($this->_dnsRequestIf, "_vip")) {
$parentif = get_configured_vip_interface($this->_dnsRequestIf);
$realparentif = convert_friendly_interface_to_real_interface_name($parentif);
} else {
$realparentif = $this->_dnsRequestIf;
}
$ch = curl_init();
if ($this->_useIPv6 == false) {
curl_setopt($ch, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
}
curl_setopt($ch, CURLOPT_USERAGENT, $this->_UserAgent);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($ch, CURLOPT_INTERFACE, 'if!' . $realparentif);
curl_setopt($ch, CURLOPT_TIMEOUT, 120); // Completely empirical
switch ($this->_dnsService) {
case 'dreamhost':
case 'dreamhost-v6':
$server = 'https://api.dreamhost.com/';
$post_data['key'] = $this->_dnsPass;
$post_data['unique_id'] = uniqid($this->_dnsHost);
$post_data['cmd'] = 'dns-list_records';
$post_data['format'] = 'json';
$port = "";
if ($this->_dnsServer) {
$server = $this->_dnsServer;
}
if ($this->_dnsPort) {
$port = ":" . $this->_dnsPort;
}
curl_setopt($ch, CURLOPT_URL, $server . $port);
curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
$lookup_allowed = true;
break;
default:
break;
}
if ($lookup_allowed) {
curl_setopt($ch, CURLOPT_HEADER, 1);
$response = curl_exec($ch);
$header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
$header = substr($response, 0, $header_size);
$data = substr($response, $header_size);
$this->_checkLookupStatus($ch, $data, $header);
@curl_close($ch);
}
}
/*
* Private Function (added 23 Feb 17)
* Retrieve Lookup Status from the provided data and/or header
*/
function _checkLookupStatus($ch, $data, $header) {
if ($this->_dnsVerboseLog) {
log_error(sprintf(gettext('Dynamic DNS %1$s (%2$s): _checkLookupStatus() starting.'), $this->_dnsService, $this->_FQDN));
}
$success_str = "(" . gettext("Success") . ") ";
$error_str = "(" . gettext("Error") . ") ";
$status_intro = "phpDynDNS ({$this->_dnsHost}): ";
if ($this->_dnsService != 'ods' && @curl_error($ch)) {
$status = gettext("Curl error occurred:") . " " . curl_error($ch);
log_error($status);
$this->status = $status;
return;
}
switch ($this->_dnsService) {
case 'dreamhost':
case 'dreamhost-v6':
$result = json_decode($data,true);
if($result["result"] != "success") {
log_error($status_intro . gettext("PAYLOAD:") . " {$data}");
$this->_debug($data);
return;
} else {
foreach($result["data"] as $key => $row) {
if($row["record"] == $this->_dnsHost &&
(($row["type"] == "A" && !$this->_useIPv6)
|| ($row["type"] == "AAAA" && $this->_useIPv6)
)) {
if($row["editable"] == 0) {
log_error($status_intro . "host " . $this->_dnsHost . " is not editable.");
continue;
}
$this->_existingRecords[]=array("record"=>$row["type"], "type"=>$row["type"], "existing_val"=>$row["value"]);
}
}
}
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));
}
}
break;
default:
break;
}
}
/*
* Private Function (added 12 July 2005) [beta]
* Retrieve Update Status
*/
function _checkStatus($ch, $data, $header) {
if ($this->_dnsVerboseLog) {
log_error(sprintf(gettext('Dynamic DNS %1$s (%2$s): _checkStatus() starting.'), $this->_dnsService, $this->_FQDN));
}
$successful_update = false;
$success_str = "(" . gettext("Success") . ") ";
$error_str = "(" . gettext("Error") . ") ";
$status_intro = "phpDynDNS ({$this->_dnsHost}): ";
if ($this->_dnsService != 'ods' && @curl_error($ch)) {
$status = gettext("Curl error occurred:") . " " . curl_error($ch);
log_error($status);
$this->status = $status;
return;
}
switch ($this->_dnsService) {
case 'glesys':
$status_intro = "GleSYS ({$this->_dnsHost}): ";
if (preg_match('/Record updated/i', $data)) {
$status = $status_intro . $success_str . gettext("IP Address Changed Successfully!") . " (" . $this->_dnsIP . ")";
$successful_update = true;
} else {
$status = $status_intro . "(" . gettext("Unknown Response") . ")";
log_error($status_intro . gettext("PAYLOAD:") . " {$data}");
$this->_debug($data);
}
break;
case 'dnsomatic':
$status_intro = "DNS-O-Matic ({$this->_dnsHost}): ";
if (preg_match('/badauth/i', $data)) {
$status = $status_intro . gettext("The DNS-O-Matic username or password specified are incorrect. No updates will be distributed to services until this is resolved.");
} else if (preg_match('/notfqdn /i', $data)) {
$status = $status_intro . gettext("The hostname specified is not a fully-qualified domain name. If no hostnames included, notfqdn will be returned once.");
} else if (preg_match('/nohost/i', $data)) {
$status = $status_intro . gettext("The hostname passed could not be matched to any services configured. The service field will be blank in the return code.");
} else if (preg_match('/numhost/i', $data)) {
$status = $status_intro . gettext("Up to 20 hosts my be updated. numhost is returned if attempting to update more than 20 or update a round-robin.");
} else if (preg_match('/abuse/i', $data)) {
$status = $status_intro . gettext("The hostname is blocked for update abuse.");
} else if (preg_match('/good/i', $data)) {
$status = $status_intro . $success_str . gettext("IP Address Changed Successfully!") . " (" . $this->_dnsIP . ")";
$successful_update = true;
} else if (preg_match('/dnserr/i', $data)) {
$status = $status_intro . gettext("DNS error encountered. Stop updating for 30 minutes.");
} else {
$status = $status_intro . "(" . gettext("Unknown Response") . ")";
log_error($status_intro . gettext("PAYLOAD:") . " {$data}");
$this->_debug($data);
}
break;
case 'citynetwork':
if (preg_match('/notfqdn/i', $data)) {
$status = $status_intro . $error_str . gettext("Not A FQDN!");
} else if (preg_match('/nohost/i', $data)) {
$status = $status_intro . $error_str . gettext("No such host");
} else if (preg_match('/nochg/i', $data)) {
$status = $status_intro . $success_str . gettext("No Change In IP Address");
$successful_update = true;
} else if (preg_match('/good/i', $data)) {
$status = $status_intro . $success_str . gettext("IP Address Changed Successfully!") . " (" . $this->_dnsIP . ")";
$successful_update = true;
} else if (preg_match('/badauth/i', $data)) {
$status = $status_intro . $error_str . gettext("User Authorization Failed");
} else {
$status = $status_intro . "(" . gettext("Unknown Response") . ")";
log_error($status_intro . gettext("PAYLOAD:") . " {$data}");
$this->_debug($data);
}
break;
case 'ovh-dynhost':
case 'dyndns':
if (preg_match('/notfqdn/i', $data)) {
$status = $status_intro . $error_str . gettext("Not A FQDN!");
} else if (preg_match('/nochg/i', $data)) {
$status = $status_intro . $success_str . gettext("No Change In IP Address");
$successful_update = true;
} else if (preg_match('/good/i', $data)) {
$status = $status_intro . $success_str . gettext("IP Address Changed Successfully!") . " (" . $this->_dnsIP . ")";
$successful_update = true;
} else if (preg_match('/noauth/i', $data)) {
$status = $status_intro . $error_str . gettext("User Authorization Failed");
} else {
$status = $status_intro . "(" . gettext("Unknown Response") . ")";
log_error($status_intro . gettext("PAYLOAD:") . " {$data}");
$this->_debug($data);
}
break;
case 'dyndns-static':
if (preg_match('/notfqdn/i', $data)) {
$status = $status_intro . $error_str . gettext("Not A FQDN!");
} else if (preg_match('/nochg/i', $data)) {
$status = $status_intro . $success_str . gettext("No Change In IP Address");
$successful_update = true;
} else if (preg_match('/good/i', $data)) {
$status = $status_intro . $success_str . gettext("IP Address Changed Successfully!");
$successful_update = true;
} else if (preg_match('/noauth/i', $data)) {
$status = $status_intro . $error_str . gettext("User Authorization Failed");
} else {
$status = $status_intro . "(" . gettext("Unknown Response") . ")";
log_error($status_intro . gettext("PAYLOAD:") . " {$data}");
$this->_debug($data);
}
break;
case 'dyndns-custom':
if (preg_match('/notfqdn/i', $data)) {
$status = $status_intro . $error_str . gettext("Not A FQDN!");
} else if (preg_match('/nochg/i', $data)) {
$status = $status_intro . $success_str . gettext("No Change In IP Address");
$successful_update = true;
} else if (preg_match('/good/i', $data)) {
$status = $status_intro . $success_str . gettext("IP Address Changed Successfully!");
$successful_update = true;
} else if (preg_match('/noauth/i', $data)) {
$status = $status_intro . $error_str . gettext("User Authorization Failed");
} else {
$status = $status_intro . "(" . gettext("Unknown Response") . ")";
log_error($status_intro . gettext("PAYLOAD:") . " {$data}");
$this->_debug($data);
}
break;
case 'dhs':
break;
case 'noip':
case 'noip-free':
list($ip, $code) = explode(":", $data);
switch ($code) {
case 0:
$status = $status_intro . $success_str . gettext("IP address is current, no update performed.");
$successful_update = true;
break;
case 1:
$status = $status_intro . $success_str . gettext("DNS hostname update successful.");
$successful_update = true;
break;
case 2:
$status = $status_intro . $error_str . gettext("Hostname supplied does not exist.");
break;
case 3:
$status = $status_intro . $error_str . gettext("Invalid Username.");
break;
case 4:
$status = $status_intro . $error_str . gettext("Invalid Password.");
break;
case 5:
$status = $status_intro . $error_str . gettext("Too many updates sent.");
break;
case 6:
$status = $status_intro . $error_str . gettext("Account disabled due to violation of No-IP terms of service.");
break;
case 7:
$status = $status_intro . $error_str . gettext("Invalid IP. IP Address submitted is improperly formatted or is a private IP address or is on a blacklist.");
break;
case 8:
$status = $status_intro . $error_str . gettext("Disabled / Locked Hostname.");
break;
case 9:
$status = $status_intro . $error_str . gettext("Host updated is configured as a web redirect and no update was performed.");
break;
case 10:
$status = $status_intro . $error_str . gettext("Group supplied does not exist.");
break;
case 11:
$status = $status_intro . $success_str . gettext("DNS group update is successful.");
$successful_update = true;
break;
case 12:
$status = $status_intro . $success_str . gettext("DNS group is current, no update performed.");
$successful_update = true;
break;
case 13:
$status = $status_intro . $error_str . gettext("Update client support not available for supplied hostname or group.");
break;
case 14:
$status = $status_intro . $error_str . gettext("Hostname supplied does not have offline settings configured.");
break;
case 99:
$status = $status_intro . $error_str . gettext("Client disabled. Client should exit and not perform any more updates without user intervention.");
break;
case 100:
$status = $status_intro . $error_str . gettext("Client disabled. Client should exit and not perform any more updates without user intervention.");
break;
default:
$status = $status_intro . "(" . gettext("Unknown Response") . ")";
$this->_debug(gettext("Unknown Response:") . " " . $data);
break;
}
break;
case 'easydns':
if (preg_match('/NOACCESS/i', $data)) {
$status = $status_intro . $error_str . gettext("Authentication Failed: Username and/or Password was Incorrect.");
} else if (preg_match('/NOSERVICE/i', $data)) {
$status = $status_intro . $error_str . gettext("No Service: Dynamic DNS Service has been disabled for this domain.");
} else if (preg_match('/ILLEGAL INPUT/i', $data)) {
$status = $status_intro . $error_str . gettext("Illegal Input: Self-Explanatory");
} else if (preg_match('/TOOSOON/i', $data)) {
$status = $status_intro . $error_str . gettext("Too Soon: Not Enough Time Has Elapsed Since Last Update");
} else if (preg_match('/NOERROR/i', $data)) {
$status = $status_intro . $success_str . gettext("IP Updated Successfully!");
$successful_update = true;
} else {
$status = $status_intro . "(" . gettext("Unknown Response") . ")";
log_error($status_intro . gettext("PAYLOAD:") . " " . $data);
$this->_debug($data);
}
break;
case 'hn':
/* FIXME: add checks */
break;
case 'zoneedit':
if (preg_match('/799/i', $data)) {
$status = $status_intro . "(" . gettext("Error 799") . ") " . gettext("Update Failed!");
} else if (preg_match('/700/i', $data)) {
$status = $status_intro . "(" . gettext("Error 700") . ") " . gettext("Update Failed!");
} else if (preg_match('/200/i', $data)) {
$status = $status_intro . $success_str . gettext("IP Address Updated Successfully!");
$successful_update = true;
} else if (preg_match('/201/i', $data)) {
$status = $status_intro . $success_str . gettext("IP Address Updated Successfully!");
$successful_update = true;
} else {
$status = $status_intro . "(" . gettext("Unknown Response") . ")";
log_error($status_intro . gettext("PAYLOAD:") . " " . $data);
$this->_debug($data);
}
break;
case 'dyns':
if (preg_match("/400/i", $data)) {
$status = $status_intro . $error_str . gettext("Bad Request - The URL was malformed. Required parameters were not provided.");
} else if (preg_match('/402/i', $data)) {
$status = $status_intro . $error_str . gettext("Update Too Soon - Attempted to update too quickly since last change.");
} else if (preg_match('/403/i', $data)) {
$status = $status_intro . $error_str . gettext("Database Error - There was a server-sided database error.");
} else if (preg_match('/405/i', $data)) {
$status = $status_intro . $error_str . sprintf(gettext('Hostname Error - The hostname (%1$s) doesn\'t belong to user (%2$s).'), $this->_dnsHost, $this->_dnsUser);
} else if (preg_match('/200/i', $data)) {
$status = $status_intro . $success_str . gettext("IP Address Updated Successfully!");
$successful_update = true;
} else {
$status = $status_intro . "(" . gettext("Unknown Response") . ")";
log_error($status_intro . gettext("PAYLOAD:") . " " . $data);
$this->_debug($data);
}
break;
case 'ods':
if (preg_match("/299/i", $data)) {
$status = $status_intro . $success_str . gettext("IP Address Updated Successfully!");
$successful_update = true;
} else {
$status = $status_intro . "(" . gettext("Unknown Response") . ")";
log_error($status_intro . gettext("PAYLOAD:") . " " . $data);
$this->_debug($data);
}
break;
case 'freedns':
case 'freedns-v6':
if (preg_match("/has not changed./i", $data)) {
$status = $status_intro . $success_str . gettext("No Change In IP Address");
$successful_update = true;
} else if (preg_match("/Updated/i", $data)) {
$status = $status_intro . $success_str . gettext("IP Address Changed Successfully!");
$successful_update = true;
} else {
$status = $status_intro . "(" . gettext("Unknown Response") . ")";
log_error($status_intro . gettext("PAYLOAD:") . " " . $data);
$this->_debug($data);
}
break;
case 'dnsexit':
if (preg_match("/is the same/i", $data)) {
$status = $status_intro . $success_str . gettext("No Change In IP Address");
$successful_update = true;
} else if (preg_match("/Success/i", $data)) {
$status = $status_intro . $success_str . gettext("IP Address Changed Successfully!");
$successful_update = true;
} else {
$status = $status_intro . "(" . gettext("Unknown Response") . ")";
log_error($status_intro . gettext("PAYLOAD:") . " " . $data);
$this->_debug($data);
}
break;
case 'loopia':
if (preg_match("/nochg/i", $data)) {
$status = $status_intro . $success_str . gettext("No Change In IP Address");
$successful_update = true;
} else if (preg_match("/good/i", $data)) {
$status = $status_intro . $success_str . gettext("IP Address Changed Successfully!");
$successful_update = true;
} else if (preg_match('/badauth/i', $data)) {
$status = $status_intro . $error_str . gettext("User Authorization Failed");
} else {
$status = $status_intro . "(" . gettext("Unknown Response") . ")";
log_error($status_intro . gettext("PAYLOAD:") . " " . $data);
$this->_debug($data);
}
break;
case 'opendns':
if (preg_match('/badauth/i', $data)) {
$status = $status_intro . $error_str . gettext("Not a valid username or password!");
} else if (preg_match('/nohost/i', $data)) {
$status = $status_intro . $error_str . gettext("Hostname specified does not exist.");
$successful_update = true;
} else if (preg_match('/good/i', $data)) {
$status = $status_intro . $success_str . gettext("IP Address Changed Successfully!") . " (" . $this->_dnsIP . ")";
$successful_update = true;
} else if (preg_match('/yours/i', $data)) {
$status = $status_intro . $error_str . gettext("Hostname specified exists, but not under the username specified.");
} else if (preg_match('/abuse/i', $data)) {
$status = $status_intro . $error_str . gettext("Updating too frequently, considered abuse.");
} else {
$status = $status_intro . "(" . gettext("Unknown Response") . ")";
log_error($status_intro . gettext("PAYLOAD:") . " " . $data);
$this->_debug($data);
}
break;
case 'staticcling':
if (preg_match("/invalid ip/i", $data)) {
$status = $status_intro . $error_str . gettext("Bad Request - The IP provided was invalid.");
} else if (preg_match('/required info missing/i', $data)) {
$status = $status_intro . $error_str . gettext("Bad Request - Required parameters were not provided.");
} else if (preg_match('/invalid characters/i', $data)) {
$status = $status_intro . $error_str . gettext("Bad Request - Illegal characters in either the username or the password.");
} else if (preg_match('/bad password/i', $data)) {
$status = $status_intro . $error_str . gettext("Invalid password.");
} else if (preg_match('/account locked/i', $data)) {
$status = $status_intro . $error_str . gettext("This account has been administratively locked.");
} else if (preg_match('/update too frequent/i', $data)) {
$status = $status_intro . $error_str . gettext("Updating too frequently.");
} else if (preg_match('/DB error/i', $data)) {
$status = $status_intro . $error_str . gettext("Server side error.");
} else if (preg_match('/success/i', $data)) {
$status = $status_intro . $success_str . gettext("IP Address Updated Successfully!");
$successful_update = true;
} else {
$status = $status_intro . "(" . gettext("Unknown Response") . ")";
log_error($status_intro . gettext("PAYLOAD:") . " " . $data);
$this->_debug($data);
}
break;
case 'namecheap':
$tmp = str_replace("^M", "", $data);
$ncresponse = @xml2array($tmp);
if (preg_match("/internal server error/i", $data)) {
$status = $status_intro . $error_str . gettext("Server side error.");
} else if (preg_match("/request is badly formed/i", $data)) {
$status = $status_intro . $error_str . gettext("Badly Formed Request (check the settings).");
} else if ($ncresponse['interface-response']['ErrCount'] === "0") {
$status = $status_intro . $success_str . gettext("IP Address Updated Successfully!");
$successful_update = true;
} else if (is_numeric($ncresponse['interface-response']['ErrCount']) && ($ncresponse['interface-response']['ErrCount'] > 0)) {
$status = $status_intro . $error_str . implode(", ", $ncresponse["interface-response"]["errors"]);
$successful_update = true;
} else {
$status = $status_intro . "(" . gettext("Unknown Response") . ")";
log_error($status_intro . gettext("PAYLOAD:") . " " . $data);
$this->_debug($data);
}
break;
case 'duiadns':
case 'duiadns-v6':
if (preg_match("/error/i", $data)) {
$status = $status_intro . $error_str . gettext("Server side error.");
} else if (preg_match('/nohost/i', $data)) {
$status = $status_intro . $error_str . gettext("Bad Request - A hostname was not provided.");
} else if (preg_match('/badauth/i', $data)) {
$status = $status_intro . $error_str . gettext("Invalid username or password.");
} else if (preg_match('/good/i', $data)) {
$status = $status_intro . $success_str . gettext("IP Address Updated Successfully!");
$successful_update = true;
} else if (preg_match('/nochg/i', $data)) {
$status = $status_intro . $success_str . gettext("No Change In IP Address.");
$successful_update = true;
} else {
$status = $status_intro . "(" . gettext("Unknown Response") . ")";
log_error($status_intro . gettext("PAYLOAD:") . " " . $data);
$this->_debug($data);
}
break;
case 'he-net':
case 'he-net-v6':
if (preg_match("/badip/i", $data)) {
$status = $status_intro . $error_str . gettext("Bad Request - The IP provided was invalid.");
} else if (preg_match('/nohost/i', $data)) {
$status = $status_intro . $error_str . gettext("Bad Request - A hostname was not provided.");
} else if (preg_match('/badauth/i', $data)) {
$status = $status_intro . $error_str . gettext("Invalid username or password.");
} else if (preg_match('/good/i', $data)) {
$status = $status_intro . $success_str . gettext("IP Address Updated Successfully!");
$successful_update = true;
} else if (preg_match('/nochg/i', $data)) {
$status = $status_intro . $success_str . gettext("No Change In IP Address.");
$successful_update = true;
} else {
$status = $status_intro . "(" . gettext("Unknown Response") . ")";
log_error($status_intro . gettext("PAYLOAD:") . " " . $data);
$this->_debug($data);
}
break;
case 'he-net-tunnelbroker':
/*
-ERROR: Missing parameter(s).
-ERROR: Invalid API key or password
-ERROR: Tunnel not found
-ERROR: Another tunnel exists for this IP.
-ERROR: This tunnel is already associated with this IP address
+OK: Tunnel endpoint updated to: x.x.x.x
*/
if (preg_match("/Missing parameter/i", $data)) {
$status = $status_intro . $error_str . gettext("Bad Request - Missing/Invalid Parameters.");
} else if (preg_match('/Tunnel not found/i', $data)) {
$status = $status_intro . $error_str . gettext("Bad Request - Invalid Tunnel ID.");
} else if (preg_match('/Invalid API key or password/i', $data)) {
$status = $status_intro . $error_str . gettext("Invalid username or password.");
} else if (preg_match('/OK:/i', $data)) {
$status = $status_intro . $success_str . gettext("IP Address Updated Successfully!");
$successful_update = true;
} else if (preg_match('/This tunnel is already associated with this IP address/i', $data)) {
$status = $status_intro . $success_str . gettext("No Change In IP Address.");
$successful_update = true;
} else {
$status = $status_intro . "(" . gettext("Unknown Response") . ")";
log_error($status_intro . gettext("PAYLOAD:") . " " . $data);
$this->_debug($data);
}
break;
case 'selfhost':
if (preg_match('/notfqdn/i', $data)) {
$status = $status_intro . $error_str . gettext("Not A FQDN!");
} else if (preg_match('/nochg/i', $data)) {
$status = $status_intro . $success_str . gettext("No Change In IP Address.");
$successful_update = true;
} else if (preg_match('/good/i', $data)) {
$status = $status_intro . $success_str . gettext("IP Address Changed Successfully!") . " (" . $this->_dnsIP . ")";
$successful_update = true;
} else if (preg_match('/noauth/i', $data)) {
$status = $status_intro . $error_str . gettext("User Authorization Failed");
} else {
$status = $status_intro . "(" . gettext("Unknown Response") . ")";
log_error($status_intro . gettext("PAYLOAD:") . " " . $data);
$this->_debug($data);
}
break;
case 'route53':
case 'route53-v6':
if(preg_match('/ErrorResponse/', $data)){
$status = $status_intro . $error_str . gettext("Route53 API call failed");
log_error(sprintf("error message: %s", $data));
$status_update = false;
} else {
$status = $status_intro . $success_str . gettext("IP address changed successfully");
$successful_update = true;
}
break;
case 'custom':
case 'custom-v6':
$successful_update = false;
if ($this->_dnsResultMatch == "") {
$successful_update = true;
} else {
$this->_dnsResultMatch = str_replace("%IP%", $this->_dnsIP, $this->_dnsResultMatch);
$matches = preg_split("/(?<!\\\\)\\|/", $this->_dnsResultMatch);
foreach ($matches as $match) {
$match= str_replace("\\|", "|", $match);
if (strcmp($match, trim($data, "\t\n\r")) == 0) {
$successful_update = true;
}
}
unset ($matches);
}
if ($successful_update == true) {
$status = $status_intro . $success_str . gettext("IP Address Updated Successfully!");
} else {
$status = $status_intro . $error_str . gettext("Result did not match.") . " [" . $data . "]";
}
break;
case 'cloudflare-v6':
case 'cloudflare':
$output = json_decode($data);
if ($output->result->content === $this->_dnsIP) {
$status = $status_intro . $success_str . sprintf(gettext('%1$s updated to %2$s'), $this->_dnsHost, $this->_dnsIP);
$successful_update = true;
} elseif ($output->errors[0]->code === 9103) {
$status = $status_intro . $error_str . gettext("Invalid Credentials! Don't forget to use API Key for password field with Cloudflare.");
} elseif (($output->success) && (!$output->result[0]->id)) {
$status = $status_intro . $error_str . gettext("Zone or Host ID was not found, check the hostname.");
} else {
$status = $status_intro . gettext("UNKNOWN ERROR") . " - " . $output->errors[0]->message;
log_error($status_intro . gettext("PAYLOAD:") . " " . $data);
}
break;
case 'eurodns':
if (preg_match('/notfqdn/i', $data)) {
$status = $status_intro . $error_str . gettext("Not A FQDN!");
} else if (preg_match('/nochg/i', $data)) {
$status = $status_intro . $success_str . gettext("No Change In IP Address");
$successful_update = true;
} else if (preg_match('/good/i', $data)) {
$status = $status_intro . $success_str . gettext("IP Address Changed Successfully!") . " (" . $this->_dnsIP . ")";
$successful_update = true;
} else if (preg_match('/badauth/i', $data)) {
$status = $status_intro . $error_str . gettext("User Authorization Failed");
} else {
$status = $status_intro . "(" . gettext("Unknown Response") . ")";
log_error($status_intro . gettext("PAYLOAD:") . " " . $data);
$this->_debug($data);
}
break;
case 'gratisdns':
if (preg_match('/Forkerte værdier/i', $data)) {
$status = $status_intro . $error_str . gettext("Wrong values - Update could not be completed.");
} else if (preg_match('/Bruger login: Bruger eksistere ikke/i', $data)) {
$status = $status_intro . $error_str . gettext("Unknown username - User does not exist.");
} else if (preg_match('/Bruger login: 1Fejl i kodeord/i', $data)) {
$status = $status_intro . $error_str . gettext("Wrong password - Remember password is case sensitive.");
} else if (preg_match('/Domæne kan IKKE administreres af bruger/i', $data)) {
$status = $status_intro . $error_str . gettext("User unable to administer the selected domain.");
} else if (preg_match('/OK/i', $data)) {
$status = $status_intro . $success_str . gettext("IP Address Updated Successfully!");
$successful_update = true;
} else {
$status = $status_intro . "(" . gettext("Unknown Response") . ")";
log_error($status_intro . gettext("PAYLOAD:") . " " . $data);
$this->_debug($data);
}
break;
case 'digitalocean':
// Creating new records returns an HTTP 201, updating existing records get 200
// https://redmine.pfsense.org/issues/9171
if (preg_match("/HTTP\/2\s20[0,1]/i", $header)) {
$status = $status_intro . $success_str . gettext("IP Address Updated Successfully!");
$successful_update = true;
} else {
$status = $status_intro . "(" . gettext("Unknown Response") . ")";
log_error($status_intro . gettext("PAYLOAD:") . " " . $data);
$this->_debug($data);
}
break;
case 'dnsimple':
/* Responds with HTTP 200 on success.
Responds with HTTP 4xx on error.
Returns JSON data as body */
;
if (preg_match("/\s200\sOK/i", $header)) {
$status = $status_intro . $success_str . gettext("IP Address Updated Successfully!");
$successful_update = true;
} else if (preg_match("/\s4\d\d\s/i", $header)) {
$arrbody = json_decode($data, true);
$message = $arrbody['message'] . ".";
if (isset($arrbody['errors']['content'])) {
foreach ($arrbody['errors']['content'] as $key => $content) {
$message .= " " . $content . ".";
}
}
$status = $status_intro . $error_str . $message;
} else {
$status = $status_intro . "(" . gettext("Unknown Response") . ")";
log_error($status_intro . gettext("PAYLOAD:") . " " . $data);
$this->_debug($data);
}
break;
case 'godaddy':
case 'godaddy-v6':
/* Responds with HTTP 200 on success.
Responds with HTTP 4xx or on error.
Returns JSON data as body */
;
if (preg_match("/\s200\sOK/i", $header)) {
$status = $status_intro . $success_str . gettext("IP Address Updated Successfully!");
$successful_update = true;
} else if (preg_match("/\s4\d\d\s/i", $header)) {
$arrbody = json_decode($data, true);
$message = $arrbody['message'] . ".";
if (isset($arrbody['fields'])) {
foreach ($arrbody['fields'] as $error) {
$message .= " " . $error['path'] . ": " . $error['message'] . ".";
}
}
$status = $status_intro . $error_str . $message;
} else {
$status = $status_intro . "(" . gettext("Unknown Response") . ")";
log_error($status_intro . gettext("PAYLOAD:") . " " . $data);
$this->_debug($data);
}
break;
case 'googledomains':
if (preg_match('/notfqdn/i', $data)) {
$status = $status_intro . $error_str . gettext("Not A FQDN");
} else if (preg_match('/nochg/i', $data)) {
$status = $status_intro . $success_str . gettext("No Change In IP Address");
$successful_update = true;
} else if (preg_match('/good/i', $data)) {
$status = $status_intro . $success_str . gettext("IP Address Changed Successfully!") . " (" . $this->_dnsIP . ")";
$successful_update = true;
} else if (preg_match('/badauth/i', $data)) {
$status = $status_intro . $error_str . gettext("User Authorization Failed");
} else if (preg_match('/nohost/i', $data)) {
$status = $status_intro . $error_str . gettext("Hostname does not exist or DynDNS not enabled");
} else if (preg_match('/badagent/i', $data)) {
$status = $status_intro . $error_str . gettext("Bad request");
} else if (preg_match('/abuse/i', $data)) {
$status = $status_intro . $error_str . gettext("Dynamic DNS access has been blocked!");
} else if (preg_match('/911/i', $data)) {
$status = $status_intro . $error_str . gettext("Error on Google's end, retry in 5 minutes");
} else {
$status = $status_intro . "(" . gettext("Unknown Response") . ")";
log_error($status_intro . gettext("PAYLOAD:") . " " . $data);
$this->_debug($data);
}
break;
case 'dnsmadeeasy':
switch ($data) {
case 'success':
$status = $status_intro . $success_str . gettext("IP Address Changed Successfully!") . " (" . $this->_dnsIP . ")";
$successful_update = true;
break;
case 'error-auth':
$status = $status_intro . $error_str . gettext("Invalid username or password");
break;
case 'error-auth-suspend':
$status = $status_intro . $error_str . gettext("Account suspended");
break;
case 'error-auth-voided':
$status = $status_intro . $error_str . gettext("Account revoked");
break;
case 'error-record-invalid':
$status = $status_intro . $error_str . gettext("Record does not exist in the system. Unable to update record");
break;
case 'error-record-auth':
$status = $status_intro . $error_str . gettext("User does not have access to this record");
break;
case 'error-record-ip-same':
$status = $status_intro . $success_str . gettext("No Change In IP Address");
$successful_update = true;
break;
case 'error-system':
$status = $status_intro . $error_str . gettext("General system error recognized by the system");
break;
case 'error':
$status = $status_intro . $error_str . gettext("General system error unrecognized by the system");
break;
default:
$status = $status_intro . "(" . gettext("Unknown Response") . ")";
log_error($status_intro . gettext("PAYLOAD:") . " " . $data);
$this->_debug($data);
break;
}
break;
case 'spdyn':
case 'spdyn-v6':
if (preg_match('/notfqdn/i', $data)) {
$status = $status_intro . $error_str . gettext("Not A FQDN!");
} else if (preg_match('/nohost/i', $data)) {
$status = $status_intro . $error_str . gettext("No such host");
} else if (preg_match('/nochg/i', $data)) {
$status = $status_intro . $success_str . gettext("No Change In IP Address");
$successful_update = true;
} else if (preg_match('/good/i', $data)) {
$status = $status_intro . $success_str . gettext("IP Address Changed Successfully!") . " (" . $this->_dnsIP . ")";
$successful_update = true;
} else if (preg_match('/badauth/i', $data)) {
$status = $status_intro . $error_str . gettext("User Authorization Failed");
} else {
$status = $status_intro . "(" . gettext("Unknown Response") . ")";
log_error($status_intro . gettext("PAYLOAD:") . " " . $data);
$this->_debug($data);
}
break;
case 'all-inkl':
if (preg_match('/good\s'.$this->_dnsIP.'/i', $data)) {
$status = $status_intro . $success_str . gettext("IP Address Changed Successfully!") . " (" . $this->_dnsIP . ")";
$successful_update = true;
} else if (preg_match('/good/i', $data)) {
$status = $status_intro . $error_str . gettext("Result did not match.");
} else if (preg_match("/\s401\sUnauthorized/i", $header)) {
$status = $status_intro . $error_str . gettext("Invalid username or password");
}
else {
$status = $status_intro . "(" . gettext("Unknown Response") . ")";
log_error($status_intro . gettext("PAYLOAD:") . " " . $header.$data);
$this->_debug($data);
$this->_debug($header);
}
break;
case 'hover':
if (preg_match('/succeeded":true/i', $data)) {
$status = $status_intro . $success_str . gettext("IP Address Changed Successfully!") . " (" . $this->_dnsIP . ")";
$successful_update = true;
} else {
$status = $status_intro . "(" . gettext("Unknown Response") . ")";
log_error($status_intro . gettext("PAYLOAD:") . " " . $data);
$this->_debug($data);
}
break;
case 'cloudns':
$result = json_decode($data, true);
if ($result['status'] == 'Success') {
$successful_update = true;
} else {
log_error($result['status'] . "(" . $result['statusDescription'] . ")");
}
break;
case 'dreamhost':
case 'dreamhost-v6':
$result = json_decode($data,true);
if ($this->_dnsVerboseLog) {
log_error(sprintf(gettext('_checkStatus() results: %1$s'), $data));
}
switch ($result['data']) {
case 'success':
case 'record_added':
case 'record_removed':
$status = $status_intro . $success_str . gettext("IP Address Changed Successfully!") . " (" . $this->_dnsIP . ")";
$successful_update = true;
break;
case 'no_record':
case 'no_such_record ':
$status = $status_intro . $error_str . gettext("No record exists.");
break;
case 'no_type':
case 'no_such_type ':
$status = $status_intro . $error_str . gettext("No type exists.");
break;
case 'no_value':
case 'no_such_value ':
$status = $status_intro . $error_str . gettext("No value exists.");
break;
case 'no_such_zone':
$status = $status_intro . $error_str . gettext("No such zone exists.");
break;
case 'invalid_record':
$status = $status_intro . $error_str . gettext("The specified record is invalid.");
break;
case 'invalid_type':
$status = $status_intro . $error_str . gettext("The specified type is invalid.");
break;
case 'invalid_value':
$status = $status_intro . $error_str . gettext("The specified value is invalid.");
break;
case 'not_editable ':
$status = $status_intro . $error_str . gettext("Record is not editable.");
break;
case 'record_already_exists_not_editable':
$status = $status_intro . $error_str . gettext("Record exists but is not editable.");
break;
case 'record_already_exists_remove_first':
$status = $status_intro . $error_str . gettext("Record exists and must be removed before adding.");
break;
case 'internal_error_updating_zone':
$status = $status_intro . $error_str . gettext("A remote server error occurred updating the zone.");
break;
case 'internal_error_could_not_load_zone':
$status = $status_intro . $error_str . gettext("A remote server error occurred loading the zone.");
break;
case 'internal_error_could_not_update_zone':
$status = $status_intro . $error_str . gettext("A remote server error occurred updating the zone.");
break;
case 'internal_error_could_not_add_record':
$status = $status_intro . $error_str . gettext("A remote server error occurred adding a new record.");
break;
case 'internal_error_could_not_destroy_record ':
$status = $status_intro . $error_str . gettext("A remote server error occurred removing an existing record.");
break;
default:
break;
}
case 'azure':
case 'azurev6':
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if ($http_code == 401) {
$status = $status_intro . $error_str . gettext("User Authorization Failed");
} else if ($http_code == 201) {
$status = $status_intro . $success_str . gettext("IP Address Changed Successfully!");
$successful_update = true;
} else if ($http_code == 200) {
$status = $status_intro . $success_str . gettext("IP Address Changed Successfully!");
$successful_update = true;
} else {
$status = $status_intro . "(" . gettext("Unknown Response") . ")";
log_error($status_intro . gettext("PAYLOAD:") . " " . $http_code);
$this->_debug($data);
}
break;
default:
break;
}
if ($successful_update == true) {
/* Write WAN IP to cache file */
$wan_ip = $this->_checkIP();
if ($this->_useIPv6 == false && $wan_ip > 0) {
$currentTime = time();
notify_all_remote(sprintf(gettext('DynDNS updated IP Address on %1$s (%2$s) to %3$s'), convert_real_interface_to_friendly_descr($this->_if), $this->_if, $wan_ip));
log_error(sprintf(gettext('phpDynDNS: updating cache file %1$s: %2$s'), $this->_cacheFile, $wan_ip));
@file_put_contents($this->_cacheFile, "{$wan_ip}|{$currentTime}");
} else {
@unlink($this->_cacheFile);
}
if ($this->_useIPv6 == true && $wan_ip > 0) {
$currentTime = time();
notify_all_remote(sprintf(gettext('DynDNS updated IPv6 Address on %1$s (%2$s) to %3$s'), convert_real_interface_to_friendly_descr($this->_if), $this->_if, $wan_ip));
log_error(sprintf(gettext('phpDynDNS: updating cache file %1$s: %2$s'), $this->_cacheFile_v6, $wan_ip));
@file_put_contents($this->_cacheFile_v6, "{$wan_ip}|{$currentTime}");
} else {
@unlink($this->_cacheFile_v6);
}
}
$this->status = $status;
log_error($status);
}
/*
* Private Function (added 12 July 05) [beta]
* Return Error, Set Last Error, and Die.
*/
function _error($errorNumber = '1') {
$err_str = 'phpDynDNS: (' . gettext('ERROR!') . ') ';
$err_str_r53 = 'Route 53: (' . gettext('Error') . ') ';
switch ($errorNumber) {
case 0:
break;
case 2:
$error = $err_str . gettext('No Dynamic DNS Service provider was selected.');
break;
case 3:
$error = $err_str . gettext('No Username Provided.');
break;
case 4:
$error = $err_str . gettext('No Password Provided.');
break;
case 5:
$error = $err_str . gettext('No Hostname Provided.');
break;
case 6:
$error = $err_str . gettext('The Dynamic DNS Service provided is not yet supported.');
break;
case 7:
$error = $err_str . gettext('No Update URL Provided.');
break;
case 8:
$status = $err_str_r53 . gettext("Invalid ZoneID");
break;
case 9:
$status = $err_str_r53 . gettext("Invalid TTL");
break;
case 10:
$error = "phpDynDNS ({$this->_FQDN}): " . sprintf(gettext("No change in my IP address and/or %s days has not passed. Not updating dynamic DNS entry."), $this->_dnsMaxCacheAgeDays);
break;
default:
$error = $err_str . gettext('Unknown Response.');
/* FIXME: $data isn't in scope here */
/* $this->_debug($data); */
break;
}
$this->lastError = $error;
log_error($error);
}
/*
* Private Function (added 12 July 05) [beta]
* - Detect whether or not IP needs to be updated.
* | Written Specifically for pfSense (https://www.pfsense.org) may
* | work with other systems. pfSense base is FreeBSD.
*/
function _detectChange() {
global $debug;
if ($debug) {
log_error(sprintf(gettext('Dynamic DNS %1$s (%2$s): _detectChange() starting.'), $this->_dnsService, $this->_FQDN));
}
$currentTime = time();
$wan_ip = $this->_checkIP();
if ($wan_ip == 0) {
log_error(sprintf(gettext("Dynamic Dns (%s): Current WAN IP could not be determined, skipping update process."), $this->_FQDN));
return false;
}
$log_error = sprintf(gettext('Dynamic Dns (%1$s): Current WAN IP: %2$s'), $this->_FQDN, $wan_ip) . " ";
if ($this->_useIPv6 == true) {
if (file_exists($this->_cacheFile_v6)) {
$contents = file_get_contents($this->_cacheFile_v6);
list($cacheIP, $cacheTime) = explode('|', $contents);
$this->_debug($cacheIP.'/'.$cacheTime);
$initial = false;
$log_error .= sprintf(gettext("Cached IPv6: %s"), $cacheIP);
} else {
$cacheIP = '::';
@file_put_contents($this->_cacheFile, "::|{$currentTime}");
$cacheTime = $currentTime;
$initial = true;
$log_error .= gettext("No Cached IPv6 found.");
}
} else {
if (file_exists($this->_cacheFile)) {
$contents = file_get_contents($this->_cacheFile);
list($cacheIP, $cacheTime) = explode('|', $contents);
$this->_debug($cacheIP.'/'.$cacheTime);
$initial = false;
$log_error .= sprintf(gettext("Cached IP: %s"), $cacheIP);
} else {
$cacheIP = '0.0.0.0';
@file_put_contents($this->_cacheFile, "0.0.0.0|{$currentTime}");
$cacheTime = $currentTime;
$initial = true;
$log_error .= gettext("No Cached IP found.");
}
}
if ($this->_dnsVerboseLog) {
log_error($log_error);
}
// Convert seconds = days * hr/day * min/hr * sec/min
$maxCacheAgeSecs = $this->_dnsMaxCacheAgeDays * 24 * 60 * 60;
$needs_updating = FALSE;
/* lets determine if the item needs updating */
if ($cacheIP != $wan_ip) {
$needs_updating = true;
$update_reason = gettext("Dynamic Dns: cacheIP != wan_ip. Updating.") . " ";
$update_reason .= sprintf(gettext('Cached IP: %1$s WAN IP: %2$s'), $cacheIP, $wan_ip) . " ";
}
if (($currentTime - $cacheTime) > $maxCacheAgeSecs) {
$needs_updating = true;
$this->_forceUpdateNeeded = true;
$update_reason = sprintf(gettext("Dynamic Dns: More than %s days. Updating."), $this->_dnsMaxCacheAgeDays);
$update_reason .= " {$currentTime} - {$cacheTime} > {$maxCacheAgeSecs} ";
}
if ($initial == true) {
$needs_updating = true;
$update_reason .= gettext("Initial update.");
}
/* finally if we need updating then store the
* new cache value and return true
*/
if ($needs_updating == true) {
if ($this->_dnsVerboseLog) {
log_error("DynDns ({$this->_FQDN}): {$update_reason}");
}
return true;
}
return false;
}
/*
* Private Function (added 16 July 05) [beta]
* - Writes debug information to a file.
* - This function is only called when a unknown response
* - status is returned from a DynDNS service provider.
*/
function _debug($data) {
global $g;
if (!$g['debug']) {
return;
}
$string = date('m-d-y h:i:s').' - ('.$this->_debugID.') - ['.$this->_dnsService.'] - '.$data."\n";
$file = fopen($this->_debugFile, 'a');
fwrite($file, $string);
fclose($file);
}
function _checkIP() {
global $debug;
if ($debug) {
log_error(sprintf(gettext('Dynamic DNS %1$s (%2$s): _checkIP() starting.'), $this->_dnsService, $this->_FQDN));
}
if ($this->_useIPv6 == true) {
$ip_address = get_interface_ipv6($this->_if);
if (!is_ipaddrv6($ip_address)) {
return 0;
}
} else {
$ip_address = dyndnsCheckIP($this->_if);
if (!is_ipaddr($ip_address)) {
return 0;
}
}
if ($this->_useIPv6 == false && is_private_ip(get_interface_ip($this->_if))) {
if (is_ipaddr($ip_address)) {
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));
}
} else {
log_error(sprintf(gettext('Dynamic DNS %1$s (%2$s): IP address could not be extracted from Check IP Service'), $this->_dnsService, $this->_FQDN));
return 0;
}
} 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));
}
}
$this->_dnsIP = $ip_address;
return $ip_address;
}
}
?>
You can’t perform that action at this time.