mirror of
https://github.com/pfsense/pfsense.git
synced 2025-10-26 11:38:35 +00:00
Merge pull request #71 from ebrandi/r53dyndns
Patch to add Route 53 as new Dynamic DNS provider into dyndns infrastructure
This commit is contained in:
commit
6ffef73889
@ -21,6 +21,7 @@
|
||||
* - HE.net (dns.he.net)
|
||||
* - HE.net Tunnelbroker IP update (ipv4.tunnelbroker.net)
|
||||
* - SelfHost (selfhost.de)
|
||||
* - Amazon Route 53 (aws.amazon.com)
|
||||
* +----------------------------------------------------+
|
||||
* Requirements:
|
||||
* - PHP version 4.0.2 or higher with CURL Library
|
||||
@ -55,6 +56,7 @@
|
||||
* HE.net - Last Tested: NEVER
|
||||
* HE.net Tunnel - Last Tested: 28 June 2011
|
||||
* SelfHost - Last Tested: 26 December 2011
|
||||
+ * Amazon Route 53 - Last tested: 01 April 2012
|
||||
* +====================================================+
|
||||
*
|
||||
* @author E.Kristensen
|
||||
@ -84,6 +86,8 @@
|
||||
var $_dnsServer;
|
||||
var $_dnsPort;
|
||||
var $_dnsUpdateURL;
|
||||
var $_dnsZoneID;
|
||||
var $_dnsTTL;
|
||||
var $status;
|
||||
var $_debugID;
|
||||
var $_if;
|
||||
@ -94,7 +98,8 @@
|
||||
*/
|
||||
function updatedns ($dnsService = '', $dnsHost = '', $dnsUser = '', $dnsPass = '',
|
||||
$dnsWildcard = 'OFF', $dnsMX = '', $dnsIf = '', $dnsBackMX = '',
|
||||
$dnsServer = '', $dnsPort = '', $dnsUpdateURL = '', $forceUpdate = false) {
|
||||
$dnsServer = '', $dnsPort = '', $dnsUpdateURL = '', $forceUpdate = false,
|
||||
$dnsZoneID ='', $dnsTTL='') {
|
||||
|
||||
global $config, $g;
|
||||
|
||||
@ -114,6 +119,11 @@
|
||||
if (!$dnsPass) $this->_error(4);
|
||||
if (!$dnsHost) $this->_error(5);
|
||||
break;
|
||||
case 'route53':
|
||||
if (!$dnsZoneID) $this->_error(8);
|
||||
if (!$dnsTTL) $this->_error(9);
|
||||
break;
|
||||
|
||||
default:
|
||||
if (!$dnsUser) $this->_error(3);
|
||||
if (!$dnsPass) $this->_error(4);
|
||||
@ -128,6 +138,8 @@
|
||||
$this->_dnsPort = $dnsPort;
|
||||
$this->_dnsWildcard = $dnsWildcard;
|
||||
$this->_dnsMX = $dnsMX;
|
||||
$this->_dnsZoneID = $dnsZoneID;
|
||||
$this->_dnsTTL = $dnsTTL;
|
||||
$this->_if = get_real_interface($dnsIf);
|
||||
$this->_ifIP = get_interface_ip($dnsIf);
|
||||
|
||||
@ -163,6 +175,7 @@
|
||||
case 'namecheap':
|
||||
case 'he-net':
|
||||
case 'selfhost':
|
||||
case 'route53':
|
||||
$this->_update();
|
||||
break;
|
||||
case 'he-net-tunnelbroker':
|
||||
@ -185,7 +198,7 @@
|
||||
|
||||
log_error("DynDns: DynDns _update() starting.");
|
||||
|
||||
if ($this->_dnsService != 'ods') {
|
||||
if ($this->_dnsService != 'ods' and $this->_dnsService != 'route53 ') {
|
||||
$ch = curl_init();
|
||||
curl_setopt($ch, CURLOPT_HEADER, 0);
|
||||
curl_setopt($ch, CURLOPT_USERAGENT, $this->_UserAgent);
|
||||
@ -428,10 +441,65 @@
|
||||
$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':
|
||||
log_error("Route53: DNS update() starting.");
|
||||
|
||||
/* Setting Variables */
|
||||
$hostname = "{$this->_dnsHost}.";
|
||||
$ZoneID = $this->_dnsZoneID;
|
||||
$AccessKeyId=$this->_dnsUser;
|
||||
$SecretAccessKey=$this->_dnsPass;
|
||||
$NewIP=$this->_dnsIP;
|
||||
$NewTTL=$this->_dnsTTL;
|
||||
|
||||
/* Include Route 53 Library Class */
|
||||
require_once('/etc/inc/r53.class');
|
||||
|
||||
/* Set Amazon AWS Credentials for this record */
|
||||
$r53 = new Route53($AccessKeyId, $SecretAccessKey);
|
||||
|
||||
/* Function to find old values of records in Route 53 */
|
||||
if(!function_exists('Searchrecords')) {
|
||||
function SearchRecords($records, $name) {
|
||||
$result = array();
|
||||
foreach($records as $record) {
|
||||
if(strtolower($record['Name']) == strtolower($name)) {
|
||||
$result [] = $record;
|
||||
}
|
||||
}
|
||||
return ($result) ? $result : false;
|
||||
}}
|
||||
|
||||
$records = $r53->listResourceRecordSets("/hostedzone/$ZoneID");
|
||||
|
||||
/* Get IP for your hostname in Route 53 */
|
||||
if(false !== ($a_result = SearchRecords($records['ResourceRecordSets'], "$hostname"))) {
|
||||
$OldTTL=$a_result[0][TTL];
|
||||
$OldIP=$a_result[0][ResourceRecords][0];
|
||||
} else {
|
||||
$OldIP="";
|
||||
}
|
||||
|
||||
/* Check if we need update DNS Record */
|
||||
if ($OldIP !== $NewIP) {
|
||||
if(!empty($OldIP)) {
|
||||
/* Your Hostname already exist, deleting and creating it again */
|
||||
$changes = array();
|
||||
$changes[] = $r53->prepareChange(DELETE, $hostname, A, $OldTTL, $OldIP);
|
||||
$changes[] = $r53->prepareChange(CREATE, $hostname, A, $NewTTL, $NewIP);
|
||||
$result = $r53->changeResourceRecordSets("/hostedzone/$ZoneID", $changes);
|
||||
} else {
|
||||
/* Your Hostname dosent exist yet, creating it */
|
||||
$changes = $r53->prepareChange(CREATE, $hostname, A, $NewTTL, $NewIP);
|
||||
$result = $r53->changeResourceRecordSets("/hostedzone/$ZoneID", $changes);
|
||||
}
|
||||
}
|
||||
$this->_checkStatus(0, $result);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if ($this->_dnsService != 'ods') {
|
||||
if ($this->_dnsService != 'ods' and $this->_dnsService != 'route53') {
|
||||
$data = curl_exec($ch);
|
||||
$this->_checkStatus($ch, $data);
|
||||
@curl_close($ch);
|
||||
@ -446,7 +514,7 @@
|
||||
log_error("DynDns: DynDns _checkStatus() starting.");
|
||||
log_error("DynDns: Current Service: {$this->_dnsService}");
|
||||
$successful_update = false;
|
||||
if ($this->_dnsService != 'ods' && @curl_error($ch)) {
|
||||
if ($this->_dnsService != 'ods' and $this->_dnsService != 'route53' && @curl_error($ch)) {
|
||||
$status = "Curl error occurred: " . curl_error($ch);
|
||||
log_error($status);
|
||||
$this->status = $status;
|
||||
@ -823,6 +891,9 @@
|
||||
$this->_debug($data);
|
||||
}
|
||||
break;
|
||||
case 'route53':
|
||||
$successful_update = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if($successful_update == true) {
|
||||
@ -867,6 +938,12 @@
|
||||
case 7:
|
||||
$error = 'phpDynDNS: (ERROR!) No Update URL Provided.';
|
||||
break;
|
||||
case 8:
|
||||
$status = "Route 53: (Error) Invalid ZoneID";
|
||||
break;
|
||||
case 9:
|
||||
$status = "Route 53: (Error) Invalid TTL";
|
||||
break;
|
||||
case 10:
|
||||
$error = 'phpDynDNS: No change in my IP address and/or 25 days has not passed. Not updating dynamic DNS entry.';
|
||||
break;
|
||||
|
||||
754
etc/inc/r53.class
Normal file
754
etc/inc/r53.class
Normal file
@ -0,0 +1,754 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* Copyright (c) 2011, Dan Myers.
|
||||
* Parts copyright (c) 2008, Donovan Schonknecht.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* - Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This is a modified BSD license (the third clause has been removed).
|
||||
* The BSD license may be found here:
|
||||
* http://www.opensource.org/licenses/bsd-license.php
|
||||
*
|
||||
* Amazon Route 53 is a trademark of Amazon.com, Inc. or its affiliates.
|
||||
*
|
||||
* Route53 is based on Donovan Schonknecht's Amazon S3 PHP class, found here:
|
||||
* http://undesigned.org.za/2007/10/22/amazon-s3-php-class
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Amazon Route53 PHP class
|
||||
*
|
||||
* @link http://sourceforge.net/projects/php-r53/
|
||||
* version 0.9.0
|
||||
*
|
||||
*/
|
||||
class Route53
|
||||
{
|
||||
const API_VERSION = '2010-10-01';
|
||||
|
||||
protected $__accessKey; // AWS Access key
|
||||
protected $__secretKey; // AWS Secret key
|
||||
protected $__host;
|
||||
|
||||
public function getAccessKey() { return $this->__accessKey; }
|
||||
public function getSecretKey() { return $this->__secretKey; }
|
||||
public function getHost() { return $this->__host; }
|
||||
|
||||
protected $__verifyHost = 1;
|
||||
protected $__verifyPeer = 1;
|
||||
|
||||
// verifyHost and verifyPeer determine whether curl verifies ssl certificates.
|
||||
// It may be necessary to disable these checks on certain systems.
|
||||
// These only have an effect if SSL is enabled.
|
||||
public function verifyHost() { return $this->__verifyHost; }
|
||||
public function enableVerifyHost($enable = true) { $this->__verifyHost = $enable; }
|
||||
|
||||
public function verifyPeer() { return $this->__verifyPeer; }
|
||||
public function enableVerifyPeer($enable = true) { $this->__verifyPeer = $enable; }
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param string $accessKey Access key
|
||||
* @param string $secretKey Secret key
|
||||
* @return void
|
||||
*/
|
||||
public function __construct($accessKey = null, $secretKey = null, $host = 'route53.amazonaws.com') {
|
||||
if ($accessKey !== null && $secretKey !== null) {
|
||||
$this->setAuth($accessKey, $secretKey);
|
||||
}
|
||||
$this->__host = $host;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set AWS access key and secret key
|
||||
*
|
||||
* @param string $accessKey Access key
|
||||
* @param string $secretKey Secret key
|
||||
* @return void
|
||||
*/
|
||||
public function setAuth($accessKey, $secretKey) {
|
||||
$this->__accessKey = $accessKey;
|
||||
$this->__secretKey = $secretKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Lists the hosted zones on the account
|
||||
*
|
||||
* @param string marker A pagination marker returned by a previous truncated call
|
||||
* @param int maxItems The maximum number of items per page. The service uses min($maxItems, 100).
|
||||
* @return A list of hosted zones
|
||||
*/
|
||||
public function listHostedZones($marker = null, $maxItems = 100) {
|
||||
$rest = new Route53Request($this, 'hostedzone', 'GET');
|
||||
|
||||
if($marker !== null) {
|
||||
$rest->setParameter('marker', $marker);
|
||||
}
|
||||
if($maxItems !== 100) {
|
||||
$rest->setParameter('maxitems', $maxItems);
|
||||
}
|
||||
|
||||
$rest = $rest->getResponse();
|
||||
if($rest->error === false && $rest->code !== 200) {
|
||||
$rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status');
|
||||
}
|
||||
if($rest->error !== false) {
|
||||
$this->__triggerError('listHostedZones', $rest->error);
|
||||
return false;
|
||||
}
|
||||
|
||||
$response = array();
|
||||
if (!isset($rest->body))
|
||||
{
|
||||
return $response;
|
||||
}
|
||||
|
||||
$zones = array();
|
||||
foreach($rest->body->HostedZones->HostedZone as $z)
|
||||
{
|
||||
$zones[] = $this->parseHostedZone($z);
|
||||
}
|
||||
$response['HostedZone'] = $zones;
|
||||
|
||||
if(isset($rest->body->MaxItems)) {
|
||||
$response['MaxItems'] = (string)$rest->body->MaxItems;
|
||||
}
|
||||
|
||||
if(isset($rest->body->IsTruncated)) {
|
||||
$response['IsTruncated'] = (string)$rest->body->IsTruncated;
|
||||
if($response['IsTruncated'] == 'true') {
|
||||
$response['NextMarker'] = (string)$rest->body->NextMarker;
|
||||
}
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves information on a specified hosted zone
|
||||
*
|
||||
* @param string zoneId The id of the hosted zone, as returned by CreateHostedZoneResponse or ListHostedZoneResponse
|
||||
* In other words, if ListHostedZoneResponse shows the zone's Id as '/hostedzone/Z1PA6795UKMFR9',
|
||||
* then that full value should be passed here, including the '/hostedzone/' prefix.
|
||||
* @return A data structure containing information about the specified zone
|
||||
*/
|
||||
public function getHostedZone($zoneId) {
|
||||
// we'll strip off the leading forward slash, so we can use it as the action directly.
|
||||
$zoneId = trim($zoneId, '/');
|
||||
|
||||
$rest = new Route53Request($this, $zoneId, 'GET');
|
||||
|
||||
$rest = $rest->getResponse();
|
||||
if($rest->error === false && $rest->code !== 200) {
|
||||
$rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status');
|
||||
}
|
||||
if($rest->error !== false) {
|
||||
$this->__triggerError('getHostedZone', $rest->error);
|
||||
return false;
|
||||
}
|
||||
|
||||
$response = array();
|
||||
if (!isset($rest->body))
|
||||
{
|
||||
return $response;
|
||||
}
|
||||
|
||||
$response['HostedZone'] = $this->parseHostedZone($rest->body->HostedZone);
|
||||
$response['NameServers'] = $this->parseDelegationSet($rest->body->DelegationSet);
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new hosted zone
|
||||
*
|
||||
* @param string name The name of the hosted zone (e.g. "example.com.")
|
||||
* @param string reference A user-specified unique reference for this request
|
||||
* @param string comment An optional user-specified comment to attach to the zone
|
||||
* @return A data structure containing information about the newly created zone
|
||||
*/
|
||||
public function createHostedZone($name, $reference, $comment = '') {
|
||||
// hosted zone names must end with a period, but people will forget this a lot...
|
||||
if(strrpos($name, '.') != (strlen($name) - 1)) {
|
||||
$name .= '.';
|
||||
}
|
||||
|
||||
$data = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
|
||||
$data .= '<CreateHostedZoneRequest xmlns="https://route53.amazonaws.com/doc/'.Route53::API_VERSION."/\">\n";
|
||||
$data .= '<Name>'.$name."</Name>\n";
|
||||
$data .= '<CallerReference>'.$reference."</CallerReference>\n";
|
||||
if(strlen($comment) > 0) {
|
||||
$data .= "<HostedZoneConfig>\n";
|
||||
$data .= '<Comment>'.$comment."</Comment>\n";
|
||||
$data .= "</HostedZoneConfig>\n";
|
||||
}
|
||||
$data .= "</CreateHostedZoneRequest>\n";
|
||||
|
||||
$rest = new Route53Request($this, 'hostedzone', 'POST', $data);
|
||||
|
||||
$rest = $rest->getResponse();
|
||||
|
||||
if($rest->error === false && !in_array($rest->code, array(200, 201, 202, 204)) ) {
|
||||
$rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status');
|
||||
}
|
||||
if($rest->error !== false) {
|
||||
$this->__triggerError('createHostedZone', $rest->error);
|
||||
return false;
|
||||
}
|
||||
|
||||
$response = array();
|
||||
if (!isset($rest->body))
|
||||
{
|
||||
return $response;
|
||||
}
|
||||
|
||||
$response['HostedZone'] = $this->parseHostedZone($rest->body->HostedZone);
|
||||
$response['ChangeInfo'] = $this->parseChangeInfo($rest->body->ChangeInfo);
|
||||
$response['NameServers'] = $this->parseDelegationSet($rest->body->DelegationSet);
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves information on a specified hosted zone
|
||||
*
|
||||
* @param string zoneId The id of the hosted zone, as returned by CreateHostedZoneResponse or ListHostedZoneResponse
|
||||
* In other words, if ListHostedZoneResponse shows the zone's Id as '/hostedzone/Z1PA6795UKMFR9',
|
||||
* then that full value should be passed here, including the '/hostedzone/' prefix.
|
||||
* @return The change request data corresponding to this delete
|
||||
*/
|
||||
public function deleteHostedZone($zoneId) {
|
||||
// we'll strip off the leading forward slash, so we can use it as the action directly.
|
||||
$zoneId = trim($zoneId, '/');
|
||||
|
||||
$rest = new Route53Request($this, $zoneId, 'DELETE');
|
||||
|
||||
$rest = $rest->getResponse();
|
||||
if($rest->error === false && $rest->code !== 200) {
|
||||
$rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status');
|
||||
}
|
||||
if($rest->error !== false) {
|
||||
$this->__triggerError('deleteHostedZone', $rest->error);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!isset($rest->body))
|
||||
{
|
||||
return array();
|
||||
}
|
||||
|
||||
return $this->parseChangeInfo($rest->body->ChangeInfo);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a list of resource record sets for a given zone
|
||||
*
|
||||
* @param string zoneId The id of the hosted zone, as returned by CreateHostedZoneResponse or ListHostedZoneResponse
|
||||
* In other words, if ListHostedZoneResponse shows the zone's Id as '/hostedzone/Z1PA6795UKMFR9',
|
||||
* then that full value should be passed here, including the '/hostedzone/' prefix.
|
||||
* @param string type The type of resource record set to begin listing from. If this is specified, $name must also be specified.
|
||||
* Must be one of: A, AAAA, CNAME, MX, NS, PTR, SOA, SPF, SRV, TXT
|
||||
* @param string name The name at which to begin listing resource records (in the lexographic order of records).
|
||||
* @param int maxItems The maximum number of results to return. The service uses min($maxItems, 100).
|
||||
* @return The list of matching resource record sets
|
||||
*/
|
||||
public function listResourceRecordSets($zoneId, $type = '', $name = '', $maxItems = 100) {
|
||||
// we'll strip off the leading forward slash, so we can use it as the action directly.
|
||||
$zoneId = trim($zoneId, '/');
|
||||
|
||||
$rest = new Route53Request($this, $zoneId.'/rrset', 'GET');
|
||||
|
||||
if(strlen($type) > 0) {
|
||||
$rest->setParameter('type', $type);
|
||||
}
|
||||
if(strlen($name) > 0) {
|
||||
$rest->setParameter('name', $name);
|
||||
}
|
||||
if($maxItems != 100) {
|
||||
$rest->setParameter('maxitems', $maxItems);
|
||||
}
|
||||
|
||||
$rest = $rest->getResponse();
|
||||
if($rest->error === false && $rest->code !== 200) {
|
||||
$rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status');
|
||||
}
|
||||
if($rest->error !== false) {
|
||||
$this->__triggerError('listResourceRecordSets', $rest->error);
|
||||
return false;
|
||||
}
|
||||
|
||||
$response = array();
|
||||
if (!isset($rest->body))
|
||||
{
|
||||
return $response;
|
||||
}
|
||||
|
||||
$recordSets = array();
|
||||
foreach($rest->body->ResourceRecordSets->ResourceRecordSet as $set) {
|
||||
$recordSets[] = $this->parseResourceRecordSet($set);
|
||||
}
|
||||
|
||||
$response['ResourceRecordSets'] = $recordSets;
|
||||
|
||||
if(isset($rest->body->MaxItems)) {
|
||||
$response['MaxItems'] = (string)$rest->body->MaxItems;
|
||||
}
|
||||
|
||||
if(isset($rest->body->IsTruncated)) {
|
||||
$response['IsTruncated'] = (string)$rest->body->IsTruncated;
|
||||
if($response['IsTruncated'] == 'true') {
|
||||
$response['NextRecordName'] = (string)$rest->body->NextRecordName;
|
||||
$response['NextRecordType'] = (string)$rest->body->NextRecordType;
|
||||
}
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes the specified resource record set changes (create or delete).
|
||||
*
|
||||
* @param string zoneId The id of the hosted zone, as returned by CreateHostedZoneResponse or ListHostedZoneResponse
|
||||
* In other words, if ListHostedZoneResponse shows the zone's Id as '/hostedzone/Z1PA6795UKMFR9',
|
||||
* then that full value should be passed here, including the '/hostedzone/' prefix.
|
||||
* @param array changes An array of change objects, as they are returned by the prepareChange utility method.
|
||||
* You may also pass a single change object.
|
||||
* @param string comment An optional comment to attach to the change request
|
||||
* @return The status of the change request
|
||||
*/
|
||||
public function changeResourceRecordSets($zoneId, $changes, $comment = '') {
|
||||
// we'll strip off the leading forward slash, so we can use it as the action directly.
|
||||
$zoneId = trim($zoneId, '/');
|
||||
|
||||
$data = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
|
||||
$data .= '<ChangeResourceRecordSetsRequest xmlns="https://route53.amazonaws.com/doc/'.Route53::API_VERSION."/\">\n";
|
||||
$data .= "<ChangeBatch>\n";
|
||||
|
||||
if(strlen($comment) > 0) {
|
||||
$data .= '<Comment>'.$comment."</Comment>\n";
|
||||
}
|
||||
|
||||
if(!is_array($changes)) {
|
||||
$changes = array($changes);
|
||||
}
|
||||
|
||||
$data .= "<Changes>\n";
|
||||
foreach($changes as $change) {
|
||||
$data .= $change;
|
||||
}
|
||||
$data .= "</Changes>\n";
|
||||
|
||||
$data .= "</ChangeBatch>\n";
|
||||
$data .= "</ChangeResourceRecordSetsRequest>\n";
|
||||
|
||||
$rest = new Route53Request($this, $zoneId.'/rrset', 'POST', $data);
|
||||
|
||||
$rest = $rest->getResponse();
|
||||
if($rest->error === false && !in_array($rest->code, array(200, 201, 202, 204))) {
|
||||
$rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status');
|
||||
}
|
||||
if($rest->error !== false) {
|
||||
$this->__triggerError('changeResourceRecordSets', $rest->error);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!isset($rest->body))
|
||||
{
|
||||
return array();
|
||||
}
|
||||
|
||||
return $this->parseChangeInfo($rest->body->ChangeInfo);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves information on a specified change request
|
||||
*
|
||||
* @param string changeId The id of the change, as returned by CreateHostedZoneResponse or ChangeResourceRecordSets
|
||||
* In other words, if CreateHostedZoneResponse showed the change's Id as '/change/C2682N5HXP0BZ4',
|
||||
* then that full value should be passed here, including the '/change/' prefix.
|
||||
* @return The status of the change request
|
||||
*/
|
||||
public function getChange($changeId) {
|
||||
// we'll strip off the leading forward slash, so we can use it as the action directly.
|
||||
$zoneId = trim($changeId, '/');
|
||||
|
||||
$rest = new Route53Request($this, $changeId, 'GET');
|
||||
|
||||
$rest = $rest->getResponse();
|
||||
if($rest->error === false && $rest->code !== 200) {
|
||||
$rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status');
|
||||
}
|
||||
if($rest->error !== false) {
|
||||
$this->__triggerError('getChange', $rest->error);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!isset($rest->body))
|
||||
{
|
||||
return array();
|
||||
}
|
||||
|
||||
return $this->parseChangeInfo($rest->body->ChangeInfo);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Utility function to parse a HostedZone tag structure
|
||||
*/
|
||||
private function parseHostedZone($tag) {
|
||||
$zone = array();
|
||||
$zone['Id'] = (string)$tag->Id;
|
||||
$zone['Name'] = (string)$tag->Name;
|
||||
$zone['CallerReference'] = (string)$tag->CallerReference;
|
||||
|
||||
// these might always be set, but check just in case, since
|
||||
// their values are option on CreateHostedZone requests
|
||||
if(isset($tag->Config) && isset($tag->Config->Comment)) {
|
||||
$zone['Config'] = array('Comment' => (string)$tag->Config->Comment);
|
||||
}
|
||||
|
||||
return $zone;
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility function to parse a ChangeInfo tag structure
|
||||
*/
|
||||
private function parseChangeInfo($tag) {
|
||||
$info = array();
|
||||
$info['Id'] = (string)$tag->Id;
|
||||
$info['Status'] = (string)$tag->Status;
|
||||
$info['SubmittedAt'] = (string)$tag->SubmittedAt;
|
||||
return $info;
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility function to parse a DelegationSet tag structure
|
||||
*/
|
||||
private function parseDelegationSet($tag) {
|
||||
$servers = array();
|
||||
foreach($tag->NameServers->NameServer as $ns) {
|
||||
$servers[] = (string)$ns;
|
||||
}
|
||||
return $servers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility function to parse a ResourceRecordSet tag structure
|
||||
*/
|
||||
private function parseResourceRecordSet($tag) {
|
||||
$rrs = array();
|
||||
$rrs['Name'] = (string)$tag->Name;
|
||||
$rrs['Type'] = (string)$tag->Type;
|
||||
$rrs['TTL'] = (string)$tag->TTL;
|
||||
$rrs['ResourceRecords'] = array();
|
||||
foreach($tag->ResourceRecords->ResourceRecord as $rr) {
|
||||
$rrs['ResourceRecords'][] = (string)$rr->Value;
|
||||
}
|
||||
return $rrs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility function to prepare a Change object for ChangeResourceRecordSets requests.
|
||||
* All fields are required.
|
||||
*
|
||||
* @param string action The action to perform. One of: CREATE, DELETE
|
||||
* @param string name The name to perform the action on.
|
||||
* If it does not end with '.', then AWS treats the name as relative to the zone root.
|
||||
* @param string type The type of record being modified.
|
||||
* Must be one of: A, AAAA, CNAME, MX, NS, PTR, SOA, SPF, SRV, TXT
|
||||
* @param int ttl The time-to-live value for this record, in seconds.
|
||||
* @param array records An array of resource records to attach to this change.
|
||||
* Each member of this array can either be a string, or an array of strings.
|
||||
* Passing an array of strings will attach multiple values to a single resource record.
|
||||
* If a single string is passed as $records instead of an array,
|
||||
* it will be treated as a single-member array.
|
||||
* @return object An opaque object containing the change request.
|
||||
* Do not write code that depends on the contents of this object, as it may change at any time.
|
||||
*/
|
||||
public function prepareChange($action, $name, $type, $ttl, $records) {
|
||||
$change = "<Change>\n";
|
||||
$change .= '<Action>'.$action."</Action>\n";
|
||||
$change .= "<ResourceRecordSet>\n";
|
||||
$change .= '<Name>'.$name."</Name>\n";
|
||||
$change .= '<Type>'.$type."</Type>\n";
|
||||
$change .= '<TTL>'.$ttl."</TTL>\n";
|
||||
$change .= "<ResourceRecords>\n";
|
||||
|
||||
if(!is_array($records)) {
|
||||
$records = array($records);
|
||||
}
|
||||
|
||||
foreach($records as $record) {
|
||||
$change .= "<ResourceRecord>\n";
|
||||
if(is_array($record)) {
|
||||
foreach($record as $value) {
|
||||
$change .= '<Value>'.$value."</Value>\n";
|
||||
}
|
||||
}
|
||||
else {
|
||||
$change .= '<Value>'.$record."</Value>\n";
|
||||
}
|
||||
$change .= "</ResourceRecord>\n";
|
||||
}
|
||||
|
||||
$change .= "</ResourceRecords>\n";
|
||||
$change .= "</ResourceRecordSet>\n";
|
||||
$change .= "</Change>\n";
|
||||
|
||||
return $change;
|
||||
}
|
||||
|
||||
/**
|
||||
* Trigger an error message
|
||||
*
|
||||
* @internal Used by member functions to output errors
|
||||
* @param array $error Array containing error information
|
||||
* @return string
|
||||
*/
|
||||
public function __triggerError($functionname, $error)
|
||||
{
|
||||
if($error == false) {
|
||||
trigger_error(sprintf("Route53::%s(): Encountered an error, but no description given", $functionname), E_USER_WARNING);
|
||||
}
|
||||
else if(isset($error['curl']) && $error['curl'])
|
||||
{
|
||||
trigger_error(sprintf("Route53::%s(): %s %s", $functionname, $error['code'], $error['message']), E_USER_WARNING);
|
||||
}
|
||||
else if(isset($error['Error']))
|
||||
{
|
||||
$e = $error['Error'];
|
||||
$message = sprintf("Route53::%s(): %s - %s: %s\nRequest Id: %s\n", $functionname, $e['Type'], $e['Code'], $e['Message'], $error['RequestId']);
|
||||
trigger_error($message, E_USER_WARNING);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback handler for 503 retries.
|
||||
*
|
||||
* @internal Used by SimpleDBRequest to call the user-specified callback, if set
|
||||
* @param $attempt The number of failed attempts so far
|
||||
* @return The retry delay in microseconds, or 0 to stop retrying.
|
||||
*/
|
||||
public function __executeServiceTemporarilyUnavailableRetryDelay($attempt)
|
||||
{
|
||||
if(is_callable($this->__serviceUnavailableRetryDelayCallback)) {
|
||||
$callback = $this->__serviceUnavailableRetryDelayCallback;
|
||||
return $callback($attempt);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
final class Route53Request
|
||||
{
|
||||
private $r53, $action, $verb, $data, $parameters = array();
|
||||
public $response;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param string $r53 The Route53 object making this request
|
||||
* @param string $action SimpleDB action
|
||||
* @param string $verb HTTP verb
|
||||
* @param string $data For POST requests, the data being posted (optional)
|
||||
* @return mixed
|
||||
*/
|
||||
function __construct($r53, $action, $verb, $data = '') {
|
||||
$this->r53 = $r53;
|
||||
$this->action = $action;
|
||||
$this->verb = $verb;
|
||||
$this->data = $data;
|
||||
$this->response = new STDClass;
|
||||
$this->response->error = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set request parameter
|
||||
*
|
||||
* @param string $key Key
|
||||
* @param string $value Value
|
||||
* @param boolean $replace Whether to replace the key if it already exists (default true)
|
||||
* @return void
|
||||
*/
|
||||
public function setParameter($key, $value, $replace = true) {
|
||||
if(!$replace && isset($this->parameters[$key]))
|
||||
{
|
||||
$temp = (array)($this->parameters[$key]);
|
||||
$temp[] = $value;
|
||||
$this->parameters[$key] = $temp;
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->parameters[$key] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the response
|
||||
*
|
||||
* @return object | false
|
||||
*/
|
||||
public function getResponse() {
|
||||
|
||||
$params = array();
|
||||
foreach ($this->parameters as $var => $value)
|
||||
{
|
||||
if(is_array($value))
|
||||
{
|
||||
foreach($value as $v)
|
||||
{
|
||||
$params[] = $var.'='.$this->__customUrlEncode($v);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$params[] = $var.'='.$this->__customUrlEncode($value);
|
||||
}
|
||||
}
|
||||
|
||||
sort($params, SORT_STRING);
|
||||
|
||||
$query = implode('&', $params);
|
||||
|
||||
// must be in format 'Sun, 06 Nov 1994 08:49:37 GMT'
|
||||
$date = gmdate('D, d M Y H:i:s e');
|
||||
|
||||
$headers = array();
|
||||
$headers[] = 'Date: '.$date;
|
||||
$headers[] = 'Host: '.$this->r53->getHost();
|
||||
|
||||
$auth = 'AWS3-HTTPS AWSAccessKeyId='.$this->r53->getAccessKey();
|
||||
$auth .= ',Algorithm=HmacSHA256,Signature='.$this->__getSignature($date);
|
||||
$headers[] = 'X-Amzn-Authorization: '.$auth;
|
||||
|
||||
$url = 'https://'.$this->r53->getHost().'/'.Route53::API_VERSION.'/'.$this->action.'?'.$query;
|
||||
|
||||
// Basic setup
|
||||
$curl = curl_init();
|
||||
curl_setopt($curl, CURLOPT_USERAGENT, 'Route53/php');
|
||||
|
||||
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, ($this->r53->verifyHost() ? 1 : 0));
|
||||
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, ($this->r53->verifyPeer() ? 1 : 0));
|
||||
|
||||
curl_setopt($curl, CURLOPT_URL, $url);
|
||||
curl_setopt($curl, CURLOPT_RETURNTRANSFER, false);
|
||||
curl_setopt($curl, CURLOPT_WRITEFUNCTION, array(&$this, '__responseWriteCallback'));
|
||||
curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true);
|
||||
|
||||
// Request types
|
||||
switch ($this->verb) {
|
||||
case 'GET': break;
|
||||
case 'POST':
|
||||
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $this->verb);
|
||||
if(strlen($this->data) > 0) {
|
||||
curl_setopt($curl, CURLOPT_POSTFIELDS, $this->data);
|
||||
$headers[] = 'Content-Type: text/plain';
|
||||
$headers[] = 'Content-Length: '.strlen($this->data);
|
||||
}
|
||||
break;
|
||||
case 'DELETE':
|
||||
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'DELETE');
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
|
||||
curl_setopt($curl, CURLOPT_HEADER, false);
|
||||
|
||||
// Execute, grab errors
|
||||
if (curl_exec($curl)) {
|
||||
$this->response->code = curl_getinfo($curl, CURLINFO_HTTP_CODE);
|
||||
} else {
|
||||
$this->response->error = array(
|
||||
'curl' => true,
|
||||
'code' => curl_errno($curl),
|
||||
'message' => curl_error($curl),
|
||||
'resource' => $this->resource
|
||||
);
|
||||
}
|
||||
|
||||
@curl_close($curl);
|
||||
|
||||
// Parse body into XML
|
||||
if ($this->response->error === false && isset($this->response->body)) {
|
||||
$this->response->body = simplexml_load_string($this->response->body);
|
||||
|
||||
// Grab Route53 errors
|
||||
if (!in_array($this->response->code, array(200, 201, 202, 204))
|
||||
&& isset($this->response->body->Error)) {
|
||||
$error = $this->response->body->Error;
|
||||
$output = array();
|
||||
$output['curl'] = false;
|
||||
$output['Error'] = array();
|
||||
$output['Error']['Type'] = (string)$error->Type;
|
||||
$output['Error']['Code'] = (string)$error->Code;
|
||||
$output['Error']['Message'] = (string)$error->Message;
|
||||
$output['RequestId'] = (string)$this->response->body->RequestId;
|
||||
|
||||
$this->response->error = $output;
|
||||
unset($this->response->body);
|
||||
}
|
||||
}
|
||||
|
||||
return $this->response;
|
||||
}
|
||||
|
||||
/**
|
||||
* CURL write callback
|
||||
*
|
||||
* @param resource &$curl CURL resource
|
||||
* @param string &$data Data
|
||||
* @return integer
|
||||
*/
|
||||
private function __responseWriteCallback(&$curl, &$data) {
|
||||
$this->response->body .= $data;
|
||||
return strlen($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Contributed by afx114
|
||||
* URL encode the parameters as per http://docs.amazonwebservices.com/AWSECommerceService/latest/DG/index.html?Query_QueryAuth.html
|
||||
* PHP's rawurlencode() follows RFC 1738, not RFC 3986 as required by Amazon. The only difference is the tilde (~), so convert it back after rawurlencode
|
||||
* See: http://www.morganney.com/blog/API/AWS-Product-Advertising-API-Requires-a-Signed-Request.php
|
||||
*
|
||||
* @param string $var String to encode
|
||||
* @return string
|
||||
*/
|
||||
private function __customUrlEncode($var) {
|
||||
return str_replace('%7E', '~', rawurlencode($var));
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the auth string using Hmac-SHA256
|
||||
*
|
||||
* @internal Used by SimpleDBRequest::getResponse()
|
||||
* @param string $string String to sign
|
||||
* @return string
|
||||
*/
|
||||
private function __getSignature($string) {
|
||||
return base64_encode(hash_hmac('sha256', $string, $this->r53->getSecretKey(), true));
|
||||
}
|
||||
}
|
||||
@ -1320,7 +1320,9 @@ function services_dyndns_configure_client($conf) {
|
||||
$dnsServer = NULL,
|
||||
$dnsPort = NULL,
|
||||
$dnsUpdateURL = NULL,
|
||||
$forceUpdate = $conf['force']);
|
||||
$forceUpdate = $conf['force'],
|
||||
$dnsZoneID=$conf['zoneid'],
|
||||
$dnsTTL=$conf['ttl']);
|
||||
}
|
||||
|
||||
function services_dyndns_configure($int = "") {
|
||||
|
||||
@ -114,8 +114,8 @@ include("head.inc");
|
||||
</td>
|
||||
<td class="listlr">
|
||||
<?php
|
||||
$types = explode(",", "DNS-O-Matic, DynDNS (dynamic),DynDNS (static),DynDNS (custom),DHS,DyNS,easyDNS,No-IP,ODS.org,ZoneEdit,Loopia,freeDNS, DNSexit, OpenDNS, Namecheap, HE.net, HE.net Tunnelbroker, SelfHost");
|
||||
$vals = explode(" ", "dnsomatic dyndns dyndns-static dyndns-custom dhs dyns easydns noip ods zoneedit loopia freedns dnsexit opendns namecheap he-net he-net-tunnelbroker selfhost");
|
||||
$types = explode(",", "DNS-O-Matic, DynDNS (dynamic),DynDNS (static),DynDNS (custom),DHS,DyNS,easyDNS,No-IP,ODS.org,ZoneEdit,Loopia,freeDNS, DNSexit, OpenDNS, Namecheap, HE.net, HE.net Tunnelbroker, SelfHost, Route 53");
|
||||
$vals = explode(" ", "dnsomatic dyndns dyndns-static dyndns-custom dhs dyns easydns noip ods zoneedit loopia freedns dnsexit opendns namecheap he-net he-net-tunnelbroker selfhost route53");
|
||||
$j = 0; for ($j = 0; $j < count($vals); $j++)
|
||||
if ($vals[$j] == $dyndns['type']) {
|
||||
echo htmlspecialchars($types[$j]);
|
||||
|
||||
@ -69,6 +69,8 @@ if (isset($id) && isset($a_dyndns[$id])) {
|
||||
$pconfig['enable'] = !isset($a_dyndns[$id]['enable']);
|
||||
$pconfig['interface'] = $a_dyndns[$id]['interface'];
|
||||
$pconfig['wildcard'] = isset($a_dyndns[$id]['wildcard']);
|
||||
$pconfig['zoneid'] = $a_dyndns[$id]['zoneid'];
|
||||
$pconfig['ttl'] = isset($a_dyndns[$id]['ttl']);
|
||||
$pconfig['descr'] = $a_dyndns[$id]['descr'];
|
||||
}
|
||||
|
||||
@ -103,6 +105,8 @@ if ($_POST) {
|
||||
$dyndns['wildcard'] = $_POST['wildcard'] ? true : false;
|
||||
$dyndns['enable'] = $_POST['enable'] ? false : true;
|
||||
$dyndns['interface'] = $_POST['interface'];
|
||||
$dyndns['zoneid'] = $_POST['zoneid'];
|
||||
$dyndns['ttl'] = $_POST['ttl'];
|
||||
$dyndns['descr'] = $_POST['descr'];
|
||||
$dyndns['force'] = isset($_POST['force']);
|
||||
|
||||
@ -152,8 +156,8 @@ include("head.inc");
|
||||
<td width="78%" class="vtable">
|
||||
<select name="type" class="formselect" id="type">
|
||||
<?php
|
||||
$types = explode(",", "DNS-O-Matic, DynDNS (dynamic),DynDNS (static),DynDNS (custom),DHS,DyNS,easyDNS,No-IP,ODS.org,ZoneEdit,Loopia,freeDNS, DNSexit, OpenDNS, Namecheap, HE.net, HE.net Tunnelbroker, SelfHost");
|
||||
$vals = explode(" ", "dnsomatic dyndns dyndns-static dyndns-custom dhs dyns easydns noip ods zoneedit loopia freedns dnsexit opendns namecheap he-net he-net-tunnelbroker selfhost");
|
||||
$types = explode(",", "DNS-O-Matic, DynDNS (dynamic),DynDNS (static),DynDNS (custom),DHS,DyNS,easyDNS,No-IP,ODS.org,ZoneEdit,Loopia,freeDNS, DNSexit, OpenDNS, Namecheap, HE.net, HE.net Tunnelbroker, SelfHost, Route 53");
|
||||
$vals = explode(" ", "dnsomatic dyndns dyndns-static dyndns-custom dhs dyns easydns noip ods zoneedit loopia freedns dnsexit opendns namecheap he-net he-net-tunnelbroker selfhost route53");
|
||||
$j = 0; for ($j = 0; $j < count($vals); $j++): ?>
|
||||
<option value="<?=$vals[$j];?>" <?php if ($vals[$j] == $pconfig['type']) echo "selected";?>>
|
||||
<?=htmlspecialchars($types[$j]);?>
|
||||
@ -207,6 +211,7 @@ include("head.inc");
|
||||
<td width="78%" class="vtable">
|
||||
<input name="username" type="text" class="formfld user" id="username" size="20" value="<?=htmlspecialchars($pconfig['username']);?>">
|
||||
<br/><?= gettext("Username is required for all types except Namecheap and FreeDNS.");?>
|
||||
<br/><?= gettext("Route 53: Enter your Access Key ID.");?>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
@ -215,8 +220,29 @@ include("head.inc");
|
||||
<input name="password" type="password" class="formfld pwd" id="password" size="20" value="<?=htmlspecialchars($pconfig['password']);?>">
|
||||
<br/>
|
||||
<?=gettext("FreeDNS (freedns.afraid.org): Enter your \"Authentication Token\" provided by FreeDNS.");?>
|
||||
<br/><?= gettext("Route 53: Enter your Secret Access Key.");?>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr id="r53_zoneid" style="display:none">
|
||||
<td width="22%" valign="top" class="vncellreq"><?=gettext("Zone ID");?></td>
|
||||
<td width="78%" class="vtable">
|
||||
<input name="zoneid" type="text" class="formfld user" id="zoneid" size="20" value="<?=htmlspecialchars($pconfig['zoneid']);?>">
|
||||
<br/><?= gettext("Enter Zone ID that you received when you created your domain in Route 53.");?>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
|
||||
<tr id="r53_ttl" style="display:none">
|
||||
<td width="22%" valign="top" class="vncellreq"><?=gettext("TTL");?></td>
|
||||
<td width="78%" class="vtable">
|
||||
<input name="ttl" type="text" class="formfld user" id="ttl" size="20" value="<?=htmlspecialchars($pconfig['ttl']);?>">
|
||||
<br/><?= gettext("Choose TTL for your dns record.");?>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
|
||||
|
||||
<tr>
|
||||
<td width="22%" valign="top" class="vncell"><?=gettext("Description");?></td>
|
||||
<td width="78%" class="vtable">
|
||||
@ -244,5 +270,20 @@ include("head.inc");
|
||||
</table>
|
||||
</form>
|
||||
<?php include("fend.inc"); ?>
|
||||
|
||||
<script type="text/javascript">
|
||||
var selectmenu=document.getElementById("type")
|
||||
selectmenu.onchange=function(){
|
||||
var chosenoption=this.options[this.selectedIndex]
|
||||
if (chosenoption.value=="route53"){
|
||||
document.getElementById("r53_zoneid").style.display="";
|
||||
document.getElementById("r53_ttl").style.display="";
|
||||
} else if (chosenoption.value !="route53"){
|
||||
document.getElementById("r53_zoneid").style.display="none";
|
||||
document.getElementById("r53_ttl").style.display="none";
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user