Commit 4ac9fe67 authored by Judah - MW's avatar Judah - MW
Browse files

I #6169: Added Cloudflare lib with basic working rr_insert method

This will be the library for all Cloudflare specific logic.  It is
called by server/plugins-available/third_party_dns_plugin.inc.php
parent 72b6a4c6
Pipeline #8897 canceled with stage
<?php
/*
Copyright (c) goes here...
*/
class cloudflare {
/**
* Construct for this class
*
* @return system
*/
private $action = 'update';
private $cf_client_api = 'https://api.cloudflare.com/client/v4/'; // Docs - https://api.cloudflare.com/
private $cf_host_api = 'https://api.cloudflare.com/host-gw.html'; // Docs - https://www.cloudflare.com/docs/host-api/
public function __construct(){
}
private function handle_request($request_url, $request_method, $request_headers = null, $request_body = null) {
global $app, $conf;
$request = curl_init($request_url);
if(!is_null($request_headers)) {
curl_setopt($request, CURLOPT_HTTPHEADER, $request_headers);
}
curl_setopt($request, CURLOPT_RETURNTRANSFER, true);
switch($request_method) {
case 'GET':
break;
case 'POST':
curl_setopt($request, CURLOPT_POST, true);
curl_setopt($request, CURLOPT_POSTFIELDS, $request_body);
break;
case 'PUT':
curl_setopt($request, CURLOPT_CUSTOMREQUEST, 'PUT');
curl_setopt($request, CURLOPT_POSTFIELDS, $request_body);
break;
case 'DELETE':
curl_setopt($request, CURLOPT_CUSTOMREQUEST, 'DELETE');
break;
default:
$app->log('Unsupported HTTP Method: ' . $request_method, LOGLEVEL_ERROR);
return false;
}
$response = curl_exec($request);
$response_code = curl_errno($request);
if(!empty($response_code) && $response_code != 200) {
$response_code = curl_getinfo($request, CURLINFO_RESPONSE_CODE);
$app->log('Error ' . $response_code . ' accessing Cloudflare API: ' . $response, LOGLEVEL_ERROR);
return false;
}
curl_close($request);
return $response;
}
private function client_api($connection, $method, $resource, $body = null) {
global $app, $conf;
$url = $this->cf_client_api . $resource;
$headers = ['Content-Type: application/json'];
if(!empty($connection['user'])) {
$headers[] = 'X-Auth-Email: ' . $connection['user'];
} else {
$app->log('No Cloudflare API Email specified.', LOGLEVEL_ERROR);
return false;
}
if(!empty($connection['api_key'])) {
$headers[] = 'X-Auth-Key: ' . $connection['api_key'];
} else {
$app->log('No Cloudflare API Key specified.', LOGLEVEL_ERROR);
return false;
}
$response = $this->handle_request($url, $method, $headers, $body);
if($response === false) {
return false;
}
$decoded_response = json_decode($response, true);
if($decoded_response['success'] === false) {
foreach($decoded_response['errors'] as $error) {
$app->log('Cloudflare API Error ' . $error['code'] . ': ' . $error['message'], LOGLEVEL_DEBUG); //ERROR
var_dump($decoded_response); //REMOVE
return false;
}
}
return $decoded_response;
}
//##################################################################
public function soa_insert($event_name, $data, $connection) {
global $app, $conf;
$app->log("lib_cloudflare: ".__METHOD__);
}
public function soa_update($event_name, $data, $connection) {
global $app, $conf;
$app->log("lib_cloudflare: ".__METHOD__);
}
public function soa_delete($event_name, $data, $connection) {
global $app, $conf;
$app->log("lib_cloudflare: ".__METHOD__);
}
public function rr_insert($event_name, $data, $connection) {
global $app, $conf;
// Zone Lookup
$response = $this->client_api($connection, 'GET', 'zones/');
if($response === false) {
return false;
}
$soa_record = $app->db->queryOneRecord("SELECT * FROM dns_soa WHERE id = ?", $data['new']['zone']);
$zone_name = substr($soa_record['origin'], 0, -1);
$zone_id = '';
foreach($response['result'] as $zone) {
if($zone['name'] == $zone_name) {
$zone_id = $zone['id'];
break;
}
}
if(empty($zone_id)) {
// Could call soa_insert here instead?
$app->log('No ' . $zone_name . ' zone found in Cloudflare account: ' . $connection['user'], LOGLEVEL_ERROR);
return false;
}
// HTTP POST record
$record = [
'type' => $data['new']['type'],
'name' => $data['new']['name'],
'content' => $data['new']['data'],
'ttl' => intval($data['new']['ttl']),
'proxied' => false
];
switch($data['new']['type']) {
case 'SRV':
unset($record['name']);
unset($record['content']);
$record['data'] = ['priority' => $data['new']['aux']];
list($record['data']['weight'], $record['data']['port'], $record['data']['target']) = explode(' ', $data['new']['data'], 3);
list($record['data']['service'], $record['data']['proto'], $record['data']['name']) = explode('.', $data['new']['name'], 3);
unset($srv);
if($record['data']['name'] === null || $record['data']['name'] == $zone_name . '.') {
// Trailing dot required to explicitly define the origin, otherwise it is included as a subdomain
$record['data']['name'] = '@';
}
break;
case 'URI':
case 'MX':
$record['priority'] = intval($data['new']['aux']);
break;
}
$record_json = json_encode($record);
$response = $this->client_api($connection, 'POST', 'zones/' . $zone_id . '/dns_records', $record_json);
if($response === false) {
return false;
}
// TODO: Store record_id, zone_id, proxy status on record for faster lookups
}
public function rr_update($event_name, $data, $connection) {
global $app, $conf;
$app->log("lib_cloudflare: ".__METHOD__);
return false;
}
public function rr_delete($event_name, $data, $connection) {
global $app, $conf;
$app->log("lib_cloudflare: ".__METHOD__);
}
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment