diff --git a/includes/class/ApiHandler.php b/includes/class/ApiHandler.php new file mode 100644 index 0000000..80b5a9a --- /dev/null +++ b/includes/class/ApiHandler.php @@ -0,0 +1,124 @@ +headers = Array(); + $this->hostname = $apiip; + $this->port = $apiport; + $this->auth = $apipass; + $this->proto = $apiproto; + $this->sslverify = $apisslverify; + $this->curlh = curl_init(); + $this->method = 'GET'; + $this->content = FALSE; + $this->apiurl = ''; + } + + public function addheader($field, $content) { + $this->headers[$field] = $content; + } + + private function authheaders() { + $this->addheader('X-API-Key', $this->auth); + } + + private function apiurl() { + $tmp = new ApiHandler(); + + $tmp->url = '/api'; + $tmp->go(); + + if ($tmp->json[0]['version'] <= 1) { + $this->apiurl = $tmp->json[0]['url']; + } else { + throw new Exception("Unsupported API version"); + } + + } + + private function curlopts() { + $this->authheaders(); + $this->addheader('Accept', 'application/json'); + + curl_reset($this->curlh); + curl_setopt($this->curlh, CURLOPT_HTTPHEADER, Array()); + curl_setopt($this->curlh, CURLOPT_RETURNTRANSFER, 1); + + if (strcasecmp($this->proto, 'https')) { + curl_setopt($this->curlh, CURLOPT_SSL_VERIFYPEER, $this->sslverify); + } + + $setheaders = Array(); + + foreach ($this->headers as $k => $v) { + array_push($setheaders, join(": ", Array($k, $v))); + } + curl_setopt($this->curlh, CURLOPT_HTTPHEADER, $setheaders); + } + + private function baseurl() { + return $this->proto.'://'.$this->hostname.':'.$this->port.$this->apiurl; + } + + private function go() { + $this->curlopts(); + + if ($this->content) { + $this->addheader('Content-Type', 'application/json'); + curl_setopt($this->curlh, CURLOPT_POST, 1); + curl_setopt($this->curlh, CURLOPT_POSTFIELDS, $this->content); + } + + switch ($this->method) { + case 'POST': + curl_setopt($this->curlh, CURLOPT_POST, 1); + break; + case 'GET': + curl_setopt($this->curlh, CURLOPT_POST, 0); + break; + case 'DELETE': + case 'PATCH': + case 'PUT': + curl_setopt($this->curlh, CURLOPT_CUSTOMREQUEST, $this->method); + break; + } + + curl_setopt($this->curlh, CURLOPT_URL, $this->baseurl().$this->url); + + print "Here we go:\n"; + print "Request: ".$this->method.' '.$this->baseurl().$this->url."\n"; + if ($this->content != '') { + print "Content: ".$this->content."\n"; + } + + $return = curl_exec($this->curlh); + $code = curl_getinfo($this->curlh, CURLINFO_HTTP_CODE); + $json = json_decode($return, 1); + + if (isset($json['error'])) { + throw new Exception("API Error $code: ".$json['error']); + } elseif ($code < 200 || $code >= 300) { + if ($code == 401) { + throw new Exception("Authentication failed. Have you configured your authmethod correct?"); + } + throw new Exception("Curl Error: $code ".curl_error($this->curlh)); + } + + $this->json = $json; + } + + public function call() { + if (substr($this->url, 0, 1) == '/') { + $this->apiurl(); + } else { + $this->apiurl = '/'; + } + + $this->go(); + } +} + diff --git a/includes/class/PdnsApi.php b/includes/class/PdnsApi.php new file mode 100644 index 0000000..d9ed390 --- /dev/null +++ b/includes/class/PdnsApi.php @@ -0,0 +1,84 @@ +http = new ApiHandler(); + } + + public function listzones($q = FALSE) { + $api = clone $this->http; + $api->method = 'GET'; + if ($q) { + $api->url = "/servers/localhost/search-data?q=*".$q."*&max=25"; + $api->call(); + $ret = Array(); + $seen = Array(); + + foreach ($api->json as $result) { + if (isset($seen[$result['zone_id']])) { + continue; + } + $zone = $this->loadzone($result['zone_id']); + unset($zone['rrsets']); + array_push($ret, $zone); + $seen[$result['zone_id']] = 1; + } + + return $ret; + } + $api->url = "/servers/localhost/zones"; + $api->call(); + + return $api->json; + } + + public function loadzone($zoneid) { + $api = clone $this->http; + $api->method = 'GET'; + $api->url = "/servers/localhost/zones/$zoneid"; + $api->call(); + + return $api->json; + } + + public function savezone($zone) { + $api = clone $this->http; + // We have to split up RRSets and Zoneinfo. + // First, update the zone + $zonedata = $zone; + unset($zonedata['id']); + unset($zonedata['url']); + unset($zonedata['rrsets']); + + if ($zone['serial'] == '') { + $api->method = 'POST'; + $api->url = '/servers/localhost/zones'; + $api->content = json_encode($zonedata); + $api->call(); + + return $api->json; + } + $api->method = 'PUT'; + $api->url = $zone['url']; + $api->content = json_encode($zonedata); + $api->call(); + + // Then, update the rrsets + $api->method = 'PATCH'; + $api->content = json_encode(Array('rrsets' => $zone['rrsets'])); + $api->call(); + } + + public function deletezone($zoneid) { + $api = clone $this->http; + $api->method = 'DELETE'; + $api->url = "/servers/localhost/zones/$zoneid"; + $api->call(); + + return $api->json; + } +} + +?> diff --git a/includes/class/Zone.php b/includes/class/Zone.php new file mode 100644 index 0000000..fc2f57e --- /dev/null +++ b/includes/class/Zone.php @@ -0,0 +1,270 @@ +id = ''; + $this->name = ''; + $this->kind = ''; + $this->url = ''; + $this->serial = ''; + $this->dnssec = ''; + $this->soa_edit = ''; + $this->soa_edit_api = ''; + $this->account = ''; + $this->nameservers = Array(); + $this->rrsets = Array(); + $this->masters = Array(); + } + + public function parse($data) { + $this->setid($data['id']); + $this->setname($data['name']); + $this->setkind($data['kind']); + $this->setdnssec($data['dnssec']); + $this->setaccount($data['account']); + $this->setserial($data['serial']); + $this->url = $data['url']; + $this->setsoaedit($data['soa_edit']); + $this->setsoaeditapi($data['soa_edit_api']); + + foreach ($data['masters'] as $master) { + $this->addmaster($master); + } + + foreach ($data['rrsets'] as $rrset) { + $toadd = new RRSet($rrset['name'], $rrset['type']); + foreach ($rrset['comments'] as $comment) { + $toadd->addComment($comment['content'], $comment['account'], $comment['modified_at']); + } + foreach ($rrset['records'] as $record) { + $toadd->addRecord($record['content'], $record['disabled']); + } + $toadd->setttl($rrset['ttl']); + array_push($this->rrsets, $toadd); } + } + + public function addnameserver($nameserver) { + foreach ($this->nameservers as $ns) { + if ($nameserver == $ns) { + throw new Exception("We already have this as a nameserver"); + } + } + array_push($this->nameservers, $nameserver); + + } + + public function setserial($serial) { + $this->serial = $serial; + } + + public function setsoaedit($soaedit) { + $this->soa_edit = $soaedit; + } + + public function setsoaeditapi($soaeditapi) { + $this->soa_edit_api = $soaeditapi; + } + public function setname($name) { + $this->name = $name; + } + + public function setkind($kind) { + $this->kind = $kind; + } + + public function setaccount($account) { + $this->account = $account; + } + + public function setdnssec($dnssec) { + $this->dnssec = $dnssec; + } + + private function setid($id) { + $this->id = $id; + } + + public function addmaster($ip) { + foreach ($this->masters as $master) { + if ($ip == $master) { + throw new Exception("We already have this as a master"); + } + } + array_push($this->masters, $ip); + } + + public function deleterrset($name, $type) { + foreach ($this->rrsets as $rrset) { + if ($rrset->name == $name and $rrset->type == $type) { + $rrset->delete(); + } + } + } + + public function setrrsetttl($name, $type, $ttl) { + foreach ($this->rrsets as $rrset) { + if ($rrset->name == $name and $rrset->type == $type) { + $rrset->setttl($ttl); + } + } + } + + public function addrrset($name, $type, $content, $ttl = 3600) { + foreach ($this->rrsets as $rrset) { + if ($rrset->name == $name and $rrset->type == $type) { + throw new Exception("This rrset already exists."); + } + } + $rrset = new RRSet($name, $type, $content, $ttl); + array_push($this->rrsets, $rrset); + } + + public function addrecord($name, $type, $content, $disabled = false, $ttl = 3600) { + $found = FALSE; + + foreach ($this->rrsets as $rrset) { + if ($rrset->name == $name and $rrset->type == $type) { + $rrset->addRecord($content, $disabled); + $found = TRUE; + } + } + + if (!$found) { + throw new Exception("RRset does not exist for this record"); + } + } + + public function export() { + $ret = Array(); + $ret['account'] = $this->account; + $ret['dnssec'] = $this->dnssec; + $ret['id'] = $this->id; + $ret['kind'] = $this->kind; + $ret['masters'] = $this->masters; + $ret['name'] = $this->name; + if (count($this->nameservers) > 0) { + $ret['nameservers'] = $this->nameservers; + } + $ret['rrsets'] = $this->export_rrsets(); + $ret['serial'] = $this->serial; + $ret['soa_edit'] = $this->soa_edit; + $ret['soa_edit_api'] = $this->soa_edit_api; + $ret['url'] = $this->url; + + return $ret; + } + + private function export_rrsets() { + $ret = Array(); + foreach ($this->rrsets as $rrset) { + array_push($ret, $rrset->export()); + } + + return $ret; + } +} + +class RRSet { + public function __construct($name = '', $type = '', $content = '', $ttl = 3600) { + $this->name = $name; + $this->type = $type; + $this->ttl = $ttl; + $this->changetype = 'REPLACE'; + $this->records = Array(); + $this->comments = Array(); + + if (isset($content) and $content != '') { + $this->addRecord($content); + } + } + + public function delete() { + $this->changetype = 'DELETE'; + } + + public function setttl($ttl) { + $this->ttl = $ttl; + } + + public function addRecord($content, $disabled = false) { + foreach ($this->records as $record) { + if ($record->content == $content) { + throw Exception("Record already exists"); + } + } + + $record = new Record($content, $disabled); + array_push($this->records, $record); + } + + public function addComment($content, $account, $modified_at = false) { + $comment = new Comment($content, $account, $modified_at); + array_push($this->comments, $comment); + } + + public function export() { + $ret = Array(); + $ret['comments'] = $this->export_comments(); + $ret['name'] = $this->name; + $ret['records'] = $this->export_records(); + if ($this->changetype != 'DELETE') { + $ret['ttl'] = $this->ttl; + } + $ret['type'] = $this->type; + $ret['changetype'] = $this->changetype; + return $ret; + } + + private function export_records() { + $ret = Array(); + foreach ($this->records as $record) { + array_push($ret, $record->export()); + } + + return $ret; + } + + private function export_comments() { + $ret = Array(); + foreach ($this->comments as $comment) { + array_push($ret, $comment->export()); + } + + return $ret; + } + +} + +class Record { + public function __construct($content, $disabled = FALSE) { + $this->content = $content; + $this->disabled = $disabled; + } + + public function export() { + $ret; + + $ret['content'] = $this->content; + $ret['disabled'] = $this->disabled; + + return $ret; + } +} + +class Comment { + public function __construct($content, $account, $modified_at) { + $this->content = $content; + $this->account = $account; + $this->modified_at = $modified_at; + } + + public function export() { + $ret; + + $ret['content'] = $this->content; + $ret['account'] = $this->account; + $ret['modified_at'] = $this->modified_at; + } +} + +?>