_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": 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 "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, "ttl" => 1, "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\\/(?[^\\/]*)/', $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\\/(?[^"]*)/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\":\"(?[^\"]*)\"/", $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("/(?_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; } } ?>