summaryrefslogtreecommitdiffstats
path: root/src/etc/inc
diff options
context:
space:
mode:
authorfrank <frankthetank@users.noreply.github.com>2017-02-23 23:57:11 -0500
committerfrank <frankthetank@users.noreply.github.com>2017-02-23 23:57:11 -0500
commit9a3ec9a5917bbb3d9978dec769cf895eb56422e8 (patch)
treee9dba6bf618a57bb6b1415a1dfbe97e59b730506 /src/etc/inc
parentb11c8ef6c683c2a55f97e25963ad0ec2a118db4d (diff)
downloadpfsense-9a3ec9a5917bbb3d9978dec769cf895eb56422e8.zip
pfsense-9a3ec9a5917bbb3d9978dec769cf895eb56422e8.tar.gz
Implemented Dreamhost ISP dynamic DNS updates.
Dreamhost does not allow direct record updates through their API. Records must be deleted and then added. Unfortunately, to delete the record you must first retrieve the existing record to be able to pass back the old IP address for delete. Rather than copy what CloudFlare had done and embed several of the queries into its own update process I broke out some of the operations into _lookup_current and _remove(existing_ip) methods. This will allow for more consistent logging output if others use these features, too.
Diffstat (limited to 'src/etc/inc')
-rw-r--r--src/etc/inc/dyndns.class296
1 files changed, 296 insertions, 0 deletions
diff --git a/src/etc/inc/dyndns.class b/src/etc/inc/dyndns.class
index c88feca..72d3f23 100644
--- a/src/etc/inc/dyndns.class
+++ b/src/etc/inc/dyndns.class
@@ -60,6 +60,7 @@
* - All-Inkl (all-inkl.com)
* - DuiaDNS (www.duiadns.net)
* - DuiaDNS IPv6 (www.duiadns.net)
+ * - DreamHost DNS (www.dreamhost.com)
* +----------------------------------------------------+
* Requirements:
* - PHP version 4.0.2 or higher with the CURL Library and the PCRE Library
@@ -113,6 +114,8 @@
* All-Inkl - Last Tested: 12 November 2016
* DuiaDNS - Last Tested: 25 November 2016
* DuiaDNS IPv6 - Last Tested: 25 November 2016
+ * DreamHost - Not Tested
+ * DreamHost IPv6 - Not Tested
* +====================================================+
*
* @author E.Kristensen
@@ -160,6 +163,7 @@
var $_dnsDummyUpdateDone;
var $_forceUpdateNeeded;
var $_useIPv6;
+ var $_existingRecords;
/*
* Public Constructor Function (added 12 July 05) [beta]
@@ -235,6 +239,7 @@
case 'duiadns-v6':
case 'freedns-v6':
case 'cloudflare-v6':
+ case 'dreamhost-v6':
$this->_useIPv6 = true;
break;
default:
@@ -329,6 +334,17 @@
$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;
@@ -819,6 +835,29 @@
curl_setopt($ch, CURLOPT_USERPWD, $this->_dnsUser.':'.$this->_dnsPass);
curl_setopt($ch, CURLOPT_URL, $server . 'myip=' . $this->_dnsIP);
break;
+ case 'dreamhost':
+ case 'dreamhost-v6':
+ $needsIP = TRUE;
+ $isv6 = ($this->_dnsService === 'dreamhost-v6');
+ $server = 'https://api.dreamhost.com/';
+ $post_data['key'] = $this->_dnsUser;
+ $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 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;
default:
break;
}
@@ -832,6 +871,191 @@
@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) {
+ 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);
+ }
+
+ 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 'dreamhost':
+ case 'dreamhost-v6':
+ $server = 'https://api.dreamhost.com/';
+ $post_data['key'] = $this->_dnsUser;
+ $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);
+ 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)
+ * Retrieves current DNS records.
+ *
+ * Some services cannot perform new operations without the caller
+ * providing existing record information.
+ */
+ function _lookup_current() {
+ 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);
+ }
+
+ 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 'dreamhost':
+ case 'dreamhost-v6':
+ $server = 'https://api.dreamhost.com/';
+ $post_data['key'] = $this->_dnsUser;
+ $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);
+ 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->_checkLookupStatus($ch, $data, $header);
+ @curl_close($ch);
+ }
+ }
+
+ /*
+ * Private Function (added 12 July 2005) [beta]
+ * Retrieve Lookup Status
+ */
+ 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]
@@ -1483,6 +1707,78 @@
$this->_debug($header);
}
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':
+ $status = $status_intro . $error_str . gettext("No record exists.");
+ break;
+ case 'no_type':
+ $status = $status_intro . $error_str . gettext("No type exists.");
+ break;
+ case 'no_value':
+ $status = $status_intro . $error_str . gettext("No value exists.");
+ break;
+ case 'no_such_record ':
+ $status = $status_intro . $error_str . gettext("No record exists.");
+ break;
+ case 'no_such_type ':
+ $status = $status_intro . $error_str . gettext("No type exists.");
+ break;
+ 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;
+ }
+ default:
+ break;
}
if ($successful_update == true) {
OpenPOWER on IntegriCloud