428 lines
14 KiB
PHP
Executable File
428 lines
14 KiB
PHP
Executable File
|
|
<?php
|
|
/**
|
|
* DNS Push API - Unified DNS Management
|
|
* Supports: Cloudflare, FreeDNS, Namecheap
|
|
*
|
|
* Usage: POST /api/dns-push.php
|
|
* Params: domain_id, provider, action (push, verify, delete)
|
|
*/
|
|
|
|
header('Content-Type: application/json');
|
|
|
|
function getDB() {
|
|
static $pdo = null;
|
|
if ($pdo === null) {
|
|
$pdo = new PDO("pgsql:host=localhost;dbname=adx_system", "admin", "admin123",
|
|
[PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
|
|
}
|
|
return $pdo;
|
|
}
|
|
|
|
// =====================================================
|
|
// CLOUDFLARE API
|
|
// =====================================================
|
|
class CloudflareAPI {
|
|
private $email;
|
|
private $apiKey;
|
|
private $apiToken;
|
|
private $baseUrl = 'https://api.cloudflare.com/client/v4';
|
|
|
|
public function __construct($accountId) {
|
|
$pdo = getDB();
|
|
$stmt = $pdo->prepare("SELECT * FROM admin.cloudflare_accounts WHERE id = ?");
|
|
$stmt->execute([$accountId]);
|
|
$account = $stmt->fetch(PDO::FETCH_ASSOC);
|
|
|
|
$this->email = $account['email'] ?? '';
|
|
$this->apiKey = $account['api_key'] ?? '';
|
|
$this->apiToken = $account['api_token'] ?? '';
|
|
}
|
|
|
|
private function request($endpoint, $method = 'GET', $data = null) {
|
|
$ch = curl_init($this->baseUrl . $endpoint);
|
|
|
|
$headers = ['Content-Type: application/json'];
|
|
if ($this->apiToken) {
|
|
$headers[] = 'Authorization: Bearer ' . $this->apiToken;
|
|
} else {
|
|
$headers[] = 'X-Auth-Email: ' . $this->email;
|
|
$headers[] = 'X-Auth-Key: ' . $this->apiKey;
|
|
}
|
|
|
|
curl_setopt_array($ch, [
|
|
CURLOPT_RETURNTRANSFER => true,
|
|
CURLOPT_HTTPHEADER => $headers,
|
|
CURLOPT_CUSTOMREQUEST => $method,
|
|
CURLOPT_TIMEOUT => 30
|
|
]);
|
|
|
|
if ($data && in_array($method, ['POST', 'PUT', 'PATCH'])) {
|
|
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
|
|
}
|
|
|
|
$response = curl_exec($ch);
|
|
$error = curl_error($ch);
|
|
curl_close($ch);
|
|
|
|
if ($error) {
|
|
return ['success' => false, 'errors' => [['message' => $error]]];
|
|
}
|
|
|
|
return json_decode($response, true);
|
|
}
|
|
|
|
public function getZoneId($domain) {
|
|
// Extraire le domaine racine
|
|
$parts = explode('.', $domain);
|
|
$rootDomain = implode('.', array_slice($parts, -2));
|
|
|
|
$result = $this->request('/zones?name=' . $rootDomain);
|
|
|
|
if ($result['success'] && !empty($result['result'])) {
|
|
return $result['result'][0]['id'];
|
|
}
|
|
return null;
|
|
}
|
|
|
|
public function createRecord($zoneId, $type, $name, $content, $ttl = 1, $proxied = false) {
|
|
return $this->request("/zones/$zoneId/dns_records", 'POST', [
|
|
'type' => $type,
|
|
'name' => $name,
|
|
'content' => $content,
|
|
'ttl' => $ttl,
|
|
'proxied' => $proxied
|
|
]);
|
|
}
|
|
|
|
public function listRecords($zoneId, $type = null, $name = null) {
|
|
$params = [];
|
|
if ($type) $params[] = "type=$type";
|
|
if ($name) $params[] = "name=$name";
|
|
$query = $params ? '?' . implode('&', $params) : '';
|
|
|
|
return $this->request("/zones/$zoneId/dns_records$query");
|
|
}
|
|
|
|
public function deleteRecord($zoneId, $recordId) {
|
|
return $this->request("/zones/$zoneId/dns_records/$recordId", 'DELETE');
|
|
}
|
|
|
|
public function pushDNSRecords($domain, $records) {
|
|
$results = [];
|
|
$zoneId = $this->getZoneId($domain);
|
|
|
|
if (!$zoneId) {
|
|
return ['success' => false, 'error' => 'Zone not found for domain: ' . $domain];
|
|
}
|
|
|
|
foreach ($records as $record) {
|
|
$name = $record['name'] === '@' ? $domain : $record['name'] . '.' . $domain;
|
|
|
|
// Vérifier si le record existe déjà
|
|
$existing = $this->listRecords($zoneId, $record['type'], $name);
|
|
|
|
if (!empty($existing['result'])) {
|
|
// Supprimer l'ancien
|
|
foreach ($existing['result'] as $old) {
|
|
$this->deleteRecord($zoneId, $old['id']);
|
|
}
|
|
}
|
|
|
|
// Créer le nouveau
|
|
$result = $this->createRecord(
|
|
$zoneId,
|
|
$record['type'],
|
|
$name,
|
|
$record['content'],
|
|
$record['ttl'] ?? 1,
|
|
$record['proxied'] ?? false
|
|
);
|
|
|
|
$results[] = [
|
|
'record' => $record['type'] . ' ' . $record['name'],
|
|
'success' => $result['success'] ?? false,
|
|
'id' => $result['result']['id'] ?? null,
|
|
'error' => $result['errors'][0]['message'] ?? null
|
|
];
|
|
}
|
|
|
|
return ['success' => true, 'results' => $results];
|
|
}
|
|
}
|
|
|
|
// =====================================================
|
|
// FREEDNS API (via scraping)
|
|
// =====================================================
|
|
class FreeDNSAPI {
|
|
private $cookie;
|
|
private $accountId;
|
|
private $baseUrl = 'https://freedns.afraid.org';
|
|
|
|
public function __construct($accountId) {
|
|
$this->accountId = $accountId;
|
|
$pdo = getDB();
|
|
$stmt = $pdo->prepare("SELECT * FROM admin.freedns_accounts WHERE id = ?");
|
|
$stmt->execute([$accountId]);
|
|
$account = $stmt->fetch(PDO::FETCH_ASSOC);
|
|
$this->cookie = $account['cookie'] ?? '';
|
|
}
|
|
|
|
public function login($username, $password) {
|
|
$ch = curl_init($this->baseUrl . '/zc.php?action=auth');
|
|
curl_setopt_array($ch, [
|
|
CURLOPT_RETURNTRANSFER => true,
|
|
CURLOPT_POST => true,
|
|
CURLOPT_POSTFIELDS => http_build_query([
|
|
'username' => $username,
|
|
'password' => $password,
|
|
'submit' => 'Login'
|
|
]),
|
|
CURLOPT_HEADER => true,
|
|
CURLOPT_FOLLOWLOCATION => true,
|
|
CURLOPT_USERAGENT => 'Mozilla/5.0'
|
|
]);
|
|
|
|
$response = curl_exec($ch);
|
|
curl_close($ch);
|
|
|
|
preg_match_all('/Set-Cookie:\s*([^;]+)/', $response, $matches);
|
|
$this->cookie = implode('; ', $matches[1] ?? []);
|
|
|
|
if (strpos($this->cookie, 'dns_cookie') !== false) {
|
|
// Sauvegarder le cookie
|
|
$pdo = getDB();
|
|
$stmt = $pdo->prepare("UPDATE admin.freedns_accounts SET cookie = ?, last_login = NOW() WHERE id = ?");
|
|
$stmt->execute([$this->cookie, $this->accountId]);
|
|
|
|
return ['success' => true];
|
|
}
|
|
|
|
return ['success' => false, 'error' => 'Login failed'];
|
|
}
|
|
|
|
public function addRecord($subdomain, $baseDomain, $type, $value) {
|
|
// Cette fonction nécessite le scraping de FreeDNS
|
|
// Implémentation simplifiée
|
|
return ['success' => false, 'error' => 'FreeDNS requires manual configuration'];
|
|
}
|
|
}
|
|
|
|
// =====================================================
|
|
// NAMECHEAP API
|
|
// =====================================================
|
|
class NamecheapAPI {
|
|
private $apiUser;
|
|
private $apiKey;
|
|
private $username;
|
|
private $clientIP;
|
|
private $baseUrl = 'https://api.namecheap.com/xml.response';
|
|
|
|
public function __construct($accountId) {
|
|
$pdo = getDB();
|
|
$stmt = $pdo->prepare("SELECT * FROM admin.namecheap_accounts WHERE id = ?");
|
|
$stmt->execute([$accountId]);
|
|
$account = $stmt->fetch(PDO::FETCH_ASSOC);
|
|
|
|
$this->apiUser = $account['api_user'] ?? $account['username'];
|
|
$this->apiKey = $account['api_key'] ?? '';
|
|
$this->username = $account['username'] ?? '';
|
|
$this->clientIP = $account['client_ip'] ?? $_SERVER['SERVER_ADDR'];
|
|
}
|
|
|
|
private function request($command, $params = []) {
|
|
$defaultParams = [
|
|
'ApiUser' => $this->apiUser,
|
|
'ApiKey' => $this->apiKey,
|
|
'UserName' => $this->username,
|
|
'ClientIp' => $this->clientIP,
|
|
'Command' => $command
|
|
];
|
|
|
|
$allParams = array_merge($defaultParams, $params);
|
|
$url = $this->baseUrl . '?' . http_build_query($allParams);
|
|
|
|
$ch = curl_init($url);
|
|
curl_setopt_array($ch, [
|
|
CURLOPT_RETURNTRANSFER => true,
|
|
CURLOPT_TIMEOUT => 30
|
|
]);
|
|
|
|
$response = curl_exec($ch);
|
|
curl_close($ch);
|
|
|
|
return simplexml_load_string($response);
|
|
}
|
|
|
|
public function getDomains() {
|
|
return $this->request('namecheap.domains.getList');
|
|
}
|
|
|
|
public function getHosts($sld, $tld) {
|
|
return $this->request('namecheap.domains.dns.getHosts', [
|
|
'SLD' => $sld,
|
|
'TLD' => $tld
|
|
]);
|
|
}
|
|
|
|
public function setHosts($sld, $tld, $records) {
|
|
$params = [
|
|
'SLD' => $sld,
|
|
'TLD' => $tld
|
|
];
|
|
|
|
$i = 1;
|
|
foreach ($records as $record) {
|
|
$params["HostName$i"] = $record['name'];
|
|
$params["RecordType$i"] = $record['type'];
|
|
$params["Address$i"] = $record['content'];
|
|
$params["TTL$i"] = $record['ttl'] ?? 1800;
|
|
$i++;
|
|
}
|
|
|
|
return $this->request('namecheap.domains.dns.setHosts', $params);
|
|
}
|
|
|
|
public function pushDNSRecords($domain, $records) {
|
|
$parts = explode('.', $domain);
|
|
$tld = array_pop($parts);
|
|
$sld = array_pop($parts);
|
|
|
|
// Récupérer les records existants
|
|
$existing = $this->getHosts($sld, $tld);
|
|
|
|
// Fusionner avec les nouveaux
|
|
$allRecords = [];
|
|
|
|
// Garder les existants qui ne sont pas remplacés
|
|
if (isset($existing->CommandResponse->DomainDNSGetHostsResult->host)) {
|
|
foreach ($existing->CommandResponse->DomainDNSGetHostsResult->host as $host) {
|
|
$allRecords[] = [
|
|
'name' => (string)$host['Name'],
|
|
'type' => (string)$host['Type'],
|
|
'content' => (string)$host['Address'],
|
|
'ttl' => (int)$host['TTL']
|
|
];
|
|
}
|
|
}
|
|
|
|
// Ajouter/remplacer les nouveaux
|
|
foreach ($records as $newRecord) {
|
|
$found = false;
|
|
foreach ($allRecords as &$existing) {
|
|
if ($existing['name'] === $newRecord['name'] && $existing['type'] === $newRecord['type']) {
|
|
$existing['content'] = $newRecord['content'];
|
|
$found = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!$found) {
|
|
$allRecords[] = $newRecord;
|
|
}
|
|
}
|
|
|
|
$result = $this->setHosts($sld, $tld, $allRecords);
|
|
|
|
return [
|
|
'success' => (string)$result['Status'] === 'OK',
|
|
'results' => $allRecords
|
|
];
|
|
}
|
|
}
|
|
|
|
// =====================================================
|
|
// MAIN API HANDLER
|
|
// =====================================================
|
|
function getDNSRecordsFromDB($domainId) {
|
|
$pdo = getDB();
|
|
|
|
// Récupérer le domaine
|
|
$stmt = $pdo->prepare("SELECT domain FROM admin.domains_pool WHERE id = ?");
|
|
$stmt->execute([$domainId]);
|
|
$domain = $stmt->fetchColumn();
|
|
|
|
if (!$domain) {
|
|
return ['error' => 'Domain not found'];
|
|
}
|
|
|
|
// Récupérer les IPs MTA actives
|
|
$stmt = $pdo->query("SELECT main_ip FROM admin.mta_servers WHERE status = 'Activated' AND main_ip IS NOT NULL LIMIT 5");
|
|
$ips = $stmt->fetchAll(PDO::FETCH_COLUMN);
|
|
|
|
if (empty($ips)) {
|
|
$ips = ['176.52.128.44', '119.8.153.154', '101.44.3.125'];
|
|
}
|
|
|
|
// Générer les records via la fonction SQL
|
|
$ipArray = "ARRAY['" . implode("','", $ips) . "']";
|
|
$stmt = $pdo->query("SELECT * FROM admin.generate_dns_records('$domain', $ipArray)");
|
|
$records = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|
|
|
// Convertir au format API
|
|
$formatted = [];
|
|
foreach ($records as $r) {
|
|
$formatted[] = [
|
|
'type' => $r['record_type'],
|
|
'name' => $r['record_name'],
|
|
'content' => $r['record_value'],
|
|
'ttl' => 1
|
|
];
|
|
}
|
|
|
|
return ['domain' => $domain, 'records' => $formatted, 'mta_ips' => $ips];
|
|
}
|
|
|
|
function pushDNS($domainId, $provider, $providerAccountId) {
|
|
$dnsData = getDNSRecordsFromDB($domainId);
|
|
|
|
if (isset($dnsData['error'])) {
|
|
return $dnsData;
|
|
}
|
|
|
|
switch ($provider) {
|
|
case 'cloudflare':
|
|
$api = new CloudflareAPI($providerAccountId);
|
|
return $api->pushDNSRecords($dnsData['domain'], $dnsData['records']);
|
|
|
|
case 'namecheap':
|
|
$api = new NamecheapAPI($providerAccountId);
|
|
return $api->pushDNSRecords($dnsData['domain'], $dnsData['records']);
|
|
|
|
case 'freedns':
|
|
return ['success' => false, 'error' => 'FreeDNS requires manual configuration via web interface'];
|
|
|
|
default:
|
|
return ['success' => false, 'error' => 'Unknown provider: ' . $provider];
|
|
}
|
|
}
|
|
|
|
// Handle request
|
|
$action = $_REQUEST['action'] ?? 'status';
|
|
$domainId = $_REQUEST['domain_id'] ?? null;
|
|
$provider = $_REQUEST['provider'] ?? 'cloudflare';
|
|
$providerAccountId = $_REQUEST['provider_account_id'] ?? 1;
|
|
|
|
switch ($action) {
|
|
case 'generate':
|
|
// Juste générer les records sans pousser
|
|
echo json_encode(getDNSRecordsFromDB($domainId));
|
|
break;
|
|
|
|
case 'push':
|
|
// Générer et pousser vers le provider
|
|
echo json_encode(pushDNS($domainId, $provider, $providerAccountId));
|
|
break;
|
|
|
|
case 'status':
|
|
default:
|
|
echo json_encode([
|
|
'status' => 'ok',
|
|
'endpoints' => [
|
|
'generate' => '?action=generate&domain_id=123',
|
|
'push' => '?action=push&domain_id=123&provider=cloudflare&provider_account_id=1'
|
|
],
|
|
'providers' => ['cloudflare', 'namecheap', 'freedns']
|
|
]);
|
|
}
|
|
|